Win32程序窗口句柄未正确存储问题:原因何在?
问题分析与解决
你的代码核心问题是对象副本与原始对象的分离:
- 在
UiObjects构造函数中,你将Canvas和Output成员的副本存入了Objects向量,而非引用或指针。 - 在
WM_CREATE消息处理中,你遍历向量创建窗口后,仅更新了向量内副本的hObjectWnd字段,但MyObjects.Output这个独立成员的hObjectWnd始终是初始的NULL。 - 因此点击Canvas时,
IsWindow(MyObjects.Output.hObjectWnd)检测的是未初始化的NULL,自然返回false。
解决方法一:用向量统一管理UI对象(推荐)
去掉单独的Canvas和Output成员,直接通过向量存储所有UI对象,通过标识或索引访问:
- 修改
UiObjects定义,给Object添加标识字段:
static class UiObjects { public: enum ObjectClass { Custom }; struct Object { LPWSTR lpClassName; LPWSTR lpWindowName; DWORD dwStyle; LONG x; LONG y; LONG nWidth; LONG nHeigth; HMENU hMenu; HWND hObjectWnd; ObjectClass objectType; COLORREF color; enum ObjectId { CanvasId, OutputId } id; // 添加标识字段 }; std::vector<Object> Objects; UiObjects(); } MyObjects;
- 更新构造函数,直接向向量添加对象:
UiObjects::UiObjects() { Objects.push_back({ L"myVirtualSandbox Canvas Class", L"Canvas", WS_VISIBLE | WS_CHILD | WS_BORDER, CANVAS_HOR_OFFSET, CANVAS_VER_OFFSET, CANVAS_WIDTH, CANVAS_HEIGTH, NULL, NULL, ObjectClass::Custom, 0, Object::CanvasId }); Objects.push_back({ L"EDIT", L"Output", WS_VISIBLE | WS_CHILD | WS_BORDER, CANVAS_HOR_OFFSET, CANVAS_VER_OFFSET + CANVAS_HEIGTH + OUTPUT_VER_OFFSET, CANVAS_WIDTH, OUTPUT_HEIGTH, NULL, NULL, ObjectClass::Custom, 0, Object::OutputId }); }
- 在
canvasWndProc中通过标识查找Output窗口:
case WM_LBUTTONDOWN: { POINT point = { }; point.x = GET_X_LPARAM(lParam); point.y = GET_Y_LPARAM(lParam); System::Diagnostics::Debug::WriteLine("Clicked in Canvas."); HWND hOutputWnd = NULL; for (auto& obj : MyObjects.Objects) { if (obj.id == UiObjects::Object::OutputId) { hOutputWnd = obj.hObjectWnd; break; } } if (IsWindow(hOutputWnd)) { SendMessage(hOutputWnd, WM_SETTEXT, NULL, (LPARAM)L"Test."); } else { System::Diagnostics::Debug::WriteLine("Is not.."); } break; }
解决方法二:让向量存储对象指针
保持Canvas和Output成员,修改向量为存储指针,确保修改的是原始对象:
- 修改
UiObjects的向量类型:
static class UiObjects { public: enum ObjectClass { Custom }; struct Object { LPWSTR lpClassName; LPWSTR lpWindowName; DWORD dwStyle; LONG x; LONG y; LONG nWidth; LONG nHeigth; HMENU hMenu; HWND hObjectWnd; ObjectClass objectType; COLORREF color; }; Object Canvas, Output; std::vector<Object*> Objects; // 修改为指针向量 UiObjects(); } MyObjects;
- 更新构造函数,存入原始对象的指针:
UiObjects::UiObjects() { Canvas = { L"myVirtualSandbox Canvas Class", L"Canvas", WS_VISIBLE | WS_CHILD | WS_BORDER, CANVAS_HOR_OFFSET, CANVAS_VER_OFFSET, CANVAS_WIDTH, CANVAS_HEIGTH, NULL, NULL, ObjectClass::Custom, 0 }; Objects.push_back(&Canvas); // 存储原始对象指针 Output = { L"EDIT", L"Output", WS_VISIBLE | WS_CHILD | WS_BORDER, CANVAS_HOR_OFFSET, CANVAS_VER_OFFSET + CANVAS_HEIGTH + OUTPUT_VER_OFFSET, CANVAS_WIDTH, OUTPUT_HEIGTH, NULL, NULL, ObjectClass::Custom, 0 }; Objects.push_back(&Output); // 存储原始对象指针 }
- 修改
WM_CREATE中的循环逻辑:
for (int i = 0; i < MyObjects.Objects.size(); i++) { UiObjects::Object* obj = MyObjects.Objects[i]; // 通过指针访问对象 HWND hObjectWnd = CreateWindow( obj->lpClassName, obj->lpWindowName, obj->dwStyle, obj->x, obj->y, obj->nWidth, obj->nHeigth, hWnd, obj->hMenu, hInstance, NULL ); obj->hObjectWnd = hObjectWnd; // 修改原始对象的窗口句柄 }
此方法下你原来的canvasWndProc代码无需修改,MyObjects.Output.hObjectWnd会被正确赋值,IsWindow检测即可通过。
内容的提问来源于stack exchange,提问作者thielo06
相关产品推荐
相关产品推荐

