青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

luqingfei@C++

為中華之崛起而崛起!
兼聽則明,偏聽則暗。

Win32匯編--使用資源--菜單和加速鍵

 

使用資源 —— 菜單和加速鍵

 

主菜單,頂層菜單

彈出式菜單,子菜單

右鍵彈出式菜單

系統(tǒng)彈出式菜單

 

菜單中的菜單項(xiàng)有好幾種,從資源定義的角度來看,分隔用的橫線也是一個菜單項(xiàng),除橫線外其他菜單項(xiàng)可以供用戶選擇,也可以設(shè)置為“禁止”或“灰化”狀態(tài)暫時停用。

 

菜單項(xiàng)上的圓點(diǎn)表示選中標(biāo)記是互斥的,對鉤表示是不互斥的。

 

加速鍵就是菜單項(xiàng)的快捷鍵。表示當(dāng)窗口是激活的時候,不必打開菜單,直接按快捷鍵就相當(dāng)于選擇了菜單項(xiàng)。

 

菜單和加速鍵的資源定義

資源腳本文件舉例:

//Menu.rc

#include <resource.h>

#define ICO_MAIN                     0x1000           //圖標(biāo)

#define IDM_MAIN                    0x2000           //菜單

#define IDA_MAIN                     0x2000           //加速鍵

#define IDM_OPEN                    0x4101

#define IDM_OPTION                0x4102

#define IDM_EXIT                            0x4103

#define IDM_SETFONT              0x4201

#define IDM_SETCOLOR            0x4202

#define IDM_INACT                   0x4203

#define IDM_GRAY                    0x4204

#define IDM_BIG                        0x4205

#define IDM_SMALL                  0x4206

#define IDM_LIST                      0x4207

#define IDM_DETALL                 0x4208

#define IDM_TOOLBAR              0x4209

#define IDM_TOOLBARTEXT     0x4210

#define IDM_INPUTBAR             0x4211

#define IDM_STATUSBAR           0x4212

#define IDM_HELP                     0x4301

#define IDM_ABOUT                  0x4302

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN           ICON             “Main.ico”

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

IDM_MAIN           menu             discardable

BEGIN

                     popup “文件(&F)”

                     BEGIN

                                   menuitem              打開文件(&O)…”, IDM_OPEN

                                   menuitem              關(guān)閉文件(&C)…”, IDM_OPTION

                                   menuitem              separator

                                   menuitem              退出(&X)”, IDM_EXIT

                     END

                     popup “查看(&V)”

                     BEGIN

                                   menuitem              字體(&F)…\tAlt+F”, IDM_SETFONT

                                   menuitem              背景色(&B) …\tCtrl+Alt+B”, IDM_SETCOLOR

                                   menuitem              separator

                                   menuitem              被禁用的菜單項(xiàng)”, IDM_INACT, INACTIVE

                                   menuitem              被灰化的菜單項(xiàng)”, IDM_GRAY, GRAYED

                                   menuitem              separator

                                   menuitem              大圖標(biāo)(&G)”, IDM_BIG

                                   menuitem              小圖標(biāo)(&M)”, IDM_SMALL

                                   menuitem              列表(&L)”, IDM_LIST

                                   menuitem              詳細(xì)資料(&D)”, IDM_DETAIL

                                   menuitem              separator

                                   menuitem              工具欄(&T)”

                                   BEGIN

                                                 menuitem              標(biāo)準(zhǔn)按鈕(&S)”, IDM_TOOLBAR

                                                 menuitem              文字標(biāo)簽(&C)”, IDM_TOOLBARTEXT

                                                 menuitem              命令欄(&I)”, IDM_INPUTBAR

                                   END

                                   menuitem              狀態(tài)欄(&U)”, IDM_STATUSBAR

                     END

                     popup “幫助(&H)” HELP

                     BEGIN

                                   menuitem              幫助主題(&H)\F1”, IDM_HELP

                                   menuitem              separator

                                   menuitem              關(guān)于本程序(&A)…”, IDM_ABOUT

                     END

END

//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

IDA_MAIN           accelerators

BEGIN

                     VK_F1, IDM_HELP, VIRTKEY

                     “B”,        IDM_SETCOLOR, VIRTKEY, CONTROL, ALT

                     “F”,        IDM_SETFONT, VIRTKEY, ALT

END

//編譯上述文件使用的makefile文件如下:

NAME = Menu

OBJS = $(NAME).obj

RES = $(NAME).res

 

LINK_FLAG = /subsystem:windows

ML_FLAG = /c /coff

 

$(NAME).exe: $(OBJ) $(RES)

                     Link $(LINK_FLAG) $(OBJS) $(RES)

 

.asm .obj:

                     ml $(ML_FLAG) $<

 

.rc .res:

                     rc $<

 

clean:

                     del *.obj

                     del *.res

 

為了編譯資源文件,makefile中多了一個資源編譯的隱含規(guī)則:

.rc .res:

              rc $<

同時在exe文件的依賴文件中增加了Menu.res文件。

 

rc文件中,各種語句使用的是C語言語法格式,因?yàn)橘Y源編譯器Rc.exe根本上就是Visual C++附帶的,所以在定義等值語句的時候用的是#define,包含語句使用#include<文件名>,用到16進(jìn)制數(shù)值的時候并不是用匯編的語法在后面加h,而是用前面加0x的方法,如1234h寫為0x1234,注釋也要用前面加//的方法。

 

在腳本文件的頭部,首先要把MASM32軟件包中的resource.h文件包含進(jìn)來,這個文件中包括了資源定義中很多的預(yù)定義值,如窗口屬性與加速鍵的鍵值等。資源在程序中的引用往往用一個數(shù)值來表示,稱為資源的ID值,但在定義的時候直接使用數(shù)值不是很直觀,所以往往用#define語句將數(shù)值定義為容易記憶的字符串。

 

菜單的定義

在資源腳本文件中菜單的定義格式是:

菜單ID          MENU           [DISCARDABLE]

BEGIN

              菜單項(xiàng)定義

             

END

“菜單ID   MENU   [DISCARDABLE]”語句用來指定菜單的ID值和內(nèi)存屬性,菜單ID可以是16位的整數(shù),范圍是1~65535,在Menu.rc文件中,定義的菜單ID2000h,但菜單ID也可以字符串表示,如下面的定義:

MainMenu menu

begin

              menuitem…

end

 

表示菜單的ID是字符串型的“MainMenu”,但這樣定義的話,在程序中引用的時候就要用字符串指針代替16進(jìn)制的菜單ID值,顯得相當(dāng)不便,所以在實(shí)際應(yīng)用中通常使用16進(jìn)制數(shù)值當(dāng)做菜單ID

 

數(shù)值型ID的范圍限制在1~65535之間的原因是字符串在內(nèi)存中的線性地址總是大于10000hAPI函數(shù)檢測參數(shù)時發(fā)現(xiàn)小于10000h時就可以把它認(rèn)為是數(shù)值型的,大于10000h時就當(dāng)做字符串指針處理。

 

menu關(guān)鍵字后面的DISCARDABLE是菜單的內(nèi)存屬性,表示菜單在不再使用的時候可以暫時從內(nèi)存中釋放以節(jié)省內(nèi)存,這是一個可選屬性。菜單項(xiàng)的定義語句必須包含在beginend關(guān)鍵字之內(nèi),這兩個關(guān)鍵字也可以用花括號{}代替。

菜單項(xiàng)目的定義方法有3類:

       MENUITEM 菜單文字,命令ID[,選項(xiàng)列表]        (用法1

    MENUITEM SEPARATOR                                       (用法2

 POPUP 菜單文字[,選項(xiàng)列表]                               (用法3

       BEGIN

                     item-definitions

                    

       END

 

用法1定義的是普通菜單項(xiàng)

組成部分有:

菜單文字——顯示在菜單項(xiàng)中的字符串。如果需要字符串中某個字母帶下橫線,那么可以在字母前面加&符號,帶下橫線的字母可以被系統(tǒng)自動當(dāng)做快捷鍵。另外,如果要把加速鍵的提示信息顯示在菜單項(xiàng)的右邊,如“字體”菜單項(xiàng)中的“Alt+F”字符,可以在兩者中間加\t,表示插入一個Tab字符),寫為“字體(&F)…\tAlt+F”,這樣Tab后面的字符在顯示的時候會右對齊。

 

命令ID——用來分辨不同的菜單項(xiàng),當(dāng)菜單項(xiàng)被選中的時候,Windows會向窗口過程發(fā)送WM_COMMAND消息,消息的參數(shù)就是這個命令ID。用命令ID可以分辨用戶究竟選中了哪個菜單項(xiàng),所以不同的菜單項(xiàng)應(yīng)該定義不同的ID值,除非想讓兩個菜單項(xiàng)的功能相同。

 

選項(xiàng)——用來定義菜單項(xiàng)的各種屬性,它可以是下列數(shù)值:

       CHECKED——表示打上選定標(biāo)志(對鉤)。

       GRAYED——表示菜單項(xiàng)是灰化的。

       INACTIVE——表示菜單是禁用的。

       MENUBREAKMENUBARBREAK——表示將這個菜單項(xiàng)和以后的菜單項(xiàng)列到新的列中。

 

用法2定義的是菜單項(xiàng)之間的分隔線,顯然,分隔線是不需要字符串和選項(xiàng)的。

 

用法3定義的是彈出式菜單,頂層菜單是由多個彈出式子菜單組成的,所以在Menu.rc文件中,主菜單是由“文件”、“查看”、“幫助”3個順序定義的彈出式菜單組成的,彈出式菜單的定義也可以嵌套,如“查看”菜單中的“工具欄”又是一個彈出式菜單,在嵌套的時候要注意像寫C的源程序一樣把beginend(或者{})正確地配對。popup菜單的選項(xiàng)列表可以是以下的值:

       GRAYED——表示菜單項(xiàng)是灰化的。

       INACTIVE——表示菜單項(xiàng)是禁用的。

       HELP——表示本項(xiàng)和以后的菜單項(xiàng)是右對齊的。

 

popup菜單項(xiàng)選中的時候會自動將彈出式菜單彈出來,不需要向程序發(fā)送消息,所以在定義的參數(shù)中不需要命令ID

 

有些選項(xiàng)是可以同時定義,如果要指定超過一個的選項(xiàng),中間要用逗號隔開,但是也有些小小的限制:GRAYEDINACTIVE不能同時使用,MENUBREAKMENUBARBREAK也是不能同時使用的。

 

 

加速鍵的定義

和菜單的定義相比,加速鍵的定義要簡單得多,具體的語法如下:

加速鍵ID    ACCELERATORS

BEGIN

              鍵名,命令ID [,類型] [,選項(xiàng)]

             

END

 

加速鍵ID同樣可以是一個字符串或者是1~65535之間的數(shù)字,整個定義內(nèi)容也是用beginend(或花括號)包含起來,中間是多個加速鍵的定義項(xiàng)目,每個鍵占據(jù)一行,各字段的含義如下所示。

鍵名——表示加速鍵對應(yīng)的按鈕,可以有3種方式定義:

       ^字母”:表示Ctrl鍵加上字母鍵。

       “字母”:表示字母,這時類型必須指明是VIRTKEY

       數(shù)值:表示ASCII碼為該數(shù)值的字母,這時類型必須指明為ASCII

 

命令ID——按下加速鍵后,Windows向程序發(fā)送的命令ID。如果想把加速鍵和菜單項(xiàng)關(guān)聯(lián)起來,這里就是要關(guān)聯(lián)期間項(xiàng)的命令ID

類型——用來指定鍵的定義方式,可以是VIRTKEYASCII,分別用來表示“鍵名”字段定義的是虛擬鍵還是ASCII碼。

選項(xiàng)——可以是AltControlShift中的單個或多個,如果指定多個,則中間用逗號隔開,表示加速鍵是按鍵加上這些控制鍵的組合鍵。這些選項(xiàng)只能在類型是VIRTKEY的情況下才能使用。

 

在鍵名的定義中,系統(tǒng)按鍵如F1F2BackSpaceEsc等都是用虛擬鍵的方法定義的,Resource.h中已經(jīng)包括所有的預(yù)定義,它們是以VK_開頭的一引起值,如VK_BACKVK_TABVK_RETURNVK_ESCAPEVK_DELETEVK_F1VK_F2等,讀者可以查看Resource.h文件,下面是加速鍵定義的一些例子:

 

下面是加速鍵定義的一些例子:

“^C”,      ID                 ;Ctrl+C

“K”,        ID                 ;Shift+K

“k”,        ID,ALT          ;Alt+k

98,          ID,ASCII              ;b(字符bASCII碼為98

66,          ID,ASCII              ;BShift b

“g”,        ID                 ;g

VK_F1,   ID,VIRTKEY ;F1

VK_F2,   ID,VIRTKEY, CONTROL     ;Ctrl + F1

VK_F3,   ID,VIRTKEY,ALT,SHIFT      ;Alt + Shift + F2

 

在一個資源腳本文件中,可以定義多個菜單和多個加速鍵表,當(dāng)然也有其他各式各樣的資源,有位圖、圖標(biāo)與對話框等,這就涉及為這些資源取ID值的問題,取值的時候要掌握的原則是:

1)對于同類別的多個資源,資源ID必須為不同的值,如定義了兩個菜單,那么它們的ID就必須用不同的數(shù)值表示,否則將無法分辨。

2)對于不同類別的資源,資源ID在數(shù)值上可以是相同的,如可以將菜單和加速鍵的ID都定義為1,同時也可以有ID1的位圖或圖標(biāo)等,Windows并不會把它們搞混。

 

 

使用菜單和加速鍵

在完成資源文件所示的編寫后,來看看如何在程序中使用菜單和加速鍵,這里先列出程序的功能說明,讀者可以先嘗試一下,以便在以下的程序分析中有所印象。程序功能如下:

·程序在用戶選擇了任何一個菜單項(xiàng)以后,會彈出一個對話框,將接收到的菜單命令ID顯示出來。

·選擇“大圖標(biāo)”、“小圖標(biāo)”、“列表”和“詳細(xì)資料”菜單項(xiàng)后,選中的菜單項(xiàng)前面會出現(xiàn)一個圓點(diǎn)選中標(biāo)記,4個菜單項(xiàng)的選擇是互斥的。

·在窗口的客戶區(qū)單擊鼠標(biāo)右鍵會彈出和“查看”菜單一致的彈出式菜單。

·在標(biāo)題欄圖標(biāo)上單擊鼠標(biāo)左鍵,會彈出系統(tǒng)菜單,注意上面比默認(rèn)的菜單多了兩項(xiàng):“幫助主題”和“關(guān)于本程序”。

 

接下來,將逐步分析這些功能是如何實(shí)現(xiàn)的。下面是Menu.asm源代碼,代碼是在以前的FirstWindow程序的基礎(chǔ)上改寫的,這是編寫Win32匯編程序的一個常用方法——拷貝一個模板程序再進(jìn)行修改會節(jié)省很多的時間。

 

                .386

                .model flat,stdcall

                option casemap:none

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Include 文件定義

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

include         windows.inc

include         user32.inc

includelib      user32.lib

include         kernel32.inc

includelib      kernel32.lib

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; Equ 等值定義

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

ICO_MAIN        equ     1000h   ;圖標(biāo)

IDM_MAIN        equ     2000h   ;菜單

IDA_MAIN        equ     2000h   ;加速鍵

 

IDM_OPEN        equ     4101h

IDM_OPTION      equ     4102h

IDM_EXIT        equ     4103h

 

IDM_SETFONT     equ     4201h

IDM_SETCOLOR    equ     4202h

IDM_INACT       equ     4203h

IDM_GRAY        equ     4204h

IDM_BIG         equ     4205h

IDM_SMALL       equ     4206h

IDM_LIST        equ     4207h

IDM_DETAIL      equ     4208h

IDM_TOOLBAR     equ     4209h

IDM_TOOLBARTEXT equ     4210h

IDM_INPUTBAR    equ     4211h

IDM_STATUSBAR   equ     4212h

 

IDM_HELP        equ     4301h

IDM_ABOUT       equ     4302h

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 數(shù)據(jù)段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                .data?

hInstance       dd      ?

hWinMain        dd      ?

hMenu           dd      ?

hSubMenu        dd      ?

 

                .const

szClassName     db      'Menu Example',0

szCaptionMain   db      'Menu',0

szMenuHelp      db      '幫助主題(&H)',0

szMenuAbout     db      '關(guān)于本程序(&A)...',0

szCaption       db      '菜單選擇',0

szFormat        db      '您選擇了菜單命令:%08x',0

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 代碼段

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                .code

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 彈出窗口,顯示菜單命令ID

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_DisplayMenuItem    proc    _dwCommandID

                    local @szBuffer[256]:byte

                       

                pushad

                invoke wsprintf, addr @szBuffer, addr szFormat, _dwCommandID

                invoke MessageBox, hWinMain, addr @szBuffer, offset szCaption, MB_OK

                popad

                ret

_DisplayMenuItem    endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 退出

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_Quit           proc

                invoke DestroyWindow, hWinMain

                invoke PostQuitMessage, NULL

                ret

_Quit           endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

; 窗口過程

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_ProcWinMain    proc uses ebx edi esi, hWnd, uMsg, wParam, lParam

                local @stPos:POINT

                local @hSysMenu

 

                mov eax,uMsg

;*************************************************************************

                .if     eax == WM_CREATE

                        invoke     GetSubMenu, hMenu, 1

                        mov     hSubMenu, eax

;***************************************************************************

; 在系統(tǒng)菜單中添加菜單項(xiàng)

;***************************************************************************

                        invoke GetSystemMenu, hWnd, FALSE

                        mov     @hSysMenu, eax

                        invoke AppendMenu, @hSysMenu, MF_SEPARATOR, 0, NULL

                        invoke AppendMenu, @hSysMenu, 0, IDM_HELP, offset szMenuHelp

                        invoke AppendMenu, @hSysMenu, 0, IDM_ABOUT, offset szMenuAbout

;***************************************************************************

; 處理菜單及加速鍵消息

;***************************************************************************

                .elseif eax == WM_COMMAND

                        invoke _DisplayMenuItem, wParam

                        mov     eax, wParam

                        movzx   eax, ax

                        .if     eax == IDM_EXIT

                                call    _Quit

                        .elseif eax >= IDM_TOOLBAR && eax <= IDM_STATUSBAR

                                mov ebx, eax

                                invoke GetMenuState, hMenu, ebx, MF_BYCOMMAND

                                .if     eax == MF_CHECKED

                                        mov eax, MF_UNCHECKED

                                .else

                                        mov eax, MF_CHECKED

                                .endif

                                invoke CheckMenuItem, hMenu, ebx, eax

                        .elseif eax >= IDM_BIG && eax <= IDM_DETAIL

                                invoke CheckMenuRadioItem, hMenu, IDM_BIG, IDM_DETAIL, eax, MF_BYCOMMAND

                        .endif

;***************************************************************************

; 處理系統(tǒng)菜單消息

;***************************************************************************

                .elseif eax == WM_SYSCOMMAND

                        mov     eax, wParam

                        movzx   eax, ax

                        .if     eax == IDM_HELP || eax == IDM_ABOUT

                                invoke _DisplayMenuItem, wParam

                        .else

                                invoke DefWindowProc, hWnd, uMsg, wParam, lParam

                                ret

                        .endif

;***************************************************************************

; 單擊鼠標(biāo)右鍵時彈出一個POPUP菜單

;***************************************************************************

                .elseif eax == WM_RBUTTONDOWN

                        invoke GetCursorPos, addr @stPos

                        invoke TrackPopupMenu, hSubMenu, TPM_LEFTALIGN, @stPos.x, @stPos.y, NULL, hWnd, NULL

;***************************************************************************

                .elseif eax == WM_CLOSE

                        call    _Quit

;***************************************************************************

                .else

                        invoke     DefWindowProc,hWnd,uMsg,wParam,lParam

                        ret

                .endif

;***************************************************************************

                xor     eax,eax

                ret

_ProcWinMain    endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

_WinMain        proc

                local   @stWndClass:WNDCLASSEX

                local   @stMsg:MSG

                local   @hAccelerator

 

                invoke     GetModuleHandle,NULL

                mov     hInstance,eax

                invoke LoadMenu, hInstance, IDM_MAIN   ;獲取菜單句柄

                mov     hMenu, eax                      ;把菜單句柄存儲于hMenu變量

                invoke LoadAccelerators, hInstance,IDA_MAIN

                mov     @hAccelerator, eax

                

                invoke     RtlZeroMemory,addr @stWndClass,sizeof @stWndClass

;**************************************************************************

; 注冊窗口類

;**************************************************************************

                invoke LoadIcon, hInstance, ICO_MAIN

                mov     @stWndClass.hIcon, eax

                mov     @stWndClass.hIconSm, eax

                invoke LoadCursor, 0, IDC_ARROW

                mov     @stWndClass.hCursor, eax

                push    hInstance

                pop     @stWndClass.hInstance

                mov     @stWndClass.cbSize, sizeof WNDCLASSEX

                mov     @stWndClass.style, CS_HREDRAW or CS_VREDRAW

                mov     @stWndClass.lpfnWndProc, offset _ProcWinMain

                mov     @stWndClass.hbrBackground,COLOR_WINDOW + 1

                mov     @stWndClass.lpszClassName, offset szClassName

                invoke     RegisterClassEx, addr @stWndClass

;***************************************************************************

; 建立并顯示窗口

;***************************************************************************

                invoke     CreateWindowEx, WS_EX_CLIENTEDGE, \

                        offset szClassName, offset szCaptionMain, \

                        WS_OVERLAPPEDWINDOW, \

                        100, 100, 400, 300, \

                        NULL, hMenu, hInstance, NULL

                mov     hWinMain,eax

                invoke     ShowWindow,hWinMain,SW_SHOWNORMAL

                invoke     UpdateWindow,hWinMain

;**************************************************************************

; 消息循環(huán)

;**************************************************************************

                .while TRUE

                        invoke     GetMessage, addr @stMsg, NULL, 0, 0

                        .break     .if eax == 0

                        invoke TranslateAccelerator, hWinMain, @hAccelerator, addr @stMsg

                        .if     eax == 0

                                invoke TranslateMessage, addr @stMsg

                                invoke DispatchMessage, addr @stMsg

                        .endif

                .endw

                ret

_WinMain        endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

start:

                call    _WinMain

                invoke ExitProcess, NULL

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>

                end start

 

1、加載菜單

在窗口中加載菜單的方法有兩個:一是在注冊窗口類的時候指定類的默認(rèn)菜單;二是在建立窗口的時候在參數(shù)中指定菜單句柄。Menu.asm程序中用的是第2種方法:

       invoke CreateWindowEx, WS_EX_CLIENTEDGE, \

                     offset szClassName, offset szCaptionMain, \

                     WS_OVERLAPPEDWINDOW,\

                     100, 100, 400, 300, \

                     NULL, hMenu, hInstance, NULL

在參數(shù)中指出了hMenu。不管用哪種方法,首先都必須使用LoadMenu函數(shù)來獲取菜單句柄hMenu,如下面的語句:

       invoke     LoadMenu, hInstance, IDM_MAIN

       mov hMenu, eax

這個函數(shù)的第1個參數(shù)是用GetModuleHandle獲取的實(shí)例句柄,第2個參數(shù)指定需要裝入的菜單資源ID,函數(shù)返回菜單句柄。在得到菜單句柄以后,我們先把它放入hMenu變量保存起來以便后用。

 

當(dāng)資源文件中用字符串為名稱定義菜單而不是用數(shù)值的時候,例如:

       MainMenu      menu             //定義菜單名為字符串“MainMenu

       begin

                    

       end

那么在程序中就必須用字符串指針代替菜單ID做參數(shù):

       szMenu   “MainMenu”,0              ;在數(shù)據(jù)段中定義菜單名稱字符串

                    

                     invoke     LoadMenu, hInstance, addr szMenu            ;在程序中裝載

                     mov        hMenu, eax

注:用字符串為名稱定義資源,在資源裝載函數(shù)LoadXXXX中用戶字符串指針做參數(shù)裝入,這實(shí)際上是一個通用的方法,不僅適用于菜單資源,對于其他類別的資源也是適用的。

 

 

2、加載加速鍵

和菜單一樣,加速鍵在使用前也要裝入,參數(shù)同樣是在資源腳本文件中定義的加速鍵ID,程序中對應(yīng)的語句是:

       invoke     LoadAccelerators, hInstance, IDA_MAIN

       mov        @hAccelerator, eax

其實(shí)我們自己在程序中也可以很方便地實(shí)現(xiàn)加速鍵功能,方法是:在WM_KEYDOWN消息中判斷鍵盤消息并按照自定義的邏輯進(jìn)行處理,使用加速鍵實(shí)際上是讓Windows替我們完成這個功能,Windows實(shí)現(xiàn)的方法正是在消息循環(huán)中檢查WM_KEYDOWNWM_SYSKEYDOWN消息。下面是使用加速鍵時消息循環(huán)的代碼,請注意粗體字部分:

.while      TRUE

              invoke     GetMessage, addr @stMsg, NULL, 0, 0

              .break     .if    eax == 0

              invoke     TranslateAccelerator, hWinMain, @hAccelerator, addr @stMsg

              .if           eax == 0

                            invoke     TranslateMessage, addr @stMsg

                            invoke     DispatchMessage, addr @stMsg

              .endif

.endw

 

TranslateAccelerator函數(shù)是實(shí)現(xiàn)加速鍵功能的核心,它的參數(shù)為目標(biāo)窗口、加速鍵句柄和GetMessage取得的消息結(jié)構(gòu)。該函數(shù)檢查消息結(jié)構(gòu)中的消息,如果遇到WM_KEYDOWNWM_SYSKEYDOWN消息則檢測加速鍵資源,看按鍵是否符合某個加速鍵,符合的話則向目標(biāo)窗口發(fā)送WM_COMMANDWM_SYSCOMMAND消息,并返回TRUE,不符合的話不進(jìn)行任何處理并返回FALSE

 

由于加速鍵的鍵碼并不是用戶真正想輸入窗口的,比如用戶在寫字板中輸入文字,按Ctrl+C鍵是為了“拷貝”,而不是想把Ctrl+C鍵對應(yīng)的字符輸入文檔,所以這個Ctrl+C的鍵碼在完成加速鍵的使命后就應(yīng)該丟棄,也就是說符合加速鍵的鍵盤消息不應(yīng)該再發(fā)送給窗口,TranslateMessageDispatchMessage函數(shù)前的邏輯判斷就是這樣的意圖:只有TranslateAccelerator沒有轉(zhuǎn)換的消息(返回值eax0)才繼續(xù)處理。

 

另外,TranslateAccelerator的參數(shù)中有個“目標(biāo)窗口”,例子中是程序的主窗口hWinMain,為什么要設(shè)置這樣一個參數(shù)而不像DispatchMessage函數(shù)一樣使用MSG結(jié)構(gòu)中的hwnd呢?這是因?yàn)殒I盤消息可以產(chǎn)生于不同窗口中——既可能是主窗口,也可能是其他子窗口,如果用@stMsg.hwnd做目標(biāo)窗口,就必須在所有子窗口的窗口過程中都設(shè)置處理加速鍵消息的代碼,這顯然是一種浪費(fèi),所以一般把所有的加速鍵消息都發(fā)送到主窗口,然后集中在主窗口的窗口過程中處理WM_COMMAND消息,這樣有利精簡代碼。

 

3、菜單和加速鍵消息

當(dāng)用戶選擇了一個菜單項(xiàng)的時候,Windows向菜單所屬的窗口發(fā)送WM_COMMAND消息;而用戶按下了一個加速鍵的時候,WindowsTranslateAccelerator函數(shù)指定的目標(biāo)窗口發(fā)送WM_COMMAND消息。一般這兩種情況對應(yīng)的窗口都是主窗口,所以可以在主窗口中的窗口過程中集中處理WM_COMMAND消息,而不必考慮它究竟是菜單引發(fā)的還是加速鍵引發(fā)的。

 

WM_COMMAND消息的兩個參數(shù)是這樣定義的:

wParam的高位 = wNotifyCode         ;通知碼

wParam的低位 = wID                      ;命令ID

lParam =hwndCtl                               ;發(fā)送WM_COMMAND的子窗口句柄

除了菜單和加速鍵,WM_COMMAND消息也可以由其他子窗口引發(fā),如主窗口中的按鈕或工具欄等,lParam參數(shù)指定了引發(fā)消息的子窗口句柄,對于菜單和加速鍵引發(fā)的WM_COMMAND消息,lParam的值為零。wParam參數(shù)的低16位是命令ID,也就是資源腳本文件中菜單項(xiàng)的命令ID或加速鍵的命令ID,高16位是通知碼,菜單消息的通知碼是0,加速鍵消息的通知碼為1

 

在需要處理菜單和加速鍵消息的窗口過程中,一般需要增加一個WM_COMMAND分支來處理對應(yīng)的消息,這個分支的一般結(jié)構(gòu)為:

       .elseif             eax == WM_COMMAND     ;eax中為wMsg

                            mov        eax, wParam

                            movzx     eax, ax

                            .if           eax == 命令ID1

                                         

                            .elseif      eax == 命令ID2

                                         

                            .endif

其中movzx eax, ax指令將16位的ax擴(kuò)展到32位的eax,相當(dāng)于將eax的高16位清零,作用就是當(dāng)消息由加速鍵引起時,將高16位中的1忽略,這樣下面的分支就可以同時處理菜單和加速鍵消息,當(dāng)然讀者也可以去掉這一句,這樣下面的比較語句中就要使用ax而不是eax

 

在例子程序中,mov eax, wParam前面還有一句invoke _DisplayMenuItem, wParam, 作用是在處理WM_COMMAND消息前將wParam的值通過一個對話框顯示出來,讀者可以和資源腳本文件中定義的命令ID值對比一下,在正常使用的程序中可以去掉這一句。

 

讀者可以發(fā)現(xiàn),資源文件中定義的“字體”菜單項(xiàng)的ID0x4201,當(dāng)選中“字體”菜單項(xiàng)的時候,對話框中顯示的wParam數(shù)值正是00004201,而按下加速鍵Alt+F的時候,顯示出來的值卻是00014201了,它們的區(qū)別就是高16位中的通知碼不同。

 

4、菜單項(xiàng)的修改

在程序的運(yùn)行中也可以動態(tài)修改菜單項(xiàng),包括添加、刪除和修改操作,這些操作是通過幾個API函數(shù)來完成的:

       invoke     AppendMenu, hMenu, uFlags, uIDNewItem, lpNewItem           ;添加菜單項(xiàng)

       invoke     InsertMenu, hMenu, uPosition, uFlags, uIDNewItem, lpNewItem     ;插入菜單項(xiàng)

       invoke     ModifyMenu, hMenu, uPosition, uFlags, uIDNewItem, lpNewItem   ;修改菜單項(xiàng)

       invoke     DeleteMenu, hMenu, uPosition, uFlags        ;刪除菜單項(xiàng)

       invoke     RemoveMenu, hMenu, uPosition, uFlags      ;刪除菜單項(xiàng)

 

其中AppendMenu用來在一個菜單的最后添加菜單項(xiàng),InsertMenu則在中間插入菜單項(xiàng),ModifyMenu可以修改一個菜單項(xiàng)的文字,DeleteMenuRemoveMenu則可以刪除一個菜單項(xiàng)。

 

這些函數(shù)中的參數(shù)都雷同的,hMenu參數(shù)指要操作的菜單句柄;uPosition用來定位要操作的菜單項(xiàng),定位的方法有兩種:用命令ID定義或用位置索引,用哪一種方法取決于后面的uFlags參數(shù),當(dāng)uFlagsMF_BYCOMMAND時,uPosition為菜單項(xiàng)的命令ID,而當(dāng)uFlagsMF_BYPOSITION的時候,uPosition表示菜單項(xiàng)的位置索引,索引是從0開始的,也就是說第一個菜單項(xiàng)的索引值為0

 

AppendMenu函數(shù)總是在菜單的最后添加新的菜單項(xiàng),所以不需要uPosition參數(shù)。

對于AppendMenuInsertMenu,會有一個新的菜單項(xiàng)產(chǎn)生,uIDNewItem就表示這個新菜單項(xiàng)的命令IDlpNewItem指向新菜單項(xiàng)的文字字符串,ModifyMenu函數(shù)可以修改一個菜單項(xiàng)的命令ID或文字字符串,所以也有uIDNewItemlpNewItem參數(shù)。而用來刪除菜單項(xiàng)的DeleteMenuRemoveMenu顯然用不著uIDNewItemlpNewItem參數(shù)。

 

uFlags參數(shù)除了指定MF_BYCOMMAND還是MF_BYPOSITION外,還可以組合指定菜單項(xiàng)的其他屬性,如MF_CHECKED,MF_DISABLED, MF_ENABLED, MF_GRAYED, MF_MENUBARBREAK, MF_MENUBREAK, MF_SEPARATORMF_UNCHECKED等,從其字面上就可以看出這些屬性的含義。

 

DeleteMenuRemoveMenu的不同之外在于對popup菜單項(xiàng)的處理。當(dāng)它們用于popup屬性的菜單項(xiàng)時,DeleteMenu不僅刪除菜單項(xiàng),而且將這個popup菜單項(xiàng)的所有子項(xiàng)目全部刪除,這樣,這個popup菜單就不能在別的地方繼續(xù)使用;而RemoveMenu僅從菜單中移去這個popup菜單項(xiàng),整個popup菜單在內(nèi)存中還是存在的。以Menu.asm程序?yàn)槔瑨呤髽?biāo)右鍵彈出的菜單實(shí)際上是主菜單中的“查看”菜單項(xiàng),假如用DeleteMenu刪除主菜單中的“查看”項(xiàng)目,那么按右鍵也就彈不出菜單了,而用RemoveMenu刪除主菜單中的“查看”項(xiàng)目,按鼠標(biāo)右鍵依然可以彈出菜單。對于非popup屬性的菜單項(xiàng),DeleteMenuRemoveMenu的效果是同樣的。

 

5、使用系統(tǒng)菜單

系統(tǒng)菜單指按下了標(biāo)題欄圖標(biāo)后彈出的菜單,和窗口菜單不同,選中系統(tǒng)菜單的菜單項(xiàng)后,Windows向窗口發(fā)送的是WM_SYSCOMMAND消息而非WM_COMMAND消息。默認(rèn)的系統(tǒng)菜單中已經(jīng)有“還原”、“移動”、“大小”、“最大化”、“最小化”和“關(guān)閉”等菜單項(xiàng),這些菜單項(xiàng)的命令ID已經(jīng)預(yù)定義為SC_RESTORESC_MOVESC_SIZESC_MAXIMIZESC_MINIMIZESC_CLOSE等,如果讀者要自己處理它們,可以在WM_SYSCOMMAND消息中建立一個比較分支對它們進(jìn)行處理,一般在程序中并不自己處理WM_SYSCOMMAND消息,而是交給DefWindowProc處理。

 

如何在系統(tǒng)菜單中添加自己的菜單項(xiàng)呢?方法就是使用上面介紹的AppendMenu(當(dāng)然也可以用InsertMenu),在添加前必須用GetSystemMenu函數(shù)首先獲取系統(tǒng)菜單的句柄。例子程序在窗口初始化的時候在系統(tǒng)菜單尾添加了一個分隔線和兩個菜單項(xiàng):“幫助主題”和“關(guān)于本程序”:

       .if    eax == WM_CREATE

             

              invoke     GetSystemMenu, hWnd, FALSE

              mov        @hSysMenu, eax

              invoke     AppendMenu, @hSysMenu, MF_SEPARATOR, 0, NULL

              invoke     AppendMenu, @hSysMenu, 0, IDM_HELP, offset szMenuHelp

              invoke     AppendMenu, @hSysMenu, 0, IDM_ABOUT, offset szMenuAbout

在窗口過程中處理系統(tǒng)菜單消息的分支結(jié)構(gòu)為:

       .elseif      eax == WM_SYSCOMMAND

                     mov        eax, wParam

                     .if           ax == 自定義ID1

                                  

                     .else

                                   invoke     DefWindowProc, hWnd, uMsg, wParam, lParam

                                   ret

                     .endif

和處理WM_COMMAND消息不同的是,在WM_SYSCOMMAND消息中處理了自定義的菜單命令ID后,必須把其他命令ID交給DefWindowProc處理,并直接把返回值返回給Windows,不然的話會發(fā)現(xiàn)窗口不能移動,不能關(guān)閉,不能最小化……因?yàn)樗喈?dāng)于屏幕了所有SC_RESTORE, SC_MOVE, SC_SIZE, SC_MAXIMIZE, SC_MINIMIZESC_CLOSE等消息的處理。

 

6、右鍵彈出菜單

例子程序的一個功能是當(dāng)用戶在窗口客戶區(qū)按下鼠標(biāo)右鍵的時候彈出一個菜單,這個功能是用TrackPopupMenu函數(shù)實(shí)現(xiàn)的。TrackPopupMenu函數(shù)的用法:

       invoke     TrackPopupMenu, hMenu, uFlags, x, y, nReserved, hWnd, lpRect

這個函數(shù)本身很簡單,執(zhí)行后在參數(shù)指定的x,y位置彈出一個屬于hWnd窗口(也就是說WM_COMMAND消息發(fā)到這個窗口)的菜單,菜單句柄是hMenu。函數(shù)中的坐標(biāo)是以整個屏幕左上角為基準(zhǔn)的,所以彈出菜單的位置不一定在窗口的客戶區(qū)內(nèi),它可以是屏幕的任何一個地方。

 

uFlags參數(shù)指定一些和位置相關(guān)的選項(xiàng),它可以是PM_CENTERALIGNTPM_LEFTALIGNTPM_RIGHTALIGN三者之一,表示(x, y)坐標(biāo)是代表彈出菜單位置的中間、左上角還是右上角,一般的習(xí)慣是使用TPM_LEFTALIGN,這樣菜單會在鼠標(biāo)點(diǎn)擊處的右邊彈出。uFlags中同時還可以指定用鼠標(biāo)左鍵還是右鍵選定菜單項(xiàng),定義值可以是TPM_LEFTBUTTONTPM_RIGHTBUTTON,如果選擇TPM_RIGHTBUTTON的話,對在菜單項(xiàng)上面按鼠標(biāo)左鍵是沒有反應(yīng)的。

 

lpRect指向一個RECT結(jié)構(gòu),用來指定一個區(qū)域,當(dāng)菜單彈出后,在這個區(qū)域外單擊鼠標(biāo),菜單才會消失,如果這個參數(shù)指定為NULL的話,在菜單之外單擊鼠標(biāo),菜單就會消失。

 

在使用TrackPopupMenu之前,有幾個準(zhǔn)備工作是要做的:為了在客戶區(qū)中按下鼠標(biāo)右鍵彈出菜單,我們當(dāng)然要處理鼠標(biāo)右鍵消息,也就是說在WM_RBUTTIONDOWN消息中調(diào)用TrackPopupMenu函數(shù),一般的習(xí)慣是在鼠標(biāo)按下的地方彈出菜單,所以還要首先獲取鼠標(biāo)光標(biāo)的位置,然后在此位置彈出菜單。

 

要獲取鼠標(biāo)位置,可以用GetCursorPos函數(shù):

       invoke GetCusorPos, lpPoint

參數(shù)lpPoint指向一個POINT數(shù)據(jù)結(jié)構(gòu),這個結(jié)構(gòu)只有兩個字段:

POINT STRUCT

x     DWORD       ?

y     DWORD        ?

POINT ENDS

 

該結(jié)構(gòu)用來表示一個點(diǎn)的(x, y)坐標(biāo),GetCursorPos將當(dāng)前的鼠標(biāo)位置返回到這個結(jié)構(gòu)中,程序中的相關(guān)代碼是:

       local        @stPos:POINT             ;首先定義一個POINT結(jié)構(gòu)

      

       invoke     GetCursorPos, addr @stPos         ;獲取鼠標(biāo)位置

       invoke     TrackPopupMenu, hSubMenu, \

                     TPM_LEFTALIGN, @stPos.x, @stPos.y, NULL, hWnd, NULL

GetCursorPos獲取的鼠標(biāo)位置是一個POINT結(jié)構(gòu),但TrackPopupMenu輸入坐標(biāo)的方法是用xy兩個參數(shù),而不是一個POINT結(jié)構(gòu),所以要用結(jié)構(gòu)中的兩個字段@stPos.x@stPos.y分別輸入。

 

使用TrackPopupMenu時要注意的是,彈出的菜單句柄必須是popup類型的,而在資源文件中定義并且可以用LoadMenu函數(shù)裝入的菜單并不是popup類型的,popup菜單(如例子中的“文件”與“查看”等)只能在第二層中才能定義,在程序中用GetSubMenu得到的第二層子菜單的句柄才是popup類型的。GetSubMenu函數(shù)的用法是:

       invoke     GetSubMenu, hMenu, nPos

       .if           eax

                     mov hSubMenu, eax

       .endif

nPos參數(shù)指定要獲取的菜單的位置索引,GetSubMenu的返回值是獲取的子菜單句柄。例子用invoke GetSubMenu, hMenu, 1取得第二個子菜單(“文件”子菜單為0,“查看”子菜單為1,……)的句柄,然后在TrackPopupMenu中使用,這個菜單句柄就是主菜單中的“查看”菜單,所以按鼠標(biāo)右鍵彈出的菜單和下拉菜單中的“查看”菜單是一模一樣的。

 

 

7、菜單狀態(tài)的檢測和設(shè)置

在程序中經(jīng)常要對菜單項(xiàng)的狀態(tài)進(jìn)行設(shè)置,如剪貼板中沒有數(shù)據(jù)時,“粘貼”菜單項(xiàng)應(yīng)該灰化,窗口中沒有被選中的字符時,“拷貝”菜單項(xiàng)也應(yīng)該灰化,這樣可以給使用者一個善意的提醒。同樣,對菜單的狀態(tài)也常常需要檢測,如查看菜單項(xiàng)的狀態(tài)是否處于灰化狀態(tài)或選中狀態(tài)以便進(jìn)行下一步操作等。

 

對菜單項(xiàng)狀態(tài)的檢測可以用GetMenuState函數(shù)來完成,用法是:

       invoke     GetMenuState, hMenu, uId, uFlags

參數(shù)hMenu是菜單的句柄,uId用來定位要檢測的菜單項(xiàng),當(dāng)uFlagsMF_BYCOMMAND的時候,uId用菜單項(xiàng)的命令ID指定,當(dāng)uFlagsMF_BYPOSITION的時候,uId的值是位置索引,函數(shù)執(zhí)行后的返回值為-1時表示失敗,否則會是MF_CHECKED, MF_DISABLED, MF_GRAYED, MF_HILITE, MF_MENUBARBREAK, MF_MENUBREAKMF_SEPARATOR的組合值,它們分別表示菜單項(xiàng)的狀態(tài)是選中、禁止、灰化、高亮顯示以及3種分隔線,讀者可以用test指令測試相應(yīng)的數(shù)據(jù)位來分辨菜單項(xiàng)處于哪種狀態(tài),一般的測試代碼如下:

       invoke    GetMenuStage, hMenu, IDM_XXX, MF_BYCOMMAND

       .if           eax & MF_CHECKED

                     ;表示IDM_XXX菜單項(xiàng)現(xiàn)在是選中狀態(tài)

       .endif

 

同樣,讀者也可以用eax & MF_DISABLEDeax & MF_GRAYED等條件測試其他狀態(tài)。

 

設(shè)置菜單項(xiàng)的狀態(tài)可以用下列3個函數(shù)來實(shí)現(xiàn)不同的功能:

       invoke     EnableMenuItem, hMenu, uIDEnableItem, uEnable

       invoke     CheckMenuItem, hMenu, uIDCheckItem, uCheck

       invoke     CheckMenuRadioItem, hMenu, idFirst, idLast, idCheck, uFlags

 

EnableMenuItem函數(shù)將菜單項(xiàng)在禁用、可用和灰化狀態(tài)之間切換,uEnable可以取值為MF_DISABLED, MF_ENABLEDMF_GRAYED,分別代表這3種狀態(tài)。

 

CheckMenuItem函數(shù)將菜單項(xiàng)在非互斥的選定狀態(tài)和非選定狀態(tài)之間切換(即前面是否有對鉤),uCheck的取值可以是MF_CHECKEDMF_UNCHECKED,代表選定或非選定狀態(tài)。

 

CheckMenuRadioItem將菜單項(xiàng)在互斥的選定狀態(tài)和非選定狀態(tài)之間切換(即前面是否有圓點(diǎn)標(biāo)志),由于互斥的菜單項(xiàng)在一個范圍內(nèi)只有一個是可以選定的,當(dāng)選定另一個的時候,原來的選定應(yīng)該撤銷,idFirstidLast就指定了這個互斥范圍。函數(shù)在選定idCheck指定的菜單項(xiàng)的同時將自動清除idFirstidLast范圍內(nèi)的其他選定。所以uFlags中無需指定狀態(tài),只需指定MF_BYCOMMANDMF_BYPOSITION定位方式。

 

在這些函數(shù)的參數(shù)中,uIDEnableItem, uIDCheckItem, idFirst, idLastidCheck用來定位菜單項(xiàng),同樣,參數(shù)的取值可以是菜單項(xiàng)的命令ID或位置索引,可以在狀態(tài)參數(shù)(uEnable, uCheck, uFlags)中組合定義MF_BYCOMMANDMF_BYPOSITION來決定使用哪種方法。

 

在例子程序中,當(dāng)選中IDM_TOOLBARIDM_STATUSBAR之間的菜單項(xiàng)的時候,程序先用invoke GetMenuState, hMenu, ebx, MF_BYCOMMAND獲取當(dāng)前的狀態(tài),檢查是否選定,并將選定狀態(tài)反轉(zhuǎn)后用CheckMenuItem重新設(shè)置:

       .elseif             eax >= IDM_TOOLBAR && eax <= IDM_STATUSBAR

                            mov ebx, eax

                            invoke     GetMenuState, hMenu, ebx, MF_BYCOMMAND

                            .if           eax == MF_CHECKED

                                          mov        eax, MF_UNCHECKED

                            .else

                                          mov        eax, MF_CHECKED

                            .endif

                            invoke     CheckMenuItem, hMenu, ebx, eax

當(dāng)選中IDM_BIGIDM_DETAIL之間的菜單項(xiàng)的時候,程序用CheckMenuRadioItem將原告IDM_BIGIDM_DETAIL范圍內(nèi)的互斥選定撤銷并將當(dāng)前選定的菜單項(xiàng)加圓點(diǎn)標(biāo)記。

.elseif      eax >= IDM_BIG && eax <= IDM_DETAIL

              invoke     CheckMenuRadioItem, hMenu, IDM_BIG, IDM_DETAIL, \

                            eax, MF_BYCOMMAND

 

最后,修改菜單狀態(tài)的時機(jī)是什么時候呢?在程序中似乎不應(yīng)該隨時去檢測狀態(tài)并設(shè)置,這顯然是很浪費(fèi)資源的。Windows考慮到了這一點(diǎn):在菜單將要激活的時候,也就是用戶在菜單上按動鼠標(biāo)的時候,Windows在菜單彈出之前會向窗口過程發(fā)送WM_INITMENU消息,我們可以從容不迫地在這里進(jìn)行各種檢測,并設(shè)置對應(yīng)的菜單項(xiàng)。

 

注意:讀者可以注意到,在狀態(tài)參數(shù)中指定MF_COMMANDMF_POSITION將決定位置參數(shù)用命令ID還是位置索引表示,這個規(guī)則在所有的菜單函數(shù)中都是適用的,MF_BYCOMMAND是默認(rèn)值(它的定義值是0),如果兩者都不定義的話,位置參數(shù)代表的就是命令ID

 

8、其他菜單函數(shù)

除了前面介紹的一些函數(shù)之外,還有一些不太常用的菜單函數(shù),在這里作一個簡單的介紹。

 

菜單不一定非要在資源文件中定義,在程序中也可以用代碼來建立菜單,不過比較麻煩一點(diǎn),方法是先用CreateMenu建立一個菜單,CreateMenu函數(shù)沒有參數(shù),調(diào)用后返回一個沒有任何菜單項(xiàng)的菜單句柄,接下來就可以用AppendMenu在上面一條條地添加菜單項(xiàng)了。

 

同樣,CreatePopupMenu也可以建立一個沒有任何菜單項(xiàng)的菜單句柄,但它建立的是popup類型的菜單句柄,可以在TrackPopupMenu中直接使用。

 

如果要獲取一個窗口當(dāng)前使用的菜單句柄,那么可以使用GetMenu函數(shù):

       invoke     GetMenu, hWnd

       mov        hMenu, eax

一個菜單的總項(xiàng)數(shù)可以用GetMenuItemCount函數(shù)獲取:

       invoke     GetMenuItemCount, hMenu

不過GetMenuItemCount函數(shù)的返回值不包括子菜單展開以后的項(xiàng)數(shù),而是指最上層菜單的項(xiàng)數(shù),比如在例子程序中對hMenu統(tǒng)計的結(jié)果是3,因?yàn)?/span>Menu.rc中定論的最上層的菜單項(xiàng)是“文件”、“查看”、和“幫助”,總共3個,如果要統(tǒng)計全部展開后的項(xiàng)數(shù),那么只好用GetSubMenu一層層地統(tǒng)計下去了

 

對菜單中各個菜單項(xiàng)當(dāng)前的文字和命令ID也是可以查詢的,方法是用GetMenuStringGetMenuItemID,讀者可以參考命令手冊。

 

建立窗口時指定了菜單句柄后并不是不能改變的,我們常常見到一些編輯軟件,沒有打開文件之前菜單只有寥寥幾項(xiàng),一打開文件以后功能菜單就全部出來了,實(shí)際上這是用SetMenu函數(shù)完成的:

       invoke     SetMenu, hWnd, hMenu

 

可以在資源文件中預(yù)定義幾個不同的菜單,在使用的時候根據(jù)不同情況用SetMenu設(shè)置不同的菜單句柄。

 

使用菜單后,要涉及清除的總是,和窗口相連的菜單句柄在窗口摧毀的時候會由Windows自動釋放,不需要手工釋放,但沒有和窗口相連的菜單就要由程序自己來釋放了,方法是使用DestroyMenu函數(shù),比如沒有和窗口相連而僅用TrackPopupMenu彈出的菜單句柄:

       invoke     DestroyMenu, hMenu

 

 

posted on 2010-08-31 09:43 luqingfei 閱讀(3599) 評論(1)  編輯 收藏 引用 所屬分類: Win32匯編程語言序設(shè)計

評論

# re: Win32匯編--使用資源--菜單和加速鍵 2011-03-29 09:38 coreBugZJ

初學(xué)的匯編(用NASM),仰慕!!  回復(fù)  更多評論   

導(dǎo)航

<2010年8月>
25262728293031
1234567
891011121314
15161718192021
22232425262728
2930311234

統(tǒng)計

留言簿(6)

隨筆分類(109)

隨筆檔案(105)

Blogers

Game

Life

NodeJs

Python

Useful Webs

大牛

搜索

積分與排名

最新評論

閱讀排行榜

評論排行榜

青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久五月天婷婷| 国产精品欧美一区二区三区奶水| 91久久视频| 久久中文字幕导航| 免费成人在线视频网站| 欧美jizz19hd性欧美| 欧美高清在线一区| 亚洲精品女av网站| 亚洲精选成人| 亚洲欧美精品在线观看| 久久久久国色av免费看影院 | 亚洲第一主播视频| 香蕉久久夜色| 欧美一区=区| 免费一区二区三区| 国产精品久久毛片a| 狠狠网亚洲精品| 一区二区欧美亚洲| 久热爱精品视频线路一| 日韩视频永久免费观看| 欧美尤物一区| 欧美精品导航| 国产一区二区三区四区在线观看 | 欧美一区午夜视频在线观看| 久久综合影音| 国产女人aaa级久久久级| 91久久线看在观草草青青| 亚洲欧美日韩在线播放| 欧美wwwwww| 亚洲欧美欧美一区二区三区| 欧美成人精品一区二区三区| 国产精品亚洲综合天堂夜夜| 亚洲精品看片| 久久中文精品| 欧美一级专区免费大片| 国产精品久久夜| 宅男精品视频| 亚洲欧洲精品一区二区三区 | 麻豆精品视频在线观看视频| 日韩午夜av电影| 美女在线一区二区| 韩国三级电影久久久久久| 亚洲天堂激情| 欧美国产欧美亚州国产日韩mv天天看完整| 一区二区三区av| 欧美喷水视频| 日韩视频亚洲视频| 亚洲国产精品综合| 免费亚洲电影在线| 在线欧美视频| 美女91精品| 久久精品一本| 在线看片日韩| 男人天堂欧美日韩| 蜜臀久久99精品久久久画质超高清| 国产日韩欧美综合| 欧美中文字幕久久| 性欧美超级视频| 国产一区二区三区高清播放| 欧美伊人精品成人久久综合97 | 亚洲淫片在线视频| 欧美日韩一区二区三区视频 | 一区二区三区欧美亚洲| 91久久国产自产拍夜夜嗨| 浪潮色综合久久天堂| 免费日韩成人| 免费成人黄色| 亚洲毛片在线免费观看| 亚洲激情一区二区| 欧美三日本三级三级在线播放| 亚洲免费精品| 亚洲激情婷婷| 欧美三日本三级三级在线播放| 这里只有精品视频| 一区二区三区**美女毛片| 国产精品福利久久久| 欧美一区二区三区啪啪| 欧美一区二区黄| 亚洲电影在线| 91久久黄色| 国产精品久久久免费| 久久久www成人免费精品| 久久久无码精品亚洲日韩按摩| 亚洲国产天堂久久综合| 亚洲免费不卡| 国产欧美高清| 蜜桃久久精品乱码一区二区| 免费人成网站在线观看欧美高清 | 欧美激情视频给我| 一本一本久久a久久精品综合麻豆| 99www免费人成精品| 国产日韩欧美视频在线| 亚洲国产99| 国产乱人伦精品一区二区| 免费在线日韩av| 欧美午夜片在线观看| 久久久久久久久综合| 欧美精品久久久久久| 久久精品视频va| 日韩视频中文字幕| 中日韩男男gay无套| 黄色在线一区| 亚洲私人影吧| 亚洲伦理精品| 久久精品国产亚洲精品| 99这里只有精品| 久久久久国产一区二区| 小黄鸭精品密入口导航| 欧美激情视频网站| 美女日韩欧美| 国内精品久久久久久久影视蜜臀| 亚洲精品一区二区三区樱花 | 亚洲网站在线播放| 悠悠资源网久久精品| 亚洲一区视频| 亚洲一区二区黄色| 欧美人与性禽动交情品| 免费成人性网站| 国产亚洲精品久久久| 亚洲一区二区三区精品动漫| 99riav国产精品| 欧美大片国产精品| 亚洲综合电影| 亚洲在线电影| 欧美女人交a| 欧美激情日韩| 91久久极品少妇xxxxⅹ软件| 久久国产精品黑丝| 欧美在线国产精品| 国产精品日产欧美久久久久| 一二三四社区欧美黄| av成人免费观看| 欧美成人黄色小视频| 欧美黄色一区二区| 亚洲人成免费| 欧美精品免费播放| 日韩亚洲欧美综合| 亚洲欧美日韩人成在线播放| 国产精品久久中文| 亚洲免费综合| 久久精品国产精品亚洲| 国产一区二区三区在线播放免费观看| 午夜精品亚洲| 狂野欧美激情性xxxx欧美| 在线色欧美三级视频| 欧美成人综合一区| 亚洲精品影院在线观看| 夜夜嗨av一区二区三区网页| 欧美日韩免费观看一区二区三区| 日韩网站在线观看| 欧美在线观看你懂的| 激情综合五月天| 欧美成人精品三级在线观看| 亚洲精品三级| 午夜精品美女久久久久av福利| 国产精品网曝门| 欧美中在线观看| 亚洲风情亚aⅴ在线发布| 一区二区三区高清视频在线观看| 国产精品二区在线观看| 久久久久久91香蕉国产| 亚洲三级免费| 久久国内精品自在自线400部| 国产一区av在线| 欧美第一黄色网| 亚洲综合精品| 欧美黄色一区二区| 欧美影视一区| 日韩视频―中文字幕| 国产伦精品一区二区三区在线观看 | 亚洲精品视频一区| 国产精品国产三级国产aⅴ无密码 国产精品国产三级国产aⅴ入口 | 午夜日韩电影| 美女精品一区| 亚洲伊人第一页| 亚洲黄色毛片| 国产日韩欧美三级| 欧美激情视频一区二区三区免费| 亚洲主播在线播放| 亚洲毛片在线观看.| 久久久噜噜噜| 亚洲影视综合| 亚洲精品日产精品乱码不卡| 亚洲视频中文字幕| 另类尿喷潮videofree| 一本久久a久久精品亚洲| 久久中文在线| 亚洲自拍偷拍麻豆| 亚洲国产精品女人久久久| 国产精品你懂的| 欧美乱大交xxxxx| 久久精品视频99| 亚洲在线观看免费| 亚洲理论在线| 亚洲激情在线观看视频免费| 久久一区二区精品| 欧美一区影院| 亚洲在线观看| 亚洲伊人伊色伊影伊综合网| 亚洲精品日韩精品|