📄 lion-tut-c13.htm
字号:
<H3><FONT
color=#ff0000>分析:</FONT></H3><B>
invoke CreateFile,ADDR buffer,\</B>
<BR><B>
GENERIC_READ ,\</B>
<BR><B>
0,\</B>
<BR><B>
NULL,OPEN_EXISTING,FILE_ATTRIBUTE_ARCHIVE,\</B>
<BR><B>
NULL</B>
<P>当用户选择打开文件时,我们调用CreateFile来打开。注意我们指定GENERIC_READ(一般的读)来表示我们打开的文件只能够读出,把dwShareMode设成0,表示我们不想其他进程在我们操作文件时来存取该文件。
<P><B>
invoke CreateFileMapping,hFileRead,NULL,PAGE_READONLY,0,0,NULL</B>
<P>我们调用CreateFileMapping来在打开的文件的基础上生成内存映射文件。CreateFileMapping的语法如下:
<P><B>CreateFileMapping proto hFile:DWORD,\</B>
<BR><B>
lpFileMappingAttributes:DWORD,\</B>
<BR><B>
flProtect:DWORD,\</B>
<BR><B>
dwMaximumSizeHigh:DWORD,\</B>
<BR><B>
dwMaximumSizeLow:DWORD,\</B>
<BR><B>
lpName:DWORD</B>
<P>您应当知道该函数并没有必要把整个文件映射到内存中去,您可以用该函数来只映射文件的一部分。您可以在参数dwMaximumSizeHigh和dwMaximumSizeLow中指定内存映射文件的大小,如果您指定的值大于实际的文件,则实际的文件将增长到指定的大小,如果想要映射的内存大小正好和文件的实际大小相等,则把两个参数中都设成为0。您可以设定lpFileMappingAttributes为NULL,让WINDOWS赋予该内存映射文件于缺省的安全属性。<BR>flProtect定义了内存映射文件的保护属性,我们指定它为PAGE_READONLY来规定该内存映射文件只能够读。注意该属性不能和CreateFile中指定的属性相矛盾,否则就不能生成内存映射文件。<BR>lpName指定内存映射文件的名称,如果您想要该内存映射文件同时可以供其它的进程使用,就必须给它取个名称。不过在我们的例子中,只有我们的进程使用该内存映射文件故我们忽略该参数。
<P><B>
mov eax,OFFSET buffer</B>
<BR><B>
movzx edx,ofn.nFileOffset</B>
<BR><B>
add eax,edx</B>
<BR><B>
invoke SetWindowText,hWnd,eax</B>
<P>如果函数CreateFileMapping调用成功,我们把窗口的标题条换成被打开文件的名称。保存在缓冲区中的文件名是带有路径的全文件名,所以为了只显示文件名我们需要利用OPENFILENAME结构体中的成员nFileOffset的值来找到文件名的起始地址。
<P><B>
invoke EnableMenuItem,hMenu,IDM_OPEN,MF_GRAYED</B>
<BR><B>
invoke EnableMenuItem,hMenu,IDM_SAVE,MF_ENABLED</B>
<P>为了避免用户一次性打开多个文件,我们让“打开文件”菜单项呈灰色显示,使得打开文件的菜单项失效。函数EnableMenuItem可以用来改变菜单项的属性。
之后用户可能保存文件或者直接关闭应用程序。如果用户选择关闭应用程序,则事先必须关闭内存映射文件和打开的文件, 代码如下:
<P><B> .ELSEIF uMsg==WM_DESTROY</B>
<BR><B> .if hMapFile!=0</B>
<BR><B> call
CloseMapFile</B> <BR><B> .endif</B>
<BR><B> invoke
PostQuitMessage,NULL</B>
<P>在上面的代码段中,当WINDOWS的消息处理过程接收到WM_DESTROY消息后,它首先检测hMapFile值是否为0。如果不为0则表示相关的文件未关闭,这样就需要调用CloseMapFile来关闭它们。
<P><B>CloseMapFile PROC</B> <BR><B>
invoke CloseHandle,hMapFile</B>
<BR><B> mov
hMapFile,0</B> <BR><B> invoke
CloseHandle,hFileRead</B> <BR><B>
ret</B> <BR><B>CloseMapFile endp</B>
<P>上述过程调用是用来关闭内存映射文件和原来打开的文件的,这样可以使得程序退出时没有资源泄漏。如果用户选择保存文件的话,就弹出一个“保存文件”对话框,当用户输入了新文件的名称后,我们调用CreateFile函数来创建新文件---输出文件。
<P><B>
invoke MapViewOfFile,hMapFile,FILE_MAP_READ,0,0,0</B>
<BR><B>
mov pMemory,eax</B>
<P>在输出文件创建后我们调用MapViewOfFile来映射希望映射到内存中的部分。该函数的语法如下:
<P><B>MapViewOfFile proto hFileMappingObject:DWORD,\</B>
<BR><B>
dwDesiredAccess:DWORD,\</B>
<BR><B>
dwFileOffsetHigh:DWORD,\</B>
<BR><B>
dwFileOffsetLow:DWORD,\</B>
<BR><B>
dwNumberOfBytesToMap:DWORD</B>
<P>dwDesiredAccess用来指定我们想对文件进行的操作。在我们例子中,我们只想读,故指定标志FILE_MAP_READ。<BR>dwFileOffsetHigh
和 dwFileOffsetLow
用来指定打开文件中欲映射的起始偏移位置。我们的例子中想映射整个的文件,故指定它们的值为0。<BR>dwNumberOfBytesToMap
用来指定欲映射的字节数,如果想映射整个的文件,设定该值为0。<BR>调用MapViewOfFile后,我们希望的部分就已经映射到内存中去了。您将得到一个指向起始内存块的指针。
<P><B>
invoke GetFileSize,hFileRead,NULL</B>
<P>调用该函数可以得到文件的大小,其值通过eax传送,如果文件的长度超过4G,那么文件长度DWORD的高值部分(也即超过4G的部分)保存在FileSizeHighWord中。因为我们估计一般的文件将没有这么大,故忽略该值。
<P><B>
invoke WriteFile,hFileWrite,pMemory,eax,ADDR SizeWritten,NULL</B>
<P>把内存映射文件中的数据写到输出文件中去。
<P><B>
invoke UnmapViewOfFile,pMemory</B>
<P>写完后,我们解除映射。
<P><B>
call CloseMapFile</B>
<BR><B>
invoke CloseHandle,hFileWrite</B>
<P>关闭内存映射文件和输出文件的句柄。
<P><B>
invoke SetWindowText,hWnd,ADDR AppName</B>
<P>恢复窗口的标题条到应用程序的名称。
<P><B>
invoke EnableMenuItem,hMenu,IDM_OPEN,MF_ENABLED</B>
<BR><B>
invoke EnableMenuItem,hMenu,IDM_SAVE,MF_GRAYED</B>
<P>恢复“打开文件”和“保存文件”菜单项使的可以重新开始新的打开、编辑和保存循环。
<HR SIZE=1>
<DIV align=center>
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/textclick"></SCRIPT>
<BR></DIV><!-- 10:1 文本广告交换 -->
<DIV align=center>
<SCRIPT language=JavaScript1.1 src="../lion-tut-c13.files/c21.htm"></SCRIPT>
<!-- 10:1 文本广告交换 --></DIV>
<HR SIZE=1>
<DIV align=center>翻译:Lxx.阿龙,校对:LuoYunBin's Win32 ASM Page, <A
href="http://asm.yeah.net/">http://asm.yeah.net/</A></DIV></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -