原文: http://zetcode.com/gui/winapi/menus/

在 Windows API 教程的这一部分中,我们创建菜单。菜单是位于菜单栏中的一组命令。菜单栏包含菜单列表。 菜单可以包含菜单项或其他菜单调用子菜单。 执行命令的菜单项称为命令项或命令。 在 Windows 上,菜单栏有时称为顶层菜单。 菜单和子菜单称为弹出菜单。 菜单项通常分为一些逻辑组。 这些组由分隔符分隔。 分隔符是一条小的水平线。

一个简单的菜单

在下面的示例中,我们创建一个菜单栏和三个菜单命令。 我们还创建一个分隔符。

simplemenu.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. void AddMenus(HWND);
  4. #define IDM_FILE_NEW 1
  5. #define IDM_FILE_OPEN 2
  6. #define IDM_FILE_QUIT 3
  7. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  8. PWSTR lpCmdLine, int nCmdShow) {
  9. MSG msg;
  10. WNDCLASSW wc = {0};
  11. wc.lpszClassName = L"Simple menu";
  12. wc.hInstance = hInstance;
  13. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  14. wc.lpfnWndProc = WndProc;
  15. wc.hCursor = LoadCursor(0, IDC_ARROW);
  16. RegisterClassW(&wc);
  17. CreateWindowW(wc.lpszClassName, L"Simple menu",
  18. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  19. 100, 100, 350, 250, 0, 0, hInstance, 0);
  20. while (GetMessage(&msg, NULL, 0, 0)) {
  21. TranslateMessage(&msg);
  22. DispatchMessage(&msg);
  23. }
  24. return (int) msg.wParam;
  25. }
  26. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  27. WPARAM wParam, LPARAM lParam) {
  28. switch(msg) {
  29. case WM_CREATE:
  30. AddMenus(hwnd);
  31. break;
  32. case WM_COMMAND:
  33. switch(LOWORD(wParam)) {
  34. case IDM_FILE_NEW:
  35. case IDM_FILE_OPEN:
  36. MessageBeep(MB_ICONINFORMATION);
  37. break;
  38. case IDM_FILE_QUIT:
  39. SendMessage(hwnd, WM_CLOSE, 0, 0);
  40. break;
  41. }
  42. break;
  43. case WM_DESTROY:
  44. PostQuitMessage(0);
  45. break;
  46. }
  47. return DefWindowProcW(hwnd, msg, wParam, lParam);
  48. }
  49. void AddMenus(HWND hwnd) {
  50. HMENU hMenubar;
  51. HMENU hMenu;
  52. hMenubar = CreateMenu();
  53. hMenu = CreateMenu();
  54. AppendMenuW(hMenu, MF_STRING, IDM_FILE_NEW, L"&New");
  55. AppendMenuW(hMenu, MF_STRING, IDM_FILE_OPEN, L"&Open");
  56. AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
  57. AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
  58. AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) hMenu, L"&File");
  59. SetMenu(hwnd, hMenubar);
  60. }

两个菜单项发出短促的声音。 第三个终止应用。

  1. case WM_COMMAND:
  2. switch(LOWORD(wParam)) {
  3. case IDM_FILE_NEW:
  4. case IDM_FILE_OPEN:
  5. MessageBeep(MB_ICONINFORMATION);
  6. break;
  7. case IDM_FILE_QUIT:
  8. SendMessage(hwnd, WM_CLOSE, 0, 0);
  9. break;
  10. }
  11. break;

如果选择菜单项,则窗口过程会收到WM_COMMAND消息。 菜单项 id 在wParam值的低位字中。

  1. hMenubar = CreateMenu();
  2. hMenu = CreateMenu();

使用CreateMenu()函数创建菜单栏和菜单。

  1. AppendMenuW(hMenu, MF_STRING, IDM_FILE_NEW, L"&New");
  2. AppendMenuW(hMenu, MF_STRING, IDM_FILE_OPEN, L"&Open");
  3. AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
  4. AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
  5. AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) hMenu, L"&File");

菜单项和子菜单是使用AppendMenuW()函数创建的。 我们要附加的内容取决于标志。 MF_STRING附加标签,MF_SEPARATOR附加分隔符,MF_POPUP附加菜单。

  1. SetMenu(hwnd, hMenubar);

最后,我们设置菜单栏,调用SetMenu()函数。

Windows API 菜单 - 图1

图:简单菜单

弹出菜单

弹出菜单也称为上下文菜单。 它是在某些情况下显示的命令列表。 例如,在 Firefox Web 浏览器中,当我们右键单击网页时,将获得一个上下文菜单。 在这里,我们可以重新加载页面,返回页面或查看页面源。 如果右键单击工具栏,则将获得另一个用于管理工具栏的上下文菜单。

popupmenu.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. #define IDM_FILE_NEW 1
  4. #define IDM_FILE_OPEN 2
  5. #define IDM_FILE_QUIT 3
  6. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  7. PWSTR lpCmdLine, int nCmdShow) {
  8. MSG msg;
  9. WNDCLASSW wc = {0};
  10. wc.lpszClassName = L"Popup menu";
  11. wc.hInstance = hInstance;
  12. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  13. wc.lpfnWndProc = WndProc;
  14. wc.hCursor = LoadCursor(0, IDC_ARROW);
  15. RegisterClassW(&wc);
  16. CreateWindowW(wc.lpszClassName, L"Popup menu",
  17. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  18. 100, 100, 350, 250, 0, 0, hInstance, 0);
  19. while (GetMessage(&msg, NULL, 0, 0)) {
  20. TranslateMessage(&msg);
  21. DispatchMessage(&msg);
  22. }
  23. return (int) msg.wParam;
  24. }
  25. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  26. WPARAM wParam, LPARAM lParam) {
  27. HMENU hMenu;
  28. POINT point;
  29. switch(msg) {
  30. case WM_COMMAND:
  31. switch(LOWORD(wParam)) {
  32. case IDM_FILE_NEW:
  33. case IDM_FILE_OPEN:
  34. MessageBeep(MB_ICONINFORMATION);
  35. break;
  36. case IDM_FILE_QUIT:
  37. SendMessage(hwnd, WM_CLOSE, 0, 0);
  38. break;
  39. }
  40. break;
  41. case WM_RBUTTONUP:
  42. point.x = LOWORD(lParam);
  43. point.y = HIWORD(lParam);
  44. hMenu = CreatePopupMenu();
  45. ClientToScreen(hwnd, &point);
  46. AppendMenuW(hMenu, MF_STRING, IDM_FILE_NEW, L"&New");
  47. AppendMenuW(hMenu, MF_STRING, IDM_FILE_OPEN, L"&Open");
  48. AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
  49. AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");
  50. TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd, NULL);
  51. DestroyMenu(hMenu);
  52. break;
  53. case WM_DESTROY:
  54. PostQuitMessage(0);
  55. break;
  56. }
  57. return DefWindowProcW(hwnd, msg, wParam, lParam);
  58. }

我们有一个上下文菜单示例,其中包含三个菜单项。

  1. case WM_RBUTTONUP:
  2. point.x = LOWORD(lParam);
  3. point.y = HIWORD(lParam);
  4. ...

当光标在窗口的客户区域中时,用户释放鼠标右键时,将发布WM_RBUTTONUP消息。 lParam的低位字指定光标的 x 坐标。 高阶字指定光标的 y 坐标。 坐标相对于客户区域的左上角。

  1. hMenu = CreatePopupMenu();

CreatePopupMenu()函数创建一个弹出菜单。 它将句柄返回到新创建的菜单。 菜单最初是空的。

  1. ClientToScreen(hwnd, &point);

ClientToScreen()函数将指定点的客户坐标转换为屏幕坐标。 我们需要这些坐标才能显示上下文菜单。

  1. AppendMenuW(hMenu, MF_STRING, IDM_FILE_NEW, L"&New");
  2. AppendMenuW(hMenu, MF_STRING, IDM_FILE_OPEN, L"&Open");
  3. AppendMenuW(hMenu, MF_SEPARATOR, 0, NULL);
  4. AppendMenuW(hMenu, MF_STRING, IDM_FILE_QUIT, L"&Quit");

创建三个菜单项和一个分隔符。

  1. TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd, NULL);

TrackPopupMenu()函数在指定位置显示上下文菜单,并跟踪菜单上项目的选择。

  1. DestroyMenu(hMenu);

最后,使用DestroyMenu()函数销毁菜单对象。 未分配给窗口的菜单必须被明确销毁。

Windows API 菜单 - 图2

图:弹出菜单

复选菜单项

复选菜单项是在标签前带有复选标记的菜单项。 菜单项可以使用CheckMenuItem()函数选中或取消选中。

checkmenuitem.c

  1. #include <windows.h>
  2. #include <commctrl.h>
  3. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  4. void AddMenus(HWND);
  5. #define IDM_VIEW_STB 1
  6. HWND ghSb;
  7. HMENU ghMenu;
  8. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  9. PWSTR lpCmdLine, int nCmdShow) {
  10. MSG msg;
  11. WNDCLASSW wc = {0};
  12. wc.lpszClassName = L"Check menu item";
  13. wc.hInstance = hInstance;
  14. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  15. wc.lpfnWndProc = WndProc;
  16. wc.hCursor = LoadCursor(0, IDC_ARROW);
  17. RegisterClassW(&wc);
  18. CreateWindowW(wc.lpszClassName, L"Check menu item",
  19. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  20. 100, 100, 350, 250, 0, 0, hInstance, 0);
  21. while (GetMessage(&msg, NULL, 0, 0)) {
  22. TranslateMessage(&msg);
  23. DispatchMessage(&msg);
  24. }
  25. return (int) msg.wParam;
  26. }
  27. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  28. WPARAM wParam, LPARAM lParam) {
  29. UINT state;
  30. switch(msg) {
  31. case WM_CREATE:
  32. AddMenus(hwnd);
  33. InitCommonControls();
  34. ghSb = CreateWindowExW(0, STATUSCLASSNAMEW, NULL,
  35. WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd,
  36. (HMENU) 1, GetModuleHandle(NULL), NULL);
  37. break;
  38. case WM_COMMAND:
  39. switch(LOWORD(wParam)) {
  40. case IDM_VIEW_STB:
  41. state = GetMenuState(ghMenu, IDM_VIEW_STB, MF_BYCOMMAND);
  42. if (state == MF_CHECKED) {
  43. ShowWindow(ghSb, SW_HIDE);
  44. CheckMenuItem(ghMenu, IDM_VIEW_STB, MF_UNCHECKED);
  45. } else {
  46. ShowWindow(ghSb, SW_SHOWNA);
  47. CheckMenuItem(ghMenu, IDM_VIEW_STB, MF_CHECKED);
  48. }
  49. break;
  50. }
  51. break;
  52. case WM_SIZE:
  53. SendMessage(ghSb, WM_SIZE, wParam, lParam);
  54. break;
  55. case WM_DESTROY:
  56. PostQuitMessage(0);
  57. break;
  58. }
  59. return DefWindowProcW(hwnd, msg, wParam, lParam);
  60. }
  61. void AddMenus(HWND hwnd) {
  62. HMENU hMenubar;
  63. hMenubar = CreateMenu();
  64. ghMenu = CreateMenu();
  65. AppendMenuW(ghMenu, MF_STRING, IDM_VIEW_STB, L"&Statusbar");
  66. CheckMenuItem(ghMenu, IDM_VIEW_STB, MF_CHECKED);
  67. AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) ghMenu, L"&View");
  68. SetMenu(hwnd, hMenubar);
  69. }

在示例中,我们有一个包含一个菜单项的视图菜单。 该菜单项将显示或隐藏状态栏。 当状态栏可见时,将选中菜单项。

  1. #define IDM_VIEW_STB 1

这是将显示或隐藏状态栏的菜单项的 ID。

  1. InitCommonControls();

状态栏是常用控件。 必须使用InitCommonControls()函数对其进行初始化。

  1. ghSb = CreateWindowExW(0, STATUSCLASSNAMEW, NULL,
  2. WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hwnd,
  3. (HMENU) 1, GetModuleHandle(NULL), NULL);

此代码行创建一个状态栏控件。

  1. state = GetMenuState(ghMenu, IDM_VIEW_STB, MF_BYCOMMAND);

我们通过GetMenuState()函数获得状态栏菜单项的状态。

  1. if (state == MF_CHECKED) {
  2. ShowWindow(ghSb, SW_HIDE);
  3. CheckMenuItem(ghMenu, IDM_VIEW_STB, MF_UNCHECKED);
  4. } else {
  5. ShowWindow(ghSb, SW_SHOWNA);
  6. CheckMenuItem(ghMenu, IDM_VIEW_STB, MF_CHECKED);
  7. }

根据其状态,我们使用ShowWindow()函数显示或隐藏状态栏控件。 菜单项通过CheckMenuItem()函数被选中或取消选中。

  1. case WM_SIZE:
  2. SendMessage(ghSb, WM_SIZE, wParam, lParam);
  3. break;

调整窗口大小后,我们将调整状态栏的大小以适合窗口。

Windows API 菜单 - 图3

图:复选菜单项

单选菜单项

单选菜单项使您可以从互斥的选项列表中进行选择。 单选菜单项通过CheckMenuRadioItem()函数进行管理。

radiomenuitem.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. void AddMenus(HWND);
  4. #define IDM_MODE_MAP 1
  5. #define IDM_MODE_SAT 2
  6. #define IDM_MODE_TRA 3
  7. #define IDM_MODE_STR 4
  8. HMENU hMenu;
  9. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  10. PWSTR lpCmdLine, int nCmdShow) {
  11. MSG msg;
  12. WNDCLASSW wc = {0};
  13. wc.lpszClassName = L"Radio menu item";
  14. wc.hInstance = hInstance;
  15. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  16. wc.lpfnWndProc = WndProc;
  17. wc.hCursor = LoadCursor(0, IDC_ARROW);
  18. RegisterClassW(&wc);
  19. CreateWindowW(wc.lpszClassName, L"Radio menu item",
  20. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  21. 100, 100, 350, 250, 0, 0, hInstance, 0);
  22. while (GetMessage(&msg, NULL, 0, 0)) {
  23. TranslateMessage(&msg);
  24. DispatchMessage(&msg);
  25. }
  26. return (int) msg.wParam;
  27. }
  28. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  29. WPARAM wParam, LPARAM lParam) {
  30. switch(msg) {
  31. case WM_CREATE:
  32. AddMenus(hwnd);
  33. break;
  34. case WM_COMMAND:
  35. switch(LOWORD(wParam)) {
  36. case IDM_MODE_MAP:
  37. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  38. IDM_MODE_MAP, MF_BYCOMMAND);
  39. MessageBeep(MB_ICONERROR);
  40. break;
  41. case IDM_MODE_SAT:
  42. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  43. IDM_MODE_SAT, MF_BYCOMMAND);
  44. MessageBeep(0xFFFFFFFF);
  45. break;
  46. case IDM_MODE_TRA:
  47. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  48. IDM_MODE_TRA, MF_BYCOMMAND);
  49. MessageBeep(MB_ICONWARNING);
  50. break;
  51. case IDM_MODE_STR:
  52. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  53. IDM_MODE_STR, MF_BYCOMMAND);
  54. MessageBeep(MB_ICONINFORMATION);
  55. break;
  56. }
  57. break;
  58. case WM_DESTROY:
  59. PostQuitMessage(0);
  60. break;
  61. }
  62. return DefWindowProcW(hwnd, msg, wParam, lParam);
  63. }
  64. void AddMenus(HWND hwnd) {
  65. HMENU hMenubar;
  66. hMenubar = CreateMenu();
  67. hMenu = CreateMenu();
  68. AppendMenuW(hMenu, MF_STRING, IDM_MODE_MAP, L"&Map");
  69. AppendMenuW(hMenu, MF_STRING, IDM_MODE_SAT, L"&Satellite");
  70. AppendMenuW(hMenu, MF_STRING, IDM_MODE_TRA, L"&Traffic");
  71. AppendMenuW(hMenu, MF_STRING, IDM_MODE_STR, L"Street &view");
  72. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  73. IDM_MODE_MAP, MF_BYCOMMAND);
  74. AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) hMenu, L"&Map mode");
  75. SetMenu(hwnd, hMenubar);
  76. }

在示例中,我们有四个单选菜单项; 一次只能选择其中之一。 每个单选菜单项都会发出不同的声音。

  1. #define IDM_MODE_MAP 1
  2. #define IDM_MODE_SAT 2
  3. #define IDM_MODE_TRA 3
  4. #define IDM_MODE_STR 4

这些是单选菜单项的 ID。

  1. case IDM_MODE_MAP:
  2. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  3. IDM_MODE_MAP, MF_BYCOMMAND);
  4. MessageBeep(MB_ICONERROR);
  5. break;

CheckMenuRadioItem()检查指定的菜单项并将其设为单选项目。 此外,它清除关联的菜单项组中的所有其他菜单项。 该函数的第一个参数是包含菜单项组的菜单句柄。 最后一个参数指示前三个参数的含义; 当指定MF_BYCOMMAND时,这些参数是菜单项的 ID。 第二个参数是组中第一个菜单项的 ID,第三个参数是组中最后一个菜单项的 ID。 第四个参数是要检查的菜单标识符。

  1. ...
  2. AppendMenuW(hMenu, MF_STRING, IDM_MODE_STR, L"Street &view");
  3. CheckMenuRadioItem(hMenu, IDM_MODE_MAP, IDM_MODE_STR,
  4. IDM_MODE_MAP, MF_BYCOMMAND);
  5. AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) hMenu, L"&Map mode");
  6. ...

首先,选择第一个单选项目。

Windows API 菜单 - 图4

图:单选菜单项

子菜单

子菜单是位于另一个菜单内的菜单。

submenu.c

  1. #include <windows.h>
  2. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  3. void AddMenus(HWND);
  4. #define IDM_FILE_NEW 1
  5. #define IDM_FILE_IMPORT 2
  6. #define IDM_IMPORT_MAIL 11
  7. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  8. PWSTR lpCmdLine, int nCmdShow) {
  9. MSG msg;
  10. WNDCLASSW wc = {0};
  11. wc.lpszClassName = L"Submenu";
  12. wc.hInstance = hInstance;
  13. wc.hbrBackground = GetSysColorBrush(COLOR_3DFACE);
  14. wc.lpfnWndProc = WndProc;
  15. wc.hCursor = LoadCursor(0, IDC_ARROW);
  16. RegisterClassW(&wc);
  17. CreateWindowW(wc.lpszClassName, L"Submenu",
  18. WS_OVERLAPPEDWINDOW | WS_VISIBLE,
  19. 100, 100, 350, 250, 0, 0, hInstance, 0);
  20. while (GetMessage(&msg, NULL, 0, 0)) {
  21. TranslateMessage(&msg);
  22. DispatchMessage(&msg);
  23. }
  24. return (int) msg.wParam;
  25. }
  26. LRESULT CALLBACK WndProc(HWND hwnd, UINT msg,
  27. WPARAM wParam, LPARAM lParam) {
  28. switch(msg) {
  29. case WM_CREATE:
  30. AddMenus(hwnd);
  31. break;
  32. case WM_COMMAND:
  33. switch(LOWORD(wParam)) {
  34. case IDM_FILE_NEW:
  35. MessageBoxW(NULL, L"New file selected",
  36. L"Information", MB_OK);
  37. break;
  38. case IDM_IMPORT_MAIL:
  39. MessageBoxW(NULL, L"Import mail selected",
  40. L"Information", MB_OK);
  41. }
  42. break;
  43. case WM_DESTROY:
  44. PostQuitMessage(0);
  45. break;
  46. }
  47. return DefWindowProcW(hwnd, msg, wParam, lParam);
  48. }
  49. void AddMenus(HWND hwnd) {
  50. HMENU hMenubar = CreateMenu();
  51. HMENU hMenu = CreateMenu();
  52. HMENU hSubMenu = CreatePopupMenu();
  53. AppendMenuW(hMenu, MF_STRING, IDM_FILE_NEW, L"&New");
  54. AppendMenuW(hMenu, MF_STRING | MF_POPUP, (UINT_PTR) hSubMenu, L"&Import");
  55. AppendMenuW(hSubMenu, MF_STRING, IDM_IMPORT_MAIL, L"Import &mail");
  56. AppendMenuW(hMenubar, MF_POPUP, (UINT_PTR) hMenu, L"&File");
  57. SetMenu(hwnd, hMenubar);
  58. }

在示例中,我们有两个菜单项; 一个位于“文件”菜单中,另一个位于“文件的导入”子菜单中。 选择每个菜单项都会显示一个消息框。

  1. case IDM_IMPORT_MAIL:
  2. MessageBoxW(NULL, L"Import mail selected",
  3. L"Information", MB_OK);

当我们选择“导入邮件”子菜单项时,将显示一个带有"Import mail selected"文本的消息框。

  1. HMENU hSubMenu = CreatePopupMenu();

使用CreatePopupMenu()函数创建一个子菜单。

  1. AppendMenuW(hMenu, MF_STRING | MF_POPUP, (UINT_PTR) hSubMenu, L"&Import");

通过AppendMenuW()函数,我们在文件菜单中添加了一个子菜单。 MF_POPUP标志用于弹出菜单和子菜单。

  1. AppendMenuW(hSubMenu, MF_STRING, IDM_IMPORT_MAIL, L"Import &mail");

通常使用AppendMenuW()函数将菜单项添加到子菜单。

Windows API 菜单 - 图5

图:子菜单

在 Windows API 教程的这一部分中,我们介绍了菜单。