Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1812705
  • 博文数量: 290
  • 博客积分: 10653
  • 博客等级: 上将
  • 技术积分: 3178
  • 用 户 组: 普通用户
  • 注册时间: 2007-10-24 23:08
文章存档

2013年(6)

2012年(15)

2011年(25)

2010年(86)

2009年(52)

2008年(66)

2007年(40)

分类:

2007-12-29 16:41:12

Tutorial 12: Memory Management and File I/O

第十二课:内存管理和文件输入输出 


We will learn the rudimentary of memory management and file i/o operation in this tutorial. In addition we'll use common dialog boxes as input-output devices.

我们将在这一课中学习内存管理的基本原理和文件的I/O操作。另外我们将用通用对话框作为输入输出设备。

Download the example here.

Theory:

原理:

Memory management under Win32 from the application's point of view is quite simple and straightforward. Each process owns a 4 GB memory address space. The memory model used is called flat memory model. In this model, all segment registers (or selectors) point to the same starting address and the offset is 32-bit so an application can access memory at any point in its own address space without the need to change the value of selectors. This simplifies memory management a lot. There's no "near" or "far" pointer anymore.

从应用程序的角度来看WIN32中的内存管理是非常简单和直接的.每个程序都拥有4GB的地址空间.这种内存模式叫做平坦内存模式.在这种模式中,所有的段寄存器(或选择器)都指向同一个开始地址并且偏移量是32位的,所以一个应用程序能在它的地址空间中访问任何地址而不需要改变段选择器的值. 这种内存管理模式简单了很多.在平坦模式中再也没有了 near far 指针.( 即段内和段间转移) 
Under Win16, there are two main categories of memory API functions: Global and Local. Global-type API calls deal with memory allocated in other segments thus they're "far" memory functions. Local-type API calls deal with the local heap of the process so they're "near" memory functions. Under Win32, these two types are identical. Whether you call GlobalAlloc or LocalAlloc, you get the same result.

win16,有两种主要类型的内存API函数: 全局的和局部的.全局类型的API函数调用处理在其他段中内存分配(编译中的静态分配)从而它们是”far”内存函数. .局部类型的API调用处理一个过程的局部内存堆(编译中的动态分配)所以它们是”near”内存函数.win32,这两种类型是一样的.无论你调用的是GlobalAlloc(全局分配) 或是 LocalAlloc(局部分配),你得到的结果是一样的.


Steps in allocating and using memory are as follows:

分配和使用内存的步骤如下:

  1. Allocate a block of memory by calling GlobalAlloc. This function returns a handle to the requested memory block.

通过调用GlobalAlloc分配一个内存块.这个函数返回一个请求到的(向操作系统请求) 内存块.

  1. "Lock" the memory block by calling GlobalLock. This function accepts a handle to the memory block and returns a pointer to the memory block.

通过调用GlobalLock锁住这个内存块。这个函数接收一个内存块句柄并返回这个内存块指针。(锁住的内存块)

  1. You can use the pointer to read or write memory.

你能用指针读或写内存。

  1. "Unlock" the memory block by calling GlobalUnlock . This function invalidates the pointer to the memory block.

通过调用GlobalUnlock函数为锁住的内存块解锁。这个函数使指向那个内存块的指针无效。

  1. Free the memory block by calling GlobalFree. This function accepts the handle to the memory block.

通过调用GlobalFree函数释放申请到的内存块。这个函数接收一个内存块句柄。

You can also substitute "Global" by "Local" such as LocalAlloc, LocalLock,etc.

你也能用“Local”代替“Global”例如LocalAllocLocalLock等。


The above method can be further simplified by using a flag in GlobalAlloc call, GMEM_FIXED. If you use this flag, the return value from Global/LocalAlloc will be the pointer to the allocated memory block, not the memory block handle. You don't have to call Global/LocalLock and you can pass the pointer to Global/LocalFree without calling Global/LocalUnlock first. But in this tutorial, I'll use the "traditional" approach since you may encounter it when reading the source code of other programs.

上面这些方法能通过在GlobalAlloc调用中使用一个GMEM_FIXED标志而得到进一步的简化。如果你用这个标志,从Global/localAlloc中返回的值将是一个指向已分配内存块的指针,而不是内存块句柄。你也没必要再调用Global/LocalLock这个函数来锁定内存块 并且 在释放内存时 你能传递这个指针给Global/LocalFree而不用首先调用Global/LocalUnlock函数来为这个内存块解锁。但是在这一课中,我将使用“传统的方法因为当你阅读其他程序的源代码时你可能遭遇它 。

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:

win32中的文件i/o操作比起在DOS中的文件i/o操作具有显著的外表(伪装),但需要的步骤是相同的。你仅需要的是把DOS中的中断调用变成API调用。   下面的步骤是必须的:

  1. 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.

通过调用CreateFile函数来打开或创建文件。这个函数是非常有用的: 除文件外,它能打开通信端口,管道,磁盘驱动器或控制台。如果成功的话,它将返回一个文件或设备的句柄。然后,你能用这个句柄完成对文件和设备的操作。通过调用SetFilePointer函数来把文件指针移到想读写的地方。

  1. 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.

通过调用ReadFileWriteFile来完成读或写操作。这些函数在内存块和文件之间传递数据。所以你必须分配一个足够大的内存块来容纳数据。

  1. Close the file by calling CloseHandle. This function accepts the file handle.

 通过调用CloseHandle函数来关闭文件。这个函数接收一个文件句柄。

Content:

内容:

The program listed below displays an open file dialog box. It lets the user select a text file to open and shows the content of that file in an edit control in its client area. The user can modify the text in the edit control as he wishes, and can choose to save the content in a file.

下面的程序清单显示一个打开文件对话框。它让用户选择一个文本文件来打开并将文件的内容显示在一个编辑控件的客户区内。用户能在编辑框中按他希望的形式修改文本,并且能选择保存文件内容。

.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib

.const
IDM_OPEN equ 1
IDM_SAVE equ 2
IDM_EXIT equ 3
MAXSIZE equ 260
MEMSIZE equ 65535

EditID equ 1                            ; ID of the edit control

.data
ClassName db "Win32ASMEditClass",0
AppName  db "Win32 ASM Edit",0
EditClass db "edit",0
MenuName db "FirstMenu",0
ofn   OPENFILENAME <>
FilterString db "All Files",0,"*.*",0
             db "Text Files",0,"*.txt",0,0
buffer db MAXSIZE dup(0)

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndEdit HWND ?                               ; Handle to the edit control
hFile HANDLE ?                                   ; File handle
hMemory HANDLE ?                            ;handle to the allocated memory block
pMemory DWORD ?                            ;pointer to the allocated memory block
SizeReadWrite DWORD ?                   ; number of bytes actually read or write

.code
start:
    invoke GetModuleHandle, NULL
    mov    hInstance,eax
    invoke GetCommandLine
    mov CommandLine,eax

    invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
    invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:SDWORD
    LOCAL wc:WNDCLASSEX
    LOCAL msg:MSG
    LOCAL hwnd:HWND
    mov   wc.cbSize,SIZEOF WNDCLASSEX
    mov   wc.style, CS_HREDRAW or CS_VREDRAW
    mov   wc.lpfnWndProc, OFFSET WndProc
    mov   wc.cbClsExtra,NULL
    mov   wc.cbWndExtra,NULL
    push  hInst
    pop   wc.hInstance
    mov   wc.hbrBackground,COLOR_WINDOW+1
    mov   wc.lpszMenuName,OFFSET MenuName
    mov   wc.lpszClassName,OFFSET ClassName
    invoke LoadIcon,NULL,IDI_APPLICATION
    mov   wc.hIcon,eax
    mov   wc.hIconSm,eax
    invoke LoadCursor,NULL,IDC_ARROW
    mov   wc.hCursor,eax
    invoke RegisterClassEx, addr wc
    invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,\
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
           CW_USEDEFAULT,300,200,NULL,NULL,\
           hInst,NULL
    mov   hwnd,eax
    invoke ShowWindow, hwnd,SW_SHOWNORMAL
    invoke UpdateWindow, hwnd
    .WHILE TRUE
        invoke GetMessage, ADDR msg,NULL,0,0
        .BREAK .IF (!eax)
        invoke TranslateMessage, ADDR msg
        invoke DispatchMessage, ADDR msg
    .ENDW
    mov     eax,msg.wParam
    ret
WinMain endp

WndProc proc uses ebx hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
    .IF uMsg==WM_CREATE
        invoke CreateWindowEx,NULL,ADDR EditClass,NULL,\
                   WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or\
                   ES_AUTOHSCROLL or ES_AUTOVSCROLL,0,\
                   0,0,0,hWnd,EditID,\
                   hInstance,NULL
        mov hwndEdit,eax
        invoke SetFocus,hwndEdit
;==============================================
;        Initialize the members of OPENFILENAME 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
        mov eax,lParam
        mov edx,eax
        shr edx,16
        and eax,0ffffh
        invoke MoveWindow,hwndEdit,0,0,eax,edx,TRUE
    .ELSEIF uMsg==WM_DESTROY
        invoke PostQuitMessage,NULL
    .ELSEIF uMsg==WM_COMMAND
        mov eax,wParam
        .if lParam==0
            .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 GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
                    mov  hMemory,eax
                    invoke GlobalLock,hMemory
                    mov  pMemory,eax
                    invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
                    invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,pMemory
                    invoke CloseHandle,hFile
                    invoke GlobalUnlock,pMemory
                    invoke GlobalFree,hMemory
                .endif
                invoke SetFocus,hwndEdit
            .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 GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
                        mov  hMemory,eax
                        invoke GlobalLock,hMemory
                        mov  pMemory,eax
                        invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory
                        invoke WriteFile,hFile,pMemory,eax,ADDR SizeReadWrite,NULL
                        invoke CloseHandle,hFile
                        invoke GlobalUnlock,pMemory
                        invoke GlobalFree,hMemory
                    .endif
                    invoke SetFocus,hwndEdit
                .else
                    invoke DestroyWindow, hWnd
                .endif
            .endif
        .ELSE
            invoke DefWindowProc,hWnd,uMsg,wParam,lParam
            ret
.ENDIF
xor    eax,eax
ret
WndProc endp
end start


Analysis:

分析:

        invoke CreateWindowEx,NULL,ADDR EditClass,NULL,\
                   WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or\
                   ES_AUTOHSCROLL or ES_AUTOVSCROLL,0,\
                   0,0,0,hWnd,EditID,\
                   hInstance,NULL
        mov hwndEdit,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.

WM_CREATE节区中,我们创建一个编辑控件。注意指定控件的xywidthheight参数为空是因为我们稍后将调整这个控件的大小来覆盖整个父窗口的客户区。注意在这个例子中,我们没有必要调用ShowWindow函数来让这个控件显示在屏幕上因为我们包含了WS_VISIBLE样式。你也在父窗口中用这个技巧。

;==============================================
; Initialize the members of OPENFILENAME 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

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.

在创建了编辑控件后,我们初始化ofn结构成员变量。因为在保存文件对话框中还要用到这个结构,所以我们只初始化它的公共成员变量,这些公共成员将被GetOpenFileNameGetSaveFileName函数使用。
WM_CREATE section is a great place to do once-only initialization.

WM_CRREATE 消息的是对变量仅初始化一次的好地方。

    .ELSEIF uMsg==WM_SIZE
        mov eax,lParam
        mov edx,eax
        shr edx,16
        and eax,0ffffh
        invoke MoveWindow,hwndEdit,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.

当主窗口客户区大小被改变的时候我们收到WM_SIZE消息。在窗口第一次创建的时候我们同样能接收到这个消息。为了能接收到这个消息,窗口样式必须包含CS_VREDRAWCS_HREDRAW样式。这个时候我们将编辑控件的大小调整得和父窗口客户区一样大。首先,我们必须知道当前父窗口客户区的宽和高。lParam的高子节包含客户区的高度,低子节包含客户区的宽度。然后我们通过调用MoveWindow函数来使用这些信息从而调整编辑控件的大小。该函数不仅能改变窗口位置而且还能改变窗口大小。

            .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

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.

当用户选定文件/打开菜单项时,我们填写ofn结构的Flags成员变量并调用GetOpenFileName函数来显示一个打开文件对话框。

                .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

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函数来打开这个文件。我们指定标志位来让打开的文件能够读和写。在文件被打开后,这个函数将返回被打开的文件句柄,为了方便以后使用我们将它存储在一个全局变量中。这个函数句法如下:

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.

dwDesiredAccess指定你想在这个文件上完成的操作。

  • Open the file to query its attributes. You have to rights to read or write the data.
  • 0 打开文件并查询它的属性。你必须有权限读写它的数据。
  • GENERIC_READ   Open the file for reading.
  •        以只读方式打开文件。
  • GENERIC_WRITE  Open the file for writing.
  •        以只写方式打开文件。

dwShareMode specifies which operation you want to allow other processes to perform on the file that 's being opened.

  指定其他进程在你打开的文件上允许执行的操作。

  • 0  Don't share the file with other processes.
  • 0 不和其他进程共享这个文件
  • FILE_SHARE_READ  allow other processes to read the data from the file being opened
  •  允许其它进程从这个打开的文件中读数据。
  • FILE_SHARE_WRITE  allow other processes to write data to the file being opened.
  • 允许其它进程从这个打开的文件中写数据。 

lpSecurityAttributes has no significance under Windows 95.

该属性在win95中无效。
dwCreationDistribution specifies the action CreateFile will perform when the file specified in lpFileName exists or when it doesn't exist.

指定 当文件指定在lpFileName中的成员存在或不存在的时候CreateFile函数将执行的动作

  • CREATE_NEW Creates a new file. The function fails if the specified file already exists.
  • CREATE_NEW创建一个新文件.如果指定文件已经存在,函数无效.
  • CREATE_ALWAYS Creates a new file. The function overwrites the file if it exists.
  • CREATE_ALWAYS创建一个新文件.如果指定的文件存在,函数重写这文件.
  • OPEN_EXISTING Opens the file. The function fails if the file does not exist.
  • OPEN_EXISTING 打开文件.如果文件不存在,函数无效.
  • OPEN_ALWAYS Opens the file, if it exists. If the file does not exist, the function creates the file as if dwCreationDistribution were CREATE_NEW.
  • OPEN_ALWAYS 打开文件,如果文件存在的话.如果文件不存在,函数创建这个文件如同dwCreationDistribution 参数的值为CREATE_NEW.
  • TRUNCATE_EXISTING Opens the file. Once opened, the file is truncated so that its size is zero bytes. The calling process must open the file with at least GENERIC_WRITE access. The function fails if the file does not exist.
  • TRUNCATE_EXISTING 打开文件.一旦打开,文件被截所以它的大小是零字节.调用进程必须打开文件并且至少有GENETIC_WRITE访问权.如果文件不存在函数失效.

dwFlagsAndAttributes specifies the file attributes

dwFlagsAndAttributes 指定文件属性.

  • FILE_ATTRIBUTE_ARCHIVE The file is an archive file. Applications use this attribute to mark files for backup or removal.
  • FILE_ATTRIBUTE_ARCHIVE 文件是一档案文件.应用程序可以用这个属性作为文件备份和删除的标志.
  • FILE_ATTRIBUTE_COMPRESSED The file or directory is compressed. For a file, this means that all of the data in the file is compressed. For a directory, this means that compression is the default for newly created files and subdirectories.
  • FILE_ATTRIBUTE_COMPRESSED 文件或目录是压缩的.对于文件,意味着所有在文件中的数据都被压缩.对一目录,意味着对于新生成的文件和子目录的压缩是默认的.
  • FILE_ATTRIBUTE_NORMAL The file has no other attributes set. This attribute is valid only if used alone.
  • FILE_ATTRIBUTE_NORMAL 文件没有其它的属性设置.仅当该属性单独使用时属性才是有效的.
  • FILE_ATTRIBUTE_HIDDEN The file is hidden. It is not to be included in an ordinary directory listing.
  • FILE_ATTRIBUTE_HIDDEN 文件是隐藏文件.它并不包含在普通的目录列表中.
  • FILE_ATTRIBUTE_READONLY The file is read only. Applications can read the file but cannot write to it or delete it.
  • FILE_ATTRIBUTE_READONLY 文件是只读文件.应用程序能读这个文件但是不能写这个文件或是删除它.
  • FILE_ATTRIBUTE_SYSTEM The file is part of or is used exclusively by the operating system.
  • FILE_ATTRIBUTE_SYSTEM 文件是操作系统专用的一部分.即系统文件.

                    invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE
                    mov  hMemory,eax
                    invoke GlobalLock,hMemory
                    mov  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.

当文件被打开时,我们分配一块内存供ReadFileWriteFile函数使用.我们指定GMEM_MOVEABLE标志让Windows移动分配内存块周围的内存来整理内存.GMEM_ZERO INIT标志告诉GlobalAlloc函数用零将新分配的内存块填满.GlobalAlloc返回成功,eax包含分配内存块的句柄.我们传递这个句柄给GlobalLock函数,这个函数返回内存块的指针.

                    invoke ReadFile,hFile,pMemory,MEMSIZE-1,ADDR SizeReadWrite,NULL
                    invoke SendMessage,hwndEdit,WM_SETTEXT,NULL,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.

当内存块准备好被使用时,我们调用ReadFile函数从文件中读进数据.当文件是第一次被打开或创建时,文件指针在偏移量0的地方 .所以在这个例子中,我们从第一个字节向前的读这个文件.ReadFile的第一个参数是要读的那个文件句柄,第二个参数是存放数据的内存块指针,下一个成员是从文件中读取的字节数.第四个参数是DWORD长度的地址变量,这个成员存放从文件中实际读取的字节数.

在用数据填满这个内存块后,我们通过在WM_SETTEXT消息的lParam中包含内存块的指针并发送WM_SETTEXT消息给编辑控件来把数据放置在编辑控件中。在这个函数调用后,编辑控件将数据显示在它的客户区。

                    invoke CloseHandle,hFile
                    invoke GlobalUnlock,pMemory
                    invoke GlobalFree,hMemory
                .endif

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.

这里需要指出的是,我们再也不需要让文件保持打开状态了,因为我们的目的是把在编辑框中修改了的数据写进其它的文件中而不是原来的文件。所以我们指定文件句柄作为CloseHandle的参数,然后调用这个函数来关闭文件。下一步我们解锁这块内存并释放它。实际上你没必要在这里释放这块内存,你可以在稍后的保存操作中重新使用这块内存。但是作为演示的用途,我在这里选择释放它。

 

                invoke SetFocus,hwndEdit

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 except the Flags member.

当打开文件对话框被显示在屏幕上时,输入焦点切换给它。所以在对话框被关闭后,我们必须移动输入焦点到编辑控件上。

最后是在文件上的写操作。这里需要指出的是,用户能编辑这个编辑控件中的内容。并且当用户想把数据保存在另一个文件中时,他必须选定文件/保存菜单项,这个菜单项弹出一个保存文件对话框。产生的保存对话框和打开文件对话框有很多相似之处。事实上,它们的不同之处仅仅是函数的名字,GetOpenFileName GetSaveFileName。除了标志成员外你可以重新使用ofn结构的大多数成员。

                mov ofn.Flags,OFN_LONGNAMES or\
                                OFN_EXPLORER or OFN_HIDEREADONLY

In our case, we want to create a new file, so OFN_FILEMUSTEXIST and OFN_PATHMUSTEXIST must be left out else the dialog box will not let us create a file that doesn't already exist.
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:

在我们的例子中,我们想创建一个新的文件,所以OFN_FILEMUSTEXISTOFN_PATHMUSTEXIST标志必须被遗弃,否则这个对话框将不能让我们创建一个文件,因为这个文件不是现有的。

CreateFile函数的dwCreationDistribution 参数必须变成CREATE_NEW 因为我们想创建一个新文件。

剩下的代码除了下面这几行,其它的和那些在打开文件节区中的一样:

                        invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory
                        invoke WriteFile,hFile,pMemory,eax,ADDR 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.

 我们发送WM_GETTEXT消息给编辑控件,复制数据到我们预先提供的内存块中。在eax中的返回值是缓冲区中的数据长度。当数据复制到内存块中后,我们把它们写到新文件中。

 


This article come from Iczelion's asm page,

风向改变翻译于 2007-12-29

由于考试复习,放了一段时间。 

阅读(2152) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~