7ca1ce83972dffbb78cda5f8cf28a8d4b0b79770
[reactos.git] / reactos / dll / win32 / shell32 / shlmenu.c
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 #ifdef FM_SEPARATOR
24 #undef FM_SEPARATOR
25 #endif
26 #define FM_SEPARATOR (LPCWSTR)1
27
28 static BOOL FileMenu_AppendItemW(HMENU hMenu, LPCWSTR lpText, UINT uID, int icon,
29 HMENU hMenuPopup, int nItemHeight);
30
31 typedef struct
32 {
33 BOOL bInitialized;
34 BOOL bFixedItems;
35 /* create */
36 COLORREF crBorderColor;
37 int nBorderWidth;
38 HBITMAP hBorderBmp;
39
40 /* insert using pidl */
41 LPITEMIDLIST pidl;
42 UINT uID;
43 UINT uFlags;
44 UINT uEnumFlags;
45 LPFNFMCALLBACK lpfnCallback;
46 } FMINFO, *LPFMINFO;
47
48 typedef struct
49 { int cchItemText;
50 int iIconIndex;
51 HMENU hMenu;
52 WCHAR szItemText[1];
53 } FMITEM, * LPFMITEM;
54
55 static BOOL bAbortInit;
56
57 #define CCH_MAXITEMTEXT 256
58
59 WINE_DEFAULT_DEBUG_CHANNEL(shell);
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 { IShellFolder *lpsf, *lpsf2;
118 ULONG ulItemAttr = SFGAO_FOLDER;
119 UINT uID, uEnumFlags;
120 LPFNFMCALLBACK lpfnCallback;
121 LPCITEMIDLIST pidl;
122 WCHAR sTemp[MAX_PATH];
123 int NumberOfItems = 0, iIcon;
124 MENUINFO MenuInfo;
125 LPFMINFO menudata;
126
127 TRACE("%p %p\n", hmenu, pAlternatePidl);
128
129 MenuInfo.cbSize = sizeof(MENUINFO);
130 MenuInfo.fMask = MIM_MENUDATA;
131
132 if (! GetMenuInfo(hmenu, &MenuInfo))
133 return FALSE;
134
135 menudata = (LPFMINFO)MenuInfo.dwMenuData;
136
137 if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
138 {
139 ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
140 return 0;
141 }
142
143 if (menudata->bInitialized)
144 return 0;
145
146 pidl = (pAlternatePidl? pAlternatePidl: menudata->pidl);
147 if (!pidl)
148 return 0;
149
150 uID = menudata->uID;
151 uEnumFlags = menudata->uEnumFlags;
152 lpfnCallback = menudata->lpfnCallback;
153 menudata->bInitialized = FALSE;
154
155 SetMenuInfo(hmenu, &MenuInfo);
156
157 if (SUCCEEDED (SHGetDesktopFolder(&lpsf)))
158 {
159 if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,&IID_IShellFolder,(LPVOID *)&lpsf2)))
160 {
161 IEnumIDList *lpe = NULL;
162
163 if (SUCCEEDED (IShellFolder_EnumObjects(lpsf2, 0, uEnumFlags, &lpe )))
164 {
165
166 LPITEMIDLIST pidlTemp = NULL;
167 ULONG ulFetched;
168
169 while ((!bAbortInit) && (NOERROR == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched)))
170 {
171 if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, (LPCITEMIDLIST*)&pidlTemp, &ulItemAttr)))
172 {
173 ILGetDisplayNameExW(NULL, pidlTemp, sTemp, ILGDN_FORPARSING);
174 if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon)))
175 iIcon = FM_BLANK_ICON;
176 if ( SFGAO_FOLDER & ulItemAttr)
177 {
178 LPFMINFO lpFmMi;
179 MENUINFO MenuInfo;
180 HMENU hMenuPopup = CreatePopupMenu();
181
182 lpFmMi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
183
184 lpFmMi->pidl = ILCombine(pidl, pidlTemp);
185 lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
186
187 MenuInfo.cbSize = sizeof(MENUINFO);
188 MenuInfo.fMask = MIM_MENUDATA;
189 MenuInfo.dwMenuData = (ULONG_PTR) lpFmMi;
190 SetMenuInfo (hMenuPopup, &MenuInfo);
191
192 FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT);
193 }
194 else
195 {
196 LPWSTR pExt = PathFindExtensionW(sTemp);
197 if (pExt)
198 *pExt = 0;
199 FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT);
200 }
201 }
202
203 if (lpfnCallback)
204 {
205 TRACE("enter callback\n");
206 lpfnCallback ( pidl, pidlTemp);
207 TRACE("leave callback\n");
208 }
209
210 NumberOfItems++;
211 }
212 IEnumIDList_Release (lpe);
213 }
214 IShellFolder_Release(lpsf2);
215 }
216 IShellFolder_Release(lpsf);
217 }
218
219 if ( GetMenuItemCount (hmenu) == 0 )
220 {
221 static const WCHAR szEmpty[] = { '(','e','m','p','t','y',')',0 };
222 FileMenu_AppendItemW (hmenu, szEmpty, uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT);
223 NumberOfItems++;
224 }
225
226 menudata->bInitialized = TRUE;
227 SetMenuInfo(hmenu, &MenuInfo);
228
229 return NumberOfItems;
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 = 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 = SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR));
318 strcpyW (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 0;
358 }
359
360 menudata->bFixedItems = TRUE;
361 SetMenuInfo(hMenu, &MenuInfo);
362
363 return TRUE;
364
365 }
366
367 /**********************************************************************/
368
369 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, lpText, uID, icon, hMenuPopup, nItemHeight);
383 else
384 {
385 DWORD len = MultiByteToWideChar( CP_ACP, 0, lpText, -1, NULL, 0 );
386 LPWSTR lpszText = HeapAlloc ( GetProcessHeap(), 0, len*sizeof(WCHAR) );
387 if (!lpszText) return FALSE;
388 MultiByteToWideChar( CP_ACP, 0, 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 0;
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 BOOL WINAPI FileMenu_DeleteItemByFirstID(
739 HMENU hMenu,
740 UINT uID)
741 {
742 TRACE("%p 0x%08x\n", hMenu, uID);
743 return 0;
744 }
745
746 /*************************************************************************
747 * FileMenu_DeleteSeparator [SHELL32.142]
748 */
749 BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu)
750 {
751 TRACE("%p\n", hMenu);
752 return 0;
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 0;
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 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 HRESULT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
845 { int nItem;
846 HMENU hmSubMenu;
847 BOOL bAlreadySeparated;
848 MENUITEMINFOW miiSrc;
849 WCHAR szName[256];
850 UINT uTemp, uIDMax = uIDAdjust;
851
852 TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x 0x%04x\n",
853 hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);
854
855 if (!hmDst || !hmSrc)
856 return uIDMax;
857
858 nItem = GetMenuItemCount(hmDst);
859 if (nItem == -1)
860 return uIDMax;
861
862 if (uInsert >= (UINT)nItem) /* insert position inside menu? */
863 {
864 uInsert = (UINT)nItem; /* append on the end */
865 bAlreadySeparated = TRUE;
866 }
867 else
868 {
869 bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);
870 }
871
872 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
873 {
874 /* Add a separator between the menus */
875 InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
876 bAlreadySeparated = TRUE;
877 }
878
879
880 /* Go through the menu items and clone them*/
881 for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--)
882 {
883 miiSrc.cbSize = sizeof(MENUITEMINFOW);
884 miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
885
886 /* We need to reset this every time through the loop in case menus DON'T have IDs*/
887 miiSrc.fType = MFT_STRING;
888 miiSrc.dwTypeData = szName;
889 miiSrc.dwItemData = 0;
890 miiSrc.cch = sizeof(szName)/sizeof(WCHAR);
891
892 if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc))
893 {
894 continue;
895 }
896
897 /* 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);
898 */
899 if (miiSrc.fType & MFT_SEPARATOR)
900 {
901 /* This is a separator; don't put two of them in a row */
902 if (bAlreadySeparated)
903 continue;
904
905 bAlreadySeparated = TRUE;
906 }
907 else if (miiSrc.hSubMenu)
908 {
909 if (uFlags & MM_SUBMENUSHAVEIDS)
910 {
911 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */
912
913 if (miiSrc.wID > uIDAdjustMax) /* skip ID's higher uIDAdjustMax */
914 continue;
915
916 if (uIDMax <= miiSrc.wID) /* remember the highest ID */
917 uIDMax = miiSrc.wID + 1;
918 }
919 else
920 {
921 miiSrc.fMask &= ~MIIM_ID; /* Don't set IDs for submenus that didn't have them already */
922 }
923 hmSubMenu = miiSrc.hSubMenu;
924
925 miiSrc.hSubMenu = CreatePopupMenu();
926
927 if (!miiSrc.hSubMenu) return(uIDMax);
928
929 uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS);
930
931 if (uIDMax <= uTemp)
932 uIDMax = uTemp;
933
934 bAlreadySeparated = FALSE;
935 }
936 else /* normal menu item */
937 {
938 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */
939
940 if (miiSrc.wID > uIDAdjustMax) /* skip ID's higher uIDAdjustMax */
941 continue;
942
943 if (uIDMax <= miiSrc.wID) /* remember the highest ID */
944 uIDMax = miiSrc.wID + 1;
945
946 bAlreadySeparated = FALSE;
947 }
948
949 /* 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);
950 */
951 if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc))
952 {
953 return(uIDMax);
954 }
955 }
956
957 /* Ensure the correct number of separators at the beginning of the
958 inserted menu items*/
959 if (uInsert == 0)
960 {
961 if (bAlreadySeparated)
962 {
963 DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
964 }
965 }
966 else
967 {
968 if (_SHIsMenuSeparator(hmDst, uInsert-1))
969 {
970 if (bAlreadySeparated)
971 {
972 DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
973 }
974 }
975 else
976 {
977 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
978 {
979 /* Add a separator between the menus*/
980 InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
981 }
982 }
983 }
984 return(uIDMax);
985 }