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