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