3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * PROJECT: ReactOS user32.dll
22 * FILE: lib/user32/windows/menu.c
24 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
26 * 09-05-2001 CSH Created
29 /* INCLUDES ******************************************************************/
39 #include <user32/callback.h>
40 #include "user32/regcontrol.h"
41 #include "../controls/controls.h"
43 /* TYPES *********************************************************************/
45 #define MENU_TYPE_MASK ((MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
47 #define MENU_ITEM_TYPE(flags) \
48 ((flags) & (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR))
50 #define MENU_BAR_ITEMS_SPACE (12)
51 #define SEPARATOR_HEIGHT (5)
52 #define MENU_TAB_SPACE (8)
55 #define MF_END (0x0080)
59 #define MIIM_STRING (0x00000040)
62 #define MAKEINTATOMA(atom) ((LPCSTR)((ULONG_PTR)((WORD)(atom))))
63 #define MAKEINTATOMW(atom) ((LPCWSTR)((ULONG_PTR)((WORD)(atom))))
64 #define POPUPMENU_CLASS_ATOMA MAKEINTATOMA(32768) /* PopupMenu */
65 #define POPUPMENU_CLASS_ATOMW MAKEINTATOMW(32768) /* PopupMenu */
67 /*********************************************************************
68 * PopupMenu class descriptor
70 const struct builtin_class_descr POPUPMENU_builtin_class =
72 POPUPMENU_CLASS_ATOMW, /* name */
73 CS_GLOBALCLASS | CS_SAVEBITS | CS_DBLCLKS, /* style */
74 (WNDPROC) NULL, /* FIXME - procW */
75 sizeof(MENUINFO *), /* extra */
76 (LPCWSTR) IDC_ARROW, /* cursor */
77 (HBRUSH)COLOR_MENU /* brush */
81 /* INTERNAL FUNCTIONS ********************************************************/
83 /* Rip the fun and easy to use and fun WINE unicode string manipulation routines.
84 * Of course I didnt copy the ASM code because we want this to be portable
85 * and it needs to go away.
88 static inline unsigned int strlenW( const WCHAR *str )
95 static inline WCHAR *strncpyW( WCHAR *str1, const WCHAR *str2, int n )
98 while (n-- > 0) if (!(*str1++ = *str2++)) break;
99 while (n-- > 0) *str1++ = 0;
103 static inline WCHAR *strcpyW( WCHAR *dst, const WCHAR *src )
106 while ((*p++ = *src++));
110 static inline WCHAR *strcatW( WCHAR *dst, const WCHAR *src )
112 strcpyW( dst + strlenW(dst), src );
117 #define GET_WORD(ptr) (*(WORD *)(ptr))
120 #define GET_DWORD(ptr) (*(DWORD *)(ptr))
123 HFONT hMenuFont = NULL;
124 HFONT hMenuFontBold = NULL;
126 /**********************************************************************
127 * MENUEX_ParseResource
129 * Parse an extended menu resource and add items to the menu.
130 * Return a pointer to the end of the resource.
132 * FIXME - should we be passing an LPCSTR to a predominantly UNICODE function?
134 static LPCSTR MENUEX_ParseResource( LPCSTR res, HMENU hMenu)
142 mii.cbSize = sizeof(mii);
143 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE;
144 mii.fType = GET_DWORD(res);
145 res += sizeof(DWORD);
146 mii.fState = GET_DWORD(res);
147 res += sizeof(DWORD);
148 mii.wID = GET_DWORD(res);
149 res += sizeof(DWORD);
150 resinfo = GET_WORD(res);
152 /* Align the text on a word boundary. */
153 res += (~((int)res - 1)) & 1;
154 mii.dwTypeData = (LPWSTR) res;
155 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR);
156 /* Align the following fields on a dword boundary. */
157 res += (~((int)res - 1)) & 3;
159 if (resinfo & 1) /* Pop-up? */
161 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */
162 res += sizeof(DWORD);
163 mii.hSubMenu = CreatePopupMenu();
166 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu)))
168 DestroyMenu(mii.hSubMenu);
171 mii.fMask |= MIIM_SUBMENU;
172 mii.fType |= MF_POPUP;
174 else if(!*mii.dwTypeData && !(mii.fType & MF_SEPARATOR))
176 DbgPrint("WARN: Converting NULL menu item %04x, type %04x to SEPARATOR\n",
178 mii.fType |= MF_SEPARATOR;
180 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii);
182 while (!(resinfo & MF_END));
187 /**********************************************************************
190 * Parse a standard menu resource and add items to the menu.
191 * Return a pointer to the end of the resource.
193 * NOTE: flags is equivalent to the mtOption field
195 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu, BOOL unicode )
204 flags = GET_WORD(res);
206 /* remove MF_END flag before passing it to AppendMenu()! */
207 end = (flags & MF_END);
208 if(end) flags ^= MF_END;
211 if(!(flags & MF_POPUP))
218 res += strlen(str) + 1;
220 res += (strlenW((LPCWSTR)str) + 1) * sizeof(WCHAR);
221 if (flags & MF_POPUP)
223 hSubMenu = CreatePopupMenu();
224 if(!hSubMenu) return NULL;
225 if(!(res = MENU_ParseResource(res, hSubMenu, unicode)))
228 AppendMenuA(hMenu, flags, (UINT)hSubMenu, str);
230 AppendMenuW(hMenu, flags, (UINT)hSubMenu, (LPCWSTR)str);
232 else /* Not a popup */
235 AppendMenuA(hMenu, flags, id, *str ? str : NULL);
237 AppendMenuW(hMenu, flags, id,
238 *(LPCWSTR)str ? (LPCWSTR)str : NULL);
247 User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength)
251 hUser32 = GetModuleHandleW(L"USER32");
252 Result = (LRESULT)LoadMenuW(hUser32, L"SYSMENU");
253 return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS));
260 NONCLIENTMETRICSW ncm;
262 /* get the menu font */
263 if(!hMenuFont || !hMenuFontBold)
265 ncm.cbSize = sizeof(ncm);
266 if(!SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0))
268 DbgPrint("MenuInit(): SystemParametersInfoW(SPI_GETNONCLIENTMETRICS) failed!\n");
272 hMenuFont = CreateFontIndirectW(&ncm.lfMenuFont);
273 if(hMenuFont == NULL)
275 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFont) failed!\n");
279 ncm.lfMenuFont.lfWeight = max(ncm.lfMenuFont.lfWeight + 300, 1000);
280 hMenuFontBold = CreateFontIndirectW(&ncm.lfMenuFont);
281 if(hMenuFontBold == NULL)
283 DbgPrint("MenuInit(): CreateFontIndirectW(hMenuFontBold) failed!\n");
293 MenuGetMenuBarHeight(HWND hWnd, ULONG MenuBarWidth, LONG OrgX, LONG OrgY)
300 MenuId = GetWindowLong(hWnd, GWL_ID);
301 Menu = MenuGetMenu((HMENU)MenuId);
306 hDC = GetDCEx(hWnd, 0, DCX_CACHE | DCX_WINDOW);
307 SelectObject(hDC, hMenuFont);
308 SetRect(&Rect, OrgX, OrgY, OrgX + MenuBarWidth,
309 OrgY + GetSystemMetrics(SM_CYMENU));
310 MenuMenuBarCalcSize(hDC, &Rect, Menu, hWnd);
311 ReleaseDC(hWnd, hDC);*/
312 return(GetSystemMetrics(SM_CYMENU));
316 MeasureMenuItem(HWND hWnd, HMENU mnu, HDC hDC, MENUITEMINFOW *mii, RECT *mir, LPWSTR str)
319 MEASUREITEMSTRUCT mis;
322 if(mii->fType & MFT_OWNERDRAW)
324 /* send WM_MEASUREITEM message to window */
325 mis.CtlType = ODT_MENU;
327 mis.itemID = mii->wID;
330 mis.itemData = mii->dwItemData;
331 res = (BOOL)SendMessageW(hWnd, WM_MEASUREITEM, 0, (LPARAM)&mis);
334 mir->right = mir->left + mis.itemWidth;
335 mir->bottom = mir->top + mis.itemHeight;
339 /* FIXME calculate size internally assuming the menu item is empty */
340 mir->right = mir->left + 1;
341 mir->bottom = mir->top + 1;
347 GetTextExtentPoint32W(hDC, str, mii->cch, &sz);
348 /* FIXME calculate the size of the menu item */
349 mir->right = mir->left + sz.cx + 6;
350 mir->bottom = mir->top + max(sz.cy, GetSystemMetrics(SM_CYMENU));
356 DrawMenuItem(HWND hWnd, HMENU mnu, HDC hDC, MENUITEMINFOW *mii, RECT *mir, LPWSTR str)
361 if(mii->fType & MFT_OWNERDRAW)
363 /* send WM_DRAWITEM message to window */
364 dis.CtlType = ODT_MENU;
366 dis.itemID = mii->wID;
367 dis.itemAction = ODA_DRAWENTIRE; /* FIXME */
368 dis.itemState = 0; /* FIXME */
369 dis.hwndItem = (HWND)mnu;
371 RtlCopyMemory(&dis.rcItem, mir, sizeof(RECT));
372 dis.itemData = mii->dwItemData;
373 res = (BOOL)SendMessageW(hWnd, WM_DRAWITEM, 0, (LPARAM)&dis);
378 /* FIXME draw the menu item */
379 SetTextColor(hDC, COLOR_MENUTEXT);
380 DrawTextW(hDC, str, mii->cch, mir, DT_SINGLELINE | DT_VCENTER | DT_CENTER);
387 MenuDrawMenuBar(HDC hDC, LPRECT Rect, HWND hWnd, BOOL Draw)
393 DWORD BufSize, Items, Items2;
395 RECT *omir, *mir = NULL;
398 height = Rect->bottom - Rect->top;
399 mnu = GetMenu(hWnd); /* Fixme - pass menu handle as parameter */
400 /* get menu item list size */
401 BufSize = NtUserBuildMenuItemList(mnu, (VOID*)1, 0, 0);
404 /* FIXME cache menu bar items using NtUserDrawMenuBarTemp()
405 instead of allocating and deallocating memory everytime */
407 hHeap = GetProcessHeap();
408 hBuf = HeapAlloc(hHeap, 0, BufSize);
410 return(Rect->bottom - Rect->top);
412 /* copy menu items into buffer */
413 Items = Items2 = NtUserBuildMenuItemList(mnu, Buf, BufSize, 0);
415 /* calculate menu item rectangles */
419 mii = (LPMENUITEMINFOW)Buf;
420 Buf += sizeof(MENUITEMINFOW);
426 Buf += (mii->cch + 1) * sizeof(WCHAR);
432 mir->left = omir->right + 1;
433 mir->top = omir->top;
434 mir->right += mir->left;
435 mir->bottom += mir->top;
439 mir->left = Rect->left;
440 mir->top = Rect->top;
442 MeasureMenuItem(hWnd, mnu, hDC, mii, mir, str);
444 height = max(height, mir->top + mir->bottom);
445 /* DbgPrint("Measure menu item %ws: (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
448 height = max(height, GetSystemMetrics(SM_CYMENU));
451 /* draw menu items */
454 mii = (LPMENUITEMINFOW)Buf;
455 Buf += sizeof(MENUITEMINFOW);
461 Buf += (mii->cch + 1) * sizeof(WCHAR);
465 /* DbgPrint("Draw menu item %ws at (%d, %d, %d, %d)\n", str, mir->left, mir->top, mir->right, mir->bottom); */
466 DrawMenuItem(hWnd, mnu, hDC, mii, mir, str);
470 HeapFree(hHeap, 0, hBuf);
478 MenuTrackMouseMenuBar(HWND hWnd, ULONG Ht, POINT Pt)
484 MenuTrackKbdMenuBar(HWND hWnd, ULONG wParam, ULONG Key)
488 /* FUNCTIONS *****************************************************************/
491 MenuIsStringItem(ULONG TypeData)
493 return((TypeData & MENU_TYPE_MASK) == MF_STRING);
501 AppendMenuA(HMENU hMenu,
506 return(InsertMenuA(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
515 AppendMenuW(HMENU hMenu,
520 return(InsertMenuW(hMenu, -1, uFlags | MF_BYPOSITION, uIDNewItem,
529 CheckMenuItem(HMENU hmenu,
533 return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck);
541 CheckMenuRadioItem(HMENU hmenu,
558 return NtUserCreateMenu();
566 CreatePopupMenu(VOID)
568 /* FIXME - add MF_POPUP style? */
569 return NtUserCreateMenu();
577 DeleteMenu(HMENU hMenu,
581 return NtUserDeleteMenu(hMenu, uPosition, uFlags);
589 DestroyMenu(HMENU hMenu)
591 return NtUserDestroyMenu(hMenu);
599 DrawMenuBar(HWND hWnd)
602 /* FIXME - return NtUserCallHwndLock(hWnd, 0x55); */
611 EnableMenuItem(HMENU hMenu,
615 return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable);
625 /* FIXME - return NtUserEndMenu(); */
636 return (HMENU)NtUserCallOneParam((DWORD)hWnd, ONEPARAM_ROUTINE_GETMENU);
644 GetMenuBarInfo(HWND hwnd,
658 GetMenuCheckMarkDimensions(VOID)
660 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK),
661 GetSystemMetrics(SM_CYMENUCHECK)));
669 GetMenuDefaultItem(HMENU hMenu,
673 return NtUserGetMenuDefaultItem(hMenu, fByPos, gmdiFlags);
681 GetMenuInfo(HMENU hmenu,
687 if(!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO)))
690 RtlZeroMemory(&mi, sizeof(MENUINFO));
691 mi.cbSize = sizeof(MENUINFO);
692 mi.fMask = lpcmi->fMask;
694 res = NtUserMenuInfo(hmenu, &mi, FALSE);
696 memcpy(lpcmi, &mi, sizeof(MENUINFO));
705 GetMenuItemCount(HMENU hMenu)
707 return NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
715 GetMenuItemID(HMENU hMenu,
720 mii.cbSize = sizeof(MENUITEMINFOW);
721 mii.fMask = MIIM_ID | MIIM_SUBMENU;
723 if(!NtUserMenuItemInfo(hMenu, nPos, MF_BYPOSITION, &mii, FALSE))
728 if(mii.hSubMenu) return -1;
729 if(mii.wID == 0) return -1;
743 LPMENUITEMINFOA lpmii)
759 LPMENUITEMINFOW lpmii)
770 GetMenuItemRect(HWND hWnd,
791 mii.cbSize = sizeof(MENUITEMINFOW);
792 mii.fMask = MIIM_STATE | MIIM_TYPE | MIIM_SUBMENU;
795 if(NtUserMenuItemInfo(hMenu, uId, uFlags, &mii, FALSE))
800 nSubItems = (UINT)NtUserBuildMenuItemList(mii.hSubMenu, NULL, 0, 0);
802 /* FIXME - ported from wine, does that work (0xff)? */
803 if(GetLastError() != ERROR_INVALID_MENU_HANDLE)
804 return (nSubItems << 8) | ((mii.fState | mii.fType) & 0xff);
806 return (UINT)-1; /* Invalid submenu */
809 /* FIXME - ported from wine, does that work? */
810 return (mii.fType | mii.fState);
861 mi.cbSize = sizeof(mi);
862 mi.fMask = MIIM_SUBMENU;
863 if(NtUserMenuItemInfo(hMenu, (UINT)nPos, MF_BYPOSITION, &mi, FALSE))
882 return NtUserHiliteMenuItem(hwnd, hmenu, uItemHilite, uHilite);
899 mii.cbSize = sizeof(MENUITEMINFOA);
900 mii.fMask = MIIM_FTYPE | MIIM_STRING;
903 if(uFlags & MF_BITMAP)
905 mii.fType |= MFT_BITMAP;
907 else if(uFlags & MF_OWNERDRAW)
909 mii.fType |= MFT_OWNERDRAW;
911 mii.dwTypeData = (LPSTR)lpNewItem;
912 if(uFlags & MF_POPUP)
914 mii.fMask |= MIIM_SUBMENU;
915 mii.hSubMenu = (HMENU)uIDNewItem;
919 mii.fMask |= MIIM_ID;
920 mii.wID = (UINT)uIDNewItem;
922 return InsertMenuItemA(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
935 LPCMENUITEMINFOA lpmii)
938 UNICODE_STRING MenuText;
940 BOOL CleanHeap = FALSE;
943 if((lpmii->cbSize == sizeof(MENUITEMINFOA)) ||
944 (lpmii->cbSize == sizeof(MENUITEMINFOA) - sizeof(HBITMAP)))
946 RtlMoveMemory ( &mi, lpmii, lpmii->cbSize );
948 /* copy the text string */
949 if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
950 (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
952 Status = HEAP_strdupAtoW ( &mi.dwTypeData, (LPCSTR)mi.dwTypeData, &mi.cch );
953 if (!NT_SUCCESS (Status))
955 SetLastError (RtlNtStatusToDosError(Status));
958 RtlInitUnicodeString(&MenuText, (PWSTR)mi.dwTypeData);
959 mi.dwTypeData = (LPWSTR)&MenuText;
963 res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
965 if ( CleanHeap ) HEAP_free ( mi.dwTypeData );
980 LPCMENUITEMINFOW lpmii)
983 UNICODE_STRING MenuText;
985 BOOL CleanHeap = FALSE;
986 HANDLE hHeap = RtlGetProcessHeap();
987 mi.hbmpItem = (HBITMAP)0;
989 // while we could just pass 'lpmii' to win32k, we make a copy so that
990 // if a bad user passes bad data, we crash his process instead of the
993 if((lpmii->cbSize == sizeof(MENUITEMINFOW)) ||
994 (lpmii->cbSize == sizeof(MENUITEMINFOW) - sizeof(HBITMAP)))
996 memcpy(&mi, lpmii, lpmii->cbSize);
998 /* copy the text string */
999 if((mi.fMask & (MIIM_TYPE | MIIM_STRING)) &&
1000 (MENU_ITEM_TYPE(mi.fType) == MF_STRING) && mi.dwTypeData)
1004 if(!RtlCreateUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData))
1006 SetLastError (RtlNtStatusToDosError(STATUS_NO_MEMORY));
1009 mi.dwTypeData = (LPWSTR)&MenuText;
1010 mi.cch = MenuText.Length / sizeof(WCHAR);
1015 res = NtUserInsertMenuItem(hMenu, uItem, fByPosition, &mi);
1017 if(CleanHeap) RtlFreeHeap (hHeap, 0, mi.dwTypeData);
1032 UINT_PTR uIDNewItem,
1036 mii.cbSize = sizeof(MENUITEMINFOW);
1037 mii.fMask = MIIM_FTYPE | MIIM_STRING;
1040 if(uFlags & MF_BITMAP)
1042 mii.fType |= MFT_BITMAP;
1044 else if(uFlags & MF_OWNERDRAW)
1046 mii.fType |= MFT_OWNERDRAW;
1048 mii.dwTypeData = (LPWSTR)lpNewItem;
1049 if(uFlags & MF_POPUP)
1051 mii.fMask |= MIIM_SUBMENU;
1052 mii.hSubMenu = (HMENU)uIDNewItem;
1056 mii.fMask |= MIIM_ID;
1057 mii.wID = (UINT)uIDNewItem;
1059 return InsertMenuItemW(hMenu, uPosition, (WINBOOL)!(MF_BYPOSITION & uFlags), &mii);
1072 SetLastError(ERROR_SUCCESS);
1073 ret = NtUserBuildMenuItemList(hMenu, NULL, 0, 0);
1074 return ((ret == (DWORD)-1) || (GetLastError() == ERROR_INVALID_MENU_HANDLE));
1082 LoadMenuA(HINSTANCE hInstance,
1085 HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4));
1086 if (Resource == NULL)
1090 return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource)));
1098 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate)
1100 return(LoadMenuIndirectW(lpMenuTemplate));
1108 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate)
1111 WORD version, offset;
1112 LPCSTR p = (LPCSTR)lpMenuTemplate;
1114 version = GET_WORD(p);
1119 case 0: /* standard format is version of 0 */
1120 offset = GET_WORD(p);
1121 p += sizeof(WORD) + offset;
1122 if (!(hMenu = CreateMenu())) return 0;
1123 if (!MENU_ParseResource(p, hMenu, TRUE))
1129 case 1: /* extended format is version of 1 */
1130 offset = GET_WORD(p);
1131 p += sizeof(WORD) + offset;
1132 if (!(hMenu = CreateMenu())) return 0;
1133 if (!MENUEX_ParseResource(p, hMenu))
1135 DestroyMenu( hMenu );
1140 DbgPrint("LoadMenuIndirectW(): version %d not supported.\n", version);
1150 LoadMenuW(HINSTANCE hInstance,
1153 HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU);
1154 if (Resource == NULL)
1158 return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource)));
1186 UINT_PTR uIDNewItem,
1203 UINT_PTR uIDNewItem,
1221 return NtUserRemoveMenu(hMenu, uPosition, uFlags);
1232 return NtUserSetMenu(hWnd, hMenu, TRUE);
1246 return NtUserSetMenuDefaultItem(hMenu, uItem, fByPos);
1261 if(lpcmi->cbSize != sizeof(MENUINFO))
1264 memcpy(&mi, lpcmi, sizeof(MENUINFO));
1265 return NtUserMenuInfo(hmenu, &mi, TRUE);
1278 HBITMAP hBitmapUnchecked,
1279 HBITMAP hBitmapChecked)
1294 WINBOOL fByPosition,
1295 LPMENUITEMINFOA lpmii)
1310 WINBOOL fByPosition,
1311 LPMENUITEMINFOW lpmii)
1330 CONST RECT *prcRect)
1360 SetMenuContextHelpId(HMENU hmenu,
1361 DWORD dwContextHelpId)
1363 return NtUserSetMenuContextHelpId(hmenu, dwContextHelpId);
1372 GetMenuContextHelpId(HMENU hmenu)
1375 mi.cbSize = sizeof(MENUINFO);
1376 mi.fMask = MIM_HELPID;
1378 if(NtUserMenuInfo(hmenu, &mi, FALSE))
1380 return mi.dwContextHelpID;