.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\GDI32.INC INCLUDELIB \MASM32\LIB\USER32.LIB INCLUDELIB \MASM32\LIB\KERNEL32.LIB INCLUDELIB \MASM32\LIB\GDI32.LIB .DATA CLASSNAME DB "SIMPLEWINCLASS",0 APPNAME DB "OUR FIRST WINDOW",0 MOUSECLICK DB 0 ; 0=no click yet .DATA? hInstance HINSTANCE ? CommandLine LPSTR ? hitpoint POINT <> .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:DWORD 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,NULL 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,NULL,ADDR CLASSNAME,ADDR APPNAME,\ WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\ CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,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 DISPATCHMESSAGE, ADDR MSG .ENDW MOV EAX,MSG.WPARAM RET WINMAIN ENDP WNDPROC PROC HWND:HWND, UMSG:UINT, WPARAM:WPARAM, LPARAM:LPARAM LOCAL HDC:HDC LOCAL PS:PAINTSTRUCT .IF UMSG==WM_DESTROY INVOKE POSTQUITMESSAGE,NULL .ELSEIF UMSG==WM_LBUTTONDOWN MOV EAX,LPARAM AND EAX,0FFFFH MOV HITPOINT.X,EAX MOV EAX,LPARAM SHR EAX,16 MOV HITPOINT.Y,EAX MOV MOUSECLICK,TRUE INVOKE INVALIDATERECT,HWND,NULL,TRUE .ELSEIF UMSG==WM_PAINT INVOKE BEGINPAINT,HWND, ADDR PS MOV HDC,EAX .IF MOUSECLICK INVOKE LSTRLEN,ADDR APPNAME INVOKE TEXTOUT,HDC,HITPOINT.X,HITPOINT.Y,ADDR APPNAME,EAX .ENDIF INVOKE ENDPAINT,HWND, ADDR PS .ELSE INVOKE DEFWINDOWPROC,HWND,UMSG,WPARAM,LPARAM RET .ENDIF XOR EAX,EAX RET WNDPROC ENDP END START
.ELSEIF UMSG==WM_LBUTTONDOWN MOV EAX,LPARAM AND EAX,0FFFFH MOV HITPOINT.X,EAX MOV EAX,LPARAM SHR EAX,16 MOV HITPOINT.Y,EAX MOV MOUSECLICK,TRUE INVOKE INVALIDATERECT,HWND,NULL,TRUE
窗口过程处理了WM_LBUTTONDOWN消息,当接收到该消息时,lParam中包含了相对于窗口客户区左上角的坐标,我们把它保存下来,放到一个结构体变量(POINT)中,该结构体变量的定义如下:
然后我们把标志量MouseClick设为TRUE,这表明至少有一次在客户区的左键按下消息。
MOV EAX,LPARAM AND EAX,0FFFFH MOV HITPOINT.X,EAX
由于lParam是一个32位长的数,其中高、底16位分别包括了x、y坐标所以我们做一些小处理,以便保存它们。
SHR EAX,16 MOV HITPOINT.Y,EAX保存完坐标后我们设标志MouseClick为TRUE,这是在处理WM_PAINT时用来判断是否有鼠标左键按下消息。然后我们调用InvalidateRect()函数迫使WINDOWS重新绘制客户区。
.IF MouseClick
绘制客户区的代码首先检测MouseClick标志位,再决定是否重绘。因为我们在首次显示窗口时还没有左键按下的消息,所以我们在初始时把该标志设为FALSE,告诉WINDOWS不要重绘客户区,当有左键按下的消息时,它会在鼠标按下的位置绘制字符串。注意在调用TextOut()函数时,其关于字符串长度的参数是调用lstrlen()函数来计算的。
INVOKE LSTRLEN,ADDR APPNAME INVOKE TEXTOUT,HDC,HITPOINT.X,HITPOINT.Y,ADDR APPNAME,EAX .ENDIF