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