WM_DRAWITEM中HMENU与HWND强制转换比较是否正确?
你的判断方式是错误的,正确做法看这里
首先明确:你不能把HMENU和HWND强制转成int来比较,这是完全错误的操作,原因有两点:
- HMENU(菜单句柄)和HWND(窗口句柄)是Windows系统中完全独立的两种句柄类型,分别对应不同的内核对象,它们的值没有任何逻辑关联,强制比较毫无意义。
- 在64位程序中,句柄是64位指针,而int是32位类型,强制转换会导致指针截断,直接破坏原有值,肯定会判断错误。
另外要纠正一个认知:根据MSDN文档,当DRAWITEMSTRUCT的CtlType为ODT_MENU(菜单自绘场景)时,hwndItem字段表示的是拥有该菜单的窗口的HWND,而不是菜单本身的HMENU——这也是你原来的比较完全不成立的核心原因。
正确的判断方法
下面给你两种实用的方案,根据你的场景选择:
方案1:用菜单项ID范围判断(最简单)
给你的自定义上下文菜单的所有菜单项分配一个唯一的ID区间,比如从0x1000到0x1FFF,然后在WM_DRAWITEM中判断当前项的ID是否在这个范围内:
// 提前定义你的自定义菜单ID范围 #define MY_CUSTOM_MENU_ID_START 0x1000 #define MY_CUSTOM_MENU_ID_END 0x1FFF LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_DRAWITEM: { LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam; // 先确认是菜单自绘消息 if (drawItem->CtlType == ODT_MENU) { // 判断ID是否属于你的自定义菜单范围 if (drawItem->itemID >= MY_CUSTOM_MENU_ID_START && drawItem->itemID <= MY_CUSTOM_MENU_ID_END) { // 这里就是你的自定义菜单项,执行你的绘制逻辑 // ... } } return 0; } // 其他消息处理... } return DefWindowProc(hWnd, msg, wParam, lParam); }
方案2:关联菜单句柄判断(更精准)
如果你不想依赖ID范围,可以在弹出菜单时把你的HMENU临时存储到窗口属性中,然后在WM_DRAWITEM中取出并验证当前项是否属于这个菜单:
// 定义一个唯一的属性名,用来存储菜单句柄 #define MY_POPUP_MENU_PROPERTY L"CustomPopupMenuHandle" // 弹出上下文菜单的代码 void ShowMyCustomMenu(HWND hWnd, int x, int y) { HMENU hMyMenu = highlightMenu->getHighlightMenuId(); // 将菜单句柄存入窗口属性 SetProp(hWnd, MY_POPUP_MENU_PROPERTY, (HANDLE)hMyMenu); // 弹出菜单 TrackPopupMenu(hMyMenu, TPM_LEFTALIGN | TPM_TOPALIGN, x, y, 0, hWnd, NULL); // 菜单关闭后移除属性,避免内存泄漏 RemoveProp(hWnd, MY_POPUP_MENU_PROPERTY); } // WM_DRAWITEM消息处理 case WM_DRAWITEM: { LPDRAWITEMSTRUCT drawItem = (LPDRAWITEMSTRUCT)lParam; if (drawItem->CtlType == ODT_MENU) { // 取出存储的自定义菜单句柄 HMENU hMyMenu = (HMENU)GetProp(drawItem->hwndItem, MY_POPUP_MENU_PROPERTY); if (hMyMenu != NULL) { // 验证当前项是否属于这个菜单 MENUITEMINFO mii = {0}; mii.cbSize = sizeof(MENUITEMINFO); mii.fMask = MIIM_ID; if (GetMenuItemInfo(hMyMenu, drawItem->itemID, FALSE, &mii)) { // 确认是你的自定义菜单项,执行绘制逻辑 // ... } } } return 0; }
内容的提问来源于stack exchange,提问作者Irbis
相关产品推荐
相关产品推荐

