瑞鲁手机APP下载网_专注推荐好用的手机APP和游戏APP

Win32 处理键盘输入消息

Win32 ASM详解 十二 内存管理和文件输入/输出

查看人次:1摘自:瑞鲁下载网

本课中我们将学习基本的内存管理和文件输入/输出操作方面的知识。另外我们还将用上课学的通用对话框作为我们的显示“设备”。

 

理论:

从用户的角度来看,WIN32的内存管理是非常简单和明了的。每一个应用程序都有自己独立的4G地址空间,这种内存模式叫做“平坦”型地址模式,所有的段寄存器或描述符都指向同样的起始地址,所有的地址偏移都是32位的长度,这样一个应用程序无须变换选择符就可以存取自己的多达4G的地址空间。这种内存管理模式是非常简洁而便于管理的,而且我们再不用和那些令人讨厌的“near”和“far”指针打交道了。在W16下有两种主要类型的API:全局和局部。“全局”的API 分配在其他的段中,这样从内存角度来看他们是一些“far”(远)函数或者叫远过程调用,“局部”API只要和进程的堆打交道,所以把它们叫做“near”(近)函数或者近过程调用。而在WIN32中,这两种内存模式是相同的,无论您调用GlobalAlloc还是LocalAlloc,结果都是一样。至于分配和使用内存的过程都是一样的:

 

 

调用GlobalAlloc函数分配一块内存,该函数会返回分配的内存句柄。

调用GlobalLock函数锁定内存块,该函数接受一个内存句柄作为参数,然后返回一个指向被锁定的内存块的指针。

您可以用该指针来读写内存。

调用GlobalUnlock函数来解锁先前被锁定的内存,该函数使得指向内存块的指针无效。

调用GlobalFree函数来释放内存块。您必须传给该函数一个内存句柄。

 

 

在WIN32中您也可以用“Local”替代内存分配API函数带有“Global”字样的函数中的“Global”,也即用LocalAlloc、LocalLock等。在调用函数GlobalAlloc时使用GMEM_FIXED标志位可以更进一步简化操作。使用了该标志后,Global/LocalAlloc返回的是指向已分配内存的指针而不是句柄,这样也就不用调用Global/LocalLock来锁定内存了,释放内存时只要直接调用Global/LocalFree就可以了。不过在本课中我们只使用传统的方法,因为其它地方有许多的源代码是用这种方法写的。

 

WIN32的文件输入/输出API和DOS下的从外表上看几乎一样(译者注:也许不管内部实现多么不同,可以想象所有的文件系统暴露给应用程序编写者的接口的功能应该基本相同),不同的只是把DOS下的中断方式处理文件输入/输出变成了对API函数的调用。以下是基本的步骤:  

 

 

调用CreateFile函数生成一个文件,该函数可以应用在多方面,除了磁盘文件外,我们还可以用来打开通讯端口、管道、驱动程序或控制台。如果成功的话,会返回指向文件或设备的句柄。然后可以使用该句柄去完成对文件或设备操作。调用SetFilePointer来把文件指针移到想读写的地方。.

然后调用ReadFile 或 WriteFile来完成实际的读写。这些函数会自己处理文件和内存之间的数据传送,这样免得您自己去做分配内存等繁杂的琐事。

调用CloseHandle来关闭文件。该函数接受一个先前打开的文件句柄。

 

 

内容:

 

下面的代码段演示了:打开一个“打开文件”对话框,用户可以选择打开一个文本文件,然后在一个编辑控件中打开该文本文件的内容,另外用户还可以编辑该文本文件的内容并选择保存。

 

.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

 

分析:

        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

 

处理 WM_CREATE消息时,我们创建一个编辑控件。请注意,我们把该控件大小的有关参数都设成0,因为我们稍后将重新设置该编辑控件的大小,使得其覆盖父窗口的整个客户区。注意:本例中我们没有必要调用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

创建完编辑控件后,我们初始话ofn变量的成员。因为稍后在保存文件时还要使用该结构体变量,所以此处只初始化要用到的公共部分。WM_CREATE 消息的处理部分是进行这种初始化的绝佳之处。

    .ELSEIF uMsg==WM_SIZE         mov eax,lParam         mov edx,eax         shr edx,16         and eax,0ffffh         invoke MoveWindow,hwndEdit,0,0,eax,edx,TRUE

当主窗口的客户区部分大小改变时,我们的应用程序将接收到WM_SIZE 消息。当然该窗口第一次显示时,我们也将接收到该消息。要接收到该消息,主窗口必须有CS_VREDRAW和CS_HREDRAW风格。我们应该把缩放编辑控件的动作放到此处。我们要把编辑控件变成和我们的窗口客户区一样大,所以先得要得到父窗口客户区的大小。这些值包含在参数lParam中,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

当用户选择了File/Open菜单项时,我们填充ofn的其他成员,然后调用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

如果用户选择了一个文件时,我们调用CreateFile函数来打开。我们设置标志位来让该函数的文件能够读写。文件打开后我们把返回的文件句柄保存在一个全局变量中以便以后使用。CreateFile函数应用非常广泛,其原型如下:

CreateFile proto lpFileName:DWORD,\                            dwDesiredAccess:DWORD,\                            dwShareMode:DWORD,\                            lpSecurityAttributes:DWORD,\                            dwCreationDistribution:DWORD\,                            dwFlagsAndAttributes:DWORD\,                            hTemplateFile:DWORD

dwDesiredAccess 指定想要进行的操作。

 

 

0  打开文件查询它的属性。

GENERIC_READ   打开文件读

GENERIC_WRITE  打开文件写.

dwShareMode 指定文件的共享模式。

 

 

0  不让其他进程共享,即当您打开该文件后,其他进程欲打开该文件时将失败。

FILE_SHARE_READ  允许其他进程读。

FILE_SHARE_WRITE  允许其他进程写。

 

 

lpSecurityAttributes 该属性在WIN95下无效。 dwCreationDistribution 指定欲生成的文件在其已存在和未存在时应做的动作。

 

 

 

CREATE_NEW 生成一个新文件。如果文件已存在则失败。

CREATE_ALWAYS 无论文件是否存在都生成一个新文件。

OPEN_EXISTING 打开存在的文件。如果文件不存在则失败。

OPEN_ALWAYS 打开文件,如果该文件不存在则生成,这和在dwCreationDistribution 中设置 CREATE_NEW标志位一样。

TRUNCATE_EXISTING打开文件。打开时该文件的长度裁减到零(也即完全不要原来的文件了)。这要求调用进程必须有GENERIC_WRITE的权利,如果指定的文件不存在,该函数返回失败。

 

dwFlagsAndAttributes 指定文件的属性。

 

 

 

FILE_ATTRIBUTE_ARCHIVE 该文件具有一般的归档文件的属性。用户可以用该标志位来标记文件的删除和备份。

FILE_ATTRIBUTE_COMPRESSED 文件或目录是压缩的。对于文件来说是压缩其中的所有数据,而对于目录来说新生成的子目录和文件都要压缩。

FILE_ATTRIBUTE_NORMAL 该文件没有一般的属性集。该标志位只能单独使用。

FILE_ATTRIBUTE_HIDDEN 该文件是隐藏文件,当浏览一般的文件目录时将不显示它。

FILE_ATTRIBUTE_READONLY 该文件是只读文件。应用程序可以读其中的内容,但不可以写。

FILE_ATTRIBUTE_SYSTEM 该文件是系统文件。

                    invoke GlobalAlloc,GMEM_MOVEABLE or GMEM_ZEROINIT,MEMSIZE                     mov  hMemory,eax                     invoke GlobalLock,hMemory                     mov  pMemory,eax

文件打开后,我们将分配一块内存供随后的API 函数ReadFile 和 WriteFile使用。我们使用标志GMEM_MOVEABLE来使得WINDOWS总是把内存块移到可靠的内存中去,GMEM_ZEROINIT告诉WINDOWS把刚刚分配的内存置为零。如果GlobalAlloc调用成功的话,会在eax中返回内存块的句柄,我们把该句柄传给GlobalLock函数以得到指向内存块的指针。

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

使内存块可用后,我们调用ReadFile函数从文件中读数据。对于第一次打开的文件,文件的指针放在偏移0处,像本例中我们从偏移0处往前读。ReadFile的第一个参数是文件句柄,第二个参数是指向内存块的指针,接下来的参数是要读的数据的长度,第四个参数是一个指向DWORD型的参数的指针,它用来存放实际读的数据的长度。读完了后,我们把这些内容存放到编辑控件中,这要用消息传递来完成,我们把消息WM_SETTEXT传给编辑控件,其中的参数lParam中包含指向内存块的指针。到此处,编辑控件就可以在它的客户区显示文件的内容了。

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

我们不再需要让文件打开了,因为我们的目的是把修改后的数据保存到另一个文件而不是先前的那一个文件中去。所以我们可以调用CloseHandle来关闭文件。接下来我们解锁内存块,再释放它。实际上我们可以暂不释放内存块,而在以后的操作中重新利用。我们为了演示的原由,选择了释放它。

                invoke SetFocus,hwndEdit

当打开文件对话框显示在屏幕上时,输入的焦点切换到了该对话框上。所以在该对话框关闭后,我们必须把焦点切换到编辑控件上。 现在打开文件的阶段结束了,用户可以编辑他们打开的文件了。当用户想把修改后的内容保存到磁盘上时,必须选择File/Save菜单项,这时会显示一个保存文件对话框。显示保存文件对话框其实和打开打开文件对话框基本一样。您甚至可以认为他们的不同只是函数名称不一样而已。此处可以复用大多数ofn变量先前设置的成员的值。

                mov ofn.Flags,OFN_LONGNAMES or\                                 OFN_EXPLORER or OFN_HIDEREADONLY

本例中我们将生成一个新文件,所以一定不能有 OFN_FILEMUSTEXIST 和 OFN_PATHMUSTEXIST标志位。dwCreationDistribution 参数应当有CREATE_NEW标志位。 接下来的代码和打开问对话框基本一样。最后调用:

                        invoke SendMessage,hwndEdit,WM_GETTEXT,MEMSIZE-1,pMemory                         invoke WriteFile,hFile,pMemory,eax,ADDR SizeReadWrite,NULL

现在我们把修改后的数据从编辑控件中写回内存块,再从内存块写回新文件。

相关文摘:破解文章 windows
标题名称:《Win32 处理键盘输入消息》
本文网址:https://www.sdruilu.cn/news/tpart-21818.html