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 static const WCHAR szEmpty[] = { '(','e','m','p','t','y',')',0 }; 235 FileMenu_AppendItemW (hmenu, szEmpty, uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT); 236 NumberOfItems++; 237 } 238 239 menudata->bInitialized = TRUE; 240 SetMenuInfo(hmenu, &MenuInfo); 241 242 return NumberOfItems; 243 } 244 /************************************************************************* 245 * FileMenu_Create [SHELL32.114] 246 * 247 * NOTES 248 * for non-root menus values are 249 * (ffffffff,00000000,00000000,00000000,00000000) 250 */ 251 HMENU WINAPI FileMenu_Create ( 252 COLORREF crBorderColor, 253 int nBorderWidth, 254 HBITMAP hBorderBmp, 255 int nSelHeight, 256 UINT uFlags) 257 { 258 MENUINFO MenuInfo; 259 LPFMINFO menudata; 260 261 HMENU hMenu = CreatePopupMenu(); 262 263 TRACE("0x%08x 0x%08x %p 0x%08x 0x%08x hMenu=%p\n", 264 crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu); 265 266 menudata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO)); 267 menudata->crBorderColor = crBorderColor; 268 menudata->nBorderWidth = nBorderWidth; 269 menudata->hBorderBmp = hBorderBmp; 270 271 MenuInfo.cbSize = sizeof(MENUINFO); 272 MenuInfo.fMask = MIM_MENUDATA; 273 MenuInfo.dwMenuData = (ULONG_PTR) menudata; 274 SetMenuInfo (hMenu, &MenuInfo); 275 276 return hMenu; 277 } 278 279 /************************************************************************* 280 * FileMenu_Destroy [SHELL32.118] 281 * 282 * NOTES 283 * exported by name 284 */ 285 void WINAPI FileMenu_Destroy (HMENU hmenu) 286 { 287 LPFMINFO menudata; 288 289 TRACE("%p\n", hmenu); 290 291 FileMenu_DeleteAllItems (hmenu); 292 293 menudata = FM_GetMenuInfo(hmenu); 294 295 SHFree( menudata->pidl); 296 HeapFree(GetProcessHeap(), 0, menudata); 297 298 DestroyMenu (hmenu); 299 } 300 301 /************************************************************************* 302 * FileMenu_AppendItem [SHELL32.115] 303 * 304 */ 305 static BOOL FileMenu_AppendItemW( 306 HMENU hMenu, 307 LPCWSTR lpText, 308 UINT uID, 309 int icon, 310 HMENU hMenuPopup, 311 int nItemHeight) 312 { 313 MENUITEMINFOW mii; 314 LPFMITEM myItem; 315 LPFMINFO menudata; 316 MENUINFO MenuInfo; 317 318 319 TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n", 320 hMenu, (lpText!=FM_SEPARATOR) ? debugstr_w(lpText) : NULL, 321 uID, icon, hMenuPopup, nItemHeight); 322 323 ZeroMemory (&mii, sizeof(MENUITEMINFOW)); 324 325 mii.cbSize = sizeof(MENUITEMINFOW); 326 327 if (lpText != FM_SEPARATOR) 328 { 329 int len = strlenW (lpText); 330 myItem = SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR)); 331 strcpyW (myItem->szItemText, lpText); 332 myItem->cchItemText = len; 333 myItem->iIconIndex = icon; 334 myItem->hMenu = hMenu; 335 mii.fMask = MIIM_DATA; 336 mii.dwItemData = (ULONG_PTR) myItem; 337 } 338 339 if ( hMenuPopup ) 340 { /* sub menu */ 341 mii.fMask |= MIIM_TYPE | MIIM_SUBMENU; 342 mii.fType = MFT_OWNERDRAW; 343 mii.hSubMenu = hMenuPopup; 344 } 345 else if (lpText == FM_SEPARATOR ) 346 { mii.fMask |= MIIM_ID | MIIM_TYPE; 347 mii.fType = MFT_SEPARATOR; 348 } 349 else 350 { /* normal item */ 351 mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE; 352 mii.fState = MFS_ENABLED | MFS_DEFAULT; 353 mii.fType = MFT_OWNERDRAW; 354 } 355 mii.wID = uID; 356 357 InsertMenuItemW (hMenu, (UINT)-1, TRUE, &mii); 358 359 /* set bFixedItems to true */ 360 MenuInfo.cbSize = sizeof(MENUINFO); 361 MenuInfo.fMask = MIM_MENUDATA; 362 363 if (! GetMenuInfo(hMenu, &MenuInfo)) 364 return FALSE; 365 366 menudata = (LPFMINFO)MenuInfo.dwMenuData; 367 if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO))) 368 { 369 ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize); 370 return FALSE; 371 } 372 373 menudata->bFixedItems = TRUE; 374 SetMenuInfo(hMenu, &MenuInfo); 375 376 return TRUE; 377 378 } 379 380 /**********************************************************************/ 381 382 BOOL WINAPI FileMenu_AppendItemAW( 383 HMENU hMenu, 384 LPCVOID lpText, 385 UINT uID, 386 int icon, 387 HMENU hMenuPopup, 388 int nItemHeight) 389 { 390 BOOL ret; 391 392 if (!lpText) return FALSE; 393 394 if (SHELL_OsIsUnicode() || lpText == FM_SEPARATOR) 395 ret = FileMenu_AppendItemW(hMenu, lpText, uID, icon, hMenuPopup, nItemHeight); 396 else 397 { 398 DWORD len = MultiByteToWideChar( CP_ACP, 0, lpText, -1, NULL, 0 ); 399 LPWSTR lpszText = HeapAlloc ( GetProcessHeap(), 0, len*sizeof(WCHAR) ); 400 if (!lpszText) return FALSE; 401 MultiByteToWideChar( CP_ACP, 0, lpText, -1, lpszText, len ); 402 ret = FileMenu_AppendItemW(hMenu, lpszText, uID, icon, hMenuPopup, nItemHeight); 403 HeapFree( GetProcessHeap(), 0, lpszText ); 404 } 405 406 return ret; 407 } 408 409 /************************************************************************* 410 * FileMenu_InsertUsingPidl [SHELL32.110] 411 * 412 * NOTES 413 * uEnumFlags any SHCONTF flag 414 */ 415 int WINAPI FileMenu_InsertUsingPidl ( 416 HMENU hmenu, 417 UINT uID, 418 LPCITEMIDLIST pidl, 419 UINT uFlags, 420 UINT uEnumFlags, 421 LPFNFMCALLBACK lpfnCallback) 422 { 423 TRACE("%p 0x%08x %p 0x%08x 0x%08x %p\n", 424 hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 425 426 pdump (pidl); 427 428 bAbortInit = FALSE; 429 430 FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 431 432 return FM_InitMenuPopup(hmenu, NULL); 433 } 434 435 /************************************************************************* 436 * FileMenu_ReplaceUsingPidl [SHELL32.113] 437 * 438 * FIXME: the static items are deleted but won't be refreshed 439 */ 440 int WINAPI FileMenu_ReplaceUsingPidl( 441 HMENU hmenu, 442 UINT uID, 443 LPCITEMIDLIST pidl, 444 UINT uEnumFlags, 445 LPFNFMCALLBACK lpfnCallback) 446 { 447 TRACE("%p 0x%08x %p 0x%08x %p\n", 448 hmenu, uID, pidl, uEnumFlags, lpfnCallback); 449 450 FileMenu_DeleteAllItems (hmenu); 451 452 FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback); 453 454 return FM_InitMenuPopup(hmenu, NULL); 455 } 456 457 /************************************************************************* 458 * FileMenu_Invalidate [SHELL32.111] 459 */ 460 void WINAPI FileMenu_Invalidate (HMENU hMenu) 461 { 462 FIXME("%p\n",hMenu); 463 } 464 465 /************************************************************************* 466 * FileMenu_FindSubMenuByPidl [SHELL32.106] 467 */ 468 HMENU WINAPI FileMenu_FindSubMenuByPidl( 469 HMENU hMenu, 470 LPCITEMIDLIST pidl) 471 { 472 FIXME("%p %p\n",hMenu, pidl); 473 return 0; 474 } 475 476 /************************************************************************* 477 * FileMenu_AppendFilesForPidl [SHELL32.124] 478 */ 479 int WINAPI FileMenu_AppendFilesForPidl( 480 HMENU hmenu, 481 LPCITEMIDLIST pidl, 482 BOOL bAddSeparator) 483 { 484 LPFMINFO menudata; 485 486 menudata = FM_GetMenuInfo(hmenu); 487 488 menudata->bInitialized = FALSE; 489 490 FM_InitMenuPopup(hmenu, pidl); 491 492 if (bAddSeparator) 493 FileMenu_AppendItemW (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT); 494 495 TRACE("%p %p 0x%08x\n",hmenu, pidl,bAddSeparator); 496 497 return 0; 498 } 499 /************************************************************************* 500 * FileMenu_AddFilesForPidl [SHELL32.125] 501 * 502 * NOTES 503 * uEnumFlags any SHCONTF flag 504 */ 505 int WINAPI FileMenu_AddFilesForPidl ( 506 HMENU hmenu, 507 UINT uReserved, 508 UINT uID, 509 LPCITEMIDLIST pidl, 510 UINT uFlags, 511 UINT uEnumFlags, 512 LPFNFMCALLBACK lpfnCallback) 513 { 514 TRACE("%p 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n", 515 hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 516 517 return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback); 518 519 } 520 521 522 /************************************************************************* 523 * FileMenu_TrackPopupMenuEx [SHELL32.116] 524 */ 525 BOOL WINAPI FileMenu_TrackPopupMenuEx ( 526 HMENU hMenu, 527 UINT uFlags, 528 int x, 529 int y, 530 HWND hWnd, 531 LPTPMPARAMS lptpm) 532 { 533 TRACE("%p 0x%08x 0x%x 0x%x %p %p\n", 534 hMenu, uFlags, x, y, hWnd, lptpm); 535 return TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm); 536 } 537 538 /************************************************************************* 539 * FileMenu_GetLastSelectedItemPidls [SHELL32.107] 540 */ 541 BOOL WINAPI FileMenu_GetLastSelectedItemPidls( 542 UINT uReserved, 543 LPCITEMIDLIST *ppidlFolder, 544 LPCITEMIDLIST *ppidlItem) 545 { 546 FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem); 547 return FALSE; 548 } 549 550 #define FM_ICON_SIZE 16 551 #define FM_Y_SPACE 4 552 #define FM_SPACE1 4 553 #define FM_SPACE2 2 554 #define FM_LEFTBORDER 2 555 #define FM_RIGHTBORDER 8 556 /************************************************************************* 557 * FileMenu_MeasureItem [SHELL32.112] 558 */ 559 LRESULT WINAPI FileMenu_MeasureItem( 560 HWND hWnd, 561 LPMEASUREITEMSTRUCT lpmis) 562 { 563 LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData); 564 HDC hdc = GetDC(hWnd); 565 SIZE size; 566 LPFMINFO menuinfo; 567 568 TRACE("%p %p %s\n", hWnd, lpmis, debugstr_w(pMyItem->szItemText)); 569 570 GetTextExtentPoint32W(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size); 571 572 lpmis->itemWidth = size.cx + FM_LEFTBORDER + FM_ICON_SIZE + FM_SPACE1 + FM_SPACE2 + FM_RIGHTBORDER; 573 lpmis->itemHeight = (size.cy > (FM_ICON_SIZE + FM_Y_SPACE)) ? size.cy : (FM_ICON_SIZE + FM_Y_SPACE); 574 575 /* add the menubitmap */ 576 menuinfo = FM_GetMenuInfo(pMyItem->hMenu); 577 if (menuinfo->nBorderWidth) 578 lpmis->itemWidth += menuinfo->nBorderWidth; 579 580 TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight); 581 ReleaseDC (hWnd, hdc); 582 return 0; 583 } 584 /************************************************************************* 585 * FileMenu_DrawItem [SHELL32.105] 586 */ 587 LRESULT WINAPI FileMenu_DrawItem( 588 HWND hWnd, 589 LPDRAWITEMSTRUCT lpdis) 590 { 591 LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData); 592 COLORREF clrPrevText, clrPrevBkgnd; 593 int xi,yi,xt,yt; 594 HIMAGELIST hImageList; 595 RECT TextRect; 596 LPFMINFO menuinfo; 597 598 TRACE("%p %p %s\n", hWnd, lpdis, debugstr_w(pMyItem->szItemText)); 599 600 if (lpdis->itemState & ODS_SELECTED) 601 { 602 clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT)); 603 clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHT)); 604 } 605 else 606 { 607 clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_MENUTEXT)); 608 clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_MENU)); 609 } 610 611 CopyRect(&TextRect, &(lpdis->rcItem)); 612 613 /* add the menubitmap */ 614 menuinfo = FM_GetMenuInfo(pMyItem->hMenu); 615 if (menuinfo->nBorderWidth) 616 TextRect.left += menuinfo->nBorderWidth; 617 618 TextRect.left += FM_LEFTBORDER; 619 xi = TextRect.left + FM_SPACE1; 620 yi = TextRect.top + FM_Y_SPACE/2; 621 TextRect.bottom -= FM_Y_SPACE/2; 622 623 xt = xi + FM_ICON_SIZE + FM_SPACE2; 624 yt = yi; 625 626 ExtTextOutW (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL); 627 628 Shell_GetImageLists(0, &hImageList); 629 ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL); 630 631 TRACE("-- 0x%04x 0x%04x 0x%04x 0x%04x\n", TextRect.left, TextRect.top, TextRect.right, TextRect.bottom); 632 633 SetTextColor(lpdis->hDC, clrPrevText); 634 SetBkColor(lpdis->hDC, clrPrevBkgnd); 635 636 return TRUE; 637 } 638 639 /************************************************************************* 640 * FileMenu_InitMenuPopup [SHELL32.109] 641 * 642 * NOTES 643 * The filemenu is an ownerdrawn menu. Call this function responding to 644 * WM_INITPOPUPMENU 645 * 646 */ 647 BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu) 648 { 649 FM_InitMenuPopup(hmenu, NULL); 650 return TRUE; 651 } 652 653 /************************************************************************* 654 * FileMenu_HandleMenuChar [SHELL32.108] 655 */ 656 LRESULT WINAPI FileMenu_HandleMenuChar( 657 HMENU hMenu, 658 WPARAM wParam) 659 { 660 FIXME("%p 0x%08lx\n",hMenu,wParam); 661 return 0; 662 } 663 664 /************************************************************************* 665 * FileMenu_DeleteAllItems [SHELL32.104] 666 * 667 * NOTES 668 * exported by name 669 */ 670 BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu) 671 { 672 MENUITEMINFOW mii; 673 LPFMINFO menudata; 674 675 int i; 676 677 TRACE("%p\n", hmenu); 678 679 ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); 680 mii.cbSize = sizeof(MENUITEMINFOW); 681 mii.fMask = MIIM_SUBMENU|MIIM_DATA; 682 683 for (i = 0; i < GetMenuItemCount( hmenu ); i++) 684 { GetMenuItemInfoW(hmenu, i, TRUE, &mii ); 685 686 SHFree((LPFMINFO)mii.dwItemData); 687 688 if (mii.hSubMenu) 689 FileMenu_Destroy(mii.hSubMenu); 690 } 691 692 while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){}; 693 694 menudata = FM_GetMenuInfo(hmenu); 695 696 menudata->bInitialized = FALSE; 697 698 return TRUE; 699 } 700 701 /************************************************************************* 702 * FileMenu_DeleteItemByCmd [SHELL32.117] 703 * 704 */ 705 BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID) 706 { 707 MENUITEMINFOW mii; 708 709 TRACE("%p 0x%08x\n", hMenu, uID); 710 711 ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); 712 mii.cbSize = sizeof(MENUITEMINFOW); 713 mii.fMask = MIIM_SUBMENU; 714 715 GetMenuItemInfoW(hMenu, uID, FALSE, &mii ); 716 if ( mii.hSubMenu ) 717 { 718 /* FIXME: Do what? */ 719 } 720 721 DeleteMenu(hMenu, MF_BYCOMMAND, uID); 722 return TRUE; 723 } 724 725 /************************************************************************* 726 * FileMenu_DeleteItemByIndex [SHELL32.140] 727 */ 728 BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos) 729 { 730 MENUITEMINFOW mii; 731 732 TRACE("%p 0x%08x\n", hMenu, uPos); 733 734 ZeroMemory ( &mii, sizeof(MENUITEMINFOW)); 735 mii.cbSize = sizeof(MENUITEMINFOW); 736 mii.fMask = MIIM_SUBMENU; 737 738 GetMenuItemInfoW(hMenu, uPos, TRUE, &mii ); 739 if ( mii.hSubMenu ) 740 { 741 /* FIXME: Do what? */ 742 } 743 744 DeleteMenu(hMenu, MF_BYPOSITION, uPos); 745 return TRUE; 746 } 747 748 /************************************************************************* 749 * FileMenu_DeleteItemByFirstID [SHELL32.141] 750 */ 751 BOOL WINAPI FileMenu_DeleteItemByFirstID( 752 HMENU hMenu, 753 UINT uID) 754 { 755 TRACE("%p 0x%08x\n", hMenu, uID); 756 return FALSE; 757 } 758 759 /************************************************************************* 760 * FileMenu_DeleteSeparator [SHELL32.142] 761 */ 762 BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu) 763 { 764 TRACE("%p\n", hMenu); 765 return FALSE; 766 } 767 768 /************************************************************************* 769 * FileMenu_EnableItemByCmd [SHELL32.143] 770 */ 771 BOOL WINAPI FileMenu_EnableItemByCmd( 772 HMENU hMenu, 773 UINT uID, 774 BOOL bEnable) 775 { 776 TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable); 777 return FALSE; 778 } 779 780 /************************************************************************* 781 * FileMenu_GetItemExtent [SHELL32.144] 782 * 783 * NOTES 784 * if the menu is too big, entries are getting cut away!! 785 */ 786 DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos) 787 { RECT rect; 788 789 FIXME("%p 0x%08x\n", hMenu, uPos); 790 791 if (GetMenuItemRect(0, hMenu, uPos, &rect)) 792 { FIXME("0x%04x 0x%04x 0x%04x 0x%04x\n", 793 rect.right, rect.left, rect.top, rect.bottom); 794 return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom); 795 } 796 return 0x00100010; /*FIXME*/ 797 } 798 799 /************************************************************************* 800 * FileMenu_AbortInitMenu [SHELL32.120] 801 * 802 */ 803 void WINAPI FileMenu_AbortInitMenu (void) 804 { TRACE("\n"); 805 bAbortInit = TRUE; 806 } 807 808 /************************************************************************* 809 * SHFind_InitMenuPopup [SHELL32.149] 810 * 811 * Get the IContextMenu instance for the submenu of options displayed 812 * for the Search entry in the Classic style Start menu. 813 * 814 * PARAMETERS 815 * hMenu [in] handle of menu previously created 816 * hWndParent [in] parent window 817 * w [in] no pointer (0x209 over here) perhaps menu IDs ??? 818 * x [in] no pointer (0x226 over here) 819 * 820 * RETURNS 821 * LPXXXXX pointer to struct containing a func addr at offset 8 822 * or NULL at failure. 823 */ 824 EXTERN_C IContextMenu * WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, UINT w, UINT x) 825 { 826 FIXME("hmenu=%p hwnd=%p 0x%08x 0x%08x stub\n", 827 hMenu,hWndParent,w,x); 828 return NULL; /* this is supposed to be a pointer */ 829 } 830 831 /************************************************************************* 832 * _SHIsMenuSeparator (internal) 833 */ 834 static BOOL _SHIsMenuSeparator(HMENU hm, int i) 835 { 836 MENUITEMINFOW mii; 837 838 mii.cbSize = sizeof(MENUITEMINFOW); 839 mii.fMask = MIIM_TYPE; 840 mii.cch = 0; /* WARNING: We MUST initialize it to 0*/ 841 if (!GetMenuItemInfoW(hm, i, TRUE, &mii)) 842 { 843 return(FALSE); 844 } 845 846 if (mii.fType & MFT_SEPARATOR) 847 { 848 return(TRUE); 849 } 850 851 return(FALSE); 852 } 853 854 /************************************************************************* 855 * Shell_MergeMenus [SHELL32.67] 856 */ 857 UINT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags) 858 { int nItem; 859 HMENU hmSubMenu; 860 BOOL bAlreadySeparated; 861 MENUITEMINFOW miiSrc; 862 WCHAR szName[256]; 863 UINT uTemp, uIDMax = uIDAdjust; 864 865 TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x 0x%04x\n", 866 hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags); 867 868 if (!hmDst || !hmSrc) 869 return uIDMax; 870 871 nItem = GetMenuItemCount(hmDst); 872 if (nItem == -1) 873 return uIDMax; 874 875 if (uInsert >= (UINT)nItem) /* insert position inside menu? */ 876 { 877 uInsert = (UINT)nItem; /* append on the end */ 878 bAlreadySeparated = TRUE; 879 } 880 else 881 { 882 bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert); 883 } 884 885 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) 886 { 887 /* Add a separator between the menus */ 888 InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 889 bAlreadySeparated = TRUE; 890 } 891 892 893 /* Go through the menu items and clone them*/ 894 for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--) 895 { 896 miiSrc.cbSize = sizeof(MENUITEMINFOW); 897 miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA; 898 899 /* We need to reset this every time through the loop in case menus DON'T have IDs*/ 900 miiSrc.fType = MFT_STRING; 901 miiSrc.dwTypeData = szName; 902 miiSrc.dwItemData = 0; 903 miiSrc.cch = sizeof(szName)/sizeof(WCHAR); 904 905 if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc)) 906 { 907 continue; 908 } 909 910 /* 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); 911 */ 912 if (miiSrc.fType & MFT_SEPARATOR) 913 { 914 /* This is a separator; don't put two of them in a row */ 915 if (bAlreadySeparated) 916 continue; 917 918 bAlreadySeparated = TRUE; 919 } 920 else if (miiSrc.hSubMenu) 921 { 922 if (uFlags & MM_SUBMENUSHAVEIDS) 923 { 924 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */ 925 926 if (miiSrc.wID > uIDAdjustMax) /* skip IDs higher than uIDAdjustMax */ 927 continue; 928 929 if (uIDMax <= miiSrc.wID) /* remember the highest ID */ 930 uIDMax = miiSrc.wID + 1; 931 } 932 else 933 { 934 miiSrc.fMask &= ~MIIM_ID; /* Don't set IDs for submenus that didn't have them already */ 935 } 936 hmSubMenu = miiSrc.hSubMenu; 937 938 miiSrc.hSubMenu = CreatePopupMenu(); 939 940 if (!miiSrc.hSubMenu) return(uIDMax); 941 942 uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS); 943 944 if (uIDMax <= uTemp) 945 uIDMax = uTemp; 946 947 bAlreadySeparated = FALSE; 948 } 949 else /* normal menu item */ 950 { 951 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */ 952 953 if (miiSrc.wID > uIDAdjustMax) /* skip IDs higher than uIDAdjustMax */ 954 continue; 955 956 if (uIDMax <= miiSrc.wID) /* remember the highest ID */ 957 uIDMax = miiSrc.wID + 1; 958 959 bAlreadySeparated = FALSE; 960 } 961 962 /* 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); 963 */ 964 if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc)) 965 { 966 return(uIDMax); 967 } 968 } 969 970 /* Ensure the correct number of separators at the beginning of the 971 inserted menu items*/ 972 if (uInsert == 0) 973 { 974 if (bAlreadySeparated) 975 { 976 DeleteMenu(hmDst, uInsert, MF_BYPOSITION); 977 } 978 } 979 else 980 { 981 if (_SHIsMenuSeparator(hmDst, uInsert-1)) 982 { 983 if (bAlreadySeparated) 984 { 985 DeleteMenu(hmDst, uInsert, MF_BYPOSITION); 986 } 987 } 988 else 989 { 990 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated) 991 { 992 /* Add a separator between the menus*/ 993 InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL); 994 } 995 } 996 } 997 return(uIDMax); 998 } 999