Hi,

I've recently started learning asm, but one thing I'm stuck with at the moment is the equivalent of returning a string in a high level language.

Eg, I've got this PROC which reads data from a socket:



WS_ReadData PROC
invoke ioctlsocket, sock, FIONREAD, addr sizetoread
invoke GlobalAlloc, GHND, sizetoread
mov mHandle, eax
invoke GlobalLock, eax
mov recvbuffer, eax
invoke recv, sock, recvbuffer, sizetoread, 0
.if eax==SOCKET_ERROR
invoke MessageBox, NULL, addr txt2, addr MsgBoxCaption, MB_OK
.else
mov ebx, recvbuffer
invoke lstrcpy, addr response, addr recvbuffer
invoke MessageBox, NULL, response, addr MsgBoxCaption, MB_OK
;invoke MessageBox, NULL, recvbuffer, addr MsgBoxCaption, MB_OK
.endif
invoke GlobalUnlock, recvbuffer
invoke GlobalFree, mHandle
ret
WS_ReadData ENDP


and this is what's used to call it and 'so stuff' with the result.



invoke WS_ReadData
invoke lstrcpy, addr debugText, ebx
;invoke SetDlgItemText, hWnd, IDC_EDIT, addr recvbuffer
invoke MessageBox, NULL, addr debugText, addr MsgBoxCaption, MB_OK


This is how it is because I've read that it's best to use a reg to return data. So I've assumed that ebx is ok and I put the address of the data in there. Then pick that back up at the calling side and continue, but it doesn't work.

Can anyone help?

Cheers.

...akenny
Posted on 2001-09-01 17:52:30 by akenny
here are a few things to get you started:

    [*]Use eax as register for return value.. this is the default register and is used by all windows functions, so it's really recommended that you use it for your own procedures as well
    [*]You can return a string by returning it's address in eax.. You already did this with ebx, just change this to eax
    [*]The problem with your code is that you use GlobalUnlock/GlobalFree before you return. This means that the string is destroyed when the function returns.. As you return the address of a string, and not the string itself, you can't deallocate this string... instead, let the calling part do the unallock/free, or use a buffer in the .data? section instead of allocating one.
    [*]invoke lstrcpy, addr response, addr recvbuffer
    here, recvbuffer isn't a buffer, it is a variable that contains the address of the buffer, so remove the addr here:
    invoke lstrcpy, addr response, recvbuffer
    [*]When you return the string pointer in eax, note that windows functions only preserve ebx, esi and edi (and of course esp and ebp), so you should set eax at the end of the procedure to make sure it's not overwritten by any other function.


    Hope this helps,

    Thomas
Posted on 2001-09-01 18:04:22 by Thomas
Thanks for the help.

It's a bit late here for my brain to work through your advice, but I'll try it tomorrow.

Thanks for clearing up a few things (especially a couple that I didn't know about).

I've read through most asm tutorials on the web, but what would you recommend (apart from Iczelion's) for this type of info?

Thanks again,

...akenny
Posted on 2001-09-01 18:18:42 by akenny
Actually got to Thomas' web page and read his Tut's as well. They are quickly being established as a warm-up level set of tutorial before you get to IcZelions stuff. (No offense, but the nature of your question is discussed in these tut's, and more).

Just click on the "www" icon below his message and "surf" :)

PS: If you dont want to take my word for it, read his guest book...

NaN
Posted on 2001-09-02 00:35:27 by NaN
To get flexible/reusable code, I suggest passing the output buffer
address as an argument to your procedure.

To achieve easily readable source, I suggest using anywhere
you're accessing memory. You *have* to use them when dereferencing
registers, so I suggest that you use them on variables too. Makes
it easier to see what's going on if you skim quickly through your code.
Posted on 2001-09-02 10:17:02 by f0dder