.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 INCLUDELIB \MASM32\LIB\USER32.LIB INCLUDELIB \MASM32\LIB\KERNEL32.LIB .DATA CLASSNAME DB "SIMPLEWINCLASS",0 APPNAME DB "OUR FIRST WINDOW",0 MENUNAME DB "FIRSTMENU",0 BUTTONCLASSNAME DB "BUTTON",0 BUTTONTEXT DB "MY FIRST BUTTON",0 EDITCLASSNAME DB "EDIT",0 TESTSTRING DB "WOW! I'm in an edit box now",0 .DATA? hInstance HINSTANCE ? CommandLine LPSTR ? hwndButton HWND ? hwndEdit HWND ? BUFFER DB 512 DUP(?) ; buffer to store the text retrieved from the edit box .CONST BUTTONID EQU 1 ; The control ID of the button control EDITID EQU 2 ; The control ID of the edit control IDM_HELLO EQU 1 IDM_CLEAR EQU 2 IDM_GETTEXT EQU 3 IDM_EXIT EQU 4 .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_BTNFACE+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 HWND:HWND, UMSG:UINT, WPARAM:WPARAM, LPARAM:LPARAM .IF UMSG==WM_DESTROY INVOKE POSTQUITMESSAGE,NULL .ELSEIF UMSG==WM_CREATE INVOKE CREATEWINDOWEX,WS_EX_CLIENTEDGE, ADDR EDITCLASSNAME,NULL,\ WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_LEFT OR\ ES_AUTOHSCROLL,\ 50,35,200,25,hWnd,8,hInstance,NULL MOV HWNDEDIT,EAX INVOKE SETFOCUS, HWNDEDIT INVOKE CREATEWINDOWEX,NULL, ADDR BUTTONCLASSNAME,ADDR BUTTONTEXT,\ WS_CHILD OR WS_VISIBLE OR BS_DEFPUSHBUTTON,\ 75,70,140,25,hWnd,ButtonID,hInstance,NULL MOV HWNDBUTTON,EAX .ELSEIF UMSG==WM_COMMAND MOV EAX,WPARAM .IF LPARAM==0 .IF AX==IDM_HELLO INVOKE SETWINDOWTEXT,HWNDEDIT,ADDR TESTSTRING .ELSEIF AX==IDM_CLEAR INVOKE SETWINDOWTEXT,HWNDEDIT,NULL .ELSEIF AX==IDM_GETTEXT INVOKE GETWINDOWTEXT,HWNDEDIT,ADDR BUFFER,512 INVOKE MESSAGEBOX,NULL,ADDR BUFFER,ADDR APPNAME,MB_OK .ELSE INVOKE DESTROYWINDOW,HWND .ENDIF .ELSE .IF AX==BUTTONID SHR EAX,16 .IF AX==BN_CLICKED INVOKE SENDMESSAGE,HWND,WM_COMMAND,IDM_GETTEXT,0 .ENDIF .ENDIF .ENDIF .ELSE INVOKE DEFWINDOWPROC,HWND,UMSG,WPARAM,LPARAM RET .ENDIF XOR EAX,EAX RET WNDPROC ENDP END START
我们现在开始分析:
.ELSEIF UMSG==WM_CREATE INVOKE CREATEWINDOWEX,WS_EX_CLIENTEDGE, \ ADDR EditClassName,NULL,\ WS_CHILD OR WS_VISIBLE OR WS_BORDER OR ES_LEFT\ OR ES_AUTOHSCROLL,\ 50,35,200,25,hWnd,EditID,hInstance,NULL MOV HWNDEDIT,EAX INVOKE SETFOCUS, HWNDEDIT INVOKE CREATEWINDOWEX,NULL, ADDR BUTTONCLASSNAME,\ ADDR ButtonText,\ WS_CHILD OR WS_VISIBLE OR BS_DEFPUSHBUTTON,\ 75,70,140,25,hWnd,ButtonID,hInstance,NULL MOV HWNDBUTTON,EAX
我们在WM_CREATE中产生子控件,其中在函数CreateWindowEx中给子控件窗口一个WS_EX_CLIENTEDGE风格,它使得子控件窗口看上去边界下凹,具有立体感。每一个子控件的类名都是预定义的,譬如:按钮的预定义类名是"button",编辑框是"edit"。接下来的参数是窗口风格,除了通常的窗口风格外,每一个控件都有自己的扩展风格,譬如:按钮类的扩展风格前面加有BS_,编辑框类则是:ES_,WIN32 API 参考中有所有的扩展风格的描述。注意:您在CreateWindowsEx函数中本来要传递菜单句柄的地方传入子窗口空间的ID号不会有什么副作用,因为子窗口控件本身不能有菜单。产生控件后,我们保存它们的句柄,然后调用SetFocus把焦点设到编辑控件上以便用户立即可以输入。 接下来的是如何处理控件发送的通知消息WM_COMMAND:
.ELSEIF UMSG==WM_COMMAND MOV EAX,WPARAM .IF LPARAM==0
我们以前讲过选择菜单想也会发送WM_COMMAND
消息,那我们应如何区分呢?看了下表您就会一目了然:
Low word of wParam | High word of wParam | lParam | |
Menu | Menu ID | 0 | 0 |
Control | Control ID | Notification code | Child Window Handle |
其中我们可以看到不能用wParam来区分,因为菜单和控件的ID号可能相同,而且子窗口空间的消息号也有可能为0。
IF AX==IDM_HELLO INVOKE SETWINDOWTEXT,HWNDEDIT,ADDR TESTSTRING .ELSEIF AX==IDM_CLEAR INVOKE SETWINDOWTEXT,HWNDEDIT,NULL .ELSEIF AX==IDM_GETTEXT INVOKE GETWINDOWTEXT,HWNDEDIT,ADDR BUFFER,512 INVOKE MESSAGEBOX,NULL,ADDR BUFFER,ADDR APPNAME,MB_OK
您可以调用SetWindowText函数把一字符串繁缛到编辑控件中去,为了清0,传入NULL值。SetWindowText是一个通用函数,即可以用它来设定一个窗口的标题,也可以用它来改变一个按钮上的文字。如果是要得到按钮上的文字,则调用GetWindowText。
.IF AX==BUTTONID SHR EAX,16 .IF AX==BN_CLICKED INVOKE SENDMESSAGE,HWND,WM_COMMAND,IDM_GETTEXT,0 .ENDIF .ENDIF
上面的片段是处理用户按钮事件的。他首先检查wParam的高字节看是否是按钮的ID 号,若是则检查低字节看发送的消息号是否BN_CLICKED,该消息是在按钮按下时发送的,如果一切都对,则转入处理该消息,我们可以从处理消息IDM_GETTEXT处复制全部的代码,但是更专业的办法是在发送一条IDM_GETTEXT消息让主窗口过程处理,这只要把传送的消息设置为WM_COMMAND,再把wParam的低字节中设置为IDM_GETTEXT即可。这样一来您的代码就简洁了许多,所以尽可能利用该技巧。 最后,当然不是或有或无,必须在消息循环中调用函数TranslateMessage,因为您的应用程序需要在编辑框中输入可读的文字。如果省略了该函数,就不能在编辑框中输入任何东西。