I have just finished a set of macros for performing normal file IO operations. They are almost exclusively wrappers for API file IO functions with a number of extras so that this capacity can be put into function/statement format using names that are closer to historical file operations than disconnected API functions.
The example file uses an include file for the normal prototypes, processor model and the like called masm32rt.inc which is included in the example zip file. It should be placed in the include directory in MASM32.
Feedback, comments and suggestions are welcome. I want this capacity for the next revision/update/version of MASM32.
[attachment deleted by admin]
Hutch,
Thanks for the macro :U
I found a few mistake in the macro.
WriteFile returns a BOOL value to indicate success or failure. The bytes written is returned in the parameter. And so with the ReadFile
Your fwrite and fread macro is
fread MACRO hFile,buffer,bcnt
LOCAL var
.data?
var dd ?
.code
invoke ReadFile,hFile,buffer,bcnt,ADDR var,NULL
mov eax, var
EXITM <eax> ; return bytes read
ENDM
fwrite MACRO hFile,buffer,bcnt
LOCAL var
.data?
var dd ?
.code
invoke WriteFile,hFile,buffer,bcnt,ADDR var,NULL
mov eax, var
EXITM <eax> ; return bytes written
ENDM
Could be simpler
fread MACRO hFile,buffer,bcnt
invoke ReadFile, hFile, buffer, bcnt, ADDR bcnt, NULL
EXITM <eax> ; return success or failed
ENDM
fwrite MACRO hFile, buffer, bcnt
invoke WriteFile, hFile, buffer, bcnt, Addr bcnt, NULL
EXITM <eax> ; return success or failed
ENDM
Peterpan,
I tried your changes and got compile errors. Hutch's version compiles without errors.
Paul
Peter,
Thanks for the effort. I return the DWORD vaiable because it contains useful information on the byte count that is either read or written. You can test for error conditions using GetLastError() as well as getting the return value with the current system.
Hutch,
Arrrggghh... :bdg :'(
Sorry for my english. I should not said that it is a mistake :'(
Maybe it's because of my flu. I had a a great headeache for the last couple days. Actually I just want to make it simpler, that's all.
I changed the macro to be simpler (well, for me of course :green2 ) and it is still return both values. which is the status in EAX, and the bytes read or written is in the parameter directly.
However your macro is more convinience, because we don't have to create a variable. The macro will do it for us :U
So I can call like this ( this code taken from Self Delete thread ):
SelfDelete Proc uses ESI EDI
Local lh_File:HFILE
Local ln_Bytes:DWORD, ln_MajorVersion:DWORD
Local lb_Succeed:BOOL
Local lc_FileName[MAX_PATH]:BYTE
Local l_Buffer[512]:BYTE
lea esi, lc_FileName
lea edi, l_Buffer
invoke GetModuleFileName, hInstance, esi, MAX_PATH
invoke wsprintf, edi, offset BatchText, esi, esi
mov ln_Bytes, FUNC( lstrlen, edi )
mov lh_File, fcreate( offset BatchName )
.If ( lh_File )
mov lb_Succeed, fwrite( lh_File, edi, ln_Bytes )
; lb_Succeed = status
; ln_Bytes = bytes written
fclose lh_File
.If ( lb_Succeed )
invoke ShellExecute, NULL, offset BatchOp, offset BatchName,
NULL, NULL, SW_HIDE
.else
invoke DeleteFile, offset BatchName
.endif
.endif
ret
SelfDelete EndP
Again, I'm sorry for my words. Oh there is one more macro that missing. Flushing the buffers ( FlushFileBuffers API )
pbrennick,
I'm not sure why you have the error. But the difference between the original and the changes I made, is, you have to create the variable your own and pass it in the third parameter, because it also use to return the bytes read or written. The original macro doesn't have to, the macro already take care of it.
Peterpan,
Color me silly. Your SelfDelete code in another thread compiled just fine. Guess I am getting lazy or senile, maybe both. Wouldn't that be fun?
Paul
pbrennick,
No offends, but I think you are just getting lazy. Hehehe.... :bg
Well..that is fine. I see you are one of the most active moderator here
:U
Peterpan,
As was said in my introduction, it is because I am functionally disabled and I pretty much live in a recliner these days. I very seldom walk any more and when I do I must wear braces which are very painful. Anyway, it is really nothing special about me, others would be more active if they had the same free time as I have. I can't wait for Donkey to solve his problems and get back because he is very smart.
Paul
Quote from: Peterpan on February 08, 2005, 04:23:47 PM
fread MACRO hFile,buffer,bcnt
invoke ReadFile, hFile, buffer, bcnt, ADDR bcnt, NULL
EXITM <eax> ; return success or failed
ENDM
Just from looking at this, I'd say pbrennick's compile error came from passing 'ADDR bcnt' to the macro, which then expanded to:
invoke ReadFile, hFile, buffer, bcnt, ADDR ADDR bcnt, NULL
I don't know if there is a standard regarding passing ADDR to macro's or not, but at the very least, you should keep it consistent throughout one single macro :wink
Quote from: pbrennick on February 14, 2005, 04:57:02 PM
As was said in my introduction, it is because I am functionally disabled and I pretty much live in a recliner these days. I very seldom walk any more and when I do I must wear braces which are very painful. Anyway, it is really nothing special about me, others would be more active if they had the same free time as I have. I can't wait for Donkey to solve his problems and get back because he is very smart.
pbrennick,
I truly am sorry to hear that. ::)
When I said "you are getting lazy", I thought that sometimes you get sick & tired to answer all the question, especially newbie's question. I really didn't know about your condition and I have no intention to offended you in anyway. Please accept my apologies :)
BTW, yes I do know Donkey is a smart guy ( as well as all moderators here :U ) ever since win32asmboard.cjb.net
Quote from: zoobaI don't know if there is a standard regarding passing ADDR to macro's or not, but at the very least, you should keep it consistent throughout one single macro
zoobaI agree. Well I kept my macros and other things consistent. However when I posted that, I only want to make it worked, so I didn't think too far :bg
Issues like those mentioned are why I built the macro in this form.
fread MACRO hFile,buffer,bcnt
LOCAL var
.data?
var dd ?
.code
invoke ReadFile,hFile,buffer,bcnt,ADDR var,NULL
mov eax, var
EXITM <eax> ; return bytes read
ENDM
The return value is the data section variable so that the user does not have to set the variable on the stack first.
> The return value is the data section variable so that the user does not have to set the variable on the stack first
That's ok but this strategy is not thread safe. What about a slight modifcation:
fread MACRO hFile,buffer,bcnt
push 0
invoke ReadFile,hFile,buffer,bcnt,ADDR [esp+4],NULL
pop eax
EXITM <eax> ; return bytes read
ENDM
Gustav,
Thansk for the suggestion, its an interesting idea and looks like it is safe enough to use.