程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> 匯編語言 >> 匯編教程之子窗口控件

匯編教程之子窗口控件

編輯:匯編語言

本課中我們將探討控件,這些控件是我們程序主要的輸入輸出設備。

理論:

WINDOWS 提供了幾個預定義的窗口類以方便我們的使用。大多數時間內,我們把它們用在對話框中,所以我們一般就它們叫做子窗口控件。子窗口控件會自己處理消息,並在自己狀態發生改變時通知父窗口。這樣就大大地減輕了我們的編程工作,所以我們應盡可能地利用它們。本課中我們把這些控件放在窗口中以簡化程序,但是大多數時間內子窗口控件都是放在對話框中的。我們示例中演示的子窗口控件包括:按鈕、下拉菜單、檢查框、單選按鈕、編輯框等。使用子窗口控件時,先調用CreateWindow 或 CreateWindowEx。在這裡由於WINDOWS 已經注冊了這些子控件,所以無須我們再注冊。當然我們不能改變它們的類名稱。譬如:如果您想產生一個按鈕,在調用上述兩個函數時就必須指定類名為"button"。其他必須指定的參數還有父窗口的句柄和將要產生的子控件的ID號。子控件的ID號是用來標識子控件的,故也必須是唯一 的。子控件產生後,當其狀態改變時將會向父窗口發送消息。一般我們應在父窗口的WM_CREATE消息中產生字控件。子控件向父窗口發送的消息是WM_COMMAND,並在傳遞的參數wPara的底位中包括控件的ID號,消息號在wParam的高位,lParam中則包括了子控件的窗口的句柄。各類控件有不同的消息代碼集,詳情請參見WIN32 API參考手冊。父窗口也可以通過調用函數SendMessage向子控件發送消息,其中第一個參數是子控件的窗口句柄,第二個參數是要發送的消息號,附加的參數可以在wParam和lParam中傳遞,其實只要知道了某個窗口的句柄就可以用該函數向其發送相關消息。所以產生了子窗口後必須處理WM_COMMAND消息以便可以接收到子控件的消息。

例子:

我們將產生一個窗口,在該窗口中有一個編輯框和一個按鈕。當您按下按鈕時 ,會彈出一個對話框其中顯示了您在編輯框中輸入的內容。另外,該應用程序還有一個菜單,其中有四個菜單項:

Say Hello -- 把一個字符串輸入編輯控件;

Clear Edit Box -- 清除編輯控件中的字符串;

Get Text -- 彈出對話框顯示編輯控件中的字符串;

Exit -- 退出應用程序。

.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,因為您的應用程序需要在編輯框中輸入可讀的文字。如果省略了該函數,就不能在編輯框中輸入任何東西。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved