📄 lion-tut-c13.htm
字号:
<HTML>
<head>
<link rel="stylesheet" href="../../asm.css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion's win32 asm tutorial</title>
</head>
<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<P align=center><FONT color=#0000ff size=+2>第十三课 内存映射文件</FONT></P>
<HR SIZE=1>
本课中我们将要讲解内存映射文件并且演示如何运用它。您将会发现使用内存映射文件是非常简单的。
<H3><FONT color=#ff0000>理论:</FONT></H3>
<P>如果您仔细地研究了前一课的例子,
就会发现它有一个严重的缺陷:如果您想读的内容大于系统分配的内存块怎么办?如果您想搜索的字符串刚好超过内存块的边界又该如何处理?对于第一个问题,您也许会说,只要不断地读就不解决了吗。至于第二个问题,您又会说在内存块的边界处做一些特别的处理,譬如放上一些标志位就可以了。原理上确实是行得通,但是这随问题复杂程度加深而显得非常难以处理。其中的第二个问题是有名的边界判断问题,程序中许许多多的错误都是由此引起。想一想,如果我们能够分配一个能够容纳整个文件的大内存块该多好啊,这样这两个问题不都迎刃而解了吗?是的,WIN32的内存映射文件确实允许我们分配一个装得下现实中可能存在的足够大的文件的内存。</P>
<P>利用内存映射文件您可以认为操作系统已经为您把文件全部装入了内存,然后您只要移动文件指针进行读写即可了。这样您甚至不需要调用那些分配、释放内存块和文件输入/输出的API函数,另外您可以把这用作不同的进程之间共享数据的一种办法。运用内存映射文件实际上没有涉及实际的文件操作,它更象为每个进程保留一个看得见的内存空间。至于把内存映射文件当成进程间共享数据的办法来用,则要加倍小心,因为您不得不处理数据的同步问题,否则您的应用程序也许很可能得到过时或错误的数据甚至崩溃。本课中我们将主要讲述内存映射文件,将不涉及进程间的同步。WIN32中的内存映射文件应用非常广泛,譬如:即使是系统的核心模块---PE格式文件装载器也用到了内存映射文件,因为PE格式的文件并不是一次性加载到内存中来的,譬如他它在首次加载时只加载必需加载的部分,而其他部分在用到时再加载,这正好可以利用到内存映射文件的长处。实际中的大多数文件存取都和PE加载器类似,所以您在处理该类问题时也应该充分利用内存映射文件。</P>
<P>内存映射文件本身还是有一些局限性的,譬如一旦您生成了一个内存映射文件,那么您在那个会话期间是不能够改变它的大小的。所以内存映射文件对于只读文件和不会影响其大小的文件操作是非常有用的。当然这并不意味着对于会引起改变其大小的文件操作就一定不能用内存影射文件的方法,您可以事先估计操作后的文件的可能大小,然后生成这么大小一块的内存映射文件,然后文件的长度就可以增长到这么一个大小。
我们的解释够多的了,接下来我们就看看实现的细节: </P>
<OL>
<LI>调用CreateFile打开您想要映射的文件。
<LI>调用CreateFileMapping,其中要求传入先前CreateFile返回的句柄,该函数生成一个建立在CreateFile函数创建的文件对象基础上的内存映射对象。
<LI>调用MapViewOfFile函数映射整个文件的一个区域或者整个文件到内存。该函数返回指向映射到内存的第一个字节的指针。
<LI>用该指针来读写文件。
<LI>调用UnmapViewOfFile来解除文件映射。
<LI>调用CloseHandle来关闭内存映射文件。注意必须传入内存映射文件的句柄。
<LI>调用CloseHandle来关闭文件。注意必须传入由CreateFile创建的文件的句柄。 </LI></OL>
<H3><FONT
color=#ff0000>例子:</FONT></H3>下面的例子允许用户通过“打开文件”对话框来打开一个文件,然后用内存映射文件来打开该文件,如果成功,窗口的标题条会显示打开的文件的名称,您可以通过选择“File/Save”菜单项来把换名保存。该程序将会把打开的文件的内容存到新文件中去。注意,这整个过程您根本就没有用到GlobalAlloc这样的分配内存的函数。
<P><B>.386</B> <BR><B>.model flat,stdcall</B> <BR><B>WinMain proto
:DWORD,:DWORD,:DWORD,:DWORD</B> <BR><B>include \masm32\include\windows.inc</B>
<BR><B>include \masm32\include\user32.inc</B> <BR><B>include
\masm32\include\kernel32.inc</B> <BR><B>include \masm32\include\comdlg32.inc</B>
<BR><B>includelib \masm32\lib\user32.lib</B> <BR><B>includelib
\masm32\lib\kernel32.lib</B> <BR><B>includelib \masm32\lib\comdlg32.lib</B>
<P><B>.const</B> <BR><B>IDM_OPEN equ 1</B> <BR><B>IDM_SAVE equ 2</B>
<BR><B>IDM_EXIT equ 3</B> <BR><B>MAXSIZE equ 260</B>
<P><B>.data</B> <BR><B>ClassName db "Win32ASMFileMappingClass",0</B>
<BR><B>AppName db "Win32 ASM File Mapping Example",0</B> <BR><B>MenuName
db "FirstMenu",0</B> <BR><B>ofn OPENFILENAME <></B>
<BR><B>FilterString db "All Files",0,"*.*",0</B>
<BR><B>
db "Text Files",0,"*.txt",0,0</B> <BR><B>buffer db MAXSIZE dup(0)</B>
<BR><B>hMapFile HANDLE
0
; Handle to the memory mapped file, must be</B>
<BR><B>
;initialized with 0 because we also use it as</B>
<BR><B>
;a flag in WM_DESTROY section too</B>
<P><B>.data?</B> <BR><B>hInstance HINSTANCE ?</B> <BR><B>CommandLine LPSTR ?</B>
<BR><B>hFileRead HANDLE
?
; Handle to the source file</B> <BR><B>hFileWrite HANDLE
?
; Handle to the output file</B> <BR><B>hMenu HANDLE ?</B> <BR><B>pMemory DWORD
?
; pointer to the data in the source file</B> <BR><B>SizeWritten DWORD
?
; number of bytes actually written by WriteFile</B>
<P><B>.code</B> <BR><B>start:</B>
<BR><B> invoke GetModuleHandle,
NULL</B> <BR><B> mov
hInstance,eax</B> <BR><B> invoke
GetCommandLine</B> <BR><B> mov
CommandLine,eax</B> <BR><B> invoke
WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT</B>
<BR><B> invoke ExitProcess,eax</B>
<P><B>WinMain proc
hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD</B>
<BR><B> LOCAL wc:WNDCLASSEX</B> <BR><B>
LOCAL msg:MSG</B> <BR><B> LOCAL hwnd:HWND</B>
<BR><B> mov wc.cbSize,SIZEOF WNDCLASSEX</B>
<BR><B> mov wc.style, CS_HREDRAW or CS_VREDRAW</B>
<BR><B> mov wc.lpfnWndProc, OFFSET WndProc</B>
<BR><B> mov wc.cbClsExtra,NULL</B>
<BR><B> mov wc.cbWndExtra,NULL</B>
<BR><B> push hInst</B> <BR><B>
pop wc.hInstance</B> <BR><B> mov
wc.hbrBackground,COLOR_WINDOW+1</B> <BR><B> mov
wc.lpszMenuName,OFFSET MenuName</B> <BR><B> mov
wc.lpszClassName,OFFSET ClassName</B> <BR><B> invoke
LoadIcon,NULL,IDI_APPLICATION</B> <BR><B> mov
wc.hIcon,eax</B> <BR><B> mov wc.hIconSm,eax</B>
<BR><B> invoke LoadCursor,NULL,IDC_ARROW</B>
<BR><B> mov wc.hCursor,eax</B>
<BR><B> invoke RegisterClassEx, addr wc</B>
<BR><B> invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR
ClassName,\</B>
<BR><B>
ADDR AppName, WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\</B>
<BR><B>
CW_USEDEFAULT,300,200,NULL,NULL,\</B> <BR><B> hInst,NULL</B>
<BR><B> mov hwnd,eax</B> <BR><B>
invoke ShowWindow, hwnd,SW_SHOWNORMAL</B> <BR><B> invoke
UpdateWindow, hwnd</B> <BR><B> .WHILE TRUE</B>
<BR><B> invoke GetMessage, ADDR
msg,NULL,0,0</B> <BR><B> .BREAK .IF
(!eax)</B> <BR><B> invoke
TranslateMessage, ADDR msg</B> <BR><B>
invoke DispatchMessage, ADDR msg</B> <BR><B> .ENDW</B>
<BR><B> mov eax,msg.wParam</B>
<BR><B> ret</B> <BR><B>WinMain endp</B>
<P><B>WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM</B>
<BR><B> .IF uMsg==WM_CREATE</B>
<BR><B> invoke
GetMenu,hWnd
;Obtain the menu handle</B> <BR><B>
mov hMenu,eax</B> <BR><B> mov
ofn.lStructSize,SIZEOF ofn</B> <BR><B>
push hWnd</B> <BR><B> pop
ofn.hWndOwner</B> <BR><B> push
hInstance</B> <BR><B> pop
ofn.hInstance</B> <BR><B> mov
ofn.lpstrFilter, OFFSET FilterString</B>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -