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