News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

fread or readfile?

Started by Ani_Skywalker, October 31, 2011, 05:36:49 PM

Previous topic - Next topic

Ani_Skywalker

What is the difference between these two? I assume ReadFile is a call to the Win 32 API function with the same name? Is fread the equivalent of a macro that calls ReadFile in the end? I can't find the include-files where fread is defined. Where should I search for it?

Also, here is my code, it works but you guys can probably see bad standards in it. Feel free to let me know about it.

include \masm32\include\masm32rt.inc ; All includes needed for comon MASM32-programming

.code
start:

call main
inkey ; Wait for input to close console
exit

main proc
local hFile :HANDLE
local count :DWORD
local buffer :PTR BYTE

mov hFile, fopen("008.dat")
mov count, fread(hFile, addr buffer, 1001)
fclose hFile
ret
main endp


end start



jj2007

\masm32\macros\macros.asm:
  ; ------------------------------------------------
  ; read data from an open file into a memory buffer
  ; ------------------------------------------------
    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


It is actually not the most efficient code, as it needs a global variable. Here is an alternative:
push eax ; create a slot for bytes read
mov eax, esp
invoke ReadFile, hFile, lpBuffer, bytes, eax, 0
pop eax ; bytes read

ToutEnMasm

Masm use macro.
When you don't know if it is a macro  or a function proceed as follow.
Put    .NOLIST a the start of your source
Before the instruction you want to know:
         .LISTALL
Just after the instruction you want to know:
         .NOLIST
Made a listing.
and in the listing ,if it is a macro ,you see his code expanded as this
Quote

            .NOLIST
               .LISTALL
                  SET_CRT_DEBUG_FIELD _CRTDBG_LEAK_CHECK_DF   
000002ED  6A FF      *       push    -000000001h
000002EF  E8 00000000 E   *       call   _CrtSetDbgFlag
000002F4  83 C4 04      *       add    esp, 000000004h
              1      invoke _CrtSetDbgFlag,_CRTDBG_REPORT_FLAG
              1      ;Returns the previous state of _crtDbgFlag
000002F7  83 C8 20        1      or eax,_CRTDBG_LEAK_CHECK_DF
000002FA  50         *       push   eax
000002FB  E8 00000000 E   *       call   _CrtSetDbgFlag
00000300  83 C4 04      *       add    esp, 000000004h
              1      invoke _CrtSetDbgFlag,eax
               .NOLIST



dedndave

push eax ; create a slot for bytes read
mov eax, esp
invoke ReadFile, hFile, lpBuffer, bytes, eax, 0
pop eax ; bytes read


Jochen, better if you return the count in ECX
EAX holds the status   :U

another way to go...
push eax ; create a slot for bytes read
mov eax, esp
invoke ReadFile, hFile, lpBuffer, bytes, eax, 0
pop ecx ; bytes read
cmp ecx,bytes

now, the macro returns with ZF set if bytes requested = bytes read
and, EAX has the return status

Ani_Skywalker

Now, pretend I prefer to call ReadFile directly, like this:

mov hFile, fopen("fread-readfile.dat")
push 0
push 81
push ptr$(lpBuffer)
push hFile


Wouldn't it be faster? This compiles, but gives some kind of error in runtime, the error looks to be memory-related?

dedndave

the small differences in speed are minimal compared to the time consumed by the ReadFile call
macros are handy - they can save you some typing
however, when you are learning how things work, they hide a lot of stuff

Ani_Skywalker

Dave: Yeah, that is one of the reasons I refuse to use macros. Got it to work by the way, had forgot one parameter when calling. But bellow code both compiles and runs without error.

mov hFile, fopen("fread-readfile.dat")
push 0
push bytesRead
push ptr$(lpBuffer)
push 81
push hFile
call ReadFile

dedndave

i noticed that, in your original post, you allocated 1 byte for the buffer   :P
        INCLUDE \masm32\include\masm32rt.inc

;----------------------------------------------------------

BYTES_TO_READ EQU 1001
BUFFER_SIZE   EQU 1024

;----------------------------------------------------------

        .DATA

szFileName db '008.dat',0

szErrOpen  db 'Error Opening File',13,10,0
szErrRead  db 'Error Reading File',13,10,0
szSuccess  db 'Read File Successful',13,10,0

;----------------------------------------------------------

        .CODE

main    PROC

        LOCAL   hFile:HANDLE
        LOCAL   Count:DWORD
        LOCAL   Buffer[BUFFER_SIZE]:BYTE

        INVOKE  CreateFile,offset szFileName,GENERIC_READ,FILE_SHARE_READ,
                NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL
        mov     edx,offset szErrOpen
        or      eax,eax
        jz      Report2

        mov     hFile,eax
        INVOKE  ReadFile,eax,addr Buffer,BYTES_TO_READ,addr Count,NULL
        mov     edx,offset szErrRead
        or      eax,eax
        jz      Report1

        mov     edx,offset szSuccess

Report1:
        push    edx
        INVOKE  CloseHandle,hFile
        pop     edx

Report2:
        print   edx
        ret

main    ENDP

;----------------------------------------------------------

Start:  call    main
        inkey
        exit

;----------------------------------------------------------

        END     Start

jj2007

Quote from: dedndave on October 31, 2011, 07:22:07 PM
Jochen, better if you return the count in ECX
EAX holds the status   :U
Yes, but the status is pretty useless:
QuotelpNumberOfBytesRead
Points to the number of bytes read. ReadFile sets this value to zero before doing any work or error checking
Comparing NumberOfBytesRead to zero or to the requested count is therefore a safer way to check for errors.

jj2007

Quote from: Ani_Skywalker on October 31, 2011, 07:58:04 PM
      push 0         
      push bytesRead   <<<<<<<<< sure?
      push ptr$(lpBuffer)  <<<<<<<<< attention dangerous macro!
      push 81
      push hFile   
      call ReadFile

Ani_Skywalker

Quote from: jj2007 on October 31, 2011, 08:23:18 PM
      push 0         
      push bytesRead   <<<<<<<<< sure?
      push ptr$(lpBuffer)  <<<<<<<<< attention dangerous macro!
      push 81
      push hFile   
      call ReadFile

Well, not sure, but I use an uninitialized variable, should be almost as good as setting it to zero, or? The docs suggest zero though: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx

Ah, why is it a dangerous macro and how can I turn that line to pure assembly?

jj2007

Quote from: Ani_Skywalker on October 31, 2011, 10:25:12 PM
Quote from: jj2007 on October 31, 2011, 08:23:18 PM
      push 0         
      push bytesRead   <<<<<<<<< sure?
      push ptr$(lpBuffer)  <<<<<<<<< attention dangerous macro!
      push 81
      push hFile   
      call ReadFile

Well, not sure, but I use an uninitialized variable, should be almost as good as setting it to zero, or? The docs suggest zero though: http://msdn.microsoft.com/en-us/library/windows/desktop/aa365467%28v=vs.85%29.aspx

Check the order of your paras. The doc uses the invoke order, you are pushing, so you must invert everything.

Quote
Ah, why is it a dangerous macro and how can I turn that line to pure assembly?

Just pulling your leg... but you better check what the macro does.

Gunner

Look at the file macros.asm in your masm32\macros directory to see the code of all the macros and how they are done :)
~Rob (Gunner)
- IE Zone Editor
- Gunners File Type Editor
http://www.gunnerinc.com

qWord

local buffer[1024]:BYTE
local bytesRead:DWORD
...
push 0
lea eax,bytesRead
push eax
push SIZEOF buffer
lea eax,buffer
push eax
push hFile
call ...
FPU in a trice: SmplMath
It's that simple!

Ani_Skywalker

Quote from: jj2007 on October 31, 2011, 10:35:09 PM
Check the order of your paras. The doc uses the invoke order, you are pushing, so you must invert everything.

But isn't that exactly what I am doing? I push the first parameter last, the second to first second to last, and so on? Then when the cpu reads it from the stack it should come in reverse order, meaning the first one comes first etc. Or have I got it wrong?