x86 Assembler using MASM32 Tutorial 8 - Open & Read from Existing Files



Watch the video or follow the tutorial.



Here, in tutorial 8 we will have a little look at opening and reading from files that already exist on our hard drive. We will open a text file using the Windows API function CreateFile and then read the contents of the file and display the result in a MessageBox. So, first of all open Visual MASM, if you haven't installed Visual MASM yet you can learn how to do it here. Once installed open it and learn create the default code template needed for all my tutorials here. This default code will be the starting point for most of our tutorials including this one. So, once all this is done you should be looking at the code window as seen below:


Scroll down until you see the .data section and add the following code:

openError DB "Error Creating File", 0
fileName DB "D:\Temp\File.txt", 0
errorCaption DB "Error", 0
successCaption DB "Success", 0
errorRead DB "Unable to Read from File", 0


Then scroll down to the uninitialised data section which starts with .data? and add the following code:

fhandle DD ?
bytesRead DD ?
bytesBuffer BYTE 50 DUP(?)

Then scroll down until you see the .code section and underneath the label start: and add the following code:

; CreateFile Function, Fails if no FIle Exists
Push 0
Push FILE_ATTRIBUTE_NORMAL
Push OPEN_EXISTING
Push 0
Push 0
Push GENERIC_READ
Push Offset fileName
Call CreateFile

Mov fhandle, Eax
Cmp Eax, 0FFFFFFFFh

Jnz file_opened

; If Error Previous Jump Ignored and Now We Declare Error With a MessageBox
Push MB_OK
Push Offset errorCaption
Push Offset openError
Push 0
Call MessageBox

Jmp end_

file_opened:

; Read from file
Push 0
Lea Eax, bytesRead
Push Eax
Push SIZEOF bytesBuffer
Lea Eax, bytesBuffer
Push Eax
Push fhandle
Call ReadFile

Cmp bytesRead, 0
Jnz bytes_have_been_read

; Error Reading from File
Push MB_OK
Push Offset errorCaption
Push Offset errorRead
Push 0
Call MessageBox

Jmp end_

bytes_have_been_read:

Push MB_OK
Push Offset successCaption
Push Offset bytesBuffer
Push 0
Call MessageBox

; Close file
Push fhandle
Call CloseHandle

end_:

The first function call is to CreateFile using the OPEN_EXISTING parameter which opens an existing file at the location named in the fileName variable. On my computer the location is D:\Temp so you should change this line to whatever location you have access to on your computer. The file name is not so important just make sure that the file exists at that location or an error will occur. After the CreatfIle function is complete the contents of the Eax register is loaded into the fhandle variable. If the CreateFile function was successful then the Eax register will hold the memory address of the handle to the created file, if not it will hold an error code. The compare command tests to see the Eax register holds the error code and if it doesn't the jump if not zero command takes us the part of the code that should run if the file is ready to be read. If the Eax register does hold an error code then a message box is displayed reporting the error and the program ends.

If the file is ready to be read then we read the contents of the file into the bytesBuffer variable which needs to be long enough to hold the entire contents of the file. A compare between the variable bytesRead and zero is conducted and if there was an error reading from the file then bytesRead will be zero, if not then it will be non-zero. Either way the appropriate message box is displayed showing the contents of the file if no error occurred and reporting an error message if it did. The program then ends.

The entire code looks like this:

; *************************************************************************
; 32-bit Windows Program
; *************************************************************************

.686                                      ; Enable 80686+ instruction set
.model flat, stdcall                ; Flat, 32-bit memory model (not used in 64-bit)
option casemap: none         ; Case sensitive syntax

; *************************************************************************
; MASM32 proto types for Win32 functions and structures
; *************************************************************************
include c:\masm32\include\windows.inc
include c:\masm32\include\user32.inc
include c:\masm32\include\kernel32.inc
include c:\masm32\include\masm32rt.inc     ; for using ustr$() and such like

; *************************************************************************
; MASM32 object libraries
; *************************************************************************
includelib c:\masm32\lib\user32.lib
includelib c:\masm32\lib\kernel32.lib

; *************************************************************************
; Our data section.
; *************************************************************************
.data

openError DB "Error Creating File", 0
fileName DB "D:\Temp\File.txt", 0
errorCaption DB "Error", 0
successCaption DB "Success", 0
errorRead DB "Unable to Read from File", 0

; *************************************************************************
; Our unintialised data section.
; *************************************************************************
.data?

fhandle DD ?
bytesRead DD ?
bytesBuffer BYTE 50 DUP(?)

; *************************************************************************
; Our constant section.
; *************************************************************************
.const



; *************************************************************************
; Macros
; *************************************************************************



; *************************************************************************
; Our executable assembly code starts here in the .code section
; *************************************************************************
.code

start:

     ; CreateFile Function, Fails if no FIle Exists
     Push 0
     Push FILE_ATTRIBUTE_NORMAL
     Push OPEN_EXISTING
     Push 0
     Push 0
     Push GENERIC_READ
     Push Offset fileName
     Call CreateFile

     Mov fhandle, Eax
     Cmp Eax, 0FFFFFFFFh

     Jnz file_opened

     ; If Error Previous Jump Ignored and Now We Declare Error With a MessageBox
     Push MB_OK
     Push Offset errorCaption
     Push Offset openError
     Push 0
     Call MessageBox

     Jmp end_

file_opened:

     ; Read from file
     Push 0
     Lea Eax, bytesRead
     Push Eax
     Push SIZEOF bytesBuffer
     Lea Eax, bytesBuffer
     Push Eax
     Push fhandle
     Call ReadFile

     Cmp bytesRead, 0
     Jnz bytes_have_been_read

     ; Error Reading from File
     Push MB_OK
     Push Offset errorCaption
     Push Offset errorRead
     Push 0
     Call MessageBox

     Jmp end_

bytes_have_been_read:

     Push MB_OK
     Push Offset successCaption
     Push Offset bytesBuffer
     Push 0
     Call MessageBox

     ; Close file
     Push fhandle
     Call CloseHandle

end_:

     ; Exit App
     Push 0
     Call ExitProcess

end start


Thank you for following this tutorial, I hope you found it useful. In the next tutorial we will talk a little bit about user created functions, so until then, enjoy.

Link to a text file with complete source code and more comments - here.