1、资源 |
---|
编译程序时,所有资源都会被保存到exe
文件或者dll
文件中,所以加载资源的API
函数第一传参都是程序实例句柄hInstance
。在进程启动时,资源并不会被加载到内存中,只有在需要使用时才调用函数,显式把资源加载到内存中。
每个资源都拥有一个标识符,标识符可以是数字,也可以是字符串。加载资源的函数需要的标识符传参都是字符串类型,可以使用MAKEINTRESOURCE
宏把数字标识符转换为字符串类型。
2、图标 |
---|
图标最开始是在注册窗口类时使用,如果窗口带有标题栏,那么注册窗口类时指定的图标会被显示在窗口左上角。此外,也可以在程序运行过程中,使用SetClassLong
来动态改变窗口图标。或者使用DrawIcon
在其它位置绘制图标。windows预定义了一些图标,它们标识符带有IDI_
前缀,当然我们也可以自定义图标。
在自定义图标时,同一个图标资源文件中可以包含多种尺寸的图标,但LoadIcon
加载图标的尺寸由SM_CXICON
和SM_CYICON
决定,它根据实际需要的尺寸从图标文件中选择最合适的尺寸图标,在需要情况下可能对图标进行缩放。如果需要加载其他尺寸的图标,可以使用LoadImage
。
3、鼠标指针 |
---|
使用LoadCursor
加载鼠标指针资源,可以在注册窗口类中指定窗口类的鼠标指针,也可以在程序运行过程中使用SetClassLong
修改窗口类鼠标指针,或者使用SetCursor
修改窗口当前窗口的鼠标指针。
当鼠标指针在一个窗口内移动,并且鼠标指针没有被其他窗口捕获时,windows会向该窗口发送WM_SETCURSOR
消息。在DefWindowProc
的处理中,它先把该消息发送给父窗口处理。如果返回TRUE
,则表示父窗口设置了鼠标指针,当前窗口不用再处理;否则,当前窗口继续处理WM_SETCURSOR
消息设置鼠标指针,并且在鼠标指针位于非客户区时设置成箭头,位于客户区时设置成注册窗口类指定的鼠标指针。
所以,需要动态修改鼠标指针时,应该在WM_SETCURSOR
中设置。
4、字符串资源 |
---|
使用LoadString
来加载字符串资源
5、自定义资源 |
---|
windows提供了自定义资源,其数据格式由用户定义。使用LoadResource
和FindResource
获取资源句柄,使用LockResource
把资源加载到内存,返回一个内存块句柄(内存指针),使用完后需要释放资源FreeResource
。
6、菜单 |
---|
-
菜单项
菜单中每一栏被称作一个菜单项,windows定义了一些带MF_
前缀的标志位来描述菜单项的属性。#define MF_INSERT 0x00000000L #define MF_CHANGE 0x00000080L #define MF_APPEND 0x00000100L #define MF_DELETE 0x00000200L #define MF_REMOVE 0x00001000L #define MF_BYCOMMAND 0x00000000L #define MF_BYPOSITION 0x00000400L #define MF_SEPARATOR 0x00000800L #define MF_ENABLED 0x00000000L #define MF_GRAYED 0x00000001L #define MF_DISABLED 0x00000002L #define MF_UNCHECKED 0x00000000L #define MF_CHECKED 0x00000008L #define MF_USECHECKBITMAPS 0x00000200L #define MF_STRING 0x00000000L #define MF_BITMAP 0x00000004L #define MF_OWNERDRAW 0x00000100L #define MF_POPUP 0x00000010L #define MF_MENUBARBREAK 0x00000020L #define MF_MENUBREAK 0x00000040L #define MF_UNHILITE 0x00000000L #define MF_HILITE 0x00000080L #if(WINVER >= 0x0400) #define MF_DEFAULT 0x00001000L #endif /* WINVER >= 0x0400 */ #define MF_SYSMENU 0x00002000L #define MF_HELP 0x00004000L #if(WINVER >= 0x0400) #define MF_RIGHTJUSTIFY 0x00004000L #endif /* WINVER >= 0x0400 */ #define MF_MOUSESELECT 0x00008000L #if(WINVER >= 0x0400) #define MF_END 0x00000080L /* Obsolete -- only used by old RES files */ #endif /* WINVER >= 0x0400 */
根据这些属性可以大致对菜单项进行分类:
MF_POPUP & MF_ENABLED
可以打开子菜单,每个子菜单都有菜单句柄MF_ENABLED
命令项,点击会发送WM_COMMAND
消息,每个命令项都有ID号MF_SEPARATOR
分割线
用EnableMenuItem
、CheckMenuItem
和SetMenuItemInfoA
可以修改菜单项的标志位。
-
设计菜单
菜单项的设计一般在资源管理界面中进行,但也可以在代码中使用CreateMenu
和AppendMenu
设计菜单,还可以使用DeleteMenu
、InsertMenu
、ModifyMenu
、RemoveMenu
来修改菜单。需要注意DeleteMenu
和RemoveMenu
的区别。如果菜单项是个子菜单项,DeleteMenu
会销毁子菜单,并释放其内存;RemoveMenu
不会销毁子菜单,还可以继续使用该子菜单,但需要在RemoveMenu
前获取它的句柄。 -
使用菜单
菜单设计完成后,可以在注册窗口类时指定窗口类的菜单,或者在创建窗口后使用LoadMenu
把菜单资源加载到内存,再使用SetMenu
设置窗口菜单,这两种方法都可以把菜单显示在窗口的菜单栏中。也可以使用
TrackPopupMenu
来在窗口的任意位置打开菜单,通常由鼠标右键激活。显示在窗口菜单栏的菜单,会在窗口销毁时随着窗口一起被销毁,而没被窗口引用的菜单,必须显式调用
DestroyMenu
销毁。 -
菜单相关消息
点击命令项时会发送WM_COMMAND
消息:LOWORD(wParam) 菜单ID HIWORD(wParam) 0 lParam 0 鼠标在菜单项间移动时发送
WM_MENUSELECT
消息。LOWORD(wParam) 菜单项ID或下拉菜单索引 HIWORD(wParam) 选择标记 lParam 包含所选菜单项的菜单句柄 打开下拉菜单时发送
WM_INITMENUPOPUP
消息。wParam 下拉菜单句柄 LOWORD(lParam) 下拉菜单索引 HIWORD(lParam) 1:系统菜单;0:其他菜单 -
系统菜单
CreateWindow
时使用WS_SYSMENU
样式创建窗口,窗口标题栏的左边会有一个系统菜单。windows为系统菜单定义了很多菜单项ID,但默认情况下系统菜单只包含几个菜单项,我们可以使用GetSystemMenu
获取系统菜单句柄,然后使用上面提到的函数来修改系统菜单。可以添加windows预定义的系统菜单项,或添加自定义的菜单项,也可以删除默认显示的系统菜单项。点击系统菜单的命令项不是发送WM_COMMAND
消息,而是发送WM_SYSCOMMAND
消息:LOWORD(wParam) & 0xFFF0 菜单ID HIWORD(wParam) 0 GET_X_LPARAM(lParam) 低位字表示屏幕x坐标 GET_Y_LPARAM(lParam) 高位字表示屏幕y坐标 wParam
参数的最低4位由系统内部使用,所以测试wParam
的值时应该先和0xFFF0
进行与操作。
lParam
参数带有屏幕坐标信息,是有符号数。取值为有符号数的坐标数据时应该使用GET_X_LPARAM
和GET_Y_LPARAM
,而不是LOWORD
和HIWORD
。 -
菜单相关函数
DrawMenuBar
:强制重绘菜单栏
GetSubMenu
:获取子菜单句柄
GetMenuItemCount
:获取菜单项数目
GetMenuItemID
:获取菜单项菜单ID
GetMenuString
:获取菜单项文本
GetMenuState
:获取菜单项标志
7、键盘加速键 |
---|
键盘加速键是键盘按键组合,被定义为键盘加速键的键盘组合按键会被翻译为WM_COMMAND
或WM_SYSCOMMAND
消息。
一个键盘加速键由4个属性描述:类型、ID、修饰符和键。键盘加速键有两种类型:
- 虚拟键类型,修饰符可以是
Ctrl
、Shift
和Alt
。 ASCII
字符类型,修饰符只有Alt
的组合键,但可以通过在ASCII
字符前加^
字符指定和Ctrl
组合。
可以在资源管理界面中添加加速键表、定义加速建。
使用加速键时,需要使用LoadAccelerators
先把加速键表加载到内存,然后在消息循环代码段中增加TranslateAccelerator
来翻译加速键。TranslateAccelerator
先判断msg
是否是键盘消息。如果是,则在hAccel
指定的加速键表中匹配加速键,如果匹配成功,则发送WM_COMMAND
或WM_SYSCOMMAND
消息到hwnd
指定的窗口过程。TranslateAccelerator
发送WM_COMMAND
或WM_SYSCOMMAND
前,会先把msg
中的hwnd
替换为TranslateAccelerator
的第一传参,所以所有的键盘加速键消息都会被发送到统一个窗口。如果TranslateAccelerator
把消息翻译了,返回非0值,不需要再把消息传给TranslateMessage
和DispatchMessage
;否则返回0值。
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(hwnd, hAccel, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
当加速键ID
和系统菜单项ID
一致时,TranslateAccelerator
向窗口过程发送WM_SYSCOMMAND
消息,否则发送WM_COMMAND
消息。
当加速键ID
和菜单项ID
一致时,窗口过程还会收到WM_INITMENU
、WM_INITMENUPOPUP
和WM_MENUSELECT
消息,就像菜单被选择了一样。
当加速键对应一个MF_GRAYED
或者MF_DISABLED
菜单项时,TranslateAccelerator
不会发送WM_COMMAND
或WM_SYSCOMMAND
。
LOWORD(wParam) | 加速键ID |
---|---|
HIWORD(wParam) | 1 |
lParam | 0 |