1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS user32.dll 4 * FILE: win32ss/user/user32/windows/menu.c 5 * PURPOSE: Menus 6 * 7 * PROGRAMMERS: Casper S. Hornstrup 8 * James Tabor 9 */ 10 11 #include <user32.h> 12 13 BOOL WINAPI GdiValidateHandle(HGDIOBJ hobj); 14 15 WINE_DEFAULT_DEBUG_CHANNEL(menu); 16 17 /* internal popup menu window messages */ 18 19 #define MM_SETMENUHANDLE (WM_USER + 0) 20 #define MM_GETMENUHANDLE (WM_USER + 1) 21 22 #define MENU_TYPE_MASK (MF_STRING | MF_BITMAP | MF_OWNERDRAW | MF_SEPARATOR) 23 24 #define MENU_ITEM_TYPE(flags) ((flags) & MENU_TYPE_MASK) 25 26 #define MNS_STYLE_MASK (MNS_NOCHECK|MNS_MODELESS|MNS_DRAGDROP|MNS_AUTODISMISS|MNS_NOTIFYBYPOS|MNS_CHECKORBMP) 27 28 #define MENUITEMINFO_TYPE_MASK \ 29 (MFT_STRING | MFT_BITMAP | MFT_OWNERDRAW | MFT_SEPARATOR | \ 30 MFT_MENUBARBREAK | MFT_MENUBREAK | MFT_RADIOCHECK | \ 31 MFT_RIGHTORDER | MFT_RIGHTJUSTIFY /* same as MF_HELP */ ) 32 33 #define TYPE_MASK (MENUITEMINFO_TYPE_MASK | MF_POPUP | MF_SYSMENU) 34 35 #define STATE_MASK (~TYPE_MASK) 36 37 #define MENUITEMINFO_STATE_MASK (STATE_MASK & ~(MF_BYPOSITION | MF_MOUSESELECT)) 38 39 #define MII_STATE_MASK (MFS_GRAYED|MFS_CHECKED|MFS_HILITE|MFS_DEFAULT) 40 41 /* macro to test that flags do not indicate bitmap, ownerdraw or separator */ 42 #define IS_STRING_ITEM(flags) (MF_STRING == MENU_ITEM_TYPE(flags)) 43 #define IS_MAGIC_BITMAP(id) ((id) && ((INT_PTR)(id) < 12) && ((INT_PTR)(id) >= -1)) 44 45 /********************************************************************* 46 * PopupMenu class descriptor 47 */ 48 const struct builtin_class_descr POPUPMENU_builtin_class = 49 { 50 WC_MENU, /* name */ 51 CS_SAVEBITS | CS_DBLCLKS, /* style */ 52 NULL, /* FIXME - procA */ 53 PopupMenuWndProcW, /* FIXME - procW */ 54 sizeof(MENUINFO *), /* extra */ 55 (LPCWSTR) IDC_ARROW, /* cursor */ 56 (HBRUSH)(COLOR_MENU + 1) /* brush */ 57 }; 58 59 #ifndef GET_WORD 60 #define GET_WORD(ptr) (*(WORD *)(ptr)) 61 #endif 62 #ifndef GET_DWORD 63 #define GET_DWORD(ptr) (*(DWORD *)(ptr)) 64 #endif 65 66 67 /*********************************************************************** 68 * MENU_GetMenu 69 * 70 * Validate the given menu handle and returns the menu structure pointer. 71 */ 72 FORCEINLINE PMENU MENU_GetMenu(HMENU hMenu) 73 { 74 return ValidateHandleNoErr(hMenu, TYPE_MENU); 75 } 76 77 /*********************************************************************** 78 * MENU_FindItem 79 * 80 * Find a menu item. Return a pointer on the item, and modifies *hmenu 81 * in case the item was in a sub-menu. 82 */ 83 ITEM *MENU_FindItem( HMENU *hmenu, UINT *nPos, UINT wFlags ) 84 { 85 MENU *menu; 86 ITEM *fallback = NULL; 87 UINT fallback_pos = 0; 88 UINT i; 89 PITEM pItem; 90 91 if ((*hmenu == (HMENU)0xffff) || (!(menu = MENU_GetMenu(*hmenu)))) return NULL; 92 if (wFlags & MF_BYPOSITION) 93 { 94 if (*nPos >= menu->cItems) return NULL; 95 pItem = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; 96 if (pItem) pItem = &pItem[*nPos]; 97 return pItem; 98 } 99 else 100 { 101 PITEM item = menu->rgItems ? DesktopPtrToUser(menu->rgItems) : NULL; 102 for (i = 0; item && (i < menu->cItems); i++, item++) 103 { 104 if (item->spSubMenu) 105 { 106 PMENU pSubMenu = DesktopPtrToUser(item->spSubMenu); 107 HMENU hsubmenu = UserHMGetHandle(pSubMenu); 108 ITEM *subitem = MENU_FindItem( &hsubmenu, nPos, wFlags ); 109 if (subitem) 110 { 111 *hmenu = hsubmenu; 112 return subitem; 113 } 114 else if (item->wID == *nPos) 115 { 116 /* fallback to this item if nothing else found */ 117 fallback_pos = i; 118 fallback = item; 119 } 120 } 121 else if (item->wID == *nPos) 122 { 123 *nPos = i; 124 return item; 125 } 126 } 127 } 128 129 if (fallback) 130 *nPos = fallback_pos; 131 132 return fallback; 133 } 134 135 UINT FASTCALL 136 IntGetMenuDefaultItem(PMENU Menu, BOOL fByPos, UINT gmdiFlags, DWORD *gismc) 137 { 138 UINT i = 0; 139 PITEM Item = Menu->rgItems ? DesktopPtrToUser(Menu->rgItems) : NULL; 140 141 /* empty menu */ 142 if (!Item) return -1; 143 144 while ( !( Item->fState & MFS_DEFAULT ) ) 145 { 146 i++; Item++; 147 if (i >= Menu->cItems ) return -1; 148 } 149 150 /* default: don't return disabled items */ 151 if ( (!(GMDI_USEDISABLED & gmdiFlags)) && (Item->fState & MFS_DISABLED )) return -1; 152 153 /* search rekursiv when needed */ 154 if ( (gmdiFlags & GMDI_GOINTOPOPUPS) && Item->spSubMenu ) 155 { 156 UINT ret; 157 (*gismc)++; 158 ret = IntGetMenuDefaultItem( DesktopPtrToUser(Item->spSubMenu), fByPos, gmdiFlags, gismc ); 159 (*gismc)--; 160 if ( -1 != ret ) return ret; 161 162 /* when item not found in submenu, return the popup item */ 163 } 164 return ( fByPos ) ? i : Item->wID; 165 } 166 167 static BOOL GetMenuItemInfo_common ( HMENU hmenu, 168 UINT item, 169 BOOL bypos, 170 LPMENUITEMINFOW lpmii, 171 BOOL unicode) 172 { 173 ITEM *pItem = MENU_FindItem (&hmenu, &item, bypos ? MF_BYPOSITION : 0); 174 175 //debug_print_menuitem("GetMenuItemInfo_common: ", pItem, ""); 176 177 if (!pItem) 178 { 179 SetLastError( ERROR_MENU_ITEM_NOT_FOUND); 180 return FALSE; 181 } 182 183 if( lpmii->fMask & MIIM_TYPE) 184 { 185 if( lpmii->fMask & ( MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) 186 { 187 ERR("invalid combination of fMask bits used\n"); 188 /* this does not happen on Win9x/ME */ 189 SetLastError( ERROR_INVALID_PARAMETER); 190 return FALSE; 191 } 192 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK; 193 if (pItem->hbmp && !IS_MAGIC_BITMAP(pItem->hbmp)) 194 lpmii->fType |= MFT_BITMAP; 195 lpmii->hbmpItem = pItem->hbmp; /* not on Win9x/ME */ 196 if( lpmii->fType & MFT_BITMAP) 197 { 198 lpmii->dwTypeData = (LPWSTR) pItem->hbmp; 199 lpmii->cch = 0; 200 } 201 else if( lpmii->fType & (MFT_OWNERDRAW | MFT_SEPARATOR)) 202 { 203 /* this does not happen on Win9x/ME */ 204 lpmii->dwTypeData = 0; 205 lpmii->cch = 0; 206 } 207 } 208 209 /* copy the text string */ 210 if ((lpmii->fMask & (MIIM_TYPE|MIIM_STRING))) 211 { 212 if( !pItem->Xlpstr ) 213 { // Very strange this fixes a wine test with a crash. 214 if(lpmii->dwTypeData && lpmii->cch && !(GdiValidateHandle((HGDIOBJ)lpmii->dwTypeData)) ) 215 { 216 if( unicode) 217 *((WCHAR *)lpmii->dwTypeData) = 0; 218 else 219 *((CHAR *)lpmii->dwTypeData) = 0; 220 } 221 lpmii->cch = 0; 222 } 223 else 224 { 225 int len; 226 LPWSTR text = DesktopPtrToUser(pItem->Xlpstr); 227 if (unicode) 228 { 229 len = strlenW(text); 230 if(lpmii->dwTypeData && lpmii->cch) 231 lstrcpynW(lpmii->dwTypeData, text, lpmii->cch); 232 } 233 else 234 { 235 len = WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ) - 1; 236 if(lpmii->dwTypeData && lpmii->cch) 237 if (!WideCharToMultiByte( CP_ACP, 0, text, -1, 238 (LPSTR)lpmii->dwTypeData, lpmii->cch, NULL, NULL )) 239 ((LPSTR)lpmii->dwTypeData)[lpmii->cch - 1] = 0; 240 } 241 /* if we've copied a substring we return its length */ 242 if(lpmii->dwTypeData && lpmii->cch) 243 if (lpmii->cch <= len + 1) 244 lpmii->cch--; 245 else 246 lpmii->cch = len; 247 else 248 { 249 /* return length of string */ 250 /* not on Win9x/ME if fType & MFT_BITMAP */ 251 lpmii->cch = len; 252 } 253 } 254 } 255 256 if (lpmii->fMask & MIIM_FTYPE) 257 lpmii->fType = pItem->fType & MENUITEMINFO_TYPE_MASK; 258 259 if (lpmii->fMask & MIIM_BITMAP) 260 lpmii->hbmpItem = pItem->hbmp; 261 262 if (lpmii->fMask & MIIM_STATE) 263 lpmii->fState = pItem->fState & MENUITEMINFO_STATE_MASK; 264 265 if (lpmii->fMask & MIIM_ID) 266 lpmii->wID = pItem->wID; 267 268 if (lpmii->fMask & MIIM_SUBMENU && pItem->spSubMenu ) 269 { 270 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu); 271 HMENU hSubMenu = UserHMGetHandle(pSubMenu); 272 lpmii->hSubMenu = hSubMenu; 273 } 274 else 275 { 276 /* hSubMenu is always cleared 277 * (not on Win9x/ME ) */ 278 lpmii->hSubMenu = 0; 279 } 280 281 if (lpmii->fMask & MIIM_CHECKMARKS) 282 { 283 lpmii->hbmpChecked = pItem->hbmpChecked; 284 lpmii->hbmpUnchecked = pItem->hbmpUnchecked; 285 } 286 if (lpmii->fMask & MIIM_DATA) 287 lpmii->dwItemData = pItem->dwItemData; 288 289 return TRUE; 290 } 291 292 293 // 294 // User side Menu Class Proc. 295 // 296 LRESULT WINAPI 297 PopupMenuWndProcW(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) 298 { 299 LRESULT lResult; 300 PWND pWnd; 301 302 TRACE("PMWPW : hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); 303 304 pWnd = ValidateHwnd(Wnd); 305 if (pWnd) 306 { 307 if (!pWnd->fnid) 308 { 309 if (Message != WM_NCCREATE) 310 { 311 return DefWindowProcW(Wnd, Message, wParam, lParam); 312 } 313 } 314 else 315 { 316 if (pWnd->fnid != FNID_MENU) 317 { 318 ERR("Wrong window class for Menu!\n"); 319 return 0; 320 } 321 } 322 } 323 324 switch(Message) 325 { 326 case WM_DESTROY: 327 case WM_NCDESTROY: 328 case WM_NCCREATE: 329 case WM_CREATE: 330 case MM_SETMENUHANDLE: 331 case MM_GETMENUHANDLE: 332 case MN_SETHMENU: 333 case MN_GETHMENU: 334 case WM_PAINT: 335 case WM_PRINTCLIENT: 336 { 337 TRACE("Menu Class ProcW\n"); 338 NtUserMessageCall( Wnd, Message, wParam, lParam, (ULONG_PTR)&lResult, FNID_MENU, FALSE); 339 return lResult; 340 } 341 case WM_MOUSEACTIVATE: /* We don't want to be activated */ 342 return MA_NOACTIVATE; 343 344 case WM_ERASEBKGND: 345 return 1; 346 347 case WM_SHOWWINDOW: // Not sure what this does.... 348 if (0 != wParam) 349 { 350 if (0 == GetWindowLongPtrW(Wnd, 0)) 351 { 352 OutputDebugStringA("no menu to display\n"); 353 } 354 } 355 else 356 { 357 //SetWindowLongPtrW(Wnd, 0, 0); 358 } 359 break; 360 361 default: 362 return DefWindowProcW(Wnd, Message, wParam, lParam); 363 } 364 365 return 0; 366 } 367 368 LRESULT WINAPI PopupMenuWndProcA(HWND Wnd, UINT Message, WPARAM wParam, LPARAM lParam) 369 { 370 PWND pWnd; 371 372 pWnd = ValidateHwnd(Wnd); 373 if (pWnd && !pWnd->fnid && Message != WM_NCCREATE) 374 { 375 return DefWindowProcA(Wnd, Message, wParam, lParam); 376 } 377 TRACE("YES! hwnd=%x msg=0x%04x wp=0x%04lx lp=0x%08lx\n", Wnd, Message, wParam, lParam); 378 379 switch(Message) 380 { 381 case WM_NCCREATE: 382 case WM_CREATE: 383 case WM_MOUSEACTIVATE: 384 case WM_PAINT: 385 case WM_PRINTCLIENT: 386 case WM_ERASEBKGND: 387 case WM_DESTROY: 388 case WM_NCDESTROY: 389 case WM_SHOWWINDOW: 390 case MM_SETMENUHANDLE: 391 case MM_GETMENUHANDLE: 392 case MN_SETHMENU: 393 case MN_GETHMENU: 394 return PopupMenuWndProcW(Wnd, Message, wParam, lParam); 395 396 default: 397 return DefWindowProcA(Wnd, Message, wParam, lParam); 398 } 399 return 0; 400 } 401 402 /********************************************************************** 403 * MENU_ParseResource 404 * 405 * Parse a standard menu resource and add items to the menu. 406 * Return a pointer to the end of the resource. 407 * 408 * NOTE: flags is equivalent to the mtOption field 409 */ 410 static LPCSTR MENU_ParseResource( LPCSTR res, HMENU hMenu) 411 { 412 WORD flags, id = 0; 413 HMENU hSubMenu; 414 LPCWSTR str; 415 BOOL end = FALSE; 416 417 do 418 { 419 flags = GET_WORD(res); 420 421 /* remove MF_END flag before passing it to AppendMenu()! */ 422 end = (flags & MF_END); 423 if(end) flags ^= MF_END; 424 425 res += sizeof(WORD); 426 if(!(flags & MF_POPUP)) 427 { 428 id = GET_WORD(res); 429 res += sizeof(WORD); 430 } 431 str = (LPCWSTR)res; 432 res += (strlenW(str) + 1) * sizeof(WCHAR); 433 434 if (flags & MF_POPUP) 435 { 436 hSubMenu = CreatePopupMenu(); 437 if(!hSubMenu) return NULL; 438 if(!(res = MENU_ParseResource(res, hSubMenu))) return NULL; 439 AppendMenuW(hMenu, flags, (UINT_PTR)hSubMenu, (LPCWSTR)str); 440 } 441 else /* Not a popup */ 442 { 443 AppendMenuW(hMenu, flags, id, *(LPCWSTR)str ? (LPCWSTR)str : NULL); 444 } 445 } while(!end); 446 return res; 447 } 448 449 /********************************************************************** 450 * MENUEX_ParseResource 451 * 452 * Parse an extended menu resource and add items to the menu. 453 * Return a pointer to the end of the resource. 454 */ 455 static LPCSTR MENUEX_ParseResource(LPCSTR res, HMENU hMenu) 456 { 457 WORD resinfo; 458 do 459 { 460 MENUITEMINFOW mii; 461 462 mii.cbSize = sizeof(mii); 463 mii.fMask = MIIM_STATE | MIIM_ID | MIIM_TYPE; 464 mii.fType = GET_DWORD(res); 465 res += sizeof(DWORD); 466 mii.fState = GET_DWORD(res); 467 res += sizeof(DWORD); 468 mii.wID = GET_DWORD(res); 469 res += sizeof(DWORD); 470 resinfo = GET_WORD(res); 471 res += sizeof(WORD); 472 /* Align the text on a word boundary. */ 473 res += (~((UINT_PTR)res - 1)) & 1; 474 mii.dwTypeData = (LPWSTR)res; 475 mii.cch = strlenW(mii.dwTypeData); 476 res += (1 + strlenW(mii.dwTypeData)) * sizeof(WCHAR); 477 /* Align the following fields on a dword boundary. */ 478 res += (~((UINT_PTR)res - 1)) & 3; 479 480 TRACE("Menu item: [%08x,%08x,%04x,%04x,%S]\n", 481 mii.fType, mii.fState, mii.wID, resinfo, mii.dwTypeData); 482 483 if (resinfo & 1) /* Pop-up? */ 484 { 485 /* DWORD helpid = GET_DWORD(res); FIXME: use this. */ 486 res += sizeof(DWORD); 487 mii.hSubMenu = CreatePopupMenu(); 488 if (!mii.hSubMenu) 489 { 490 ERR("CreatePopupMenu failed\n"); 491 return NULL; 492 } 493 494 if (!(res = MENUEX_ParseResource(res, mii.hSubMenu))) 495 { 496 ERR("MENUEX_ParseResource failed\n"); 497 DestroyMenu(mii.hSubMenu); 498 return NULL; 499 } 500 mii.fMask |= MIIM_SUBMENU; 501 mii.fType |= MF_POPUP; 502 } 503 else if (!mii.dwTypeData[0] && !(mii.fType & MF_SEPARATOR)) 504 { 505 WARN("Converting NULL menu item %04x, type %04x to SEPARATOR\n", 506 mii.wID, mii.fType); 507 mii.fType |= MF_SEPARATOR; 508 } 509 InsertMenuItemW(hMenu, -1, MF_BYPOSITION, &mii); 510 } while (!(resinfo & MF_END)); 511 return res; 512 } 513 514 515 /********************************************************************** 516 * MENU_mnu2mnuii 517 * 518 * Uses flags, id and text ptr, passed by InsertMenu() and 519 * ModifyMenu() to setup a MenuItemInfo structure. 520 */ 521 static void MENU_mnu2mnuii( UINT flags, UINT_PTR id, LPCWSTR str, LPMENUITEMINFOW pmii, BOOL Unicode) 522 { 523 RtlZeroMemory( pmii, sizeof( MENUITEMINFOW)); 524 pmii->cbSize = sizeof( MENUITEMINFOW); 525 pmii->fMask = MIIM_STATE | MIIM_ID | MIIM_FTYPE; 526 /* setting bitmap clears text and vice versa */ 527 if( IS_STRING_ITEM(flags)) { 528 pmii->fMask |= MIIM_STRING | MIIM_BITMAP; 529 if( !str) 530 flags |= MF_SEPARATOR; 531 /* Item beginning with a backspace is a help item */ 532 /* FIXME: wrong place, this is only true in win16 */ 533 else 534 { 535 if (Unicode) 536 { 537 if (*str == '\b') 538 { 539 flags |= MF_HELP; 540 str++; 541 } 542 } 543 else 544 { 545 LPCSTR NewItemA = (LPCSTR) str; 546 if (*NewItemA == '\b') 547 { 548 flags |= MF_HELP; 549 NewItemA++; 550 str = (LPCWSTR) NewItemA; 551 } 552 TRACE("A cch %d\n",strlen(NewItemA)); 553 } 554 } 555 pmii->dwTypeData = (LPWSTR)str; 556 } else if( flags & MFT_BITMAP){ 557 pmii->fMask |= MIIM_BITMAP | MIIM_STRING; 558 pmii->hbmpItem = (HBITMAP)str; 559 } 560 if( flags & MF_OWNERDRAW){ 561 pmii->fMask |= MIIM_DATA; 562 pmii->dwItemData = (ULONG_PTR) str; 563 } 564 if( flags & MF_POPUP && MENU_GetMenu((HMENU)id)) { 565 pmii->fMask |= MIIM_SUBMENU; 566 pmii->hSubMenu = (HMENU)id; 567 } 568 if( flags & MF_SEPARATOR) flags |= MF_GRAYED | MF_DISABLED; 569 pmii->fState = flags & MENUITEMINFO_STATE_MASK & ~MFS_DEFAULT; 570 pmii->fType = flags & MENUITEMINFO_TYPE_MASK; 571 pmii->wID = (UINT)id; 572 } 573 574 /********************************************************************** 575 * MENU_NormalizeMenuItemInfoStruct 576 * 577 * Helper for SetMenuItemInfo and InsertMenuItemInfo: 578 * check, copy and extend the MENUITEMINFO struct from the version that the application 579 * supplied to the version used by wine source. */ 580 static BOOL MENU_NormalizeMenuItemInfoStruct( const MENUITEMINFOW *pmii_in, 581 MENUITEMINFOW *pmii_out ) 582 { 583 /* do we recognize the size? */ 584 if( !pmii_in || (pmii_in->cbSize != sizeof( MENUITEMINFOW) && 585 pmii_in->cbSize != sizeof( MENUITEMINFOW) - sizeof( pmii_in->hbmpItem)) ) { 586 SetLastError( ERROR_INVALID_PARAMETER); 587 return FALSE; 588 } 589 /* copy the fields that we have */ 590 memcpy( pmii_out, pmii_in, pmii_in->cbSize); 591 /* if the hbmpItem member is missing then extend */ 592 if( pmii_in->cbSize != sizeof( MENUITEMINFOW)) { 593 pmii_out->cbSize = sizeof( MENUITEMINFOW); 594 pmii_out->hbmpItem = NULL; 595 } 596 /* test for invalid bit combinations */ 597 if( (pmii_out->fMask & MIIM_TYPE && 598 pmii_out->fMask & (MIIM_STRING | MIIM_FTYPE | MIIM_BITMAP)) || 599 (pmii_out->fMask & MIIM_FTYPE && pmii_out->fType & MFT_BITMAP)) { 600 ERR("invalid combination of fMask bits used\n"); 601 /* this does not happen on Win9x/ME */ 602 SetLastError( ERROR_INVALID_PARAMETER); 603 return FALSE; 604 } 605 /* convert old style (MIIM_TYPE) to the new and keep the old one too */ 606 if( pmii_out->fMask & MIIM_TYPE){ 607 pmii_out->fMask |= MIIM_FTYPE; 608 if( IS_STRING_ITEM(pmii_out->fType)){ 609 pmii_out->fMask |= MIIM_STRING; 610 } else if( (pmii_out->fType) & MFT_BITMAP){ 611 pmii_out->fMask |= MIIM_BITMAP; 612 pmii_out->hbmpItem = UlongToHandle(LOWORD(pmii_out->dwTypeData)); 613 } 614 } 615 if (pmii_out->fMask & MIIM_FTYPE ) 616 { 617 pmii_out->fType &= ~MENUITEMINFO_TYPE_MASK; 618 pmii_out->fType |= pmii_in->fType & MENUITEMINFO_TYPE_MASK; 619 } 620 if (pmii_out->fMask & MIIM_STATE) 621 /* Other menu items having MFS_DEFAULT are not converted 622 to normal items */ 623 pmii_out->fState = pmii_in->fState & MENUITEMINFO_STATE_MASK; 624 625 if (pmii_out->fMask & MIIM_SUBMENU) 626 { 627 if ((pmii_out->hSubMenu != NULL) && !IsMenu(pmii_out->hSubMenu)) 628 return FALSE; 629 } 630 631 return TRUE; 632 } 633 634 BOOL 635 MenuInit(VOID) 636 { 637 return TRUE; 638 } 639 640 VOID 641 MenuCleanup(VOID) 642 { 643 } 644 645 646 NTSTATUS WINAPI 647 User32LoadSysMenuTemplateForKernel(PVOID Arguments, ULONG ArgumentLength) 648 { 649 LRESULT Result = 0; 650 651 // Use this for Menu Ole!! 652 653 return(ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS)); 654 } 655 656 NTSTATUS WINAPI 657 User32CallLoadMenuFromKernel(PVOID Arguments, ULONG ArgumentLength) 658 { 659 PLOADMENU_CALLBACK_ARGUMENTS Common; 660 LRESULT Result; 661 662 Common = (PLOADMENU_CALLBACK_ARGUMENTS) Arguments; 663 664 Result = (LRESULT)LoadMenuW(Common->hModule, Common->InterSource ? MAKEINTRESOURCEW(Common->InterSource) : (LPCWSTR)&Common->MenuName); 665 666 return ZwCallbackReturn(&Result, sizeof(LRESULT), STATUS_SUCCESS); 667 } 668 669 670 /* FUNCTIONS *****************************************************************/ 671 672 /* 673 * @implemented 674 */ 675 BOOL WINAPI 676 AppendMenuA(HMENU hMenu, 677 UINT uFlags, 678 UINT_PTR uIDNewItem, 679 LPCSTR lpNewItem) 680 { 681 MENUITEMINFOW mii; 682 UNICODE_STRING UnicodeString; 683 BOOL res; 684 685 RtlInitUnicodeString(&UnicodeString, 0); 686 687 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE); 688 689 /* copy the text string, it will be one or the other */ 690 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData) 691 { 692 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData)) 693 { 694 SetLastError (ERROR_NOT_ENOUGH_MEMORY); 695 return FALSE; 696 } 697 mii.dwTypeData = UnicodeString.Buffer; 698 mii.cch = UnicodeString.Length / sizeof(WCHAR); 699 } 700 else 701 { 702 TRACE("AMA Handle bitmaps\n"); 703 } 704 ////// Answer a question, why a -1? To hunt for the end of the item list. Get it, to Append? 705 res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &UnicodeString); 706 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString ); 707 return res; 708 } 709 710 /* 711 * @implemented 712 */ 713 BOOL WINAPI 714 AppendMenuW(HMENU hMenu, 715 UINT uFlags, 716 UINT_PTR uIDNewItem, 717 LPCWSTR lpNewItem) 718 { 719 MENUITEMINFOW mii; 720 UNICODE_STRING MenuText; 721 BOOL res; 722 723 RtlInitUnicodeString(&MenuText, 0); 724 725 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE); 726 727 /* copy the text string, it will be one or the other */ 728 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData) 729 { 730 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData); 731 mii.dwTypeData = MenuText.Buffer; 732 mii.cch = MenuText.Length / sizeof(WCHAR); 733 } 734 res = NtUserThunkedMenuItemInfo(hMenu, -1, TRUE, TRUE, &mii, &MenuText); 735 return res; 736 } 737 738 /* 739 * @implemented 740 */ 741 DWORD WINAPI 742 CheckMenuItem(HMENU hmenu, 743 UINT uIDCheckItem, 744 UINT uCheck) 745 { 746 PITEM item; 747 DWORD Ret; 748 UINT uID = uIDCheckItem; 749 750 if (!ValidateHandle(hmenu, TYPE_MENU)) 751 return -1; 752 753 if (!(item = MENU_FindItem( &hmenu, &uID, uCheck ))) return -1; 754 755 Ret = item->fState & MFS_CHECKED; 756 if ( Ret == (uCheck & MFS_CHECKED)) return Ret; // Already Checked... 757 758 return NtUserCheckMenuItem(hmenu, uIDCheckItem, uCheck); 759 } 760 761 /* 762 * @implemented 763 */ 764 BOOL WINAPI 765 CheckMenuRadioItem(HMENU hMenu, 766 UINT first, 767 UINT last, 768 UINT check, 769 UINT bypos) 770 { 771 BOOL done = FALSE; 772 UINT i; 773 PITEM mi_first = NULL, mi_check; 774 HMENU m_first, m_check; 775 MENUITEMINFOW mii; 776 mii.cbSize = sizeof( mii); 777 778 for (i = first; i <= last; i++) 779 { 780 UINT pos = i; 781 782 if (!mi_first) 783 { 784 m_first = hMenu; 785 mi_first = MENU_FindItem(&m_first, &pos, bypos); 786 if (!mi_first) continue; 787 mi_check = mi_first; 788 m_check = m_first; 789 } 790 else 791 { 792 m_check = hMenu; 793 mi_check = MENU_FindItem(&m_check, &pos, bypos); 794 if (!mi_check) continue; 795 } 796 797 if (m_first != m_check) continue; 798 if (mi_check->fType == MFT_SEPARATOR) continue; 799 800 if (i == check) 801 { 802 if (!(mi_check->fType & MFT_RADIOCHECK) || !(mi_check->fState & MFS_CHECKED)) 803 { 804 mii.fMask = MIIM_FTYPE | MIIM_STATE; 805 mii.fType = (mi_check->fType & MENUITEMINFO_TYPE_MASK) | MFT_RADIOCHECK; 806 mii.fState = (mi_check->fState & MII_STATE_MASK) | MFS_CHECKED; 807 NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL); 808 } 809 done = TRUE; 810 } 811 else 812 { 813 /* MSDN is wrong, Windows does not remove MFT_RADIOCHECK */ 814 if (mi_check->fState & MFS_CHECKED) 815 { 816 mii.fMask = MIIM_STATE; 817 mii.fState = (mi_check->fState & MII_STATE_MASK) & ~MFS_CHECKED; 818 NtUserThunkedMenuItemInfo(m_check, i, bypos, FALSE, &mii, NULL); 819 } 820 } 821 } 822 return done; 823 } 824 825 /* 826 * @implemented 827 */ 828 HMENU WINAPI 829 CreateMenu(VOID) 830 { 831 return NtUserxCreateMenu(); 832 } 833 834 /* 835 * @implemented 836 */ 837 HMENU WINAPI 838 CreatePopupMenu(VOID) 839 { 840 return NtUserxCreatePopupMenu(); 841 } 842 843 /* 844 * @implemented 845 */ 846 BOOL WINAPI 847 DrawMenuBar(HWND hWnd) 848 { 849 return NtUserxDrawMenuBar(hWnd); 850 } 851 852 /* 853 * @implemented 854 */ 855 BOOL WINAPI 856 EnableMenuItem(HMENU hMenu, 857 UINT uIDEnableItem, 858 UINT uEnable) 859 { 860 return NtUserEnableMenuItem(hMenu, uIDEnableItem, uEnable); 861 } 862 863 /* 864 * @implemented 865 */ 866 HMENU WINAPI 867 GetMenu(HWND hWnd) 868 { 869 PWND Wnd = ValidateHwnd(hWnd); 870 871 if (!Wnd) 872 return NULL; 873 874 return UlongToHandle(Wnd->IDMenu); 875 } 876 877 /* 878 * @implemented 879 */ 880 LONG WINAPI 881 GetMenuCheckMarkDimensions(VOID) 882 { 883 return(MAKELONG(GetSystemMetrics(SM_CXMENUCHECK), 884 GetSystemMetrics(SM_CYMENUCHECK))); 885 } 886 887 /* 888 * @implemented 889 */ 890 DWORD 891 WINAPI 892 GetMenuContextHelpId(HMENU hmenu) 893 { 894 PMENU pMenu; 895 if ((pMenu = ValidateHandle(hmenu, TYPE_MENU))) 896 return pMenu->dwContextHelpId; 897 return 0; 898 } 899 900 /* 901 * @implemented 902 */ 903 UINT WINAPI 904 GetMenuDefaultItem(HMENU hMenu, 905 UINT fByPos, 906 UINT gmdiFlags) 907 { 908 PMENU pMenu; 909 DWORD gismc = 0; 910 if (!(pMenu = ValidateHandle(hMenu, TYPE_MENU))) 911 return (UINT)-1; 912 913 return IntGetMenuDefaultItem( pMenu, (BOOL)fByPos, gmdiFlags, &gismc); 914 } 915 916 /* 917 * @implemented 918 */ 919 BOOL WINAPI 920 GetMenuInfo(HMENU hmenu, 921 LPMENUINFO lpcmi) 922 { 923 PMENU pMenu; 924 925 if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO))) 926 { 927 SetLastError(ERROR_INVALID_PARAMETER); 928 return FALSE; 929 } 930 931 if (!(pMenu = ValidateHandle(hmenu, TYPE_MENU))) 932 return FALSE; 933 934 if (lpcmi->fMask & MIM_BACKGROUND) 935 lpcmi->hbrBack = pMenu->hbrBack; 936 937 if (lpcmi->fMask & MIM_HELPID) 938 lpcmi->dwContextHelpID = pMenu->dwContextHelpId; 939 940 if (lpcmi->fMask & MIM_MAXHEIGHT) 941 lpcmi->cyMax = pMenu->cyMax; 942 943 if (lpcmi->fMask & MIM_MENUDATA) 944 lpcmi->dwMenuData = pMenu->dwMenuData; 945 946 if (lpcmi->fMask & MIM_STYLE) 947 lpcmi->dwStyle = pMenu->fFlags & MNS_STYLE_MASK; 948 949 return TRUE; 950 } 951 952 /* 953 * @implemented 954 */ 955 int WINAPI 956 GetMenuItemCount(HMENU hmenu) 957 { 958 PMENU pMenu; 959 if ((pMenu = ValidateHandle(hmenu, TYPE_MENU))) 960 return pMenu->cItems; 961 return -1; 962 } 963 964 /* 965 * @implemented 966 */ 967 UINT WINAPI 968 GetMenuItemID(HMENU hMenu, 969 int nPos) 970 { 971 ITEM * lpmi; 972 if (!(lpmi = MENU_FindItem(&hMenu,(UINT*)&nPos,MF_BYPOSITION))) return -1; 973 if (lpmi->spSubMenu) return -1; 974 return lpmi->wID; 975 } 976 977 /* 978 * @implemented 979 */ 980 BOOL WINAPI 981 GetMenuItemInfoA( 982 HMENU hmenu, 983 UINT item, 984 BOOL bypos, 985 LPMENUITEMINFOA lpmii) 986 { 987 BOOL ret; 988 MENUITEMINFOA mii; 989 990 if( lpmii->cbSize != sizeof( mii) && 991 lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) 992 { 993 SetLastError( ERROR_INVALID_PARAMETER); 994 return FALSE; 995 } 996 memcpy( &mii, lpmii, lpmii->cbSize); 997 mii.cbSize = sizeof( mii); 998 ret = GetMenuItemInfo_common (hmenu, 999 item, 1000 bypos, 1001 (LPMENUITEMINFOW)&mii, 1002 FALSE); 1003 mii.cbSize = lpmii->cbSize; 1004 memcpy( lpmii, &mii, mii.cbSize); 1005 return ret; 1006 } 1007 1008 /* 1009 * @implemented 1010 */ 1011 BOOL WINAPI 1012 GetMenuItemInfoW( 1013 HMENU hMenu, 1014 UINT Item, 1015 BOOL bypos, 1016 LPMENUITEMINFOW lpmii) 1017 { 1018 BOOL ret; 1019 MENUITEMINFOW mii; 1020 if( lpmii->cbSize != sizeof( mii) && lpmii->cbSize != sizeof( mii) - sizeof ( mii.hbmpItem)) 1021 { 1022 SetLastError( ERROR_INVALID_PARAMETER); 1023 return FALSE; 1024 } 1025 memcpy( &mii, lpmii, lpmii->cbSize); 1026 mii.cbSize = sizeof( mii); 1027 ret = GetMenuItemInfo_common (hMenu, Item, bypos, &mii, TRUE); 1028 mii.cbSize = lpmii->cbSize; 1029 memcpy( lpmii, &mii, mii.cbSize); 1030 return ret; 1031 } 1032 1033 /* 1034 * @implemented 1035 */ 1036 UINT 1037 WINAPI 1038 GetMenuState( 1039 HMENU hMenu, 1040 UINT uId, 1041 UINT uFlags) 1042 { 1043 PITEM pItem; 1044 UINT Type = 0; 1045 TRACE("(menu=%p, id=%04x, flags=%04x);\n", hMenu, uId, uFlags); 1046 if (!(pItem = MENU_FindItem( &hMenu, &uId, uFlags ))) return -1; 1047 1048 if (!pItem->Xlpstr && pItem->hbmp) Type = MFT_BITMAP; 1049 1050 if (pItem->spSubMenu) 1051 { 1052 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu); 1053 HMENU hsubmenu = UserHMGetHandle(pSubMenu); 1054 Type |= MF_POPUP; // Fix CORE-9269 1055 if (!IsMenu(hsubmenu)) return (UINT)-1; 1056 else return (pSubMenu->cItems << 8) | ((pItem->fState|pItem->fType|Type) & 0xff); 1057 } 1058 else 1059 return (pItem->fType | pItem->fState | Type); 1060 } 1061 1062 /* 1063 * @implemented 1064 */ 1065 int 1066 WINAPI 1067 GetMenuStringA( 1068 HMENU hMenu, 1069 UINT uIDItem, 1070 LPSTR lpString, 1071 int nMaxCount, 1072 UINT uFlag) 1073 { 1074 ITEM *item; 1075 LPWSTR text; 1076 ////// wine Code, seems to be faster. 1077 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag ); 1078 1079 if (lpString && nMaxCount) lpString[0] = '\0'; 1080 1081 if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag ))) 1082 { 1083 SetLastError( ERROR_MENU_ITEM_NOT_FOUND); 1084 return 0; 1085 } 1086 1087 text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL; 1088 1089 if (!text) return 0; 1090 if (!lpString || !nMaxCount) return WideCharToMultiByte( CP_ACP, 0, text, -1, NULL, 0, NULL, NULL ); 1091 if (!WideCharToMultiByte( CP_ACP, 0, text, -1, lpString, nMaxCount, NULL, NULL )) 1092 lpString[nMaxCount-1] = 0; 1093 TRACE("A returning %s\n", lpString); 1094 return strlen(lpString); 1095 } 1096 1097 /* 1098 * @implemented 1099 */ 1100 int 1101 WINAPI 1102 GetMenuStringW( 1103 HMENU hMenu, 1104 UINT uIDItem, 1105 LPWSTR lpString, 1106 int nMaxCount, 1107 UINT uFlag) 1108 { 1109 ITEM *item; 1110 LPWSTR text; 1111 1112 TRACE("menu=%p item=%04x ptr=%p len=%d flags=%04x\n", hMenu, uIDItem, lpString, nMaxCount, uFlag ); 1113 1114 if (lpString && nMaxCount) lpString[0] = '\0'; 1115 1116 if (!(item = MENU_FindItem( &hMenu, &uIDItem, uFlag ))) 1117 { 1118 SetLastError( ERROR_MENU_ITEM_NOT_FOUND); 1119 return 0; 1120 } 1121 1122 text = item->Xlpstr ? DesktopPtrToUser(item->Xlpstr) : NULL; 1123 1124 if (!lpString || !nMaxCount) return text ? strlenW(text) : 0; 1125 if( !(text)) 1126 { 1127 lpString[0] = 0; 1128 return 0; 1129 } 1130 lstrcpynW( lpString, text, nMaxCount ); 1131 TRACE("W returning %S\n", lpString); 1132 return strlenW(lpString); 1133 } 1134 1135 /* 1136 * @implemented 1137 */ 1138 HMENU 1139 WINAPI 1140 GetSubMenu( 1141 HMENU hMenu, 1142 int nPos) 1143 { 1144 PITEM pItem; 1145 if (!(pItem = MENU_FindItem( &hMenu, (UINT*)&nPos, MF_BYPOSITION ))) return NULL; 1146 1147 if (pItem->spSubMenu) 1148 { 1149 PMENU pSubMenu = DesktopPtrToUser(pItem->spSubMenu); 1150 HMENU hsubmenu = UserHMGetHandle(pSubMenu); 1151 if (IsMenu(hsubmenu)) return hsubmenu; 1152 } 1153 return NULL; 1154 } 1155 1156 /* 1157 * @implemented 1158 */ 1159 HMENU 1160 WINAPI 1161 GetSystemMenu(HWND hWnd, BOOL bRevert) 1162 { 1163 return NtUserGetSystemMenu(hWnd, bRevert); 1164 } 1165 1166 /* 1167 * @implemented 1168 */ 1169 BOOL 1170 WINAPI 1171 InsertMenuA( 1172 HMENU hMenu, 1173 UINT uPosition, 1174 UINT uFlags, 1175 UINT_PTR uIDNewItem, 1176 LPCSTR lpNewItem) 1177 { 1178 MENUITEMINFOW mii; 1179 UNICODE_STRING UnicodeString; 1180 BOOL res; 1181 1182 RtlInitUnicodeString(&UnicodeString, 0); 1183 1184 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE); 1185 1186 /* copy the text string, it will be one or the other */ 1187 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData) 1188 { 1189 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData)) 1190 { 1191 SetLastError (ERROR_NOT_ENOUGH_MEMORY); 1192 return FALSE; 1193 } 1194 mii.dwTypeData = UnicodeString.Buffer; 1195 mii.cch = UnicodeString.Length / sizeof(WCHAR); 1196 } 1197 else 1198 { 1199 TRACE("Handle bitmaps\n"); 1200 } 1201 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &UnicodeString); 1202 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString ); 1203 return res; 1204 } 1205 1206 /* 1207 * @implemented 1208 */ 1209 BOOL 1210 WINAPI 1211 InsertMenuItemA( 1212 HMENU hMenu, 1213 UINT uItem, 1214 BOOL fByPosition, 1215 LPCMENUITEMINFOA lpmii) 1216 { 1217 MENUITEMINFOW mii; 1218 UNICODE_STRING UnicodeString; 1219 BOOL res; 1220 1221 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii); 1222 1223 RtlInitUnicodeString(&UnicodeString, 0); 1224 1225 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE; 1226 1227 /* copy the text string */ 1228 if (((mii.fMask & MIIM_STRING) || 1229 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING))) 1230 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) ) 1231 { 1232 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData)) 1233 { 1234 SetLastError (ERROR_NOT_ENOUGH_MEMORY); 1235 return FALSE; 1236 } 1237 mii.dwTypeData = UnicodeString.Buffer; 1238 mii.cch = UnicodeString.Length / sizeof(WCHAR); 1239 } 1240 else 1241 { 1242 TRACE("Handle bitmaps\n"); 1243 } 1244 res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &UnicodeString); 1245 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString ); 1246 return res; 1247 } 1248 1249 /* 1250 * @implemented 1251 */ 1252 BOOL 1253 WINAPI 1254 InsertMenuItemW( 1255 HMENU hMenu, 1256 UINT uItem, 1257 BOOL fByPosition, 1258 LPCMENUITEMINFOW lpmii) 1259 { 1260 MENUITEMINFOW mii; 1261 UNICODE_STRING MenuText; 1262 BOOL res = FALSE; 1263 1264 /* while we could just pass 'lpmii' to win32k, we make a copy so that 1265 if a bad user passes bad data, we crash his process instead of the 1266 entire kernel */ 1267 1268 TRACE("hmenu %p, item %04x, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii); 1269 1270 RtlInitUnicodeString(&MenuText, 0); 1271 1272 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE; 1273 1274 /* copy the text string */ 1275 if (((mii.fMask & MIIM_STRING) || 1276 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING))) 1277 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) ) 1278 { 1279 RtlInitUnicodeString(&MenuText, (PWSTR)lpmii->dwTypeData); 1280 mii.dwTypeData = MenuText.Buffer; 1281 mii.cch = MenuText.Length / sizeof(WCHAR); 1282 } 1283 res = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, TRUE, &mii, &MenuText); 1284 return res; 1285 } 1286 1287 /* 1288 * @implemented 1289 */ 1290 BOOL 1291 WINAPI 1292 InsertMenuW( 1293 HMENU hMenu, 1294 UINT uPosition, 1295 UINT uFlags, 1296 UINT_PTR uIDNewItem, 1297 LPCWSTR lpNewItem) 1298 { 1299 MENUITEMINFOW mii; 1300 UNICODE_STRING MenuText; 1301 BOOL res; 1302 1303 RtlInitUnicodeString(&MenuText, 0); 1304 1305 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE); 1306 1307 /* copy the text string, it will be one or the other */ 1308 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData) 1309 { 1310 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData); 1311 mii.dwTypeData = MenuText.Buffer; 1312 mii.cch = MenuText.Length / sizeof(WCHAR); 1313 } 1314 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), TRUE, &mii, &MenuText); 1315 return res; 1316 } 1317 1318 /* 1319 * @implemented 1320 */ 1321 BOOL 1322 WINAPI 1323 IsMenu( 1324 HMENU Menu) 1325 { 1326 if (ValidateHandle(Menu, TYPE_MENU)) return TRUE; 1327 return FALSE; 1328 } 1329 1330 /* 1331 * @implemented 1332 */ 1333 HMENU WINAPI 1334 LoadMenuA(HINSTANCE hInstance, 1335 LPCSTR lpMenuName) 1336 { 1337 HANDLE Resource = FindResourceA(hInstance, lpMenuName, MAKEINTRESOURCEA(4)); 1338 if (Resource == NULL) 1339 { 1340 return(NULL); 1341 } 1342 return(LoadMenuIndirectA((PVOID)LoadResource(hInstance, Resource))); 1343 } 1344 1345 /* 1346 * @implemented 1347 */ 1348 HMENU WINAPI 1349 LoadMenuIndirectA(CONST MENUTEMPLATE *lpMenuTemplate) 1350 { 1351 return(LoadMenuIndirectW(lpMenuTemplate)); 1352 } 1353 1354 /* 1355 * @implemented 1356 */ 1357 HMENU WINAPI 1358 LoadMenuIndirectW(CONST MENUTEMPLATE *lpMenuTemplate) 1359 { 1360 HMENU hMenu; 1361 WORD version, offset; 1362 LPCSTR p = (LPCSTR)lpMenuTemplate; 1363 1364 version = GET_WORD(p); 1365 p += sizeof(WORD); 1366 1367 switch (version) 1368 { 1369 case 0: /* standard format is version of 0 */ 1370 offset = GET_WORD(p); 1371 p += sizeof(WORD) + offset; 1372 if (!(hMenu = CreateMenu())) return 0; 1373 if (!MENU_ParseResource(p, hMenu)) 1374 { 1375 DestroyMenu(hMenu); 1376 return 0; 1377 } 1378 return hMenu; 1379 case 1: /* extended format is version of 1 */ 1380 offset = GET_WORD(p); 1381 p += sizeof(WORD) + offset; 1382 if (!(hMenu = CreateMenu())) return 0; 1383 if (!MENUEX_ParseResource(p, hMenu)) 1384 { 1385 DestroyMenu( hMenu ); 1386 return 0; 1387 } 1388 return hMenu; 1389 default: 1390 ERR("Menu template version %d not supported.\n", version); 1391 return 0; 1392 } 1393 } 1394 1395 /* 1396 * @implemented 1397 */ 1398 HMENU WINAPI 1399 LoadMenuW(HINSTANCE hInstance, 1400 LPCWSTR lpMenuName) 1401 { 1402 HANDLE Resource = FindResourceW(hInstance, lpMenuName, RT_MENU); 1403 if (Resource == NULL) 1404 { 1405 return(NULL); 1406 } 1407 return(LoadMenuIndirectW((PVOID)LoadResource(hInstance, Resource))); 1408 } 1409 1410 /* 1411 * @implemented 1412 */ 1413 BOOL 1414 WINAPI 1415 ModifyMenuA( 1416 HMENU hMenu, 1417 UINT uPosition, 1418 UINT uFlags, 1419 UINT_PTR uIDNewItem, 1420 LPCSTR lpNewItem) 1421 { 1422 MENUITEMINFOW mii; 1423 UNICODE_STRING UnicodeString; 1424 BOOL res; 1425 1426 RtlInitUnicodeString(&UnicodeString, 0); 1427 1428 MENU_mnu2mnuii( uFlags, uIDNewItem, (LPCWSTR)lpNewItem, &mii, FALSE); 1429 1430 /* copy the text string, it will be one or the other */ 1431 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData) 1432 { 1433 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData)) 1434 { 1435 SetLastError (ERROR_NOT_ENOUGH_MEMORY); 1436 return FALSE; 1437 } 1438 mii.dwTypeData = UnicodeString.Buffer; 1439 mii.cch = UnicodeString.Length / sizeof(WCHAR); 1440 } 1441 else 1442 { 1443 TRACE("Handle bitmaps\n"); 1444 } 1445 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &UnicodeString); 1446 if ( UnicodeString.Buffer ) RtlFreeUnicodeString ( &UnicodeString ); 1447 return res; 1448 } 1449 1450 /* 1451 * @implemented 1452 */ 1453 BOOL 1454 WINAPI 1455 ModifyMenuW( 1456 HMENU hMenu, 1457 UINT uPosition, 1458 UINT uFlags, 1459 UINT_PTR uIDNewItem, 1460 LPCWSTR lpNewItem) 1461 { 1462 MENUITEMINFOW mii; 1463 UNICODE_STRING MenuText; 1464 BOOL res; 1465 1466 RtlInitUnicodeString(&MenuText, 0); 1467 1468 MENU_mnu2mnuii( uFlags, uIDNewItem, lpNewItem, &mii, TRUE); 1469 1470 /* copy the text string, it will be one or the other */ 1471 if (lpNewItem && mii.fMask & MIIM_STRING && !mii.hbmpItem && mii.dwTypeData) 1472 { 1473 RtlInitUnicodeString(&MenuText, (PWSTR)mii.dwTypeData); 1474 mii.dwTypeData = MenuText.Buffer; 1475 mii.cch = MenuText.Length / sizeof(WCHAR); 1476 } 1477 else 1478 { 1479 TRACE("Handle bitmaps\n"); 1480 } 1481 res = NtUserThunkedMenuItemInfo(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), FALSE, &mii, &MenuText); 1482 return res; 1483 } 1484 1485 /* 1486 * @implemented 1487 */ 1488 BOOL WINAPI 1489 SetMenu(HWND hWnd, 1490 HMENU hMenu) 1491 { 1492 return NtUserSetMenu(hWnd, hMenu, TRUE); 1493 } 1494 1495 /* 1496 * @implemented 1497 */ 1498 BOOL 1499 WINAPI 1500 SetMenuInfo( 1501 HMENU hmenu, 1502 LPCMENUINFO lpcmi) 1503 { 1504 MENUINFO mi; 1505 BOOL res = FALSE; 1506 1507 if (!lpcmi || (lpcmi->cbSize != sizeof(MENUINFO))) 1508 { 1509 SetLastError(ERROR_INVALID_PARAMETER); 1510 return res; 1511 } 1512 1513 memcpy(&mi, lpcmi, sizeof(MENUINFO)); 1514 return NtUserThunkedMenuInfo(hmenu, (LPCMENUINFO)&mi); 1515 } 1516 1517 /* 1518 * @implemented 1519 */ 1520 BOOL 1521 WINAPI 1522 SetMenuItemBitmaps( 1523 HMENU hMenu, 1524 UINT uPosition, 1525 UINT uFlags, 1526 HBITMAP hBitmapUnchecked, 1527 HBITMAP hBitmapChecked) 1528 { 1529 MENUITEMINFOW uItem; 1530 memset ( &uItem, 0, sizeof(uItem) ); 1531 uItem.cbSize = sizeof(MENUITEMINFOW); 1532 uItem.fMask = MIIM_CHECKMARKS; 1533 uItem.hbmpUnchecked = hBitmapUnchecked; 1534 uItem.hbmpChecked = hBitmapChecked; 1535 return SetMenuItemInfoW(hMenu, uPosition, (BOOL)(uFlags & MF_BYPOSITION), &uItem); 1536 } 1537 1538 /* 1539 * @implemented 1540 */ 1541 BOOL 1542 WINAPI 1543 SetMenuItemInfoA( 1544 HMENU hmenu, 1545 UINT item, 1546 BOOL bypos, 1547 LPCMENUITEMINFOA lpmii) 1548 { 1549 MENUITEMINFOW mii; 1550 UNICODE_STRING UnicodeString; 1551 BOOL Ret; 1552 1553 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hmenu, item, bypos, lpmii); 1554 1555 RtlInitUnicodeString(&UnicodeString, 0); 1556 1557 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &mii )) return FALSE; 1558 /* 1559 * MIIM_STRING == good 1560 * MIIM_TYPE & MFT_STRING == good 1561 * MIIM_STRING & MFT_STRING == good 1562 * MIIM_STRING & MFT_OWNERDRAW == good 1563 */ 1564 if (((mii.fMask & MIIM_STRING) || 1565 ((mii.fMask & MIIM_TYPE) && (MENU_ITEM_TYPE(mii.fType) == MF_STRING))) 1566 && mii.dwTypeData && !(GdiValidateHandle((HGDIOBJ)mii.dwTypeData)) ) 1567 { 1568 /* cch is ignored when the content of a menu item is set by calling SetMenuItemInfo. */ 1569 if (!RtlCreateUnicodeStringFromAsciiz(&UnicodeString, (LPSTR)mii.dwTypeData)) 1570 { 1571 SetLastError (ERROR_NOT_ENOUGH_MEMORY); 1572 return FALSE; 1573 } 1574 mii.dwTypeData = UnicodeString.Buffer; 1575 mii.cch = UnicodeString.Length / sizeof(WCHAR); 1576 } 1577 else 1578 { 1579 UnicodeString.Buffer = NULL; 1580 } 1581 Ret = NtUserThunkedMenuItemInfo(hmenu, item, bypos, FALSE, &mii, &UnicodeString); 1582 if (UnicodeString.Buffer != NULL) RtlFreeUnicodeString(&UnicodeString); 1583 return Ret; 1584 } 1585 1586 /* 1587 * @implemented 1588 */ 1589 BOOL 1590 WINAPI 1591 SetMenuItemInfoW( 1592 HMENU hMenu, 1593 UINT uItem, 1594 BOOL fByPosition, 1595 LPCMENUITEMINFOW lpmii) 1596 { 1597 MENUITEMINFOW MenuItemInfoW; 1598 UNICODE_STRING UnicodeString; 1599 BOOL Ret; 1600 1601 TRACE("hmenu %p, item %u, by pos %d, info %p\n", hMenu, uItem, fByPosition, lpmii); 1602 1603 RtlInitUnicodeString(&UnicodeString, 0); 1604 1605 if (!MENU_NormalizeMenuItemInfoStruct( (const MENUITEMINFOW *)lpmii, &MenuItemInfoW )) return FALSE; 1606 1607 if (((MenuItemInfoW.fMask & MIIM_STRING) || 1608 ((MenuItemInfoW.fMask & MIIM_TYPE) && 1609 (MENU_ITEM_TYPE(MenuItemInfoW.fType) == MF_STRING))) 1610 && MenuItemInfoW.dwTypeData && !(GdiValidateHandle((HGDIOBJ)MenuItemInfoW.dwTypeData)) ) 1611 { 1612 RtlInitUnicodeString(&UnicodeString, (PCWSTR)MenuItemInfoW.dwTypeData); 1613 MenuItemInfoW.cch = strlenW(MenuItemInfoW.dwTypeData); 1614 } 1615 Ret = NtUserThunkedMenuItemInfo(hMenu, uItem, fByPosition, FALSE, &MenuItemInfoW, &UnicodeString); 1616 1617 return Ret; 1618 } 1619 1620 /* 1621 * @implemented 1622 */ 1623 BOOL 1624 WINAPI 1625 SetSystemMenu ( 1626 HWND hwnd, 1627 HMENU hMenu) 1628 { 1629 if(!hwnd) 1630 { 1631 SetLastError(ERROR_INVALID_WINDOW_HANDLE); 1632 return FALSE; 1633 } 1634 if(!hMenu) 1635 { 1636 SetLastError(ERROR_INVALID_MENU_HANDLE); 1637 return FALSE; 1638 } 1639 return NtUserSetSystemMenu(hwnd, hMenu); 1640 } 1641 1642 BOOL 1643 WINAPI 1644 TrackPopupMenu( 1645 HMENU Menu, 1646 UINT Flags, 1647 int x, 1648 int y, 1649 int Reserved, 1650 HWND Wnd, 1651 CONST RECT *Rect) 1652 { 1653 return NtUserTrackPopupMenuEx( Menu, 1654 Flags, 1655 x, 1656 y, 1657 Wnd, 1658 NULL); // LPTPMPARAMS is null 1659 } 1660 1661 /* 1662 * @unimplemented 1663 */ 1664 LRESULT 1665 WINAPI 1666 MenuWindowProcA( 1667 HWND hWnd, 1668 ULONG_PTR Result, 1669 UINT Msg, 1670 WPARAM wParam, 1671 LPARAM lParam 1672 ) 1673 { 1674 if ( Msg < WM_USER) 1675 { 1676 return PopupMenuWndProcA(hWnd, Msg, wParam, lParam ); 1677 } 1678 return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, TRUE); 1679 } 1680 1681 /* 1682 * @unimplemented 1683 */ 1684 LRESULT 1685 WINAPI 1686 MenuWindowProcW( 1687 HWND hWnd, 1688 ULONG_PTR Result, 1689 UINT Msg, 1690 WPARAM wParam, 1691 LPARAM lParam 1692 ) 1693 { 1694 if ( Msg < WM_USER) 1695 { 1696 return PopupMenuWndProcW(hWnd, Msg, wParam, lParam ); 1697 } 1698 return NtUserMessageCall(hWnd, Msg, wParam, lParam, Result, FNID_MENU, FALSE); 1699 } 1700 1701 /* 1702 * @implemented 1703 */ 1704 BOOL 1705 WINAPI 1706 ChangeMenuW( 1707 HMENU hMenu, 1708 UINT cmd, 1709 LPCWSTR lpszNewItem, 1710 UINT cmdInsert, 1711 UINT flags) 1712 { 1713 /* 1714 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert 1715 for MF_DELETE. We should check the parameters for all others 1716 MF_* actions also (anybody got a doc on ChangeMenu?). 1717 */ 1718 1719 switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT)) 1720 { 1721 case MF_APPEND : 1722 return AppendMenuW(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem); 1723 1724 case MF_DELETE : 1725 return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE); 1726 1727 case MF_CHANGE : 1728 return ModifyMenuW(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem); 1729 1730 case MF_REMOVE : 1731 return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert, 1732 flags &~ MF_REMOVE); 1733 1734 default : /* MF_INSERT */ 1735 return InsertMenuW(hMenu, cmd, flags, cmdInsert, lpszNewItem); 1736 }; 1737 } 1738 1739 /* 1740 * @implemented 1741 */ 1742 BOOL 1743 WINAPI 1744 ChangeMenuA( 1745 HMENU hMenu, 1746 UINT cmd, 1747 LPCSTR lpszNewItem, 1748 UINT cmdInsert, 1749 UINT flags) 1750 { 1751 /* 1752 FIXME: Word passes the item id in 'cmd' and 0 or 0xffff as cmdInsert 1753 for MF_DELETE. We should check the parameters for all others 1754 MF_* actions also (anybody got a doc on ChangeMenu?). 1755 */ 1756 1757 switch(flags & (MF_APPEND | MF_DELETE | MF_CHANGE | MF_REMOVE | MF_INSERT)) 1758 { 1759 case MF_APPEND : 1760 return AppendMenuA(hMenu, flags &~ MF_APPEND, cmdInsert, lpszNewItem); 1761 1762 case MF_DELETE : 1763 return DeleteMenu(hMenu, cmd, flags &~ MF_DELETE); 1764 1765 case MF_CHANGE : 1766 return ModifyMenuA(hMenu, cmd, flags &~ MF_CHANGE, cmdInsert, lpszNewItem); 1767 1768 case MF_REMOVE : 1769 return RemoveMenu(hMenu, flags & MF_BYPOSITION ? cmd : cmdInsert, 1770 flags &~ MF_REMOVE); 1771 1772 default : /* MF_INSERT */ 1773 return InsertMenuA(hMenu, cmd, flags, cmdInsert, lpszNewItem); 1774 }; 1775 } 1776 1777