Here are my simple file handling functions coded with Poasm. Masm and Poasm are using the same object file format, so the assembled procedures can be used with Masm.

ReadFileToMem :

.386
.model flat,stdcall
option casemap:none

include filefunc.inc

READFILE_MEMINFO STRUCT

    hHeap      DWORD  ?
    hMem        DWORD  ?
    FileSize    DWORD  ?

READFILE_MEMINFO ENDS   

PUBLIC  ReadFileToMem@8

.code

;  ReadFileToMem PROC pFileName:DWORD,pMemInfo:DWORD

;  pFileName      :  pointer to name of the file
;  pMemInfo        :  pointer to structure for allocated memory information

;  Return values  :  if the function succeeds, eax is NULL.
;                      if the function fails, the return value contains the error code                     


ReadFileToMem@8:

    sub    esp,2*4                            ; reserve 8 bytes for the local variables
    push    esi
    mov    esi,DWORD PTR
    invoke  GetProcessHeap
    test    eax,eax
    jne    @f
    mov    eax,1
    jmp    error
@@:
    mov    READFILE_MEMINFO.hHeap,eax ; save the handle of the process heap
    invoke  CreateFile,DWORD PTR ,GENERIC_READ,0,0,\
            OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,0
    cmp    eax,INVALID_HANDLE_VALUE
    jne    @f
    mov    eax,2
    jmp    error
@@:
    mov    DWORD PTR ,eax              ; save the handle of file
    invoke  GetFileSize,eax,0
    mov    READFILE_MEMINFO.FileSize,eax
    invoke  HeapAlloc,READFILE_MEMINFO.hHeap,HEAP_ZERO_MEMORY,eax
    mov    READFILE_MEMINFO.hMem,eax      ; save the address of the allocated memory
    lea    ecx,DWORD PTR               ; get the address of number of bytes read
    invoke  ReadFile,DWORD PTR ,eax,READFILE_MEMINFO.FileSize,ecx,0
    test    eax,eax
    jnz    @f
    mov    eax,3
    jmp    error
@@:   
    invoke  CloseHandle,DWORD PTR
    xor    eax,eax

error:   
   
    pop    esi
    add    esp,2*4                        ; balance the stack
    ret    2*4

;  ENDP ReadFileToMem

END


WriteFileToDisc :


.386
.model flat,stdcall
option casemap:none

include filefunc.inc

PUBLIC  WriteFileToDisc@12

.code

;  WriteFileToDisc PROC pFileName:DWORD,pMemory:DWORD,nSize:DWORD

;  pFileName      :  pointer to name of the file
;  pMemory        :  address of buffer to write file
;  nSize          :  number of bytes to write

;  Return values  :  if the function succeeds, eax is non-NULL
;                  :  if the function fails, the return value is NULL   


WriteFileToDisc@12:

    sub    esp,2*4                ; reserve 8 bytes for the local variables
    invoke  CreateFile,DWORD PTR ,GENERIC_WRITE,0,0,\
            CREATE_ALWAYS,FILE_ATTRIBUTE_ARCHIVE,0
    cmp    eax,INVALID_HANDLE_VALUE
    jne    @f
    xor    eax,eax
    jmp    finish
@@:
    mov    DWORD PTR ,eax    ; save the handle of file
    lea    ecx,DWORD PTR   ; get the address of number of bytes written
    invoke  WriteFile,eax,DWORD PTR ,DWORD PTR ,ecx,0
    test    eax,eax
    jz      finish
    invoke  CloseHandle,DWORD PTR

finish:

    add    esp,2*4                ; balance the stack
    ret    3*4

;  ENDP WriteFileToDisc

END


FreeMemory :

.386
.model flat,stdcall
option casemap:none

HeapFree PROTO :DWORD,:DWORD,:DWORD

READFILE_MEMINFO STRUCT

    hHeap      DWORD  ?
    hMem        DWORD  ?
    FileSize    DWORD  ?

READFILE_MEMINFO ENDS   

PUBLIC FreeMemory@4

.code

;  FreeMemory  PROC pMemInfo

;  pMemInfo    :  pointer to structure for allocated memory information

FreeMemory@4:

    mov    eax,DWORD PTR
    invoke  HeapFree,READFILE_MEMINFO.hHeap,0,READFILE_MEMINFO.hMem
    ret    4

;  ENDP FreeMemory

END
Attachments:
Posted on 2007-12-29 07:55:24 by Vortex
A bit of (constructive, hopefully) criticism:

EAX is 0, not NULL, on error... you really should only talk about NULL when dealing with pointer values.

Why are you using HEAP_ZERO_MEMORY when you're going to fill the entire allocated memory with data read from file? Waste of CPU cycles :)

Why are you using a hHeap when you only support using the process default heap?

It's probably a better idea to do away with the heap and use VirtualAlloc instead, unless most files read this way will be <4kb. And if you're dealing with a lot of small files, perhaps you should use a separate heap to reduce fragmentation of the main heap...
Posted on 2007-12-29 10:14:22 by f0dder
Since asm does not support type casting like ((void *)0) - the ANSI definition of NULL, I assume that NULL is equal to 0 for practical programming. You can think that it's a kind of simulation of NULL pointer. Normally, the NULL pointer and 0 are not the same thing but this assumption should be a solution to make easier the life. You can think it like this one : engineering calculations are always an approximation as they cannot give exact results like in mathematics.

I am accustomed to use HEAP_ZERO_MEMORY. You are right, I can replace it with HEAP_GENERATE_EXCEPTIONS

hHeap is preserved with the intention to limit the call to GetProcessHeap to one time. The user would like to use hHeap to allocate another block of memory. My FreeMemory function also uses this value to release the allocated memory block.

It's in my mind to create another version of ReadFileToMem using VirtualAlloc. The heap functions are OK for small files and practical programming.

Posted on 2007-12-30 03:48:16 by Vortex

Since asm does not support type casting like ((void *)0) - the ANSI definition of NULL, I assume that NULL is equal to 0 for practical programming. You can think that it's a kind of simulation of NULL pointer. Normally, the NULL pointer and 0 are not the same thing but this assumption should be a solution to make easier the life. You can think it like this one : engineering calculations are always an approximation as they cannot give exact results like in mathematics.

Yes, NULL is equal to 0 (and for ISO C++, actually defined as 0 instead of the ANSI-C pointer type), but you have to consider the semantic value of using NULL - it's traditionally been used when dealing with pointer values, so when seeing a NULL, most people will expect that the argument is a pointer. Using NULL for zero integers is plain confusing.

You could also use NULL instead of MB_OK, you could use POWER_ACTION_CRITICAL instead of GENERIC_READ, etc... do you catch my drift? :)


I am accustomed to use HEAP_ZERO_MEMORY. You are right, I can replace it with HEAP_GENERATE_EXCEPTIONS

Just pass a 0 instead, indicating you don't need any special options. Using HEAP_GENERATE_EXCEPTIONS would require you to set up exception-handling code...


hHeap is preserved with the intention to limit the call to GetProcessHeap to one time. The user would like to use hHeap to allocate another block of memory. My FreeMemory function also uses this value to release the allocated memory block.

This is pretty much a non-optimization, GetProcessHeap is a very inexpensive call, instead you waste a bit of memory for every open file. Okay, I can't think of any scenario where the memory would add up enough to be a problem, but as long as you're only using the default process heap, there isn't much use in storing hHeap.


It's in my mind to create another version of ReadFileToMem using VirtualAlloc. The heap functions are OK for small files and practical programming.

Yes, the heap is good for small allocations, that's what is what meant for. And VirtualAlloc rounds your size allocations up to 4kb, as well as aligning the memory to 64kb boundaries, so it's only good when you're dealing with larger allocations... but in that situation, I'd choose it over heap functions any time, any day.

Anyway, hope you don't take this as your code being bashed, it's a few relatively minor points on the way to perfection :)
Posted on 2007-12-30 05:49:50 by f0dder
This is pretty much a non-optimization, GetProcessHeap is a very inexpensive call, instead you waste a bit of memory for every open file. Okay, I can't think of any scenario where the memory would add up enough to be a problem, but as long as you're only using the default process heap, there isn't much use in storing hHeap.


Storing hHeap should be more faster than calling repeatly GetProcessHeap Optimizing every line of this routine does not worth much, very few people would be interested in a super-optimized ReadFile function. Anyway, calling GetProcessHeap of stroring the value should not be an issue here.

I have no problem with your comments.
Posted on 2007-12-30 06:26:31 by Vortex

Storing hHeap should be more faster than calling repeatly GetProcessHeap Optimizing every line of this routine does not worth much, very few people would be interested in a super-optimized ReadFile function. Anyway, calling GetProcessHeap of stroring the value should not be an issue here.

Slightly faster, yes, but it's a micro-optimization that's pretty pointless; all GetProcessHeap does is giving you a value from the TEB, no ring3<>ring0 stuff going on. For the sake of completeness and considering how simple the function is, I suppose it's okay to post the disassembly here:


.text:7D4D8DF9 GetProcessHeap  proc near
.text:7D4D8DF9                mov    eax, large fs:18h
.text:7D4D8DFF                mov    eax,
.text:7D4D8E02                mov    eax,
.text:7D4D8E05                retn
.text:7D4D8E05 GetProcessHeap  endp


So sure, it's slightly faster not calling it, but you'll have a hard time measuring any performance gain. It's funny that you say "very few people would be interested in a super-optimized ReadFile function", but still have applied a micro-optimization like this :)
Posted on 2007-12-30 06:46:34 by f0dder