鱼C论坛

 找回密码
 立即注册
查看: 1040|回复: 3

创建系统托盘菜单后创建子窗口WM_COMMAND出错

[复制链接]
发表于 2024-7-28 03:59:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x

  1. #define ID_TUOPAN WM_USER + 1
  2. #define ID_TUOPAN_CALLBACK WM_USER + 2
  3. #define ID_TUOPAN_OPEN WM_USER + 3
  4. #define ID_TUOPAN_EXIT WM_USER + 4
  5. LRESULT CALLBACK WndProc ( HWND, UINT, WPARAM, LPARAM );
  6. LRESULT CALLBACK ChildMenu_WndProc ( HWND, UINT, WPARAM, LPARAM );

  7. int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  8. {
  9. // ...注册主窗口类和创建窗口

  10.     wndclass.lpfnWndProc = ChildMenu_WndProc;
  11.     wndclass.lpszClassName = cm_ClassName;
  12.     wndclass.lpszMenuName = NULL;
  13.     if (!RegisterClassEx(&wndclass)){
  14.         MessageBox(NULL, TEXT("注册子窗口类失败!"), szAppName, MB_ICONERROR);
  15.         return 0;
  16.     }

  17.     while (GetMessage(&msg, NULL, 0, 0))
  18.     {
  19.         TranslateMessage(&msg);
  20.         DispatchMessage(&msg);
  21.     }
  22.    
  23.     return msg.wParam;
  24. }

  25. LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  26. {
  27.     HDC hdc;
  28.     PAINTSTRUCT ps;
  29.     RECT rect;
  30.    
  31.     TCHAR szbuffer[] = TEXT("你好 World!");
  32.    
  33.     switch (message)
  34.     {
  35.     case WM_PAINT:
  36.         hdc = BeginPaint(hwnd, &ps);
  37.         GetClientRect(hwnd, &rect);
  38.         DrawTextEx(hdc, szbuffer, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER, NULL);
  39.         EndPaint(hwnd, &ps);
  40.         return 0;

  41.     case WM_CREATE:
  42.         // 系统托盘
  43.         NOTIFYICONDATA nid;
  44.         nid.cbSize = sizeof(NOTIFYICONDATA);
  45.         nid.hWnd = hwnd;
  46.         nid.uID = ID_TUOPAN;
  47.         nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
  48.         nid.uCallbackMessage = ID_TUOPAN_CALLBACK;
  49.         nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  50.         StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), szAppName);
  51.         Shell_NotifyIcon(NIM_ADD, &nid);
  52.         // // 子窗口1 , 这里取消注释后WM_COMMAND和WM_CLOSE、WM_DESTROY包括子窗口过程函数的都会出错
  53.         // HWND ChildMenu_hwnd = CreateWindowEx(
  54.         //     0, cm_ClassName, cm_ClassName,
  55.         //     WS_CHILD | WS_VISIBLE,
  56.         //     0, 0, 100, 100,
  57.         //     hwnd, NULL, NULL, NULL);
  58.         // if (!ChildMenu_hwnd){
  59.         //     MessageBox(NULL, TEXT("创建子窗口——ChildMenu_hwnd失败!"), szAppName, MB_ICONERROR);
  60.         //     return 0;
  61.         // }
  62.         return DefWindowProc(hwnd, message, wParam, lParam);

  63.     case ID_TUOPAN_CALLBACK:
  64.         switch (lParam){
  65.         case WM_LBUTTONDBLCLK:
  66.             ShowWindow(hwnd, SW_SHOW);
  67.             break;
  68.         case WM_RBUTTONDOWN:
  69.             POINT pt;
  70.             GetCursorPos(&pt);
  71.             HMENU hMenu = CreatePopupMenu();
  72.             AppendMenu(hMenu, MF_STRING, ID_TUOPAN_OPEN, TEXT("打开"));
  73.             AppendMenu(hMenu, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
  74.             AppendMenu(hMenu, MF_STRING, ID_TUOPAN_EXIT, TEXT("Exit"));
  75.             TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
  76.             DestroyMenu(hMenu);
  77.             break;
  78.         }
  79.         return 0;
  80.     case WM_COMMAND:
  81.         switch (wParam){
  82.         case ID_TUOPAN_OPEN:
  83.             ShowWindow(hwnd, SW_SHOW);
  84.             break;
  85.         case ID_TUOPAN_EXIT:
  86.             DestroyWindow(hwnd);
  87.             break;
  88.         }
  89.         return 0;

  90.     case WM_CLOSE:
  91.         ShowWindow(hwnd, SW_HIDE);
  92.         return 0;
  93.    
  94.     case WM_DESTROY:
  95.         Shell_NotifyIcon(NIM_DELETE, &nid);
  96.         // DestroyWindow(ChildMenu_hwnd);
  97.         PostQuitMessage(0);
  98.         return 0;

  99.     }

  100.     return DefWindowProc(hwnd, message, wParam, lParam);
  101. }
复制代码

WM_COMMAND和WM_CLOSE、WM_DESTROY红线,编译器错误提示gcc: jump to case label
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-7-28 04:04:10 | 显示全部楼层
这个问题的根源在于C语言的`switch`语句。`jump to case label`错误提示是因为你的代码中有可能出现跳过了某些变量的定义,导致编译器不知该如何处理这些变量。

首先,让我给你解释一下错误发生的原因。在 `switch (wParam)` 里面,`ID_TUOPAN_OPEN` 和 `ID_TUOPAN_EXIT` 的处理部分,你并没有定义`wParam`可能会涉及到的所有情况,而是直接使用了一个`case`标签,这让编译器感到疑惑。

解决这个问题的方法通常是确保每个 `case` 里面的所有变量都是清晰定义的,并且在适当的位置进行初始化。根据文中的结构,下面是调整后的代码片段:

  1. switch (message)
  2. {
  3.     // ... 其他消息处理

  4.     case WM_COMMAND:
  5.         switch (LOWORD(wParam)) // 使用LOWORD获取实际的命令ID
  6.         {
  7.         case ID_TUOPAN_OPEN:
  8.             ShowWindow(hwnd, SW_SHOW);
  9.             break;
  10.         case ID_TUOPAN_EXIT:
  11.             DestroyWindow(hwnd);
  12.             break;
  13.         default: // 提供一个默认处理,避免未捕捉区域
  14.             break;
  15.         }
  16.         return 0;

  17.     // ... 其他消息处理
  18. }
复制代码


另外,请确保在创建子窗口时,`CreateWindowEx`所使用的参数都正确无误,尤其是类名和窗口的父窗口。只要你没有错过这些细节,基本上应该能解决你的问题。

最后,保持幽默!就像写代码一样,永远不要忘记调试时的笑声可能是最佳的“缺陷修复工具”!所以,当遇到错误时,不如跟着代码一起“跳舞”一下,看看能否找到更好的解决方案!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 0 反对 1

使用道具 举报

 楼主| 发表于 2024-7-28 13:15:31 | 显示全部楼层
FishC 发表于 2024-7-28 04:04
这个问题的根源在于C语言的`switch`语句。`jump to case label`错误提示是因为你的代码中有可能出现跳过了 ...

没有解决,还是同样的问题取消子窗口的注释后一样有错误。子窗口没有做任何处理

  1. LRESULT CALLBACK ChildMenu_WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  2. {
  3.     return DefWindowProc(hwnd, message, wParam, lParam);
  4. }
复制代码

小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-7-28 13:15:47 | 显示全部楼层
h_meww 发表于 2024-07-28 13:15
没有解决,还是同样的问题取消子窗口的注释后一样有错 ...


好吧,我们再来深入了解一下这个问题。看来取消子窗口的注释,导致了编译器在处理 `WM_COMMAND`、`WM_CLOSE` 和 `WM_DESTROY` 时出现了问题。

### 问题分析

编译器的错误 `jump to case label` 通常表示在 `switch` 语句中存在不一致的控制流。在你的代码中,虽然 `ChildMenu_WndProc` 没有实际处理任何消息,但它仍然在被调用,并且可能与主窗口过程中的消息处理产生了冲突。

### 解决方案

为了防止这种情况发生,可以尝试以下几个步骤:

1. **确保子窗口类已注册**:在调用 `CreateWindowEx` 之前确认所需的窗口类已经正确注册。

2. **改变`switch`的方式**:在`WM_COMMAND`的`switch`中,将传递给它的`wParam`使用`LOWORD`进行分解,以确保访问的是消息标识符,而不是其他信息。

3. **不需要在`WndProc`中使用未定义变量**:如果你在 `WM_CREATE` 中创建了子窗口,但并没有适当初始化它,可能会发生未定义行为。

4. **保留`DestroyWindow`调用**:确保在 `WM_DESTROY` 中能够正确释放和清理资源。

### 改善后的代码示例

下面是改善后的代码片段:

  1. #include <windows.h>
  2. #include <commctrl.h>

  3. #define ID_TUOPAN WM_USER + 1
  4. #define ID_TUOPAN_CALLBACK WM_USER + 2
  5. #define ID_TUOPAN_OPEN WM_USER + 3
  6. #define ID_TUOPAN_EXIT WM_USER + 4

  7. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  8. LRESULT CALLBACK ChildMenu_WndProc(HWND, UINT, WPARAM, LPARAM);

  9. TCHAR szAppName[] = TEXT("MyApp");

  10. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
  11. {
  12.     // 注册主窗口类和创建窗口
  13.    
  14.     WNDCLASS wndclass = {0};
  15.     wndclass.lpfnWndProc = WndProc;
  16.     wndclass.hInstance = hInstance;
  17.     wndclass.lpszClassName = szAppName;

  18.     if (!RegisterClass(&wndclass)) {
  19.         return 0;
  20.     }

  21.     HWND hwnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW,
  22.                               CW_USEDEFAULT, CW_USEDEFAULT, 500, 400,
  23.                               NULL, NULL, hInstance, NULL);

  24.     ShowWindow(hwnd, nCmdShow);
  25.     UpdateWindow(hwnd);

  26.     MSG msg;
  27.     while (GetMessage(&msg, NULL, 0, 0))
  28.     {
  29.         TranslateMessage(&msg);
  30.         DispatchMessage(&msg);
  31.     }

  32.     return msg.wParam;
  33. }

  34. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  35. {
  36.     switch (message)
  37.     {
  38.         case WM_CREATE:
  39.             // 这里你可以取消注释并创建子窗口
  40.             {
  41.                 WNDCLASS childClass = {0};
  42.                 childClass.lpfnWndProc = ChildMenu_WndProc;
  43.                 childClass.hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
  44.                 childClass.lpszClassName = TEXT("ChildMenuClass");

  45.                 if (!RegisterClass(&childClass)) {
  46.                     MessageBox(NULL, TEXT("注册子窗口类失败!"), szAppName, MB_ICONERROR);
  47.                     return 0;
  48.                 }

  49.                 // 创建子窗口
  50.                 HWND ChildMenu_hwnd = CreateWindowEx(
  51.                     0, TEXT("ChildMenuClass"), TEXT("子窗口"),
  52.                     WS_CHILD | WS_VISIBLE,
  53.                     0, 0, 200, 200,
  54.                     hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
  55.                
  56.                 if (!ChildMenu_hwnd) {
  57.                     MessageBox(NULL, TEXT("创建子窗口失败!"), szAppName, MB_ICONERROR);
  58.                     return 0;
  59.                 }
  60.             }
  61.             return 0;

  62.         case WM_COMMAND:
  63.             switch (LOWORD(wParam)) // 使用LOWORD来确保获取命令ID
  64.             {
  65.                 case ID_TUOPAN_OPEN:
  66.                     ShowWindow(hwnd, SW_SHOW);
  67.                     break;
  68.                 case ID_TUOPAN_EXIT:
  69.                     DestroyWindow(hwnd);
  70.                     break;
  71.             }
  72.             return 0;

  73.         case WM_CLOSE:
  74.             ShowWindow(hwnd, SW_HIDE);
  75.             return 0;
  76.         
  77.         case WM_DESTROY:
  78.             PostQuitMessage(0);
  79.             return 0;
  80.     }

  81.     return DefWindowProc(hwnd, message, wParam, lParam);
  82. }

  83. LRESULT CALLBACK ChildMenu_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
  84. {
  85.     // 现在这个子窗口不处理任何消息
  86.     return DefWindowProc(hwnd, message, wParam, lParam);
  87. }
复制代码


### 注意事项
- 确保每次创建子窗口时,都提供唯一的类名。
- 对于 `ChildMenu_WndProc`,如果将来需要添加更多处理逻辑,它可以单独定义。
- 当涉及到多窗口时,请确保每个窗口都有适当的消息处理,这样可以避免兼容性问题。

如果还有问题,请记得举手哦,我们继续协作调试!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-6-4 20:13

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表