FASM -- Win32彙編學習11

子窗口控件

本節課程中,我們將討論控件。這些控件作爲是我們輸入輸出的設備。

 

    理論:

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

 

  例子:

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

    1. say hello    把一段字符串輸入到編輯框中。

    2. Clear Edit Box    清除編輯框中的字符串。

    3. Get Text     彈出對話框顯示編輯空中的內容。

    4. Exit 退出程序

       

代碼:

        format PE GUI 4.0
       
        include 'win32ax.inc'
   
   
        macro memmov [dst, src]
        {
            common
            push [src]
            pop [dst]
        }
       


.data
        ;**************數據********************
        szClassName db 'first Window',0
        szWndName db 'My first program',0
        szMenuName db 'MyMenu',0
        szTestString db 'Wow! i am in an edit box now', 0
        EditName db 'edit',0
        ButtonName db 'button',0
        ButtonText db 'My first button',0
        szBuffer db 50 dup (?)
        hInstanse rd 1
        hIcon          rd 1
        hCursor          rd 1
        hWndow rd 1
        lpCommand rd 1
        hButton rd 1
        hEdit rd 1
        IDM_TEXT equ 1
        IDM_HELLO equ 2
        IDM_CLEAR equ 3
        IDM_EXIT equ 4
        BUTTONID =    5
        EDITID   = 6
       
.text


entry $

       
    xor edi, edi
    invoke GetModuleHandle, edi
    or eax, eax
    jz .fail
    mov [hInstanse], eax
    invoke GetCommandLine,edi
    mov [lpCommand], eax
    stdcall _WndMain, hInstanse, edi, [lpCommand],SW_SHOWDEFAULT

.fail:
    invoke ExitProcess,NULL       

    proc _WndMain hInstance:DWORD, hPrevInstance:DWORD, lpCmdLine:DWORD, nCmdShow:DWORD
            local @wc:WNDCLASSEX
            local @Msg:MSG
    local @hMenu:DWORD
   
            invoke RtlZeroMemory, addr @wc, sizeof.WNDCLASSEX
            invoke LoadIcon, NULL,IDI_ASTERISK   
            mov [hIcon], eax
            invoke LoadCursor, NULL,IDC_ARROW
            mov [hCursor], eax
            mov [@wc.cbSize], sizeof.WNDCLASSEX
            mov [@wc.style], CS_HREDRAW or CS_VREDRAW
            mov [@wc.lpfnWndProc], _WndProc
            mov [@wc.cbClsExtra], NULL
            mov [@wc.cbWndExtra], NULL
            memmov @wc.hInstance, hInstance
            memmov @wc.hIcon, hIcon
            memmov @wc.hCursor, hCursor
            mov [@wc.hCursor], hCursor
            mov [@wc.hbrBackground], COLOR_WINDOW + 1
            mov [@wc.lpszMenuName], NULL
            mov [@wc.lpszClassName], szClassName
            invoke RegisterClassEx, addr @wc
            invoke LoadMenu,[hInstanse], szMenuName
            mov [@hMenu], eax
           
            invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr szClassName, szWndName, WS_OVERLAPPEDWINDOW,/
                        CW_USEDEFAULT, CW_USEDEFAULT, 300, 200,/
                        NULL, [@hMenu] , [hInstanse] , NULL
            mov [hWndow], eax
            invoke ShowWindow,[hWndow],SW_SHOWNORMAL
            invoke UpdateWindow,[hWndow]
       
        .GetMsg:   
            invoke GetMessage,addr @Msg,NULL, 0, 0
            or eax, eax
            je .QUIT
            invoke TranslateMessage,addr @Msg
            invoke DispatchMessage,addr @Msg
            jmp .GetMsg
   
        .QUIT:
            mov eax, [@Msg.wParam]
            ret

endp
       
   
   
    proc _WndProc uses ebx esi edi, hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
   
            cmp [uMsg], WM_DESTROY
            je finish
            cmp [uMsg], WM_COMMAND
            je .command
            cmp [uMsg], WM_CREATE
            je .create
            invoke DefWindowProc,[hWnd],[uMsg],[wParam], [lParam]
            ret
       
    .create:
            invoke CreateWindowEx,NULL, ButtonName, ButtonText, /
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON, /
                    75, 70, 140, 25, [hWnd] , BUTTONID, [hInstanse], NULL
            or eax, eax
            je faild
                   
            mov [hButton], eax
           
            invoke CreateWindowEx,WS_EX_CLIENTEDGE, EditName, NULL,/
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL, /
                        50, 35, 200, 25, [hWnd], EDITID, [hInstanse], NULL
            mov [hEdit], eax
    invoke SetFocus, [hEdit]
            jmp Myend
    .command:
            mov eax ,[wParam]
            and eax, 0FFFFh
            cmp eax, IDM_TEXT
            je _text
            cmp eax, IDM_HELLO
            je _hello
            cmp eax, IDM_CLEAR
            je _clear
            cmp eax, IDM_EXIT
            je _exit
            jmp Myend
    _text:
            invoke GetWindowText,[hEdit], szBuffer, 50
            invoke MessageBox, NULL, szBuffer, 'test', MB_OK
            jmp Myend
           
    _hello:
        invoke SetWindowText, [hEdit], szTestString
            jmp Myend
    _clear:
            invoke SetWindowText, [hEdit], NULL
            jmp Myend
    _exit:
        invoke DestroyWindow, [hWnd]
        jmp Myend
    faild:
            invoke MessageBox,NULL, 'faild', 'test', MB_OK
            jmp Myend
finish:

            invoke PostQuitMessage, NULL
    Myend:   
            xor eax, eax
        ret
    endp
   
   
.import
       
library kernel32, 'kernel32.dll',/
            user32, 'user32.dll'
include 'api/kernel32.inc'
include 'api/user32.inc'   


section '.rsrc' data readable resource from 'resourcename.RES'    

分析:

 

   .create:
            invoke CreateWindowEx,NULL, ButtonName, ButtonText, /
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON, /
                    75, 70, 140, 25, [hWnd] , BUTTONID, [hInstanse], NULL
            or eax, eax
            je faild
                   
            mov [hButton], eax
           
            invoke CreateWindowEx,WS_EX_CLIENTEDGE, EditName, NULL,/
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or ES_AUTOHSCROLL, /
                        50, 35, 200, 25, [hWnd], EDITID, [hInstanse], NULL
            mov [hEdit], eax
    invoke SetFocus, [hEdit]
            jmp Myend

    我們在WM_CREATE消息中建立子窗口控件,在上面我也以及說了,我們一般都是在WM_CREATE消息中創建子窗口控件的。 我們通過CreatWindowEx函數來創建子窗口控件,因爲這些子窗口控件都是windows預定義的類,這些類都是註冊過的,且它們內部自己處理消息,當子窗口控件發生改變時向我們的父窗口發送WM_COMMADN消息。 創建子窗口控件沒什麼好講的,我們在建立編輯框的時候給它附加了一個WS_EX_CLIENTEDGE外觀,這使得看起來編輯下凹,具有立體感。每一個子控件的id都是預定義的,例如按鈕的預定義類名是“button”,編輯框的預定義類名是“edit”。接下來的參數是窗口風格,除了通常的風格外,每一個控件也有自己的擴展風格,譬如按鈕類的擴展風格前面加BS_,編輯框的類則是ES_。Win32 API參考中所有的風格描述,注意:您在CreateWindowsEx函數中本來要傳遞菜單句柄的地方傳入子窗口空間的ID號不會有什麼副作用,因爲子窗口控件本身不能有菜單。產生控件後,我們保存它們的句柄,然後調用SetFocus把焦點設到編輯控件上以便用戶立即可以輸入。接下來的是如何處理控件發送的通知消息WM_COMMAND。

    .command:
            mov eax ,[wParam]
            and eax, 0FFFFh
            cmp eax, IDM_TEXT
            je _text
            cmp eax, IDM_HELLO
            je _hello
            cmp eax, IDM_CLEAR
            je _clear
            cmp eax, IDM_EXIT
            je _exit
            jmp Myend
    _text:
            invoke GetWindowText,[hEdit], szBuffer, 50
            invoke MessageBox, NULL, szBuffer, 'test', MB_OK
            jmp Myend
           
    _hello:
        invoke SetWindowText, [hEdit], szTestString
            jmp Myend
    _clear:
            invoke SetWindowText, [hEdit], NULL
            jmp Myend
    _exit:
        invoke DestroyWindow, [hWnd]
            jmp Myend
    faild:
            invoke MessageBox,NULL, 'faild', 'test', MB_OK
            jmp Myend

 

這裏我們通過判斷菜單項的ID號來進行處理。如果是選擇say hello菜單,則通過調用SetWindowText設置編輯框一段字符串。 如果選擇 Get Text 菜單則通過 GetWindowText函數獲得編輯框中的內容並保存到緩衝區中。然後通過MessageBox顯示緩衝區中的內容。其次如果選擇的是Clear Edit Box消息,則調用SetWindowText設置編輯框的內容爲NULL,(則此時編輯框的內容爲空)。     如果選擇exit菜單項,則調用DestroyWindow函數銷燬窗口,從而結束程序。

cmp ax, BUTTONID
je _Button
_Button:
shr eax, 16
cmp eax, BN_CLICKED
jne Myend
invoke SendMessage,[hWnd] , WM_COMMAND, IDM_TEXT, NULL
jmp Myend

上面的片段是處理用戶按鈕事件的。他首先檢查wParam的低字節看是否是按鈕的ID 號,若是則檢查高字節看發送的消息號是否BN_CLICKED,該消息是在按鈕按下時發送的,如果一切都對,則轉入處理該消息,我們可以從處理消息IDM_GETTEXT處複製全部的代碼,但是更專業的辦法是在發送一條IDM_GETTEXT消息讓主窗口過程處理,這隻要把傳送的消息設置爲WM_COMMAND,再把wParam的低字節中設置爲IDM_GETTEXT即可。這樣一來您的代碼就簡潔了許多,所以儘可能利用該技巧。最後,當然不是或有或無,必須在消息循環中調用函數TranslateMessage,因爲您的應用程序需要在編輯框中輸入可讀的文字。如果省略了該函數,就不能在編輯框中輸入任何東西。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章