【第六节】windows sdk编程:Windows 中的资源
引言
资源是 Windows 应用程序图形用户界面(GUI)的重要组成部分,它们是应用程序中使用的各类数据,如光标、位图、图标、加速键、菜单、字符串和对话框等。这些数据在编译后会被包含在 EXE 文件中。虽然无法直接定位和操作资源,但可以通过相关函数来获取和操作这些资源。
一、光标资源
1.1 应用程序操作光标资源的步骤
(1) 选择或创建光标形式
可以使用 Windows 系统提供的光标,也可以通过图形编辑工具自定义光标形式,并将其保存为扩展名为 `.cur` 的文件。
(2)在资源文件中定义光标资源
如果使用自定义光标,需要在资源文件中定义该光标资源,格式如下:
光标名 CURSOR 光标文件名(.cur)
(3)加载光标资源
应用程序通过调用 `LoadCursor` 函数加载光标资源,并获取光标的句柄,语法如下:
LoadCursor(hThisInst, lpszCursorname)
其中:
- `hThisInst`: 应用程序的当前实例句柄
- `lpszCursorname`: 光标的名称
Windows 系统光标标识与形状
1.2 显示光标的三种方式
(1)在窗口类的 `hCursor` 字段指定光标
(2)使用 `SetClassLong` 函数修改光标
(3)使用 `SetCursor` 函数暂时修改光标
应用程序通常在定义窗口类时加载光标资源。例如,以下代码为窗口类 `wndclass` 加载“沙漏”光标:
WNDCLASS wndclass;
……
wndclass.hCursor = LoadCursor(hThisInst, IDC_WAIT);
……
此外,应用程序还可以通过调用 `SetClassLong` 函数来改变光标形式。例如:
HWND hButton = CreateWindow(L"button", L"hehe", WS_CHILD | WS_VISIBLE, 100, 100, 200, 200, (HMENU)10001, hInst, NULL);
HCURSOR hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CURSOR1));
SetClassLong(hButton, GCL_HCURSOR, (LONG)hCursor);
执行上述代码后,当鼠标移动到该按钮时,光标会变为自定义的光标。
二、图标
图标是一种小的图形图像,在 Windows 图形用户界面中,图标通常用于代表最小化的窗口对象,例如应用程序、目录等。
Windows 应用程序中操作图标资源的方法
(1)选择或创建图标形式
可以使用 Windows 系统提供的图标,也可以通过图形编辑工具自定义图标形式,并将其保存为扩展名为 `.ico` 的文件。
(2)在资源文件中定义图标资源
如果使用自定义图标,需要在资源文件中定义该图标资源,格式如下:
图标名 ICON 图标文件名(.ico)
(3)在应用程序中加载图标资源
应用程序通过调用 `LoadIcon` 函数加载图标资源,语法如下:
LoadIcon(hThisInst, lpszIconname)
其中:
- `hThisInst`: 应用程序的当前实例句柄
- `lpszIconname`: 图标的名称
Windows 系统图标标识与形状
应用程序通常在定义窗口类时加载图标资源。例如,以下代码为窗口类 `wndclass` 加载“问号”图标:
WNDCLASS wndclass;
……
wndclass.hIcon = LoadIcon(hThisInst, IDI_QUESTION);
……
此外,应用程序还可以通过调用 `LoadIcon` 函数动态地加载图标资源。
三、 菜单
3.1 菜单外观及组成
菜单通常由以下几部分组成:
(1)窗口主菜单条
(2)下拉式菜单框
(3)选项热键标识
(4)选项加速键标识
(5)选项分隔线
3.2 创建菜单的过程
(1)在窗口类中加载菜单
(2)在创建窗口时加载菜单
应用程序可以在调用 `CreateWindow` 函数创建窗口时加载菜单。加载方法如下:
HMENU LoadMenu(hInstance, lpszMenuName);
其中:
- `hInstance`: 当前程序的实例句柄
- `lpszMenuName`: 菜单的 ID
例如,以下代码在创建窗口时加载名称为 `"Menu"` 的窗口菜单:
HWND hwnd;
HMENU hMenu; ……
hMenu = LoadMenu(hInstance, "Menu");
hwnd = CreateWindow(…, …, …, …, …, …, …, hMenu, …, …);
(3)动态加载菜单
通过调用 `SetMenu` 函数可以动态地加载菜单,从而提高应用程序的灵活性。例如:
SetMenu(hwnd, hMenu);
动态加载菜单允许在同一个应用程序中实现多种不同的功能界面操作。
例如,假设定义了两个菜单 `Menu1` 和 `Menu2`,并且分别实现了相应的功能选项。通过调用 `SetMenu` 函数可以在两个菜单之间切换,从而实现不同界面的操作。示例代码如下:
HMENU hMenu1;
HMENU hMenu2; ……
// 应用程序定义窗口时使用 Menu1 作为初始菜单
hMenu1 = LoadMenu(hInstance, "Menu1");
hwnd = CreateWindow(…, …, …, …, …, …, …, hMenu1, …, …);
// 应用程序将窗口菜单切换为 Menu2
hMenu2 = LoadMenu(hInstance, "Menu2");
SetMenu(hwnd, hMenu2); ……
3.3 操作选项
(1)禁止或激活选项
可以在资源描述文件中设定选项的初始状态为禁止或激活,也可以通过调用 `EnableMenuItem` 函数来改变选项的状态。
DWORD EnableMenuItem(HMENU hmenu, UINT wIDEnableItem, UINT dwEnable);
其中:
- `hmenu`: 菜单句柄
- `wIDEnableItem`: 禁止或激活的选项标识。根据 `dwEnable` 的取值,该标识可以是选项的 ID 值,也可以是选项在菜单中的位置
- `dwEnable`: 选项操作标识
选项的常用选项及其说明
例如,以下代码禁止弹出式菜单“文件”中的“打开”选项:
EnableMenuItem(hmenu, IDM_OPEN, MF_BYCOMMAND | MF_DISABLED);
(2)设置或取消选中标志
除了在资源描述文件中设置选项为 `CHECKED` 外,还可以通过调用 `CheckMenuItem` 函数来设置或取消选中标志。
DWORD CheckMenuItem(HMENU hmenu, UINT wIDCheckItem, UINT dwCheck);
`dwCheck` 选项的常用选项及其说明
(3)增加选项
- 在尾部增加
应用程序可以通过调用 `AppendMenu` 函数在菜单尾部增加选项。
BOOL AppendMenu(HMENU hmenu, UINT dwFlag, UINT dwIDNewItem, LPCTSTR lpNewItem);
例如,以下代码在弹出式菜单“文件”的末尾增加一项“关于”:
AppendMenu(hmenu, MF_ENABLED, IDM_ABOUT, "关于(&A)");
- 插入
应用程序可以通过调用 `InsertMenu` 函数在菜单中插入新的选项。
BOOL InsertMenu(HMENU hmenu, UINT wPosition, UINT dwFlag, UINT dwIDNewItem, LPCTSTR lpNewItem);
例如,以下代码在弹出式菜单“文件”的“退出”项之前插入新的选项“打印”:
InsertMenu(hmenu, IDM_EXIT, MF_BYCOMMAND | MF_ENABLED, IDM_PRINT, "打印(&P)");
(4)删除选项
应用程序可以通过调用 `DeleteMenu` 函数删除菜单中的选项。
BOOL DeleteMenu(HMENU hmenu, UINT wPosition, UINT dwFlag);
例如,以下代码删除弹出式菜单“文件”中的“另存为”选项:
DeleteMenu(hmenu, IDM_SAVEAS, MF_BYCOMMAND);
(5)修改选项
应用程序可以通过调用 `ModifyMenu` 函数修改菜单中的选项。
BOOL ModifyMenu(HMENU hmenu, UINT wPosition, UINT dwFlag, UINT dwIDNewItem, LPCTSTR lpNewItem);
例如,以下代码将弹出式菜单“文件”中的“打印”项修改为“加载”项:
ModifyMenu(hmenu, IDM_OPEN, MF_BYCOMMAND, IDM_LOAD, "加载(&F)");
3.4 创建菜单
在资源编辑器中创建一个菜单资源的步骤如下:
(1)单击“插入”下拉菜单中的“资源”选项。
(2)双击“Menu”选项。
(3)双击菜单项虚框。
(4)在“菜单项属性”对话框中输入该项的标题。如果该项是弹出式菜单,则勾选 `Popup` 复选框。
(5)在对话框中输入选项的标识(ID)、标题及相应的菜单属性。
四、综合代码案例
以下是一个综合性的C++代码案例,展示了如何在Windows应用程序中使用资源,包括加载光标、图标、菜单,并创建一个带有这些资源的窗口。代码中还展示了如何处理菜单选项和光标的变化。
完整代码示例
#include <windows.h>
#include <string>
#include "resource.h"// 资源ID定义
#define IDC_CUSTOM_CURSOR 101
#define IDI_CUSTOM_ICON 102
#define IDM_MAIN_MENU 103
#define IDM_FILE_OPEN 104
#define IDM_FILE_EXIT 105// 全局变量
HINSTANCE hInst; // 应用程序实例句柄// 窗口过程函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {switch (msg) {case WM_CREATE:{// 窗口创建时加载菜单HMENU hMenu = LoadMenu(hInst, MAKEINTRESOURCE(IDM_MAIN_MENU));SetMenu(hwnd, hMenu);}break;case WM_COMMAND:{// 处理菜单选项switch (LOWORD(wParam)) {case IDM_FILE_OPEN:{MessageBox(hwnd, L"打开文件选项被点击", L"菜单操作", MB_OK);}break;case IDM_FILE_EXIT:{PostQuitMessage(0); // 退出程序}break;}}break;case WM_SETCURSOR:{// 当鼠标移动到窗口时,改变光标形状if (LOWORD(lParam) == HTCLIENT) {HCURSOR hCursor = LoadCursor(hInst, MAKEINTRESOURCE(IDC_CUSTOM_CURSOR));SetCursor(hCursor);return TRUE; // 表示已经处理了光标设置}}break;case WM_DESTROY:{PostQuitMessage(0); // 退出程序}break;default:return DefWindowProc(hwnd, msg, wParam, lParam); // 默认消息处理}return 0;
}// 应用程序入口函数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {// 初始化全局变量hInst = hInstance;// 注册窗口类WNDCLASS wc = {};wc.lpfnWndProc = WndProc; // 窗口过程函数wc.hInstance = hInstance; // 应用程序实例句柄wc.lpszClassName = L"ResourceExampleClass";wc.hCursor = LoadCursor(NULL, IDC_ARROW); // 默认光标wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_CUSTOM_ICON)); // 自定义图标RegisterClass(&wc);// 创建窗口HWND hwnd = CreateWindow(L"ResourceExampleClass", // 窗口类名L"资源使用示例", // 窗口标题WS_OVERLAPPEDWINDOW, // 窗口样式CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, // 窗口位置和大小NULL, // 父窗口句柄NULL, // 菜单句柄hInstance, // 应用程序实例句柄NULL // 附加数据);if (hwnd == NULL) {return 0;}// 显示窗口ShowWindow(hwnd, nCmdShow);UpdateWindow(hwnd);// 消息循环MSG msg;while (GetMessage(&msg, NULL, 0, 0)) {TranslateMessage(&msg);DispatchMessage(&msg);}return (int)msg.wParam;
}
资源文件(`.rc`文件)
在资源文件中定义光标、图标和菜单资源:
#include <windows.h>
#include <winres.h>
#include <commctrl.h>
#include "resource.h"// 自定义光标资源
IDC_CUSTOM_CURSOR CURSOR "custom_cursor.cur"// 自定义图标资源
IDI_CUSTOM_ICON ICON "custom_icon.ico"// 主菜单资源
IDM_MAIN_MENU MENU
BEGIN
POPUP "文件"
BEGIN
MENUITEM "打开", IDM_FILE_OPEN
MENUITEM "退出", IDM_FILE_EXIT
END
END
头文件(`resource.h`)
定义资源ID:
#ifndef RESOURCE_H
#define RESOURCE_H#define IDC_CUSTOM_CURSOR 101
#define IDI_CUSTOM_ICON 102
#define IDM_MAIN_MENU 103
#define IDM_FILE_OPEN 104
#define IDM_FILE_EXIT 105#endif // RESOURCE_H
代码说明
1. 窗口类注册:
- 使用`LoadCursor`加载默认光标。
- 使用`LoadIcon`加载自定义图标。
2. 窗口创建:
- 在`WM_CREATE`消息中加载菜单资源,并通过`SetMenu`函数将菜单附加到窗口。
3. 菜单操作:
- 在`WM_COMMAND`消息中处理菜单选项的点击事件。
- 点击“打开”选项时,弹出一个消息框。
- 点击“退出”选项时,调用`PostQuitMessage`退出程序。
4. 光标设置:
- 在`WM_SETCURSOR`消息中,当鼠标移动到窗口客户区时,加载自定义光标并设置光标形状。
5. 资源文件:
- 定义了自定义光标、图标和菜单资源。
6. 消息循环:
- 使用`GetMessage`、`TranslateMessage`和`DispatchMessage`处理窗口消息。
运行效果
1. 窗口显示时,标题栏显示自定义图标。
2. 鼠标移动到窗口客户区时,光标变为自定义光标。
3. 点击“文件”菜单中的“打开”选项,弹出消息框。
4. 点击“退出”选项,程序退出。