Author Topic: Writing files  (Read 3882 times)

gelatine1

  • Member
  • **
  • Posts: 217
Writing files
« on: June 13, 2014, 05:55:13 AM »
Hello, I have been trying to do some file handling but it is not working quite well. From iczelions tutorial I got that I had Several steps to do :
  • Allocate a block of memory by calling GlobalAlloc. This function returns a handle to the requested memory block.
  • "Lock" the memory block by calling GlobalLock. This function accepts a handle to the memory block and returns a pointer to the memory block.
  • You can use the pointer to read or write memory.
  • "Unlock" the memory block by calling GlobalUnlock . This function invalidates the pointer to the memory block.
  • Free the memory block by calling GlobalFree. This function accepts the handle to the memory block.

And that I should also use this :

  • Open or Create the file by calling CreateFile function. This function is very versatile: in addition to files, it can open communication ports, pipes, disk drives or console. On success, it returns a handle to file or device. You can then use this handle to perform operations on the file or device.

    Move the file pointer to the desired location by calling SetFilePointer.
  • Perform read or write operation by calling ReadFile or WriteFile. These functions transfer data from a block of memory to or from the file. So you have to allocate a block of memory large enough to hold the data.
  • Close the file by calling CloseHandle. This function accepts the file handle.

I tried to use this to write to a file in an assembly program but it simply crashes (together with the MSDN reference). I don't really know what is going wrong or where. Does anyone see my mistake ? The code is below:

Code: [Select]
.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
include \masm32\include\masm32.inc
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib

.data
file db "C:\hi.txt",0 ;file to open

.data?
pmem dd ? ;memory pointer
hmem dd ? ; memory handle
fhandle dd ? ; file handle

.code
start:
invoke GlobalAlloc,GHND,65535 ; Allocate memory
mov hmem,eax

invoke GlobalLock,hmem ;Get pointer of memory
mov pmem,eax

mov ax,65
shl eax,16
mov ax,66 ;Set eax to "AB"

mov [pmem],eax

invoke CreateFile, file, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL ;Create the file
mov fhandle,eax

invoke WriteFile, fhandle, pmem, 128, NULL, NULL ;write the "AB" to the file

invoke CloseHandle, fhandle ;close file handle

invoke GlobalUnlock,hmem
invoke GlobalFree,hmem


end start

I believe my mistake is somewhere using the pmem stuff but I am not sure. Any help is welcome,
Jannes

dedndave

  • Member
  • *****
  • Posts: 8825
  • Still using Abacus 2.0
    • DednDave
Re: Writing files
« Reply #1 on: June 13, 2014, 06:11:50 AM »
Code: [Select]
mov ax,65
shl eax,16
mov ax,66 ;Set eax to "AB"

mov [pmem],eax

2 issues, here

first, you can
Code: [Select]
    mov     eax,410042h   ;this is actually "BA" - because lower-order bytes are written to lower-order addresses
but, more importantly...
the mov [pmem] instruction overwrites the pointer - oops!
for masm syntax,
Code: [Select]
    mov     [pmem],eaxis the same as
Code: [Select]
    mov     pmem,eaxwriting to the address of a stored pointer is an illegal operation

what you want to do is to get the pointer into a register, then write to the address
as it happens, the pointer is already in EAX   :biggrin:
Code: [Select]
invoke GlobalLock,hmem ;Get pointer of memory
mov pmem,eax
        mov dword ptr [eax],420041h   ;"AB"

jj2007

  • Member
  • *****
  • Posts: 10107
  • Assembler is fun ;-)
    • MasmBasic
Re: Writing files
« Reply #2 on: June 13, 2014, 07:16:17 AM »
Code: [Select]
mov ax,65
shl eax,16
mov ax,66 ;Set eax to "AB"

mov [pmem],eax
...
Code: [Select]
    mov     eax,410042h   ;this is actually "BA" - because lower-order bytes are written to lower-order addresses

Jannes,
Are you sure you want Unicode? For ANSI, it would be
mov al,65
   shl eax, 8
   mov al, 66 ;Set eax to "AB"

and, more precisely in your case:
   mov pmem, eax
        mov dword ptr [eax], 4241h   ;"AB"
        ; mov dword ptr [eax], "BA"     ; "AB" in human-readable format ;-)

If you really want Unicode instead, remember that most editors expect a BOM.

gelatine1

  • Member
  • **
  • Posts: 217
Re: Writing files
« Reply #3 on: June 13, 2014, 08:43:20 PM »
Thanks for the replies :) I wanted to use ANSI indeed and I did not know that writing to the address of a stored pointer is an illegal operation.
Still I am getting a runtime error. I used Ollydbg and I found that after executing the call to CreateFile it gets stuck on this line (I don't even know how it got there)
address opcode instruction
778EF7DA 8A10 MOV DL,BYTE PTR DS: [EAX]

EDIT:
I was randomly playing with the code and then I found out that if I replace the
Code: [Select]
invoke CreateFile, addr file, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
mov fhandle,eax
by
Code: [Select]
invoke CreateFile, addr file, GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL
mov ecx,eax
mov fhandle,ecx

Then the code works as expected but in my opinion this does not make sense... So could anyone please explain me why this worked ?
Thanks in advance
« Last Edit: June 13, 2014, 09:48:15 PM by gelatine1 »

qWord

  • Member
  • *****
  • Posts: 1473
  • The base type of a type is the type itself
    • SmplMath macros
Re: Writing files
« Reply #4 on: June 13, 2014, 10:11:28 PM »
I did not know that writing to the address of a stored pointer is an illegal operation.
It is not illegal, but it  makes not much sense (in your program) to overwrite the pointer value itself. Also, movable memory is not needed (-> use GMEM_FIXED or GPTR) and you should check the return values of the API calls (especially for memory allocation).
Then the code works as expected but in my opinion this does not make sense... So could anyone please explain me why this worked ?
luck!? Or maybe an invalid handle value stops WriteFile from using an invalid pointer.

Code: [Select]
include \masm32\include\masm32rt.inc

BUFFER_SIZE EQU 128

.const
szfile db "hi.txt",0 ; file to open
.code
main proc
LOCAL pmem:PBYTE
LOCAL fhandle:HANDLE
LOCAL NumberOfBytesWritten:DWORD
LOCAL NumberOfBytesToWrite:DWORD

invoke GlobalAlloc,GPTR,BUFFER_SIZE ; Allocate memory, zero initialized
.if eax
mov pmem,eax

mov WORD ptr [eax],"BA"
mov NumberOfBytesToWrite,2

invoke CreateFile, ADDR szfile, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ;Create the file
mov fhandle,eax

.if eax == INVALID_HANDLE_VALUE
fn MessageBox,0,LastError$(),"can not create file",MB_OK
.else

invoke WriteFile, fhandle, pmem, NumberOfBytesToWrite, ADDR NumberOfBytesWritten, NULL ;write the "AB" to the file

mov eax,NumberOfBytesToWrite
.if NumberOfBytesWritten != eax
; handle error
.endif

invoke CloseHandle, fhandle ;close file handle

.endif

invoke GlobalFree,pmem
.endif
invoke ExitProcess,0
main endp
end main
MREAL macros - when you need floating point arithmetic while assembling!