📄 lion-tut-c08.htm
字号:
<html>
<head>
<link rel="stylesheet" href="../../asm.css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion's win32 asm tutorial</title>
</head>
<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<p align="center"><font size="5"><u><strong><font color="#0000FF">第八课 菜单</font></strong></u></font></p>
<hr size="1">
本课中我们将在我们的应用程序中加入一个菜单。
<h3><font color="#ff0000">理论:</font></h3>
菜单可以说是WINDOWS最重要的元素之一。有了它,用户可以方便地选择操作命令.用户只要细读一下所有的菜单项就可以明了应用程序所提供的大概功能,而且可以立即操作,无须去阅读手册了.正因为菜单给了用户一种方便的方式,所以您在应用程序中加入菜单时就要遵守一般的标准.譬如:一般头两个菜单项是"File"和"Edit",最后是"Help",您可以在这中间插入您要定义的菜单项.如果所运行的菜单命令会弹出一个对话框,那么就要在该菜单项后加入省略符(...).菜单是一种资源,除菜单外还有其它像对话框,字符串,图标,位图资源等.在链接时链接程序将把资源加入到可执行程序中去,最后我们的执行程序中就既包括机器指令又包括了资源.
您可以在任何文本编辑器中编写脚本文件,在文件中您可以指定资源呈现出来的外观和其它的一些属性.当然更直观的方法是用资源编辑器,通常资源编辑器都打包在编译环境中,像Visual
C++, Borland C++等都带了资源编辑器. 我们可以按以下方式来定义一个菜单资源: <br>
<ul>
<b>MyMenu MENU</b> <br>
<b>{</b> <br>
<b> [menu list here]</b> <br>
<b>}</b>
</ul>
这和C语言中的结构体的定义非常相似。
MyMenu类似于被定义的变量,而MENU则类似于关键字。当然您可以用另外一种办法,那就是用BEGIN和END来代替花括号,这和PASCAL语言中的风格相同。 <br>
在菜单项的列表中是一大串的MENUITEM和POPUP语句。MENUITEM定义了一个菜单项,当选择后不会激活对话框。它的语法如下:
<ul>
<b>MENUITEM "&text", ID [,options]</b>
</ul>
它由关键字MENUITEM开头,紧跟在MENUITEM后的是指菜单项的名称字符串,符号“&“后的第一个字符将会带下画线,它也是该菜单项的快捷键。ID的作用当该菜单被选中时,WINDOWS的消息处理过程用来区分菜单项用的。毫无疑问,ID号必须唯一。options有以下可供选择的属性:
<dl>
<ul>
<li> <b>GRAYED</b> 代表该菜单项处于非激活状态,即当其被选中时不会产生WM_COMMAND消息。该菜单以灰色显示。</li>
<li> <b>INACTIVE</b> 代表该菜单项处于非激活状态,即当其被选中时不会产生WM_COMMAND消息。该菜单以正常颜色显示。</li>
<li> <b>MENUBREAK</b> 该菜单项和随后的菜单项会显示在新列中。(译者注:比较难描述,请做实验。)</li>
<li> <b>HELP</b> 该菜单项和随后的菜单项右对齐。(译者注:我在WINDOWS2000下编译有该标志的菜单项,该标志好像没起作用)</li>
</ul>
您可以单独使用以上标志位,也可以把它们或在一起。当然INACTIVE和GRAYED不能同时使用。
POPUP的语法如下:
<dl><b>POPUP "&text" [,options]</b> <br>
<b>{</b> <br>
<b> [menu list]</b> <br>
<b>}</b></dl>
POPUP定义了一个菜单项当该菜单项被选中时又会弹出一个子菜单。另外有一种特别类型的MENUITEM语句MENUITEM SEPARATOR,它表示在菜单项位置画一条分隔线。
定义完菜单后,您就可以在程序中使用脚本中定义的菜单资源了。
您可以在程序的两个地方(或叫做用两种方式)使用它们:
<ul>
<li> 在WNDCLASSEX结构体的成员lpszMenuName中。譬如,您有一个菜单“FirstMenu“,您可以按如下方法把它联系到您的窗口:</li>
<ul>
<ul>
<b>.DATA</b>
<ul>
<b>MenuName db "FirstMenu",0</b>
</ul>
<b>...........................</b> <br>
<b>...........................</b> <br>
<b>.CODE</b>
<ul>
<b>...........................</b> <br>
<b>mov wc.lpszMenuName, OFFSET MenuName</b> <br>
<b>...........................</b>
</ul>
</ul>
</ul>
<li> 在CreateWindowEx函数中指明菜单的句柄:</li>
<ul>
<ul>
<b>.DATA</b>
<ul>
<b>MenuName db "FirstMenu",0</b> <br>
<b>hMenu HMENU ?</b>
</ul>
<b>...........................</b> <br>
<b>...........................</b> <br>
<b>.CODE</b>
<ul>
<b>...........................</b> <br>
<b>invoke LoadMenu, hInst, OFFSET MenuName</b> <br>
<b>mov hMenu, eax</b> <br>
<b>invoke CreateWindowEx,NULL,OFFSET ClsName,\</b> <br>
<b>
OFFSET Caption, WS_OVERLAPPEDWINDOW,\</b> <br>
<b>
CW_USEDEFAULT,CW_USEDEFAULT,\</b> <br>
<b>
CW_USEDEFAULT,CW_USEDEFAULT,\</b> <br>
<b>
NULL,\</b> <br>
<b> hMenu,\</b>
<br>
<b>
hInst,\</b> <br>
<b>
NULL\</b> <br>
<b>...........................</b>
</ul>
</ul>
</ul>
</ul>
您也许会问,这两着之间有什么不同呢?当您用第一种方法时,由于是在窗口类中指定,故所有由该窗口类派生的窗口都将有相同的菜单。如果您想要从相同的类中派生的窗口有不同的菜单那就要使用第二中方法,该方法中通过函数CreateWindowEx指定的菜单会“覆盖”WNDCLASSEX结构体中指定的菜单。
接下来我们看看当用户选择了一个菜单项时它是如何通知WINDOWS 窗口过程的:
当用户选择了一个菜单项时,WINDOWS窗口过程会接收到一个WM_COMMAND消息,传进来的参数wParam的底字节包含了菜单项的ID号。
好了,上面就是关于菜单项的一切,下面我们就来实践。
<h3> <font color="#ff0000">例子:</font></h3>
第一个例子显示了指定一个菜单项的第一种方法:
<p><b>.386</b> <br>
<b>.model flat,stdcall</b> <br>
<b>option casemap:none</b>
<p><b>WinMain proto :DWORD,:DWORD,:DWORD,:DWORD</b>
<p><b>include \masm32\include\windows.inc</b> <br>
<b>include \masm32\include\user32.inc</b> <br>
<b>include \masm32\include\kernel32.inc</b> <br>
<b>includelib \masm32\lib\user32.lib</b> <br>
<b>includelib \masm32\lib\kernel32.lib</b>
<p><b>.data</b> <br>
<b>ClassName db "SimpleWinClass",0</b> <br>
<b>AppName db "Our First Window",0</b> <br>
<b>MenuName db "FirstMenu",0
; The name of our menu in the resource file.</b> <br>
<b>Test_string db "You selected Test menu item",0</b> <br>
<b>Hello_string db "Hello, my friend",0</b> <br>
<b>Goodbye_string db "See you again, bye",0</b>
<p><b>.data?</b> <br>
<b>hInstance HINSTANCE ?</b> <br>
<b>CommandLine LPSTR ?</b>
<p><b>.const</b> <br>
<b>IDM_TEST equ 1
; Menu IDs</b> <br>
<b>IDM_HELLO equ 2</b> <br>
<b>IDM_GOODBYE equ 3</b> <br>
<b>IDM_EXIT equ 4</b>
<p><b>.code</b> <br>
<b>start:</b> <br>
<b> invoke GetModuleHandle, NULL</b> <br>
<b> mov hInstance,eax</b> <br>
<b> invoke GetCommandLine<br>
mov CommandLine,eax</b> <br>
<b> invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT</b>
<br>
<b> invoke ExitProcess,eax</b>
<p><b>WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD</b>
<br>
<b> LOCAL wc:WNDCLASSEX</b> <br>
<b> LOCAL msg:MSG</b> <br>
<b> LOCAL hwnd:HWND</b> <br>
<b> mov wc.cbSize,SIZEOF WNDCLASSEX</b> <br>
<b> mov wc.style, CS_HREDRAW or CS_VREDRAW</b>
<br>
<b> mov wc.lpfnWndProc, OFFSET WndProc</b> <br>
<b> mov wc.cbClsExtra,NULL</b> <br>
<b> mov wc.cbWndExtra,NULL</b> <br>
<b> push hInst</b> <br>
<b> pop wc.hInstance</b> <br>
<b> mov wc.hbrBackground,COLOR_WINDOW+1</b>
<br>
<b> mov wc.lpszMenuName,OFFSET MenuName
; Put our menu name here</b> <br>
<b> mov wc.lpszClassName,OFFSET ClassName</b>
<br>
<b> invoke LoadIcon,NULL,IDI_APPLICATION</b> <br>
<b> mov wc.hIcon,eax</b> <br>
<b> mov wc.hIconSm,eax</b> <br>
<b> invoke LoadCursor,NULL,IDC_ARROW</b> <br>
<b> mov wc.hCursor,eax</b> <br>
<b> invoke RegisterClassEx, addr wc</b> <br>
<b> invoke CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\</b>
<br>
<b> WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\</b>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -