File
I/O under Win32 bears remarkable semblance to that under DOS. The steps
needed are the same. You only have to change interrupts to API calls and
it's done. The required steps are the followings:
[hwnd:
0
ClassName:
'SimpleWinClass' 0
AppName:
'Our Main Window' 0
MenuName:
'FirstMenu' 0
DlgName:
'MyDialog' 0
TestString:
'Hello, everybody' 0]
____________________________________________________________________________________________
[CR 13 LF 10]
[IDM_EXIT 1 IDM_ABOUT 2 IDC_EDIT 3000 IDC_BUTTON 3001 IDC_EXIT 3002 DialogID 1000]
[MenuID 2000 M00_File 2001 M00_Open 2002 M00_Save_as 2003 M00_Exit 2004]
____________________________________________________________________________________________
; Window Class Structure:
[DLGWINDOWEXTRA 30]
[WindowClassEx:
wc_Size: len wc_style: &CS_HREDRAW+&CS_VREDRAW
WndProc: MainWindowProc
wc_ClsExtra: 0 wc_WndExtra: DLGWINDOWEXTRA
hInstance: 0
wc_hIcon: 0 wc_hCursor:
0
wc_hbrBackground: 6
wc_MenuName: MenuID wc_ClassName: ClassName
wc_hIconSm: 0]
[FilterStrings:
B§ 'All Files' 0 '*.*' 0
'Text Files' 0 '*.txt' 0 0]
[UserFileFilter:
0 # 50] [FullChoosenFile: 0 #50] [ChoosenFile: 0 #20]
[OFN_FLAGS
&OFN_FILEMUSTEXIST+&OFN_PATHMUSTEXIST+&OFN_LONGNAMES+&OFN_EXPLORER+&OFN_HIDEREADONLY]
[OpenFileNameStructure:
len hwndFileOwner: 0 OF_hInstance: 0 FilterStrings
userFileFilter 200 &NULL FullChoosenFile 200
ChoosenFile
200 &NULL OpenFileTitle OFN_FLAGS
nFileOffsetinChoosenFile: W§ 0 nFileExtensioninChoosenFile:
0
DefaultExtension: D§ &NULL
HookCustomData: &NULL HookProcPtr: &NULL HookTemplateName:
0]
[OpenFileTitle:
'-=Our First Open File Dialog Box=-: Choose the file to open' 0]
[EditClass: 'edit'0] [EditID 1]
[FileHandle: 0 FileSize: 0 FileMemory: 0 pMemory: 0 SizeReadWrite: 0]
[FirstMessage:
0 #7]
__________________________________________________________________________________________
Main:
call 'Kernel32.GetModuleHandleA' 0 | mov D§hInstance eax, D§OF_hinstance eax
call 'User32.LoadIconA' &NULL &IDI_APPLICATION | mov D§wc_hIcon eax, D§wc_hIconSm eax
call 'User32.LoadCursorA' 0 &IDC_ARROW | mov D§wc_hCursor eax
call 'User32.RegisterClassExA' WindowClassEx
call 'User32.CreateWindowExA' &WS_EX_CLIENTEDGE ClassName
AppName,
&WS_OVERLAPPEDWINDOW &CW_USEDEFAULT &CW_USEDEFAULT 300 200,
&NULL &NULL D§hInstance 0
mov D§hwnd eax, D§hwndFileOwner eax
call 'User32.ShowWindow' D§hwnd &SW_SHOWNORMAL | call 'User32.UpdateWindow'
D§hwnd
jmp L1>
L0:
call 'User32.TranslateMessage' Firstmessage
call 'User32.DispatchMessageA' Firstmessage
L1: call 'User32.GetMessageA' FirstMessage 0 0 0
cmp eax 0 | ja L0<
call 'Kernel32.ExitProcess' 0
_______________________________________________________________________________________
[AddString
| mov esi #1 | While B§esi ne 0 | movsb | End_While]
[NextLine
| mov al CR | stosb | mov al LF | stosb]
[EditHandle: 0]
Proc
MainWindowProc:
Arguments @Adressee, @Message, @wParam, @lParam
pushad
.If D@Message = &WM_DESTROY
call 'User32.PostQuitMessage' &NULL
.Else_If D@Message = &WM_COMMAND
mov eax D@wParam
..If D@lParam = 0
...If ax = M00_Open
call 'Comdlg32.GetOpenFileNameA' OpenFileNameStructure
On eax = &TRUE, call LoadFile
call 'User32.SetFocus' EditHandle
...Elseif ax = M00_Save_as
call 'Comdlg32.GetSaveFileNameA' OpenFileNameStructure
On eax = &TRUE, call WriteFile
call 'User32.SetFocus' EditHandle
...Else
call 'User32.DestroyWindow' D§hWnd
...End_If
..End_If
.Else_If D@Message = &WM_CREATE
call 'User32.CreateWindowExA' &NULL EditClass &NULL,
&WS_VISIBLE+&WS_CHILD+&ES_MULTILINE+&ES_AUTOHSCROLL+&ES_AUTOVSCROLL,
0 0 0 0 D@Adressee EditID D§hInstance &NULL
mov D§EditHandle eax
call 'User32.SetFocus' D§EditHandle
.Else_If D@Message = &WM_SIZE
mov eax D@lParam, edx eax | shr edx 16 | and eax 0FFFF
call 'User32.MoveWindow' D§EditHandle 0 0 eax edx &TRUE
.Else
popad
call 'User32.DefWindowProcA' D@Adressee D@Message D@wParam D@lParam
Exit
.End_If
popad | mov eax &FALSE
EndP
_______________________________________________________________________________________
LoadFile:
call 'KERNEL32.CreateFileA' FullChoosenFile,
&GENERIC_READ+&GENERIC_WRITE,
&FILE_SHARE_READ+&FILE_SHARE_WRITE,
&NULL &OPEN_EXISTING &FILE_ATTRIBUTE_ARCHIVE &NULL
mov D§FileHandle eax
call 'KERNEL32.GetFileSize' D§FileHandle &NULL | and eax
0FFFF | mov D§FileSize eax
call 'KERNEL32.GlobalAlloc' &GPTR D§FileSize | mov D§pMemory
eax
call 'KERNEL32.ReadFile' D§FileHandle D§pMemory D§FileSize
SizeReadWrite &NULL
call 'User32.SendMessageA' D§EditHandle &WM_SETTEXT &NULL
D§pMemory
call 'KERNEL32.CloseHandle' D§FileHandle
call 'KERNEL32.GlobalFree' D§pMemory
ret
_______________________________________________________________________________________
WriteFile:
call 'KERNEL32.CreateFileA' FullChoosenFile,
&GENERIC_READ+&GENERIC_WRITE,
&FILE_SHARE_READ+&FILE_SHARE_WRITE,
&NULL &CREATE_NEW &FILE_ATTRIBUTE_ARCHIVE &NULL
mov D§FileHandle eax
call 'KERNEL32.GlobalAlloc' &GMEM_MOVEABLE+&GMEM_ZEROINIT D§FileSize
mov D§FileMemory eax
call 'KERNEL32.GlobalLock' D§FileMemory
mov D§pMemory eax
call 'User32.SendMessageA' D§EditHandle &WM_GETTEXT D§FileSize
D§pMemory
call 'KERNEL32.WriteFile' D§FileHandle D§pMemory eax SizeReadWrite
&NULL
call 'KERNEL32.CloseHandle' D§FileHandle
call 'KERNEL32.GlobalUnlock' D§pMemory
call 'KERNEL32.GlobalFree' D§FileMemory
ret
call 'User32.CreateWindowExA' &WS_EX_CLIENTEDGE ClassName
AppName,
&WS_OVERLAPPEDWINDOW &CW_USEDEFAULT &CW_USEDEFAULT 300 200,
&NULL &NULL D§hInstance 0
mov D§hwnd eax, D§hwndFileOwner eax
In
WM_CREATE section, we create an edit control. Note that the parameters
that specify x, y, width,height of the control are all zeroes since we
will resize the control later to cover the whole client area of the parent
window.
Note
that in this case, we don't have to call ShowWindow to make the edit control
appear on the screen because we include WS_VISIBLE style. You can use this
trick in the parent window too.
After
creating the edit control, we take this time to initialize the members
of ofn. Because we want to reuse ofn in the save as dialog box too, we
fill in only the *common* members that're used by both GetOpenFileName
and GetSaveFileName.
WM_CREATE
section is a great place to do once-only initialization.
.Else_If D@Message = &WM_SIZE
mov eax D@lParam, edx eax | shr edx 16 | and eax 0FFFF
call 'User32.MoveWindow' D§EditHandle 0 0 eax edx &TRUE
We
receive WM_SIZE messages when the size of the client area of our main window
changes. We also receive it when the window is first created. In order
to be able to receive this message, the window class styles must include
CS_VREDRAW and CS_HREDRAW styles. We use this opportunity to resize our
edit control to the same size as the client area of the parent window.
First we have to know the current width and height of the client area of
the parent window. We get this info from lParam. The high word of lParam
contains the height and the low word of lParam the width of the client
area. We then use the information to resize the edit control by calling
MoveWindow function which, in addition to changing the position of the
window, can alter the size too.
...If ax = M00_Open
call 'Comdlg32.GetOpenFileNameA' OpenFileNameStructure
On eax = &TRUE, call LoadFile
call 'User32.SetFocus' EditHandle
When the user selects File/Open menu item, we fill in the Flags member of ofn structure and call GetOpenFileName function to display the open file dialog box.
On eax = &TRUE, call LoadFile
call 'User32.SetFocus' EditHandle
After the user selects a file to open, we call CreateFile to open the file. We specifies that the function should try to open the file for read and write. After the file is opened, the function returns the handle to the opened file which we store in a global variable for future use. This function has the following syntax:
CreateFile
proto lpFileName:DWORD,\
dwDesiredAccess:DWORD,\
dwShareMode:DWORD,\
lpSecurityAttributes:DWORD,\
dwCreationDistribution:DWORD\,
dwFlagsAndAttributes:DWORD\,
hTemplateFile:DWORD
dwDesiredAccess specifies which operation you want to perform on the file.
call 'KERNEL32.GlobalAlloc' &GPTR D§FileSize | mov D§pMemory eax
When
the file is opened, we allocate a block of memory for use by ReadFile and
WriteFile functions. We specify GMEM_MOVEABLE flag to let Windows
move the memory block around to consolidate memory. GMEM_ZEROINIT flag
tells GlobalAlloc to fill the newly allocated memory block with zeroes.
When
GlobalAlloc returns successfully, eax contains the handle to the allocated
memory block. We pass this handle to GlobalLock function which returns
a pointer to the memory block.
call 'KERNEL32.ReadFile' D§FileHandle D§pMemory D§FileSize
SizeReadWrite &NULL
call 'User32.SendMessageA' D§EditHandle &WM_SETTEXT &NULL
D§pMemory
When
the memory block is ready for use, we call ReadFile function to read data
from the file. When a file is first opened or created, the file pointer
is at offset 0. So in this case, we start reading from the first byte in
the file onwards. The first parameter of ReadFile is the handle of the
file to read, the second is the pointer to the memory block to hold the
data, next is the number of bytes to read from the file, the fourth param
is the address of the variable of DWORD size that will be filled with the
number of bytes actually read from the file.
After
we fill the memory block with the data, we put the data into the edit control
by sending WM_SETTEXT message to the edit control with lParam containing
the pointer to the memory block. After this call, the edit control shows
the data in its client area.
call 'KERNEL32.CloseHandle' D§FileHandle
call 'KERNEL32.GlobalFree' D§pMemory
At this point, we have no need to keep the file open any longer since our purpose is to write the modified data from the edit control to another file, not the original file. So we close the file by calling CloseHandle with the file handle as its parameter. Next we unlock the memory block and free it. Actually you don't have to free the memory at this point, you can reuse the memory block during the save operation later. But for demonstration purpose , I choose to free it here.
call 'User32.SetFocus' D§EditHandle
When
the open file dialog box is displayed on the screen, the input focus shifts
to it. So after the open file dialog is closed, we must move the input
focus back to the edit control.
This
end the read operation on the file. At this point, the user can edit the
content of the edit control.And when he wants to save the data to another
file, he must select File/Save as menuitem which displays a save as dialog
box. The creation of the save as dialog box is not much different from
the open file dialog box. In fact, they differ in only the name of the
functions, GetOpenFileName and GetSaveFileName. You can reuse most members
of the ofn structure too.
mov ofn.Flags,OFN_LONGNAMES or\
OFN_EXPLORER or OFN_HIDEREADONLY
The
dwCreationDistribution parameter of the CreateFile function must be changed
to CREATE_NEW since we want to create a new file.
The
remaining code is identical to those in the open file section except the
following:
call 'User32.SendMessageA' D§EditHandle &WM_GETTEXT D§FileSize
D§pMemory
call 'KERNEL32.WriteFile' D§FileHandle D§pMemory eax SizeReadWrite
&NULL
We
send WM_GETTEXT message to the edit control to copy the data from it to
the memory block we provide, the return value in eax is the length of the
data inside the buffer. After the data is in the memory block, we write
them to the new file.