1 /* 2 * see www.geocities.com/SiliconValley/4942/filemenu.html 3 * 4 * Copyright 1999, 2000 Juergen Schmied 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 19 */ 20 21 #define WIN32_NO_STATUS 22 #define _INC_WINDOWS 23 #define COBJMACROS 24 25 #include <windef.h> 26 #include <winbase.h> 27 #include <shlobj.h> 28 #include <undocshell.h> 29 #include <shlwapi.h> 30 #include <wine/debug.h> 31 #include <wine/unicode.h> 32 33 #include "pidl.h" 34 #include "shell32_main.h" 35 36 #ifdef FM_SEPARATOR 37 #undef FM_SEPARATOR 38 #endif 39 #define FM_SEPARATOR (LPCWSTR)1 40 41 static BOOL FileMenu_AppendItemW(HMENU hMenu, LPCWSTR lpText, UINT uID, int icon, 42 HMENU hMenuPopup, int nItemHeight); 43 44 typedef struct 45 { 46 BOOL bInitialized; 47 BOOL bFixedItems; 48 /* create */ 49 COLORREF crBorderColor; 50 int nBorderWidth; 51 HBITMAP hBorderBmp; 52 53 /* insert using pidl */ 54 LPITEMIDLIST pidl; 55 UINT uID; 56 UINT uFlags; 57 UINT uEnumFlags; 58 LPFNFMCALLBACK lpfnCallback; 59 } FMINFO, *LPFMINFO; 60 61 typedef struct 62 { int cchItemText; 63 int iIconIndex; 64 HMENU hMenu; 65 WCHAR szItemText[1]; 66 } FMITEM, * LPFMITEM; 67 68 static BOOL bAbortInit; 69 70 #define CCH_MAXITEMTEXT 256 71 72 WINE_DEFAULT_DEBUG_CHANNEL(shell); 73 74 static LPFMINFO FM_GetMenuInfo(HMENU hmenu) 75 { 76 MENUINFO MenuInfo; 77 LPFMINFO menudata; 78 79 MenuInfo.cbSize = sizeof(MENUINFO); 80 MenuInfo.fMask = MIM_MENUDATA; 81 82 if (! GetMenuInfo(hmenu, &MenuInfo)) 83 return NULL; 84 85 menudata = (LPFMINFO)MenuInfo.dwMenuData; 86 87 if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) 88 { 89 ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); 90 return 0; 91 } 92 93 return menudata; 94 95 } 96 /************************************************************************* 97 * FM_SetMenuParameter [internal] 98 * 99 */ 100 static LPFMINFO FM_SetMenuParameter( 101 HMENU hmenu, 102 UINT uID, 103 LPCITEMIDLIST pidl, 104 UINT uFlags, 105 UINT uEnumFlags, 106 LPFNFMCALLBACK lpfnCallback) 107 { 108 LPFMINFO menudata; 109 110 TRACE("\n"); 111 112 menudata = FM_GetMenuInfo(hmenu); 113 114 SHFree(menudata->pidl); 115 116 menudata->uID = uID; 117 menudata->pidl = ILClone(pidl); 118 menudata->uFlags = uFlags; 119 menudata->uEnumFlags = uEnumFlags; 120 menudata->lpfnCallback = lpfnCallback; 121 122 return menudata; 123 } 124 125 /************************************************************************* 126 * FM_InitMenuPopup [internal] 127 * 128 */ 129 static int FM_InitMenuPopup(HMENU hmenu, LPCITEMIDLIST pAlternatePidl) 130 { IShellFolder *lpsf, *lpsf2; 131 ULONG ulItemAttr = SFGAO_FOLDER; 132 UINT uID, uEnumFlags; 133 LPFNFMCALLBACK lpfnCallback; 134 LPCITEMIDLIST pidl; 135 WCHAR sTemp[MAX_PATH]; 136 int NumberOfItems = 0, iIcon; 137 MENUINFO MenuInfo; 138 LPFMINFO menudata; 139 140 TRACE("%p %p\n", hmenu, pAlternatePidl); 141 142 MenuInfo.cbSize = sizeof(MENUINFO); 143 MenuInfo.fMask = MIM_MENUDATA; 144 145 if (! GetMenuInfo(hmenu, &MenuInfo)) 146 return FALSE; 147 148 menudata = (LPFMINFO)MenuInfo.dwMenuData; 149 150 if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) 151 { 152 ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); 153 return 0; 154 } 155 156 if (menudata->bInitialized) 157 return 0; 158 159 pidl = (pAlternatePidl? pAlternatePidl: menudata->pidl); 160 if (!pidl) 161 return 0; 162 163 uID = menudata->uID; 164 uEnumFlags = menudata->uEnumFlags; 165 lpfnCallback = menudata->lpfnCallback; 166 menudata->bInitialized = FALSE; 167 168 SetMenuInfo(hmenu, &MenuInfo); 169 170 if (SUCCEEDED (SHGetDesktopFolder(&lpsf))) 171 { 172 if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,&IID_IShellFolder,(LPVOID *)&lpsf2))) 173 { 174 IEnumIDList *lpe = NULL; 175 176 if (SUCCEEDED (IShellFolder_EnumObjects(lpsf2, 0, uEnumFlags, &lpe ))) 177 { 178 179 LPITEMIDLIST pidlTemp = NULL; 180 ULONG ulFetched; 181 182 while ((!bAbortInit) && (S_OK == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched))) 183 { 184 if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, (LPCITEMIDLIST*)&pidlTemp, &ulItemAttr))) 185 { 186 ILGetDisplayNameExW(NULL, pidlTemp, sTemp, ILGDN_FORPARSING); 187 if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon))) 188 iIcon = FM_BLANK_ICON; 189 if ( SFGAO_FOLDER & ulItemAttr) 190 { 191 LPFMINFO lpFmMi; 192 MENUINFO MenuInfo; 193 HMENU hMenuPopup = CreatePopupMenu(); 194 195 lpFmMi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO)); 196 197 lpFmMi->pidl = ILCombine(pidl, pidlTemp); 198 lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS; 199 200 MenuInfo.cbSize = sizeof(MENUINFO); 201 MenuInfo.fMask = MIM_MENUDATA; 202 MenuInfo.dwMenuData = (ULONG_PTR) lpFmMi; 203 SetMenuInfo (hMenuPopup, &MenuInfo); 204 205 FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT); 206 } 207 else 208 { 209 LPWSTR pExt = PathFindExtensionW(sTemp); 210 if (pExt) 211 *pExt = 0; 212 FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT); 213 } 214 } 215 216 if (lpfnCallback) 217 { 218 TRACE("enter callback\n"); 219 lpfnCallback ( pidl, pidlTemp); 220 TRACE("leave callback\n"); 221 } 222 223 NumberOfItems++; 224 } 225 IEnumIDList_Release (lpe); 226 } 227 IShellFolder_Release(lpsf2); 228 } 229 IShellFolder_Release(lpsf); 230 } 231 232 if ( GetMenuItemCount (hmenu) == 0 ) 233 { 234 FileMenu_AppendItemW (hmenu, L"(empty)", uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT); 235 NumberOfItems++; 236 } 237 238 menudata->bInitialized = TRUE; 239 SetMenuInfo(hmenu, &MenuInfo); 240 241 return NumberOfItems; 242 } 243 /************************************************************************* 244 * FileMenu_Create [SHELL32.114] 245 * 246 * NOTES 247 * for non-root menus values are 248 * (ffffffff,00000000,00000000,00000000,00000000) 249 */ 250 HMENU WINAPI FileMenu_Create ( 251 COLORREF crBorderColor, 252 int nBorderWidth, 253 HBITMAP hBorderBmp, 254 int nSelHeight, 255 UINT uFlags) 256 { 257 MENUINFO MenuInfo; 258 LPFMINFO menudata; 259 260 HMENU hMenu = CreatePopupMenu(); 261 262 TRACE("0x%08x 0x%08x %p 0x%08x 0x%08x hMenu=%p\n", 263 crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu); 264 265 menudata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO)); 266 menudata->crBorderColor = crBorderColor; 267 menudata->nBorderWidth = nBorderWidth; 268 menudata->hBorderBmp = hBorderBmp; 269 270 MenuInfo.cbSize = sizeof(MENUINFO); 271 MenuInfo.fMask = MIM_MENUDATA; 272 MenuInfo.dwMenuData = (ULONG_PTR) menudata; 273 SetMenuInfo (hMenu, &MenuInfo); 274 275 return hMenu; 276 } 277 278 /************************************************************************* 279 * FileMenu_Destroy [SHELL32.118] 280 * 281 * NOTES 282 * exported by name 283 */ 284 void WINAPI FileMenu_Destroy (HMENU hmenu) 285 { 286 LPFMINFO menudata; 287 288 TRACE("%p\n", hmenu); 289 290 FileMenu_DeleteAllItems (hmenu); 291 292 menudata = FM_GetMenuInfo(hmenu); 293 294 SHFree( menudata->pidl); 295 HeapFree(GetProcessHeap(), 0, menudata); 296 297 DestroyMenu (hmenu); 298 } 299 300 /************************************************************************* 301 * FileMenu_AppendItem [SHELL32.115] 302 * 303 */ 304 static BOOL FileMenu_AppendItemW( 305 HMENU hMenu, 306 LPCWSTR lpText, 307 UINT uID, 308 int icon, 309 HMENU hMenuPopup, 310 int nItemHeight) 311 { 312 MENUITEMINFOW mii; 313 LPFMITEM myItem; 314 LPFMINFO menudata; 315 MENUINFO MenuInfo; 316 317 318 TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n", 319 hMenu, (lpText!=FM_SEPARATOR) ? debugstr_w(lpText) : NULL, 320 uID, icon, hMenuPopup, nItemHeight); 321 322 ZeroMemory (&mii, sizeof(MENUITEMINFOW)); 323 324 mii.cbSize = sizeof(MENUITEMINFOW); 325 326 if (lpText != FM_SEPARATOR) 327 { 328 int len = strlenW (lpText); 329 myItem = SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR)); 330 strcpyW (myItem->szItemText, lpText); 331 myItem->cchItemText = len; 332 myItem->iIconIndex = icon; 333 myItem->hMenu = hMenu; 334 mii.fMask = MIIM_DATA; 335 mii.dwItemData = (ULONG_PTR) myItem; 336 } 337 338 if ( hMenuPopup ) 339 { /* sub menu */ 340 mii.fMask |= MIIM_TYPE | MIIM_SUBMENU; 341 mii.fType = MFT_OWNERDRAW; 342 mii.hSubMenu = hMenuPopup; 343 } 344 else if (lpText == FM_SEPARATOR ) 345 { mii.fMask |= MIIM_ID | MIIM_TYPE; 346 mii.fType = MFT_SEPARATOR; 347 } 348 else 349 { /* normal item */ 350 mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE; 351 mii.fState = MFS_ENABLED | MFS_DEFAULT; 352 mii.fType = MFT_OWNERDRAW; 353 } 354 mii.wID = uID; 355 356 InsertMenuItemW (hMenu, (UINT)-1, TRUE, &mii); 357 358 /* set bFixedItems to true */ 359 MenuInfo.cbSize = sizeof(MENUINFO); 360 MenuInfo.fMask = MIM_MENUDATA; 361 362 if (! GetMenuInfo(hMenu, &MenuInfo)) 363 return FALSE; 364 365 menudata = (LPFMINFO)MenuInfo.dwMenuData; 366 if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) 367 { 368 ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); 369 return FALSE; 370 } 371 372 menudata->bFixedItems = TRUE; 373 SetMenuInfo(hMenu, &MenuInfo); 374 375 return TRUE; 376 377 } 378 379 /**********************************************************************/ 380 381 BOOL WINAPI FileMenu_AppendItemAW( 382 HMENU hMenu, 383 LPCVOID lpText, 384 UINT uID, 385 int icon, 386 HMENU hMenuPopup, 387 int nItemHeight) 388 { 389 BOOL ret; 390 391 if (!lpText) return FALSE; 392 393 if (SHELL_OsIsUnicode() || lpText == FM_SEPARATOR) 394 ret = FileMenu_AppendItemW(hMenu, lpText, uID, icon, hMenuPopup, nItemHeight); 395 else 396 { 397 DWORD len = MultiByteToWideChar( CP_ACP, 0, lpText, -1, NULL, 0 ); 398 LPWSTR lpszText = HeapAlloc ( GetProcessHeap(), 0, len*sizeof(WCHAR) ); 399 if (!lpszText) return FALSE; 400 MultiByteToWideChar( CP_ACP, 0, lpText, -1, lpszText, len ); 401 ret = FileMenu_AppendItemW(hMenu, lpszText, uID, icon, hMenuPopup, nItemHeight); 402 HeapFree( GetProcessHeap(), 0, lpszText ); 403 } 404 405 return ret; 406 } 407 408 /************************************************************************* 409 * FileMenu_InsertUsingPidl [SHELL32.110] 410 * 411 * NOTES 412 * uEnumFlags any SHCONTF flag 413 */ 414 int WINAPI FileMenu_InsertUsingPidl ( 415 HMENU hmenu, 416 UINT uID, 417 LPCITEMIDLIST pidl, 418 UINT uFlags, 419 UINT uEnumFlags, 420 LPFNFMCALLBACK lpfnCallback) 421 { 422 TRACE("%p 0x%08x %p 0x%08x 0x%08x %p\n", 423 hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 424 425 pdump (pidl); 426 427 bAbortInit = FALSE; 428 429 FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 430 431 return FM_InitMenuPopup(hmenu, NULL); 432 } 433 434 /************************************************************************* 435 * FileMenu_ReplaceUsingPidl [SHELL32.113] 436 * 437 * FIXME: the static items are deleted but won't be refreshed 438 */ 439 int WINAPI FileMenu_ReplaceUsingPidl( 440 HMENU hmenu, 441 UINT uID, 442 LPCITEMIDLIST pidl, 443 UINT uEnumFlags, 444 LPFNFMCALLBACK lpfnCallback) 445 { 446 TRACE("%p 0x%08x %p 0x%08x %p\n", 447 hmenu, uID, pidl, uEnumFlags, lpfnCallback); 448 449 FileMenu_DeleteAllItems (hmenu); 450 451 FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback); 452 453 return FM_InitMenuPopup(hmenu, NULL); 454 } 455 456 /************************************************************************* 457 * FileMenu_Invalidate [SHELL32.111] 458 */ 459 void WINAPI FileMenu_Invalidate (HMENU hMenu) 460 { 461 FIXME("%p\n",hMenu); 462 } 463 464 /************************************************************************* 465 * FileMenu_FindSubMenuByPidl [SHELL32.106] 466 */ 467 HMENU WINAPI FileMenu_FindSubMenuByPidl( 468 HMENU hMenu, 469 LPCITEMIDLIST pidl) 470 { 471 FIXME("%p %p\n",hMenu, pidl); 472 return 0; 473 } 474 475 /************************************************************************* 476 * FileMenu_AppendFilesForPidl [SHELL32.124] 477 */ 478 int WINAPI FileMenu_AppendFilesForPidl( 479 HMENU hmenu, 480 LPCITEMIDLIST pidl, 481 BOOL bAddSeparator) 482 { 483 LPFMINFO menudata; 484 485 menudata = FM_GetMenuInfo(hmenu); 486 487 menudata->bInitialized = FALSE; 488 489 FM_InitMenuPopup(hmenu, pidl); 490 491 if (bAddSeparator) 492 FileMenu_AppendItemW (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT); 493 494 TRACE("%p %p 0x%08x\n",hmenu, pidl,bAddSeparator); 495 496 return 0; 497 } 498 /************************************************************************* 499 * FileMenu_AddFilesForPidl [SHELL32.125] 500 * 501 * NOTES 502 * uEnumFlags any SHCONTF flag 503 */ 504 int WINAPI FileMenu_AddFilesForPidl ( 505 HMENU hmenu, 506 UINT uReserved, 507 UINT uID, 508 LPCITEMIDLIST pidl, 509 UINT uFlags, 510 UINT uEnumFlags, 511 LPFNFMCALLBACK lpfnCallback) 512 { 513 TRACE("%p 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n", 514 hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 515 516 return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 517 518 } 519 520 521 /************************************************************************* 522 * FileMenu_TrackPopupMenuEx [SHELL32.116] 523 */ 524 BOOL WINAPI FileMenu_TrackPopupMenuEx ( 525 HMENU hMenu, 526 UINT uFlags, 527 int x, 528 int y, 529 HWND hWnd, 530 LPTPMPARAMS lptpm) 531 { 532 TRACE("%p 0x%08x 0x%x 0x%x %p %p\n", 533 hMenu, uFlags, x, y, hWnd, lptpm); 534 return TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm); 535 } 536 537 /************************************************************************* 538 * FileMenu_GetLastSelectedItemPidls [SHELL32.107] 539 */ 540 BOOL WINAPI FileMenu_GetLastSelectedItemPidls( 541 UINT uReserved, 542 LPCITEMIDLIST *ppidlFolder, 543 LPCITEMIDLIST *ppidlItem) 544 { 545 FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem); 546 return FALSE; 547 } 548 549 #define FM_ICON_SIZE 16 550 #define FM_Y_SPACE 4 551 #define FM_SPACE1 4 552 #define FM_SPACE2 2 553 #define FM_LEFTBORDER 2 554 #define FM_RIGHTBORDER 8 555 /************************************************************************* 556 * FileMenu_MeasureItem [SHELL32.112] 557 */ 558 LRESULT WINAPI FileMenu_MeasureItem( 559 HWND hWnd, 560 LPMEASUREITEMSTRUCT lpmis) 561 { 562 LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData); 563 HDC hdc = GetDC(hWnd); 564 SIZE size; 565 LPFMINFO menuinfo; 566 567 TRACE("%p %p %s\n", hWnd, lpmis, debugstr_w(pMyItem->szItemText)); 568 569 GetTextExtentPoint32W(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size); 570 571 lpmis->itemWidth = size.cx + FM_LEFTBORDER + FM_ICON_SIZE + FM_SPACE1 + FM_SPACE2 + FM_RIGHTBORDER; 572 lpmis->itemHeight = (size.cy > (FM_ICON_SIZE + FM_Y_SPACE)) ? size.cy : (FM_ICON_SIZE + FM_Y_SPACE); 573 574 /* add the menubitmap */ 575 menuinfo = FM_GetMenuInfo(pMyItem->hMenu); 576 if (menuinfo->nBorderWidth) 577 lpmis->itemWidth += menuinfo->nBorderWidth; 578 579 TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight); 580 ReleaseDC (hWnd, hdc); 581 return 0; 582 } 583 /************************************************************************* 584 * FileMenu_DrawItem [SHELL32.105] 585 */ 586 LRESULT WINAPI FileMenu_DrawItem( 587 HWND hWnd, 588 LPDRAWITEMSTRUCT lpdis) 589 { 590 LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData); 591 COLORREF clrPrevText, clrPrevBkgnd; 592 int xi,yi,xt,yt; 593 HIMAGELIST hImageList; 594 RECT TextRect; 595 LPFMINFO menuinfo; 596 597 TRACE("%p %p %s\n", hWnd, lpdis, debugstr_w(pMyItem->szItemText)); 598 599 if (lpdis->itemState & ODS_SELECTED) 600 { 601 clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)); 602 clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHT)); 603 } 604 else 605 { 606 clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_MENUTEXT)); 607 clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_MENU)); 608 } 609 610 TextRect = lpdis->rcItem; 611 612 /* add the menubitmap */ 613 menuinfo = FM_GetMenuInfo(pMyItem->hMenu); 614 if (menuinfo->nBorderWidth) 615 TextRect.left += menuinfo->nBorderWidth; 616 617 TextRect.left += FM_LEFTBORDER; 618 xi = TextRect.left + FM_SPACE1; 619 yi = TextRect.top + FM_Y_SPACE/2; 620 TextRect.bottom -= FM_Y_SPACE/2; 621 622 xt = xi + FM_ICON_SIZE + FM_SPACE2; 623 yt = yi; 624 625 ExtTextOutW (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL); 626 627 Shell_GetImageLists(0, &hImageList); 628 ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL); 629 630 TRACE("-- %s\n", wine_dbgstr_rect(&TextRect)); 631 632 SetTextColor(lpdis->hDC, clrPrevText); 633 SetBkColor(lpdis->hDC, clrPrevBkgnd); 634 635 return TRUE; 636 } 637 638 /************************************************************************* 639 * FileMenu_InitMenuPopup [SHELL32.109] 640 * 641 * NOTES 642 * The filemenu is an ownerdrawn menu. Call this function responding to 643 * WM_INITPOPUPMENU 644 * 645 */ 646 BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu) 647 { 648 FM_InitMenuPopup(hmenu, NULL); 649 return TRUE; 650 } 651 652 /************************************************************************* 653 * FileMenu_HandleMenuChar [SHELL32.108] 654 */ 655 LRESULT WINAPI FileMenu_HandleMenuChar( 656 HMENU hMenu, 657 WPARAM wParam) 658 { 659 FIXME("%p 0x%08lx\n",hMenu,wParam); 660 return 0; 661 } 662 663 /************************************************************************* 664 * FileMenu_DeleteAllItems [SHELL32.104] 665 * 666 * NOTES 667 * exported by name 668 */ 669 BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu) 670 { 671 MENUITEMINFOW mii; 672 LPFMINFO menudata; 673 674 int i; 675 676 TRACE("%p\n", hmenu); 677 678 ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); 679 mii.cbSize = sizeof(MENUITEMINFOW); 680 mii.fMask = MIIM_SUBMENU|MIIM_DATA; 681 682 for (i = 0; i < GetMenuItemCount( hmenu ); i++) 683 { GetMenuItemInfoW(hmenu, i, TRUE, &mii ); 684 685 SHFree((LPFMINFO)mii.dwItemData); 686 687 if (mii.hSubMenu) 688 FileMenu_Destroy(mii.hSubMenu); 689 } 690 691 while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){}; 692 693 menudata = FM_GetMenuInfo(hmenu); 694 695 menudata->bInitialized = FALSE; 696 697 return TRUE; 698 } 699 700 /************************************************************************* 701 * FileMenu_DeleteItemByCmd [SHELL32.117] 702 * 703 */ 704 BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID) 705 { 706 MENUITEMINFOW mii; 707 708 TRACE("%p 0x%08x\n", hMenu, uID); 709 710 ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); 711 mii.cbSize = sizeof(MENUITEMINFOW); 712 mii.fMask = MIIM_SUBMENU; 713 714 GetMenuItemInfoW(hMenu, uID, FALSE, &mii ); 715 if ( mii.hSubMenu ) 716 { 717 /* FIXME: Do what? */ 718 } 719 720 DeleteMenu(hMenu, MF_BYCOMMAND, uID); 721 return TRUE; 722 } 723 724 /************************************************************************* 725 * FileMenu_DeleteItemByIndex [SHELL32.140] 726 */ 727 BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos) 728 { 729 MENUITEMINFOW mii; 730 731 TRACE("%p 0x%08x\n", hMenu, uPos); 732 733 ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); 734 mii.cbSize = sizeof(MENUITEMINFOW); 735 mii.fMask = MIIM_SUBMENU; 736 737 GetMenuItemInfoW(hMenu, uPos, TRUE, &mii ); 738 if ( mii.hSubMenu ) 739 { 740 /* FIXME: Do what? */ 741 } 742 743 DeleteMenu(hMenu, MF_BYPOSITION, uPos); 744 return TRUE; 745 } 746 747 /************************************************************************* 748 * FileMenu_DeleteItemByFirstID [SHELL32.141] 749 */ 750 BOOL WINAPI FileMenu_DeleteItemByFirstID( 751 HMENU hMenu, 752 UINT uID) 753 { 754 TRACE("%p 0x%08x\n", hMenu, uID); 755 return FALSE; 756 } 757 758 /************************************************************************* 759 * FileMenu_DeleteSeparator [SHELL32.142] 760 */ 761 BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu) 762 { 763 TRACE("%p\n", hMenu); 764 return FALSE; 765 } 766 767 /************************************************************************* 768 * FileMenu_EnableItemByCmd [SHELL32.143] 769 */ 770 BOOL WINAPI FileMenu_EnableItemByCmd( 771 HMENU hMenu, 772 UINT uID, 773 BOOL bEnable) 774 { 775 TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable); 776 return FALSE; 777 } 778 779 /************************************************************************* 780 * FileMenu_GetItemExtent [SHELL32.144] 781 * 782 * NOTES 783 * if the menu is too big, entries are getting cut away!! 784 */ 785 DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos) 786 { RECT rect; 787 788 FIXME("%p 0x%08x\n", hMenu, uPos); 789 790 if (GetMenuItemRect(0, hMenu, uPos, &rect)) 791 { 792 FIXME("%s\n", wine_dbgstr_rect(&rect)); 793 return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom); 794 } 795 return 0x00100010; /*FIXME*/ 796 } 797 798 /************************************************************************* 799 * FileMenu_AbortInitMenu [SHELL32.120] 800 * 801 */ 802 void WINAPI FileMenu_AbortInitMenu (void) 803 { TRACE("\n"); 804 bAbortInit = TRUE; 805 } 806 807 /************************************************************************* 808 * SHFind_InitMenuPopup [SHELL32.149] 809 * 810 * Get the IContextMenu instance for the submenu of options displayed 811 * for the Search entry in the Classic style Start menu. 812 * 813 * PARAMETERS 814 * hMenu [in] handle of menu previously created 815 * hWndParent [in] parent window 816 * w [in] no pointer (0x209 over here) perhaps menu IDs ??? 817 * x [in] no pointer (0x226 over here) 818 * 819 * RETURNS 820 * LPXXXXX pointer to struct containing a func addr at offset 8 821 * or NULL at failure. 822 */ 823 IContextMenu * WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, UINT w, UINT x) 824 { 825 FIXME("hmenu=%p hwnd=%p 0x%08x 0x%08x stub\n", 826 hMenu,hWndParent,w,x); 827 return NULL; /* this is supposed to be a pointer */ 828 } 829 830 /************************************************************************* 831 * _SHIsMenuSeparator (internal) 832 */ 833 static BOOL _SHIsMenuSeparator(HMENU hm, int i) 834 { 835 MENUITEMINFOW mii; 836 837 mii.cbSize = sizeof(MENUITEMINFOW); 838 mii.fMask = MIIM_TYPE; 839 mii.cch = 0; /* WARNING: We MUST initialize it to 0*/ 840 if (!GetMenuItemInfoW(hm, i, TRUE, &mii)) 841 { 842 return(FALSE); 843 } 844 845 if (mii.fType & MFT_SEPARATOR) 846 { 847 return(TRUE); 848 } 849 850 return(FALSE); 851 } 852 853 /************************************************************************* 854 * Shell_MergeMenus [SHELL32.67] 855 */ 856 UINT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags) 857 { int nItem; 858 HMENU hmSubMenu; 859 BOOL bAlreadySeparated; 860 MENUITEMINFOW miiSrc; 861 WCHAR szName[256]; 862 UINT uTemp, uIDMax = uIDAdjust; 863 864 TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x 0x%04x\n", 865 hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags); 866 867 if (!hmDst || !hmSrc) 868 return uIDMax; 869 870 nItem = GetMenuItemCount(hmDst); 871 if (nItem == -1) 872 return uIDMax; 873 874 if (uInsert >= (UINT)nItem) /* insert position inside menu? */ 875 { 876 uInsert = (UINT)nItem; /* append on the end */ 877 bAlreadySeparated = TRUE; 878 } 879 else 880 { 881 bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert); 882 } 883 884 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) 885 { 886 /* Add a separator between the menus */ 887 InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 888 bAlreadySeparated = TRUE; 889 } 890 891 892 /* Go through the menu items and clone them*/ 893 for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--) 894 { 895 miiSrc.cbSize = sizeof(MENUITEMINFOW); 896 miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA; 897 898 /* We need to reset this every time through the loop in case menus DON'T have IDs*/ 899 miiSrc.fType = MFT_STRING; 900 miiSrc.dwTypeData = szName; 901 miiSrc.dwItemData = 0; 902 miiSrc.cch = sizeof(szName)/sizeof(WCHAR); 903 904 if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc)) 905 { 906 continue; 907 } 908 909 /* TRACE("found menu=0x%04x %s id=0x%04x mask=0x%08x smenu=0x%04x\n", hmSrc, debugstr_a(miiSrc.dwTypeData), miiSrc.wID, miiSrc.fMask, miiSrc.hSubMenu); 910 */ 911 if (miiSrc.fType & MFT_SEPARATOR) 912 { 913 /* This is a separator; don't put two of them in a row */ 914 if (bAlreadySeparated) 915 continue; 916 917 bAlreadySeparated = TRUE; 918 } 919 else if (miiSrc.hSubMenu) 920 { 921 if (uFlags & MM_SUBMENUSHAVEIDS) 922 { 923 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */ 924 925 if (miiSrc.wID > uIDAdjustMax) /* skip IDs higher than uIDAdjustMax */ 926 continue; 927 928 if (uIDMax <= miiSrc.wID) /* remember the highest ID */ 929 uIDMax = miiSrc.wID + 1; 930 } 931 else 932 { 933 miiSrc.fMask &= ~MIIM_ID; /* Don't set IDs for submenus that didn't have them already */ 934 } 935 hmSubMenu = miiSrc.hSubMenu; 936 937 miiSrc.hSubMenu = CreatePopupMenu(); 938 939 if (!miiSrc.hSubMenu) return(uIDMax); 940 941 uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS); 942 943 if (uIDMax <= uTemp) 944 uIDMax = uTemp; 945 946 bAlreadySeparated = FALSE; 947 } 948 else /* normal menu item */ 949 { 950 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */ 951 952 if (miiSrc.wID > uIDAdjustMax) /* skip IDs higher than uIDAdjustMax */ 953 continue; 954 955 if (uIDMax <= miiSrc.wID) /* remember the highest ID */ 956 uIDMax = miiSrc.wID + 1; 957 958 bAlreadySeparated = FALSE; 959 } 960 961 /* TRACE("inserting menu=0x%04x %s id=0x%04x mask=0x%08x smenu=0x%04x\n", hmDst, debugstr_a(miiSrc.dwTypeData), miiSrc.wID, miiSrc.fMask, miiSrc.hSubMenu); 962 */ 963 if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc)) 964 { 965 return(uIDMax); 966 } 967 } 968 969 /* Ensure the correct number of separators at the beginning of the 970 inserted menu items*/ 971 if (uInsert == 0) 972 { 973 if (bAlreadySeparated) 974 { 975 DeleteMenu(hmDst, uInsert, MF_BYPOSITION); 976 } 977 } 978 else 979 { 980 if (_SHIsMenuSeparator(hmDst, uInsert-1)) 981 { 982 if (bAlreadySeparated) 983 { 984 DeleteMenu(hmDst, uInsert, MF_BYPOSITION); 985 } 986 } 987 else 988 { 989 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) 990 { 991 /* Add a separator between the menus*/ 992 InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 993 } 994 } 995 } 996 return(uIDMax); 997 } 998