Page 1 of 1

MASM-Basic File Handling

#1 Hooker  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 5
  • View blog
  • Posts: 29
  • Joined: 17-August 12

Posted 22 October 2012 - 04:35 AM

MASM-Basic file handling
In this tutorial w'ell learn the basic file handling methods.we'll create a simple text editor which can open and save files.
To open and save a file we must fill the OPENFILENAME structure and pass it as parameter for necessary functions.
The members of OPENFILENAME structure are

OPENFILENAME STRUCT


lStructSize DWORD ?
hwndOwner HWND ?
hInstance HINSTANCE ?
lpstrFilter LPCSTR ?
lpstrCustomFilter LPSTR ?
nMaxCustFilter DWORD ?
nFilterIndex DWORD ?
lpstrFile LPSTR ?
nMaxFile DWORD ?
lpstrFileTitle LPSTR ?
nMaxFileTitle DWORD ?
lpstrInitialDir LPCSTR ?
lpstrTitle LPCSTR ?
Flags DWORD ?
nFileOffset WORD ?
nFileExtension WORD ?
lpstrDefExt LPCSTR ?
lCustData LPARAM ?
lpfnHook DWORD ?
lpTemplateName LPCSTR ?


OPENFILENAME ENDS


OPENFILENAME structure has many members but filling the necessary members is enough for us. The necessary members of structure are
lStructSize ->size of the OPENFILENAME structure
hwndOwner ->handle of our main window.
hInstance ->our hInstance
lpstrFilter ->Pointer to a buffer containing pairs of null-terminated filter strings. we can also use NULL but it won't filter our files.
lpstrFile ->we pass the offset of buffer where the filename with fullpath name is stored
nMaxFile ->the size of the lpstrFile buffer.The buffer should be at least 256 characters long.
Flags ->A set of bit flags you can use to initialize the dialog box which determines the style and charecteristics of dialog box.
The above are the frequently filled members of OPENFILENAME structure
lpstrTitle ->Pointer to a string to be placed in the title bar of the dialog box. If NULL or not initialized it use system default (Open)
lpstrInitialDir ->A pointer to the string that specifies initial file directory.If not set it uses the current directory
nFileOffset ->The full file name is stored here after selecting a file from open file dialog box.
lpfnHook ->Pointer to the hook procedure, often not used.

After filling necessary members we can call GetOpenFileName or GetSaveFileName.

I've attached the full source code of the program, we'll discuss only necessary procedures here,

DlgProc proc hWnd:HWND,uMsg:UINT,wParam:WPARAM,lParam:LPARAM
LOCAL rect:RECT
LOCAL SizeReadWrite:DWORD

.if uMsg==WM_INITDIALOG
	invoke GetDlgItem,hWnd,IDC_EDIT
	mov hwndEdit,eax
	;Fill the members of ofn structure
	 mov ofn.lStructSize,SIZEOF ofn 
        push hWnd 
        pop  ofn.hWndOwner 
        push hInstance 
        pop  ofn.hInstance 
        mov  ofn.lpstrFilter, OFFSET FilterString 
        mov  ofn.lpstrFile, OFFSET buffer 
        mov  ofn.nMaxFile,MAXSIZE
.elseif uMsg==WM_SIZE
	invoke GetClientRect,hWnd,addr rect
	invoke MoveWindow,hwndEdit,0,0,rect.right,rect.bottom,TRUE
.elseif uMsg==WM_COMMAND
		.if lParam==0
			mov eax,wParam
		.if ax==IDM_OPEN
			mov  ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY 
			 invoke GetOpenFileName, ADDR ofn 
			.if eax==TRUE
			 invoke CreateFile,ADDR buffer,\ 
				GENERIC_READ or GENERIC_WRITE ,\ 
				FILE_SHARE_READ or FILE_SHARE_WRITE,\ 
				NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,\ 
				NULL 
			mov hFile,eax 
			invoke Allocandlock
			invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
			invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory 
			invoke SetTitle,hWnd
			invoke Cleanup
			.endif
		.elseif ax==IDM_SAVE
			mov ofn.Flags,OFN_LONGNAMES or\ 
                                OFN_EXPLORER or OFN_HIDEREADONLY 
			 invoke GetSaveFileName, ADDR ofn
			.if eax==TRUE
			invoke CreateFile,ADDR buffer,\ 
				GENERIC_READ or GENERIC_WRITE ,\ 
				FILE_SHARE_READ or FILE_SHARE_WRITE,\ 
				NULL,CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,\ 
				NULL			
			mov hFile,eax 
			invoke Allocandlock
			invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory
			mov ebx,eax
			invoke WriteFile,hFile,pMemory,ebx,ADDR SizeReadWrite,NULL
			invoke SetTitle,hWnd
			invoke Cleanup
			.endif
		 .elseif ax==IDM_NEW
			invoke Cleanup
			invoke SetWindowText,hwndEdit,NULL
			invoke SetWindowText,hWnd,addr AppName
		.elseif ax==IDM_EXIT
			invoke PostMessage,hWnd,WM_CLOSE,0,0
		.elseif ax==IDM_ABOUT
			invoke ShellAbout,hWnd,addr AppName,addr Details,0
		.endif
	.endif
.elseif uMsg==WM_CLOSE
	invoke EndDialog,hWnd,0
.else
mov eax,FALSE
ret
.endif
mov eax,TRUE
Ret
DlgProc endp

Cleanup proc
	invoke CloseHandle,hFile 
	invoke GlobalUnlock,pMemory 
	invoke GlobalFree,hMemory
xor eax,eax
Ret
Cleanup endp

Allocandlock proc
       invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE 
       mov  hMemory,eax 
       invoke GlobalLock,hMemory 
       mov  pMemory,eax
xor eax,eax
Ret
Allocandlock endp

SetTitle proc hWin:HWND
       mov     eax,OFFSET buffer 
       movzx  edx,ofn.nFileOffset 
       add      eax,edx 
       invoke SetWindowText,hWin,eax 
xor eax,eax
Ret
SetTitle endp



In this program i have used four procedures so we must include a prototype for every procedure in the beginning of the program.
It is good to have many procedures in our programs to minimize the repetition of the same code again and again.
ok, we'll analyse the above program.
LOCAL rect:RECT
LOCAL SizeReadWrite:DWORD

.if uMsg==WM_INITDIALOG
	invoke GetDlgItem,hWnd,IDC_EDIT
	mov hwndEdit,eax
	;Fill the members of ofn structure
	 mov ofn.lStructSize,SIZEOF ofn 
        push hWnd 
        pop  ofn.hWndOwner 
        push hInstance 
        pop  ofn.hInstance 
        mov  ofn.lpstrFilter, OFFSET FilterString 
        mov  ofn.lpstrFile, OFFSET buffer 
        mov  ofn.nMaxFile,MAXSIZE


As we know dialog boxes dosen't send WM_CREATE message instead they use WM_INITDIALOG message. This seems the suitable place for filling the necessary members of openfilename structure and get the handles for the controls we created in the resource editor.
We use GetDlgItem to get handle of our editcontrol. we fill the members of ofn as discussed above.
we also define two local variables in stack for later use.

.elseif uMsg==WM_SIZE
	invoke GetClientRect,hWnd,addr rect
	invoke MoveWindow,hwndEdit,0,0,rect.right,rect.bottom,TRUE



Every window recieves WM_SIZE message after once created we use this oppurtunity for resizing our edit control to the whole window size. We call GetClientRect API which retrieves the coordinates of a window's client area the right and bottom members contain the width and height of the window.Then we call MoveWindow function to resize our edit control to the client area size.(we can also use GetWindowRect API function)
.elseif uMsg==WM_COMMAND
		.if lParam==0
			mov eax,wParam
		.if ax==IDM_OPEN
			mov  ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY 
			 invoke GetOpenFileName, ADDR ofn 
			.if eax==TRUE
			 invoke CreateFile,ADDR buffer,\ 
				GENERIC_READ or GENERIC_WRITE ,\ 
				FILE_SHARE_READ or FILE_SHARE_WRITE,\ 
				NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,\ 
				NULL 
			mov hFile,eax 


WM_COMMAND message is sent when the user selects a command item from a menu.we confirm that message is send from the menu by checking the lParam is NULL. Incase of message from button controls and others things we recive handle of the button control in lParam so it won't be NULL.We have selected Open in menu item.
Then its time set out flags for our ofn structure
OFN_PATHMUSTEXIST -> specifies user can type only valid path and filenames.
OFN_FILEMUSTEXIST -> Specifies that the user can type only names of existing files in the File Name entry field.
OFN_LONGNAMES -> this flag cause dialogbox to use long file names
OFN_EXPLORER -> To use explorer like interface in Dialogbox
OFN_HIDEREADONLY ->hides readonly checkbox

Everything is set it's time to call GetOpenFileName function which returns TRUE in eax if a file is selected.Then we create a file with Createfile API function in the access modes we use GENERIC_READ or GENERIC_WRITE as the term explains we can read and write data in file, To set how the file is shared we use FILE_SHARE_READ or FILE_SHARE_WRITE,we dont use any security attributes so set as NULL.
Then we set what should be done incase of file exist and does not exist.
OPEN_EXISTING ->Opens the file. The function fails if the file does not exist.
FILE_ATTRIBUTE_ARCHIVE The file should be archived. Applications use this attribute to mark files for backup or removal.and we use NULL for the flags since we dont need any. Then we save the handle of the file.

invoke Allocandlock


The we use our procedure we defined which contains the code to allocate and lock file in memory.
Allocandlock proc
       invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE 
       mov  hMemory,eax 
       invoke GlobalLock,hMemory 
       mov  pMemory,eax
xor eax,eax
Ret
Allocandlock endp



We use GlobalAlloc function which allocates the specified number of bytes from the heap.MEM_MOVEABLE - Allocates movable memory,
GMEM_ZEROINIT - Initializes memory contents to zero.
Then we store the handle of the memory.The GlobalLock function locks a global memory object and returns a pointer we store it as pointer for our memory.we clear contents of eax and return from the procedure.

	invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
	invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory 


ReadFile function read data from the file from the position indicated by the pointer. we specify the 'number of bytes to be read' in which the total memory block that can be allocated by GlobalAlloc function is 65536 minus 1(ie,MEMSIZE-1 would be 65534) nearly full of the memory block that can be allocated by GlobalAlloc function.number of bytes read is where the function stores how many bytes were actually read.
Then we set the text in our edit control with WM_SETTEXT message.
	invoke SetTitle,hWnd
	invoke Cleanup


After displaying the text we should change the title of window and clean the mess (Free our memory). For thet i use two procedures
SetTitle proc hWin:HWND
       mov     eax,OFFSET buffer 
       movzx  edx,ofn.nFileOffset 
       add      eax,edx 
       invoke SetWindowText,hWin,eax 
xor eax,eax
Ret
SetTitle endp

Cleanup proc
	invoke CloseHandle,hFile 
	invoke GlobalUnlock,pMemory 
	invoke GlobalFree,hMemory
xor eax,eax
Ret
Cleanup endp



In the SetTitle proc add the contents of buffer and ofn.nFileOffset to obtain the name of the file we opened. In the cleanup proc we have closed the handle, Unlocked the memory and freed the memory.

		.elseif ax==IDM_SAVE
			mov ofn.Flags,OFN_LONGNAMES or\ 
                                OFN_EXPLORER or OFN_HIDEREADONLY 
			 invoke GetSaveFileName, ADDR ofn
			.if eax==TRUE
			invoke CreateFile,ADDR buffer,\ 
				GENERIC_READ or GENERIC_WRITE ,\ 
				FILE_SHARE_READ or FILE_SHARE_WRITE,\ 
				NULL,CREATE_NEW,FILE_ATTRIBUTE_ARCHIVE,\ 
				NULL			
			mov hFile,eax 
			invoke Allocandlock
			invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory
			mov ebx,eax
			invoke WriteFile,hFile,pMemory,ebx,ADDR SizeReadWrite,NULL
			invoke SetTitle,hWnd
			invoke Cleanup
			.endif


Similarly we set flags to call GetSaveFileName function and do same things as we did while opening a file, but we have used WM_GETTEXT since we are reading the contents of editbox and using WriteFile function we save the contents.

		.elseif ax==IDM_NEW
			invoke Cleanup
			invoke SetWindowText,hwndEdit,NULL
			invoke SetWindowText,hWnd,addr AppName
		.elseif ax==IDM_EXIT
			invoke PostMessage,hWnd,WM_CLOSE,0,0
		.elseif ax==IDM_ABOUT
			invoke ShellAbout,hWnd,addr AppName,addr Details,0



If we selected new in menuitem we clean the handles and free the memory, delete contents of edit control and restore our title bar.
In case we clicked Exit we post WM_CLOSE message then WM_CLOSE message will be placed in queue, when the turn comes program exits.
Finally if we clicked about we display the shell about box(predefined about box) with contents what we need to display.

Attached File(s)

  • Attached File  Dic.zip (15.07K)
    Number of downloads: 224


Is This A Good Question/Topic? 0
  • +

Replies To: MASM-Basic File Handling

#2 GunnerInc  Icon User is offline

  • "Hurry up and wait"
  • member icon




Reputation: 858
  • View blog
  • Posts: 2,277
  • Joined: 28-March 11

Posted 22 October 2012 - 03:37 PM

It is always a good idea to "zero" out any structure before use, so any unused members will be 0. This is important especially if a structure is on the stack, also windows will fill in members when you call GetOpen/SaveFilename and this being global struct, it will contain "stuff" you might not want to pass to the next call. There are also cases where NOT zeroing out the OPENFILENAME will strange and random bugs/crashes.

Otherwise good job, keep it up.
Was This Post Helpful? 1
  • +
  • -

#3 Hooker  Icon User is offline

  • New D.I.C Head
  • member icon

Reputation: 5
  • View blog
  • Posts: 29
  • Joined: 17-August 12

Posted 22 October 2012 - 06:26 PM

Thanks for the tip! ,I would keep in mind next time.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1