msvcrt: Added _wcscoll_l implementation.
[wine] / dlls / shell32 / shlmenu.c
1 /*
2  * see www.geocities.com/SiliconValley/4942/filemenu.html
3  *
4  * Copyright 1999, 2000 Juergen Schmied
5  * Copyright 2011 Jay Yang
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23 #include <string.h>
24
25 #define COBJMACROS
26
27 #include "windef.h"
28 #include "winbase.h"
29 #include "winreg.h"
30 #include "wingdi.h"
31 #include "winuser.h"
32 #include "shlobj.h"
33 #include "undocshell.h"
34 #include "shlwapi.h"
35 #include "shell32_main.h"
36
37 #include "pidl.h"
38 #include "wine/debug.h"
39 #include "debughlp.h"
40
41 #ifdef FM_SEPARATOR
42 #undef FM_SEPARATOR
43 #endif
44 #define FM_SEPARATOR (LPCWSTR)1
45
46 static BOOL FileMenu_AppendItemW(HMENU hMenu, LPCWSTR lpText, UINT uID, int icon,
47                                  HMENU hMenuPopup, int nItemHeight);
48
49 typedef struct
50 {
51         BOOL            bInitialized;
52         BOOL            bFixedItems;
53         /* create */
54         COLORREF        crBorderColor;
55         int             nBorderWidth;
56         HBITMAP         hBorderBmp;
57
58         /* insert using pidl */
59         LPITEMIDLIST    pidl;
60         UINT            uID;
61         UINT            uFlags;
62         UINT            uEnumFlags;
63         LPFNFMCALLBACK lpfnCallback;
64 } FMINFO, *LPFMINFO;
65
66 typedef struct
67 {       int     cchItemText;
68         int     iIconIndex;
69         HMENU   hMenu;
70         WCHAR   szItemText[1];
71 } FMITEM, * LPFMITEM;
72
73 static BOOL bAbortInit;
74
75 #define CCH_MAXITEMTEXT 256
76
77 WINE_DEFAULT_DEBUG_CHANNEL(shell);
78
79 static LPFMINFO FM_GetMenuInfo(HMENU hmenu)
80 {
81         MENUINFO        MenuInfo;
82         LPFMINFO        menudata;
83
84         MenuInfo.cbSize = sizeof(MENUINFO);
85         MenuInfo.fMask = MIM_MENUDATA;
86
87         if (! GetMenuInfo(hmenu, &MenuInfo))
88           return NULL;
89
90         menudata = (LPFMINFO)MenuInfo.dwMenuData;
91
92         if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
93         {
94           ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
95           return 0;
96         }
97
98         return menudata;
99
100 }
101 /*************************************************************************
102  * FM_SetMenuParameter                          [internal]
103  *
104  */
105 static LPFMINFO FM_SetMenuParameter(
106         HMENU hmenu,
107         UINT uID,
108         LPCITEMIDLIST pidl,
109         UINT uFlags,
110         UINT uEnumFlags,
111         LPFNFMCALLBACK lpfnCallback)
112 {
113         LPFMINFO        menudata;
114
115         TRACE("\n");
116
117         menudata = FM_GetMenuInfo(hmenu);
118
119         SHFree(menudata->pidl);
120
121         menudata->uID = uID;
122         menudata->pidl = ILClone(pidl);
123         menudata->uFlags = uFlags;
124         menudata->uEnumFlags = uEnumFlags;
125         menudata->lpfnCallback = lpfnCallback;
126
127         return menudata;
128 }
129
130 /*************************************************************************
131  * FM_InitMenuPopup                             [internal]
132  *
133  */
134 static int FM_InitMenuPopup(HMENU hmenu, LPCITEMIDLIST pAlternatePidl)
135 {       IShellFolder    *lpsf, *lpsf2;
136         ULONG           ulItemAttr = SFGAO_FOLDER;
137         UINT            uID, uEnumFlags;
138         LPFNFMCALLBACK  lpfnCallback;
139         LPCITEMIDLIST   pidl;
140         WCHAR           sTemp[MAX_PATH];
141         int             NumberOfItems = 0, iIcon;
142         MENUINFO        MenuInfo;
143         LPFMINFO        menudata;
144
145         TRACE("%p %p\n", hmenu, pAlternatePidl);
146
147         MenuInfo.cbSize = sizeof(MENUINFO);
148         MenuInfo.fMask = MIM_MENUDATA;
149
150         if (! GetMenuInfo(hmenu, &MenuInfo))
151           return FALSE;
152
153         menudata = (LPFMINFO)MenuInfo.dwMenuData;
154
155         if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
156         {
157           ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
158           return 0;
159         }
160
161         if (menudata->bInitialized)
162           return 0;
163
164         pidl = (pAlternatePidl? pAlternatePidl: menudata->pidl);
165         if (!pidl)
166           return 0;
167
168         uID = menudata->uID;
169         uEnumFlags = menudata->uEnumFlags;
170         lpfnCallback = menudata->lpfnCallback;
171         menudata->bInitialized = FALSE;
172
173         SetMenuInfo(hmenu, &MenuInfo);
174
175         if (SUCCEEDED (SHGetDesktopFolder(&lpsf)))
176         {
177           if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,&IID_IShellFolder,(LPVOID *)&lpsf2)))
178           {
179             IEnumIDList *lpe = NULL;
180
181             if (SUCCEEDED (IShellFolder_EnumObjects(lpsf2, 0, uEnumFlags, &lpe )))
182             {
183
184               LPITEMIDLIST pidlTemp = NULL;
185               ULONG ulFetched;
186
187               while ((!bAbortInit) && (S_OK == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched)))
188               {
189                 if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, (LPCITEMIDLIST*)&pidlTemp, &ulItemAttr)))
190                 {
191                   ILGetDisplayNameExW(NULL, pidlTemp, sTemp, ILGDN_FORPARSING);
192                   if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon)))
193                     iIcon = FM_BLANK_ICON;
194                   if ( SFGAO_FOLDER & ulItemAttr)
195                   {
196                     LPFMINFO lpFmMi;
197                     MENUINFO MenuInfo;
198                     HMENU hMenuPopup = CreatePopupMenu();
199
200                     lpFmMi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
201
202                     lpFmMi->pidl = ILCombine(pidl, pidlTemp);
203                     lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
204
205                     MenuInfo.cbSize = sizeof(MENUINFO);
206                     MenuInfo.fMask = MIM_MENUDATA;
207                     MenuInfo.dwMenuData = (ULONG_PTR) lpFmMi;
208                     SetMenuInfo (hMenuPopup, &MenuInfo);
209
210                     FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT);
211                   }
212                   else
213                   {
214                     LPWSTR pExt = PathFindExtensionW(sTemp);
215                     if (pExt)
216                       *pExt = 0;
217                     FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT);
218                   }
219                 }
220
221                 if (lpfnCallback)
222                 {
223                   TRACE("enter callback\n");
224                   lpfnCallback ( pidl, pidlTemp);
225                   TRACE("leave callback\n");
226                 }
227
228                 NumberOfItems++;
229               }
230               IEnumIDList_Release (lpe);
231             }
232             IShellFolder_Release(lpsf2);
233           }
234           IShellFolder_Release(lpsf);
235         }
236
237         if ( GetMenuItemCount (hmenu) == 0 )
238         {
239           static const WCHAR szEmpty[] = { '(','e','m','p','t','y',')',0 };
240           FileMenu_AppendItemW (hmenu, szEmpty, uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT);
241           NumberOfItems++;
242         }
243
244         menudata->bInitialized = TRUE;
245         SetMenuInfo(hmenu, &MenuInfo);
246
247         return NumberOfItems;
248 }
249 /*************************************************************************
250  * FileMenu_Create                              [SHELL32.114]
251  *
252  * NOTES
253  *  for non-root menus values are
254  *  (ffffffff,00000000,00000000,00000000,00000000)
255  */
256 HMENU WINAPI FileMenu_Create (
257         COLORREF crBorderColor,
258         int nBorderWidth,
259         HBITMAP hBorderBmp,
260         int nSelHeight,
261         UINT uFlags)
262 {
263         MENUINFO        MenuInfo;
264         LPFMINFO        menudata;
265
266         HMENU hMenu = CreatePopupMenu();
267
268         TRACE("0x%08x 0x%08x %p 0x%08x 0x%08x  hMenu=%p\n",
269         crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu);
270
271         menudata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
272         menudata->crBorderColor = crBorderColor;
273         menudata->nBorderWidth = nBorderWidth;
274         menudata->hBorderBmp = hBorderBmp;
275
276         MenuInfo.cbSize = sizeof(MENUINFO);
277         MenuInfo.fMask = MIM_MENUDATA;
278         MenuInfo.dwMenuData = (ULONG_PTR) menudata;
279         SetMenuInfo (hMenu, &MenuInfo);
280
281         return hMenu;
282 }
283
284 /*************************************************************************
285  * FileMenu_Destroy                             [SHELL32.118]
286  *
287  * NOTES
288  *  exported by name
289  */
290 void WINAPI FileMenu_Destroy (HMENU hmenu)
291 {
292         LPFMINFO        menudata;
293
294         TRACE("%p\n", hmenu);
295
296         FileMenu_DeleteAllItems (hmenu);
297
298         menudata = FM_GetMenuInfo(hmenu);
299
300         SHFree( menudata->pidl);
301         HeapFree(GetProcessHeap(), 0, menudata);
302
303         DestroyMenu (hmenu);
304 }
305
306 /*************************************************************************
307  * FileMenu_AppendItem                  [SHELL32.115]
308  *
309  */
310 static BOOL FileMenu_AppendItemW(
311         HMENU hMenu,
312         LPCWSTR lpText,
313         UINT uID,
314         int icon,
315         HMENU hMenuPopup,
316         int nItemHeight)
317 {
318         MENUITEMINFOW   mii;
319         LPFMITEM        myItem;
320         LPFMINFO        menudata;
321         MENUINFO        MenuInfo;
322
323
324         TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n",
325           hMenu, (lpText!=FM_SEPARATOR) ? debugstr_w(lpText) : NULL,
326           uID, icon, hMenuPopup, nItemHeight);
327
328         ZeroMemory (&mii, sizeof(MENUITEMINFOW));
329
330         mii.cbSize = sizeof(MENUITEMINFOW);
331
332         if (lpText != FM_SEPARATOR)
333         {
334           int len = strlenW (lpText);
335           myItem = SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR));
336           strcpyW (myItem->szItemText, lpText);
337           myItem->cchItemText = len;
338           myItem->iIconIndex = icon;
339           myItem->hMenu = hMenu;
340           mii.fMask = MIIM_DATA;
341           mii.dwItemData = (ULONG_PTR) myItem;
342         }
343
344         if ( hMenuPopup )
345         { /* sub menu */
346           mii.fMask |= MIIM_TYPE | MIIM_SUBMENU;
347           mii.fType = MFT_OWNERDRAW;
348           mii.hSubMenu = hMenuPopup;
349         }
350         else if (lpText == FM_SEPARATOR )
351         { mii.fMask |= MIIM_ID | MIIM_TYPE;
352           mii.fType = MFT_SEPARATOR;
353         }
354         else
355         { /* normal item */
356           mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE;
357           mii.fState = MFS_ENABLED | MFS_DEFAULT;
358           mii.fType = MFT_OWNERDRAW;
359         }
360         mii.wID = uID;
361
362         InsertMenuItemW (hMenu, (UINT)-1, TRUE, &mii);
363
364         /* set bFixedItems to true */
365         MenuInfo.cbSize = sizeof(MENUINFO);
366         MenuInfo.fMask = MIM_MENUDATA;
367
368         if (! GetMenuInfo(hMenu, &MenuInfo))
369           return FALSE;
370
371         menudata = (LPFMINFO)MenuInfo.dwMenuData;
372         if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
373         {
374           ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
375           return FALSE;
376         }
377
378         menudata->bFixedItems = TRUE;
379         SetMenuInfo(hMenu, &MenuInfo);
380
381         return TRUE;
382
383 }
384
385 /**********************************************************************/
386
387 BOOL WINAPI FileMenu_AppendItemAW(
388         HMENU hMenu,
389         LPCVOID lpText,
390         UINT uID,
391         int icon,
392         HMENU hMenuPopup,
393         int nItemHeight)
394 {
395         BOOL ret;
396
397         if (!lpText) return FALSE;
398
399         if (SHELL_OsIsUnicode() || lpText == FM_SEPARATOR)
400           ret = FileMenu_AppendItemW(hMenu, lpText, uID, icon, hMenuPopup, nItemHeight);
401         else
402         {
403           DWORD len = MultiByteToWideChar( CP_ACP, 0, lpText, -1, NULL, 0 );
404           LPWSTR lpszText = HeapAlloc ( GetProcessHeap(), 0, len*sizeof(WCHAR) );
405           if (!lpszText) return FALSE;
406           MultiByteToWideChar( CP_ACP, 0, lpText, -1, lpszText, len );
407           ret = FileMenu_AppendItemW(hMenu, lpszText, uID, icon, hMenuPopup, nItemHeight);
408           HeapFree( GetProcessHeap(), 0, lpszText );
409         }
410
411         return ret;
412 }
413
414 /*************************************************************************
415  * FileMenu_InsertUsingPidl                     [SHELL32.110]
416  *
417  * NOTES
418  *      uEnumFlags      any SHCONTF flag
419  */
420 int WINAPI FileMenu_InsertUsingPidl (
421         HMENU hmenu,
422         UINT uID,
423         LPCITEMIDLIST pidl,
424         UINT uFlags,
425         UINT uEnumFlags,
426         LPFNFMCALLBACK lpfnCallback)
427 {
428         TRACE("%p 0x%08x %p 0x%08x 0x%08x %p\n",
429         hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
430
431         pdump (pidl);
432
433         bAbortInit = FALSE;
434
435         FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
436
437         return FM_InitMenuPopup(hmenu, NULL);
438 }
439
440 /*************************************************************************
441  * FileMenu_ReplaceUsingPidl                    [SHELL32.113]
442  *
443  * FIXME: the static items are deleted but won't be refreshed
444  */
445 int WINAPI FileMenu_ReplaceUsingPidl(
446         HMENU   hmenu,
447         UINT    uID,
448         LPCITEMIDLIST   pidl,
449         UINT    uEnumFlags,
450         LPFNFMCALLBACK lpfnCallback)
451 {
452         TRACE("%p 0x%08x %p 0x%08x %p\n",
453         hmenu, uID, pidl, uEnumFlags, lpfnCallback);
454
455         FileMenu_DeleteAllItems (hmenu);
456
457         FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback);
458
459         return FM_InitMenuPopup(hmenu, NULL);
460 }
461
462 /*************************************************************************
463  * FileMenu_Invalidate                  [SHELL32.111]
464  */
465 void WINAPI FileMenu_Invalidate (HMENU hMenu)
466 {
467         FIXME("%p\n",hMenu);
468 }
469
470 /*************************************************************************
471  * FileMenu_FindSubMenuByPidl                   [SHELL32.106]
472  */
473 HMENU WINAPI FileMenu_FindSubMenuByPidl(
474         HMENU   hMenu,
475         LPCITEMIDLIST   pidl)
476 {
477         FIXME("%p %p\n",hMenu, pidl);
478         return 0;
479 }
480
481 /*************************************************************************
482  * FileMenu_AppendFilesForPidl                  [SHELL32.124]
483  */
484 int WINAPI FileMenu_AppendFilesForPidl(
485         HMENU   hmenu,
486         LPCITEMIDLIST   pidl,
487         BOOL    bAddSeparator)
488 {
489         LPFMINFO        menudata;
490
491         menudata = FM_GetMenuInfo(hmenu);
492
493         menudata->bInitialized = FALSE;
494
495         FM_InitMenuPopup(hmenu, pidl);
496
497         if (bAddSeparator)
498           FileMenu_AppendItemW (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT);
499
500         TRACE("%p %p 0x%08x\n",hmenu, pidl,bAddSeparator);
501
502         return 0;
503 }
504 /*************************************************************************
505  * FileMenu_AddFilesForPidl                     [SHELL32.125]
506  *
507  * NOTES
508  *      uEnumFlags      any SHCONTF flag
509  */
510 int WINAPI FileMenu_AddFilesForPidl (
511         HMENU   hmenu,
512         UINT    uReserved,
513         UINT    uID,
514         LPCITEMIDLIST   pidl,
515         UINT    uFlags,
516         UINT    uEnumFlags,
517         LPFNFMCALLBACK  lpfnCallback)
518 {
519         TRACE("%p 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n",
520         hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
521
522         return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
523
524 }
525
526
527 /*************************************************************************
528  * FileMenu_TrackPopupMenuEx                    [SHELL32.116]
529  */
530 BOOL WINAPI FileMenu_TrackPopupMenuEx (
531         HMENU hMenu,
532         UINT uFlags,
533         int x,
534         int y,
535         HWND hWnd,
536         LPTPMPARAMS lptpm)
537 {
538         TRACE("%p 0x%08x 0x%x 0x%x %p %p\n",
539         hMenu, uFlags, x, y, hWnd, lptpm);
540         return TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm);
541 }
542
543 /*************************************************************************
544  * FileMenu_GetLastSelectedItemPidls            [SHELL32.107]
545  */
546 BOOL WINAPI FileMenu_GetLastSelectedItemPidls(
547         UINT    uReserved,
548         LPCITEMIDLIST   *ppidlFolder,
549         LPCITEMIDLIST   *ppidlItem)
550 {
551         FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem);
552         return FALSE;
553 }
554
555 #define FM_ICON_SIZE    16
556 #define FM_Y_SPACE      4
557 #define FM_SPACE1       4
558 #define FM_SPACE2       2
559 #define FM_LEFTBORDER   2
560 #define FM_RIGHTBORDER  8
561 /*************************************************************************
562  * FileMenu_MeasureItem                         [SHELL32.112]
563  */
564 LRESULT WINAPI FileMenu_MeasureItem(
565         HWND    hWnd,
566         LPMEASUREITEMSTRUCT     lpmis)
567 {
568         LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData);
569         HDC hdc = GetDC(hWnd);
570         SIZE size;
571         LPFMINFO menuinfo;
572
573         TRACE("%p %p %s\n", hWnd, lpmis, debugstr_w(pMyItem->szItemText));
574
575         GetTextExtentPoint32W(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size);
576
577         lpmis->itemWidth = size.cx + FM_LEFTBORDER + FM_ICON_SIZE + FM_SPACE1 + FM_SPACE2 + FM_RIGHTBORDER;
578         lpmis->itemHeight = (size.cy > (FM_ICON_SIZE + FM_Y_SPACE)) ? size.cy : (FM_ICON_SIZE + FM_Y_SPACE);
579
580         /* add the menubitmap */
581         menuinfo = FM_GetMenuInfo(pMyItem->hMenu);
582         if (menuinfo->nBorderWidth)
583           lpmis->itemWidth += menuinfo->nBorderWidth;
584
585         TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight);
586         ReleaseDC (hWnd, hdc);
587         return 0;
588 }
589 /*************************************************************************
590  * FileMenu_DrawItem                            [SHELL32.105]
591  */
592 LRESULT WINAPI FileMenu_DrawItem(
593         HWND                    hWnd,
594         LPDRAWITEMSTRUCT        lpdis)
595 {
596         LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData);
597         COLORREF clrPrevText, clrPrevBkgnd;
598         int xi,yi,xt,yt;
599         HIMAGELIST hImageList;
600         RECT TextRect;
601         LPFMINFO menuinfo;
602
603         TRACE("%p %p %s\n", hWnd, lpdis, debugstr_w(pMyItem->szItemText));
604
605         if (lpdis->itemState & ODS_SELECTED)
606         {
607           clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT));
608           clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHT));
609         }
610         else
611         {
612           clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_MENUTEXT));
613           clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_MENU));
614         }
615
616         CopyRect(&TextRect, &(lpdis->rcItem));
617
618         /* add the menubitmap */
619         menuinfo = FM_GetMenuInfo(pMyItem->hMenu);
620         if (menuinfo->nBorderWidth)
621           TextRect.left += menuinfo->nBorderWidth;
622
623         TextRect.left += FM_LEFTBORDER;
624         xi = TextRect.left + FM_SPACE1;
625         yi = TextRect.top + FM_Y_SPACE/2;
626         TextRect.bottom -= FM_Y_SPACE/2;
627
628         xt = xi + FM_ICON_SIZE + FM_SPACE2;
629         yt = yi;
630
631         ExtTextOutW (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL);
632
633         Shell_GetImageLists(0, &hImageList);
634         ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL);
635
636         TRACE("-- 0x%04x 0x%04x 0x%04x 0x%04x\n", TextRect.left, TextRect.top, TextRect.right, TextRect.bottom);
637
638         SetTextColor(lpdis->hDC, clrPrevText);
639         SetBkColor(lpdis->hDC, clrPrevBkgnd);
640
641         return TRUE;
642 }
643
644 /*************************************************************************
645  * FileMenu_InitMenuPopup                       [SHELL32.109]
646  *
647  * NOTES
648  *  The filemenu is an ownerdrawn menu. Call this function responding to
649  *  WM_INITPOPUPMENU
650  *
651  */
652 BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu)
653 {
654         FM_InitMenuPopup(hmenu, NULL);
655         return TRUE;
656 }
657
658 /*************************************************************************
659  * FileMenu_HandleMenuChar                      [SHELL32.108]
660  */
661 LRESULT WINAPI FileMenu_HandleMenuChar(
662         HMENU   hMenu,
663         WPARAM  wParam)
664 {
665         FIXME("%p 0x%08lx\n",hMenu,wParam);
666         return 0;
667 }
668
669 /*************************************************************************
670  * FileMenu_DeleteAllItems                      [SHELL32.104]
671  *
672  * NOTES
673  *  exported by name
674  */
675 BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu)
676 {
677         MENUITEMINFOW   mii;
678         LPFMINFO        menudata;
679
680         int i;
681
682         TRACE("%p\n", hmenu);
683
684         ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
685         mii.cbSize = sizeof(MENUITEMINFOW);
686         mii.fMask = MIIM_SUBMENU|MIIM_DATA;
687
688         for (i = 0; i < GetMenuItemCount( hmenu ); i++)
689         { GetMenuItemInfoW(hmenu, i, TRUE, &mii );
690
691           SHFree((LPFMINFO)mii.dwItemData);
692
693           if (mii.hSubMenu)
694             FileMenu_Destroy(mii.hSubMenu);
695         }
696
697         while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){};
698
699         menudata = FM_GetMenuInfo(hmenu);
700
701         menudata->bInitialized = FALSE;
702
703         return TRUE;
704 }
705
706 /*************************************************************************
707  * FileMenu_DeleteItemByCmd                     [SHELL32.117]
708  *
709  */
710 BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID)
711 {
712         MENUITEMINFOW mii;
713
714         TRACE("%p 0x%08x\n", hMenu, uID);
715
716         ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
717         mii.cbSize = sizeof(MENUITEMINFOW);
718         mii.fMask = MIIM_SUBMENU;
719
720         GetMenuItemInfoW(hMenu, uID, FALSE, &mii );
721         if ( mii.hSubMenu )
722         {
723           /* FIXME: Do what? */
724         }
725
726         DeleteMenu(hMenu, MF_BYCOMMAND, uID);
727         return TRUE;
728 }
729
730 /*************************************************************************
731  * FileMenu_DeleteItemByIndex                   [SHELL32.140]
732  */
733 BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos)
734 {
735         MENUITEMINFOW mii;
736
737         TRACE("%p 0x%08x\n", hMenu, uPos);
738
739         ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
740         mii.cbSize = sizeof(MENUITEMINFOW);
741         mii.fMask = MIIM_SUBMENU;
742
743         GetMenuItemInfoW(hMenu, uPos, TRUE, &mii );
744         if ( mii.hSubMenu )
745         {
746           /* FIXME: Do what? */
747         }
748
749         DeleteMenu(hMenu, MF_BYPOSITION, uPos);
750         return TRUE;
751 }
752
753 /*************************************************************************
754  * FileMenu_DeleteItemByFirstID                 [SHELL32.141]
755  */
756 BOOL WINAPI FileMenu_DeleteItemByFirstID(
757         HMENU   hMenu,
758         UINT    uID)
759 {
760         TRACE("%p 0x%08x\n", hMenu, uID);
761         return FALSE;
762 }
763
764 /*************************************************************************
765  * FileMenu_DeleteSeparator                     [SHELL32.142]
766  */
767 BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu)
768 {
769         TRACE("%p\n", hMenu);
770         return FALSE;
771 }
772
773 /*************************************************************************
774  * FileMenu_EnableItemByCmd                     [SHELL32.143]
775  */
776 BOOL WINAPI FileMenu_EnableItemByCmd(
777         HMENU   hMenu,
778         UINT    uID,
779         BOOL    bEnable)
780 {
781         TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable);
782         return FALSE;
783 }
784
785 /*************************************************************************
786  * FileMenu_GetItemExtent                       [SHELL32.144]
787  *
788  * NOTES
789  *  if the menu is too big, entries are getting cut away!!
790  */
791 DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos)
792 {       RECT rect;
793
794         FIXME("%p 0x%08x\n", hMenu, uPos);
795
796         if (GetMenuItemRect(0, hMenu, uPos, &rect))
797         { FIXME("0x%04x 0x%04x 0x%04x 0x%04x\n",
798           rect.right, rect.left, rect.top, rect.bottom);
799           return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom);
800         }
801         return 0x00100010; /*FIXME*/
802 }
803
804 /*************************************************************************
805  * FileMenu_AbortInitMenu                       [SHELL32.120]
806  *
807  */
808 void WINAPI FileMenu_AbortInitMenu (void)
809 {       TRACE("\n");
810         bAbortInit = TRUE;
811 }
812
813 /*************************************************************************
814  * SHFind_InitMenuPopup                         [SHELL32.149]
815  *
816  * Get the IContextMenu instance for the submenu of options displayed
817  * for the Search entry in the Classic style Start menu.
818  *
819  * PARAMETERS
820  *  hMenu               [in] handle of menu previously created
821  *  hWndParent  [in] parent window
822  *  w                   [in] no pointer (0x209 over here) perhaps menu IDs ???
823  *  x                   [in] no pointer (0x226 over here)
824  *
825  * RETURNS
826  *  LPXXXXX                      pointer to struct containing a func addr at offset 8
827  *                                       or NULL at failure.
828  */
829 LPVOID WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, DWORD w, DWORD x)
830 {
831         FIXME("hmenu=%p hwnd=%p 0x%08x 0x%08x stub\n",
832                 hMenu,hWndParent,w,x);
833         return NULL; /* this is supposed to be a pointer */
834 }
835
836 /*************************************************************************
837  * _SHIsMenuSeparator   (internal)
838  */
839 static BOOL _SHIsMenuSeparator(HMENU hm, int i)
840 {
841         MENUITEMINFOW mii;
842
843         mii.cbSize = sizeof(MENUITEMINFOW);
844         mii.fMask = MIIM_TYPE;
845         mii.cch = 0;    /* WARNING: We MUST initialize it to 0*/
846         if (!GetMenuItemInfoW(hm, i, TRUE, &mii))
847         {
848           return(FALSE);
849         }
850
851         if (mii.fType & MFT_SEPARATOR)
852         {
853           return(TRUE);
854         }
855
856         return(FALSE);
857 }
858
859 /*************************************************************************
860  * Shell_MergeMenus                             [SHELL32.67]
861  */
862 UINT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
863 {       int             nItem;
864         HMENU           hmSubMenu;
865         BOOL            bAlreadySeparated;
866         MENUITEMINFOW   miiSrc;
867         WCHAR           szName[256];
868         UINT            uTemp, uIDMax = uIDAdjust;
869
870         TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x  0x%04x\n",
871                  hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);
872
873         if (!hmDst || !hmSrc)
874           return uIDMax;
875
876         nItem = GetMenuItemCount(hmDst);
877         if (nItem == -1)
878           return uIDMax;
879
880         if (uInsert >= (UINT)nItem)     /* insert position inside menu? */
881         {
882           uInsert = (UINT)nItem;        /* append on the end */
883           bAlreadySeparated = TRUE;
884         }
885         else
886         {
887           bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);
888         }
889
890         if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
891         {
892           /* Add a separator between the menus */
893           InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
894           bAlreadySeparated = TRUE;
895         }
896
897
898         /* Go through the menu items and clone them*/
899         for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--)
900         {
901           miiSrc.cbSize = sizeof(MENUITEMINFOW);
902           miiSrc.fMask =  MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
903
904           /* We need to reset this every time through the loop in case menus DON'T have IDs*/
905           miiSrc.fType = MFT_STRING;
906           miiSrc.dwTypeData = szName;
907           miiSrc.dwItemData = 0;
908           miiSrc.cch = sizeof(szName)/sizeof(WCHAR);
909
910           if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc))
911           {
912             continue;
913           }
914
915 /*        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);
916 */
917           if (miiSrc.fType & MFT_SEPARATOR)
918           {
919             /* This is a separator; don't put two of them in a row */
920             if (bAlreadySeparated)
921               continue;
922
923             bAlreadySeparated = TRUE;
924           }
925           else if (miiSrc.hSubMenu)
926           {
927             if (uFlags & MM_SUBMENUSHAVEIDS)
928             {
929               miiSrc.wID += uIDAdjust;                  /* add uIDAdjust to the ID */
930
931               if (miiSrc.wID > uIDAdjustMax)            /* skip IDs higher than uIDAdjustMax */
932                 continue;
933
934               if (uIDMax <= miiSrc.wID)                 /* remember the highest ID */
935                 uIDMax = miiSrc.wID + 1;
936             }
937             else
938             {
939               miiSrc.fMask &= ~MIIM_ID;                 /* Don't set IDs for submenus that didn't have them already */
940             }
941             hmSubMenu = miiSrc.hSubMenu;
942
943             miiSrc.hSubMenu = CreatePopupMenu();
944
945             if (!miiSrc.hSubMenu) return(uIDMax);
946
947             uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS);
948
949             if (uIDMax <= uTemp)
950               uIDMax = uTemp;
951
952             bAlreadySeparated = FALSE;
953           }
954           else                                          /* normal menu item */
955           {
956             miiSrc.wID += uIDAdjust;                    /* add uIDAdjust to the ID */
957
958             if (miiSrc.wID > uIDAdjustMax)              /* skip IDs higher than uIDAdjustMax */
959               continue;
960
961             if (uIDMax <= miiSrc.wID)                   /* remember the highest ID */
962               uIDMax = miiSrc.wID + 1;
963
964             bAlreadySeparated = FALSE;
965           }
966
967 /*        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);
968 */
969           if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc))
970           {
971             return(uIDMax);
972           }
973         }
974
975         /* Ensure the correct number of separators at the beginning of the
976         inserted menu items*/
977         if (uInsert == 0)
978         {
979           if (bAlreadySeparated)
980           {
981             DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
982           }
983         }
984         else
985         {
986           if (_SHIsMenuSeparator(hmDst, uInsert-1))
987           {
988             if (bAlreadySeparated)
989             {
990               DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
991             }
992           }
993           else
994           {
995             if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
996             {
997               /* Add a separator between the menus*/
998               InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
999             }
1000           }
1001         }
1002         return(uIDMax);
1003 }
1004
1005 typedef struct
1006 {
1007     IContextMenu3 IContextMenu3_iface;
1008     IContextMenu **menus;
1009     UINT *offsets;
1010     UINT menu_count;
1011     ULONG refCount;
1012 }CompositeCMenu;
1013
1014 static const IContextMenu3Vtbl CompositeCMenuVtbl;
1015
1016 static CompositeCMenu* impl_from_IContextMenu3(IContextMenu3* iface)
1017 {
1018     return CONTAINING_RECORD(iface, CompositeCMenu, IContextMenu3_iface);
1019 }
1020
1021 static HRESULT CompositeCMenu_Constructor(IContextMenu **menus,UINT menu_count, REFIID riid, void **ppv)
1022 {
1023     CompositeCMenu *ret = HeapAlloc(GetProcessHeap(),0,sizeof(CompositeCMenu));
1024     UINT i;
1025     TRACE("(%p,%u,%s,%p)\n",menus,menu_count,shdebugstr_guid(riid),ppv);
1026     if(!ret)
1027         return E_OUTOFMEMORY;
1028     ret->IContextMenu3_iface.lpVtbl = &CompositeCMenuVtbl;
1029     ret->menu_count = menu_count;
1030     ret->menus = HeapAlloc(GetProcessHeap(),0,menu_count*sizeof(IContextMenu*));
1031     if(!ret->menus)
1032     {
1033         HeapFree(GetProcessHeap(),0,ret);
1034         return E_OUTOFMEMORY;
1035     }
1036     ret->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,menu_count*sizeof(UINT));
1037     if(!ret->offsets)
1038     {
1039         HeapFree(GetProcessHeap(),0,ret->menus);
1040         HeapFree(GetProcessHeap(),0,ret);
1041         return E_OUTOFMEMORY;
1042     }
1043     ret->refCount=0;
1044     memcpy(ret->menus,menus,menu_count*sizeof(IContextMenu*));
1045     for(i=0;i<menu_count;i++)
1046         IContextMenu_AddRef(menus[i]);
1047     return IContextMenu3_QueryInterface(&(ret->IContextMenu3_iface),riid,ppv);
1048 }
1049
1050 static void CompositeCMenu_Destroy(CompositeCMenu *This)
1051 {
1052     UINT i;
1053     for(i=0;i<This->menu_count;i++)
1054         IContextMenu_Release(This->menus[i]);
1055     HeapFree(GetProcessHeap(),0,This->menus);
1056     HeapFree(GetProcessHeap(),0,This->offsets);
1057     HeapFree(GetProcessHeap(),0,This);
1058 }
1059
1060 static HRESULT WINAPI CompositeCMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, void **ppv)
1061 {
1062     TRACE("(%p)->(%s,%p)\n",iface,shdebugstr_guid(riid),ppv);
1063     if(!ppv)
1064         return E_INVALIDARG;
1065     if(IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IContextMenu) ||
1066        IsEqualIID(riid,&IID_IContextMenu2) || IsEqualIID(riid,&IID_IContextMenu3))
1067         *ppv=iface;
1068     else
1069         return E_NOINTERFACE;
1070     IContextMenu3_AddRef(iface);
1071     return S_OK;
1072 }
1073
1074 static ULONG WINAPI CompositeCMenu_AddRef(IContextMenu3 *iface)
1075 {
1076     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1077     TRACE("(%p)->()\n",iface);
1078     return ++This->refCount;
1079 }
1080
1081 static ULONG WINAPI CompositeCMenu_Release(IContextMenu3 *iface)
1082 {
1083     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1084     TRACE("(%p)->()\n",iface);
1085     if(--This->refCount)
1086         return This->refCount;
1087     CompositeCMenu_Destroy(This);
1088     return 0;
1089 }
1090
1091 static UINT CompositeCMenu_GetIndexForCommandId(CompositeCMenu *This,UINT id)
1092 {
1093     UINT low=0;
1094     UINT high=This->menu_count;
1095     while(high-low!=1)
1096     {
1097         UINT i=(high+low)/2;
1098         if(This->offsets[i]<=id)
1099             low=i;
1100         else
1101             high=i;
1102     }
1103     return low;
1104 }
1105
1106 static HRESULT WINAPI CompositeCMenu_GetCommandString(IContextMenu3* iface, UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
1107 {
1108     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1109     UINT index = CompositeCMenu_GetIndexForCommandId(This,idCmd);
1110     TRACE("(%p)->(%lx,%x,%p,%s,%u)\n",iface,idCmd,uFlags,pwReserved,pszName,cchMax);
1111     return IContextMenu_GetCommandString(This->menus[index],idCmd,uFlags,pwReserved,pszName,cchMax);
1112 }
1113
1114 static HRESULT WINAPI CompositeCMenu_InvokeCommand(IContextMenu3* iface,LPCMINVOKECOMMANDINFO pici)
1115 {
1116     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1117     TRACE("(%p)->(%p)\n",iface,pici);
1118     if(HIWORD(pici->lpVerb))
1119     {
1120         /*call each handler until one of them succeeds*/
1121         UINT i=0;
1122         for(;i<This->menu_count;i++)
1123         {
1124             HRESULT hres;
1125             if(SUCCEEDED(hres=IContextMenu_InvokeCommand(This->menus[i],pici)))
1126                 return hres;
1127         }
1128         return E_FAIL;
1129     }
1130     else
1131     {
1132         UINT id = (UINT_PTR)pici->lpVerb;
1133         UINT index = CompositeCMenu_GetIndexForCommandId(This,id);
1134         return IContextMenu_InvokeCommand(This->menus[index],pici);
1135     }
1136 }
1137
1138 static HRESULT WINAPI CompositeCMenu_QueryContextMenu(IContextMenu3 *iface, HMENU hmenu,UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
1139 {
1140     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1141     UINT i=0;
1142     UINT id_offset=idCmdFirst;
1143     TRACE("(%p)->(%p,%u,%u,%u,%x)\n",iface,hmenu,indexMenu,idCmdFirst,idCmdLast,uFlags);
1144     for(;i<This->menu_count;i++)
1145     {
1146         HRESULT hres;
1147         This->offsets[i]=id_offset;
1148         hres = IContextMenu_QueryContextMenu(This->menus[i],hmenu,indexMenu,id_offset,idCmdLast,uFlags);
1149         if(SUCCEEDED(hres))
1150             id_offset+=hres;
1151     }
1152     return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, id_offset-idCmdFirst);
1153 }
1154
1155 static HRESULT WINAPI CompositeCMenu_HandleMenuMsg(IContextMenu3 *iface, UINT uMsg, WPARAM wParam, LPARAM lParam)
1156 {
1157     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1158     HMENU menu;
1159     UINT id;
1160     UINT index;
1161     IContextMenu2 *handler;
1162     HRESULT hres;
1163     TRACE("(%p)->(%x,%lx,%lx)\n",iface,uMsg,wParam,lParam);
1164     switch(uMsg)
1165     {
1166     case WM_INITMENUPOPUP:
1167         menu = (HMENU)wParam;
1168         id = GetMenuItemID(menu,LOWORD(lParam));
1169         break;
1170     case WM_DRAWITEM:
1171         id = ((DRAWITEMSTRUCT*)lParam)->itemID;
1172         break;
1173     case WM_MEASUREITEM:
1174         id = ((MEASUREITEMSTRUCT*)lParam)->itemID;
1175         break;
1176     default:
1177         WARN("Unimplemented uMsg: 0x%x\n",uMsg);
1178         return E_NOTIMPL;
1179     }
1180     index = CompositeCMenu_GetIndexForCommandId(This,id);
1181     hres = IContextMenu_QueryInterface(This->menus[index],&IID_IContextMenu2,
1182                                        (void**)&handler);
1183     if(SUCCEEDED(hres))
1184         return IContextMenu2_HandleMenuMsg(handler,uMsg,wParam,lParam);
1185     return S_OK;
1186 }
1187
1188 static HRESULT WINAPI CompositeCMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT uMsg, WPARAM wParam, LPARAM lParam,LRESULT *plResult)
1189 {
1190     CompositeCMenu *This = impl_from_IContextMenu3(iface);
1191     HMENU menu;
1192     UINT id;
1193     UINT index;
1194     IContextMenu3 *handler;
1195     HRESULT hres;
1196     LRESULT lres;
1197     TRACE("(%p)->(%x,%lx,%lx,%p)\n",iface,uMsg,wParam,lParam,plResult);
1198     if(!plResult)
1199         plResult=&lres;
1200     switch(uMsg)
1201     {
1202     case WM_INITMENUPOPUP:
1203         menu = (HMENU)wParam;
1204         id = GetMenuItemID(menu,LOWORD(lParam));
1205         break;
1206     case WM_DRAWITEM:
1207         id = ((DRAWITEMSTRUCT*)lParam)->itemID;
1208         break;
1209     case WM_MEASUREITEM:
1210         id = ((MEASUREITEMSTRUCT*)lParam)->itemID;
1211         break;
1212     case WM_MENUCHAR:
1213         {
1214             UINT i=0;
1215             for(;i<This->menu_count;i++)
1216             {
1217                 hres = IContextMenu_QueryInterface(This->menus[i],&IID_IContextMenu3,(void**)&handler);
1218                 if(SUCCEEDED(hres))
1219                 {
1220                     hres = IContextMenu3_HandleMenuMsg2(handler,uMsg,wParam,lParam,plResult);
1221                     if(SUCCEEDED(hres) && HIWORD(*plResult))
1222                         return hres;
1223                 }
1224             }
1225         }
1226     default:
1227         WARN("Unimplemented uMsg: 0x%x\n",uMsg);
1228         return E_NOTIMPL;
1229     }
1230     index = CompositeCMenu_GetIndexForCommandId(This,id);
1231     hres = IContextMenu_QueryInterface(This->menus[index],&IID_IContextMenu3,(void**)&handler);
1232     if(SUCCEEDED(hres))
1233         return IContextMenu3_HandleMenuMsg2(handler,uMsg,wParam,lParam,plResult);
1234     return S_OK;
1235 }
1236
1237 static const IContextMenu3Vtbl CompositeCMenuVtbl=
1238 {
1239     CompositeCMenu_QueryInterface,
1240     CompositeCMenu_AddRef,
1241     CompositeCMenu_Release,
1242     CompositeCMenu_QueryContextMenu,
1243     CompositeCMenu_InvokeCommand,
1244     CompositeCMenu_GetCommandString,
1245     CompositeCMenu_HandleMenuMsg,
1246     CompositeCMenu_HandleMenuMsg2
1247 };
1248
1249 static HRESULT SHELL_CreateContextMenu(HWND hwnd, IContextMenu* system_menu,
1250                                 IShellFolder *folder, LPCITEMIDLIST folder_pidl,
1251                                 LPCITEMIDLIST *apidl, UINT cidl, const HKEY *aKeys,
1252                                 UINT cKeys,REFIID riid, void** ppv)
1253 {
1254     HRESULT ret;
1255     TRACE("(%p,%p,%p,%p,%p,%u,%p,%u,%s,%p)\n",hwnd,system_menu,folder,folder_pidl,apidl,cidl,aKeys,cKeys,shdebugstr_guid(riid),ppv);
1256     ret = CompositeCMenu_Constructor(&system_menu,1,riid,ppv);
1257     return ret;
1258 }
1259
1260 HRESULT WINAPI CDefFolderMenu_Create2(LPCITEMIDLIST pidlFolder, HWND hwnd, UINT cidl,
1261                                       LPCITEMIDLIST *apidl, IShellFolder *psf,
1262                                       LPFNDFMCALLBACK lpfn, UINT nKeys, const HKEY *ahkeys,
1263                                       IContextMenu **ppcm)
1264 {
1265     IContextMenu *system_menu;
1266     HRESULT hres;
1267     LPITEMIDLIST folder_pidl;
1268     TRACE("(%p,%p,%u,%p,%p,%u,%p,%p)\n",pidlFolder,hwnd,cidl,apidl,psf,nKeys,ahkeys,ppcm);
1269     if(!pidlFolder)
1270     {
1271         IPersistFolder2 *persist;
1272         IShellFolder_QueryInterface(psf,&IID_IPersistFolder2,(void**)&persist);
1273         IPersistFolder2_GetCurFolder(persist,&folder_pidl);
1274         IPersistFolder2_Release(persist);
1275     }
1276     else
1277         folder_pidl=ILClone(pidlFolder);
1278
1279     ItemMenu_Constructor(psf, folder_pidl, (const LPCITEMIDLIST*)apidl, cidl, &IID_IContextMenu, (void**)&system_menu);
1280     hres= SHELL_CreateContextMenu(hwnd,system_menu,psf,folder_pidl,apidl,cidl,ahkeys,nKeys,&IID_IContextMenu,(void**)ppcm);
1281     IContextMenu_Release(system_menu);
1282     ILFree(folder_pidl);
1283     return hres;
1284 }
1285
1286 HRESULT WINAPI SHCreateDefaultContextMenu(const DEFCONTEXTMENU *pdcm, REFIID riid, void **ppv)
1287 {
1288     IShellFolder *folder=pdcm->psf;
1289     LPITEMIDLIST folder_pidl;
1290     HRESULT ret;
1291     IContextMenu *system_menu;
1292     TRACE("(%p,%s,%p)\n",pdcm,shdebugstr_guid(riid),ppv);
1293     if(!pdcm->pidlFolder)
1294     {
1295         IPersistFolder2 *persist;
1296         IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
1297         IPersistFolder2_GetCurFolder(persist,&folder_pidl);
1298         IPersistFolder2_Release(persist);
1299     }
1300     else
1301         folder_pidl=ILClone(pdcm->pidlFolder);
1302     if(pdcm->cKeys==0)
1303         FIXME("Loading shell extensions using IQueryAssociations not yet supported\n");
1304
1305     ItemMenu_Constructor(folder, folder_pidl, (const LPCITEMIDLIST*)pdcm->apidl, pdcm->cidl, &IID_IContextMenu, (void**)&system_menu);
1306     ret = SHELL_CreateContextMenu(pdcm->hwnd,system_menu,folder,folder_pidl,(LPCITEMIDLIST*)pdcm->apidl,pdcm->cidl,pdcm->aKeys,pdcm->cKeys,riid,ppv);
1307     IContextMenu_Release(system_menu);
1308     ILFree(folder_pidl);
1309     return ret;
1310 }