创建系统托盘菜单后创建子窗口WM_COMMAND出错
#define ID_TUOPAN WM_USER + 1
#define ID_TUOPAN_CALLBACK WM_USER + 2
#define ID_TUOPAN_OPEN WM_USER + 3
#define ID_TUOPAN_EXIT WM_USER + 4
LRESULT CALLBACK WndProc ( HWND, UINT, WPARAM, LPARAM );
LRESULT CALLBACK ChildMenu_WndProc ( HWND, UINT, WPARAM, LPARAM );
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// ...注册主窗口类和创建窗口
wndclass.lpfnWndProc = ChildMenu_WndProc;
wndclass.lpszClassName = cm_ClassName;
wndclass.lpszMenuName = NULL;
if (!RegisterClassEx(&wndclass)){
MessageBox(NULL, TEXT("注册子窗口类失败!"), szAppName, MB_ICONERROR);
return 0;
}
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
RECT rect;
TCHAR szbuffer[] = TEXT("你好 World!");
switch (message)
{
case WM_PAINT:
hdc = BeginPaint(hwnd, &ps);
GetClientRect(hwnd, &rect);
DrawTextEx(hdc, szbuffer, -1, &rect, DT_SINGLELINE | DT_CENTER | DT_VCENTER, NULL);
EndPaint(hwnd, &ps);
return 0;
case WM_CREATE:
// 系统托盘
NOTIFYICONDATA nid;
nid.cbSize = sizeof(NOTIFYICONDATA);
nid.hWnd = hwnd;
nid.uID = ID_TUOPAN;
nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
nid.uCallbackMessage = ID_TUOPAN_CALLBACK;
nid.hIcon = LoadIcon(NULL, IDI_APPLICATION);
StringCchCopy(nid.szTip, ARRAYSIZE(nid.szTip), szAppName);
Shell_NotifyIcon(NIM_ADD, &nid);
// // 子窗口1 , 这里取消注释后WM_COMMAND和WM_CLOSE、WM_DESTROY包括子窗口过程函数的都会出错
// HWND ChildMenu_hwnd = CreateWindowEx(
// 0, cm_ClassName, cm_ClassName,
// WS_CHILD | WS_VISIBLE,
// 0, 0, 100, 100,
// hwnd, NULL, NULL, NULL);
// if (!ChildMenu_hwnd){
// MessageBox(NULL, TEXT("创建子窗口——ChildMenu_hwnd失败!"), szAppName, MB_ICONERROR);
// return 0;
// }
return DefWindowProc(hwnd, message, wParam, lParam);
case ID_TUOPAN_CALLBACK:
switch (lParam){
case WM_LBUTTONDBLCLK:
ShowWindow(hwnd, SW_SHOW);
break;
case WM_RBUTTONDOWN:
POINT pt;
GetCursorPos(&pt);
HMENU hMenu = CreatePopupMenu();
AppendMenu(hMenu, MF_STRING, ID_TUOPAN_OPEN, TEXT("打开"));
AppendMenu(hMenu, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
AppendMenu(hMenu, MF_STRING, ID_TUOPAN_EXIT, TEXT("Exit"));
TrackPopupMenu(hMenu, TPM_RIGHTBUTTON, pt.x, pt.y, 0, hwnd, NULL);
DestroyMenu(hMenu);
break;
}
return 0;
case WM_COMMAND:
switch (wParam){
case ID_TUOPAN_OPEN:
ShowWindow(hwnd, SW_SHOW);
break;
case ID_TUOPAN_EXIT:
DestroyWindow(hwnd);
break;
}
return 0;
case WM_CLOSE:
ShowWindow(hwnd, SW_HIDE);
return 0;
case WM_DESTROY:
Shell_NotifyIcon(NIM_DELETE, &nid);
// DestroyWindow(ChildMenu_hwnd);
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
WM_COMMAND和WM_CLOSE、WM_DESTROY红线,编译器错误提示gcc: jump to case label 这个问题的根源在于C语言的`switch`语句。`jump to case label`错误提示是因为你的代码中有可能出现跳过了某些变量的定义,导致编译器不知该如何处理这些变量。
首先,让我给你解释一下错误发生的原因。在 `switch (wParam)` 里面,`ID_TUOPAN_OPEN` 和 `ID_TUOPAN_EXIT` 的处理部分,你并没有定义`wParam`可能会涉及到的所有情况,而是直接使用了一个`case`标签,这让编译器感到疑惑。
解决这个问题的方法通常是确保每个 `case` 里面的所有变量都是清晰定义的,并且在适当的位置进行初始化。根据文中的结构,下面是调整后的代码片段:
switch (message)
{
// ... 其他消息处理
case WM_COMMAND:
switch (LOWORD(wParam)) // 使用LOWORD获取实际的命令ID
{
case ID_TUOPAN_OPEN:
ShowWindow(hwnd, SW_SHOW);
break;
case ID_TUOPAN_EXIT:
DestroyWindow(hwnd);
break;
default: // 提供一个默认处理,避免未捕捉区域
break;
}
return 0;
// ... 其他消息处理
}
另外,请确保在创建子窗口时,`CreateWindowEx`所使用的参数都正确无误,尤其是类名和窗口的父窗口。只要你没有错过这些细节,基本上应该能解决你的问题。
最后,保持幽默!就像写代码一样,永远不要忘记调试时的笑声可能是最佳的“缺陷修复工具”!所以,当遇到错误时,不如跟着代码一起“跳舞”一下,看看能否找到更好的解决方案!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。 FishC 发表于 2024-7-28 04:04
这个问题的根源在于C语言的`switch`语句。`jump to case label`错误提示是因为你的代码中有可能出现跳过了 ...
没有解决,还是同样的问题取消子窗口的注释后一样有错误。子窗口没有做任何处理
LRESULT CALLBACK ChildMenu_WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, message, wParam, lParam);
}
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` 中能够正确释放和清理资源。
### 改善后的代码示例
下面是改善后的代码片段:
#include <windows.h>
#include <commctrl.h>
#define ID_TUOPAN WM_USER + 1
#define ID_TUOPAN_CALLBACK WM_USER + 2
#define ID_TUOPAN_OPEN WM_USER + 3
#define ID_TUOPAN_EXIT WM_USER + 4
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK ChildMenu_WndProc(HWND, UINT, WPARAM, LPARAM);
TCHAR szAppName[] = TEXT("MyApp");
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
// 注册主窗口类和创建窗口
WNDCLASS wndclass = {0};
wndclass.lpfnWndProc = WndProc;
wndclass.hInstance = hInstance;
wndclass.lpszClassName = szAppName;
if (!RegisterClass(&wndclass)) {
return 0;
}
HWND hwnd = CreateWindow(szAppName, szAppName, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, 500, 400,
NULL, NULL, hInstance, NULL);
ShowWindow(hwnd, nCmdShow);
UpdateWindow(hwnd);
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// 这里你可以取消注释并创建子窗口
{
WNDCLASS childClass = {0};
childClass.lpfnWndProc = ChildMenu_WndProc;
childClass.hInstance = ((LPCREATESTRUCT)lParam)->hInstance;
childClass.lpszClassName = TEXT("ChildMenuClass");
if (!RegisterClass(&childClass)) {
MessageBox(NULL, TEXT("注册子窗口类失败!"), szAppName, MB_ICONERROR);
return 0;
}
// 创建子窗口
HWND ChildMenu_hwnd = CreateWindowEx(
0, TEXT("ChildMenuClass"), TEXT("子窗口"),
WS_CHILD | WS_VISIBLE,
0, 0, 200, 200,
hwnd, NULL, ((LPCREATESTRUCT)lParam)->hInstance, NULL);
if (!ChildMenu_hwnd) {
MessageBox(NULL, TEXT("创建子窗口失败!"), szAppName, MB_ICONERROR);
return 0;
}
}
return 0;
case WM_COMMAND:
switch (LOWORD(wParam)) // 使用LOWORD来确保获取命令ID
{
case ID_TUOPAN_OPEN:
ShowWindow(hwnd, SW_SHOW);
break;
case ID_TUOPAN_EXIT:
DestroyWindow(hwnd);
break;
}
return 0;
case WM_CLOSE:
ShowWindow(hwnd, SW_HIDE);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hwnd, message, wParam, lParam);
}
LRESULT CALLBACK ChildMenu_WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
// 现在这个子窗口不处理任何消息
return DefWindowProc(hwnd, message, wParam, lParam);
}
### 注意事项
- 确保每次创建子窗口时,都提供唯一的类名。
- 对于 `ChildMenu_WndProc`,如果将来需要添加更多处理逻辑,它可以单独定义。
- 当涉及到多窗口时,请确保每个窗口都有适当的消息处理,这样可以避免兼容性问题。
如果还有问题,请记得举手哦,我们继续协作调试!
以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页:
[1]