Framework for the doppler effect.
[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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include <string.h>
22
23 #include "winreg.h"
24 #include "shlobj.h"
25 #include "undocshell.h"
26 #include "shlwapi.h"
27 #include "heap.h"
28 #include "shell32_main.h"
29 #include "shlguid.h"
30
31 #include "pidl.h"
32 #include "wine/debug.h"
33
34 static BOOL FileMenu_AppendItemA(HMENU hMenu, LPCSTR lpText, UINT uID, int icon,
35                                  HMENU hMenuPopup, int nItemHeight);
36
37 typedef struct
38 {
39         BOOL            bInitialized;
40         BOOL            bFixedItems;
41         /* create */
42         COLORREF        crBorderColor;
43         int             nBorderWidth;
44         HBITMAP         hBorderBmp;
45
46         /* insert using pidl */
47         LPITEMIDLIST    pidl;
48         UINT            uID;
49         UINT            uFlags;
50         UINT            uEnumFlags;
51         LPFNFMCALLBACK lpfnCallback;
52 } FMINFO, *LPFMINFO;
53
54 typedef struct
55 {       int     cchItemText;
56         int     iIconIndex;
57         HMENU   hMenu;
58         char    szItemText[1];
59 } FMITEM, * LPFMITEM;
60
61 static BOOL bAbortInit;
62
63 #define CCH_MAXITEMTEXT 256
64
65 WINE_DEFAULT_DEBUG_CHANNEL(shell);
66
67 LPFMINFO FM_GetMenuInfo(HMENU hmenu)
68 {       MENUINFO        MenuInfo;
69         LPFMINFO        menudata;
70
71         MenuInfo.cbSize = sizeof(MENUINFO);
72         MenuInfo.fMask = MIM_MENUDATA;
73
74         if (! GetMenuInfo(hmenu, &MenuInfo))
75           return NULL;
76
77         menudata = (LPFMINFO)MenuInfo.dwMenuData;
78
79         if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
80         {
81           ERR("menudata corrupt: %p %lu\n", menudata, MenuInfo.cbSize);
82           return 0;
83         }
84
85         return menudata;
86
87 }
88 /*************************************************************************
89  * FM_SetMenuParameter                          [internal]
90  *
91  */
92 static LPFMINFO FM_SetMenuParameter(
93         HMENU hmenu,
94         UINT uID,
95         LPCITEMIDLIST pidl,
96         UINT uFlags,
97         UINT uEnumFlags,
98         LPFNFMCALLBACK lpfnCallback)
99 {
100         LPFMINFO        menudata;
101
102         TRACE("\n");
103
104         menudata = FM_GetMenuInfo(hmenu);
105
106         if ( menudata->pidl)
107         { SHFree(menudata->pidl);
108         }
109
110         menudata->uID = uID;
111         menudata->pidl = ILClone(pidl);
112         menudata->uFlags = uFlags;
113         menudata->uEnumFlags = uEnumFlags;
114         menudata->lpfnCallback = lpfnCallback;
115
116         return menudata;
117 }
118
119 /*************************************************************************
120  * FM_InitMenuPopup                             [internal]
121  *
122  */
123 static int FM_InitMenuPopup(HMENU hmenu, LPITEMIDLIST pAlternatePidl)
124 {       IShellFolder    *lpsf, *lpsf2;
125         ULONG           ulItemAttr = SFGAO_FOLDER;
126         UINT            uID, uFlags, uEnumFlags;
127         LPFNFMCALLBACK  lpfnCallback;
128         LPITEMIDLIST    pidl;
129         char            sTemp[MAX_PATH];
130         int             NumberOfItems = 0, iIcon;
131         MENUINFO        MenuInfo;
132         LPFMINFO        menudata;
133
134         TRACE("%p %p\n", hmenu, pAlternatePidl);
135
136         MenuInfo.cbSize = sizeof(MENUINFO);
137         MenuInfo.fMask = MIM_MENUDATA;
138
139         if (! GetMenuInfo(hmenu, &MenuInfo))
140           return FALSE;
141
142         menudata = (LPFMINFO)MenuInfo.dwMenuData;
143
144         if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
145         {
146           ERR("menudata corrupt: %p %lu\n", menudata, MenuInfo.cbSize);
147           return 0;
148         }
149
150         if (menudata->bInitialized)
151           return 0;
152
153         pidl = ((pAlternatePidl) ? pAlternatePidl : menudata->pidl);
154         if (!pidl)
155           return 0;
156
157         uID = menudata->uID;
158         uFlags = menudata->uFlags;
159         uEnumFlags = menudata->uEnumFlags;
160         lpfnCallback = menudata->lpfnCallback;
161         menudata->bInitialized = FALSE;
162
163         SetMenuInfo(hmenu, &MenuInfo);
164
165         if (SUCCEEDED (SHGetDesktopFolder(&lpsf)))
166         {
167           if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,(REFIID)&IID_IShellFolder,(LPVOID *)&lpsf2)))
168           {
169             IEnumIDList *lpe = NULL;
170
171             if (SUCCEEDED (IShellFolder_EnumObjects(lpsf2, 0, uEnumFlags, &lpe )))
172             {
173
174               LPITEMIDLIST pidlTemp = NULL;
175               ULONG ulFetched;
176
177               while ((!bAbortInit) && (NOERROR == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched)))
178               {
179                 if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, &pidlTemp, &ulItemAttr)))
180                 {
181                   ILGetDisplayName( pidlTemp, sTemp);
182                   if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon)))
183                     iIcon = FM_BLANK_ICON;
184                   if ( SFGAO_FOLDER & ulItemAttr)
185                   {
186                     LPFMINFO lpFmMi;
187                     MENUINFO MenuInfo;
188                     HMENU hMenuPopup = CreatePopupMenu();
189
190                     lpFmMi = (LPFMINFO) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
191
192                     lpFmMi->pidl = ILCombine(pidl, pidlTemp);
193                     lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;
194
195                     MenuInfo.cbSize = sizeof(MENUINFO);
196                     MenuInfo.fMask = MIM_MENUDATA;
197                     MenuInfo.dwMenuData = (DWORD) lpFmMi;
198                     SetMenuInfo (hMenuPopup, &MenuInfo);
199
200                     FileMenu_AppendItemA (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT);
201                   }
202                   else
203                   {
204                     ((LPSTR)PathFindExtensionA(sTemp))[0] = 0x00;
205                     FileMenu_AppendItemA (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT);
206                   }
207                 }
208
209                 if (lpfnCallback)
210                 {
211                   TRACE("enter callback\n");
212                   lpfnCallback ( pidl, pidlTemp);
213                   TRACE("leave callback\n");
214                 }
215
216                 NumberOfItems++;
217               }
218               IEnumIDList_Release (lpe);
219             }
220             IShellFolder_Release(lpsf2);
221           }
222           IShellFolder_Release(lpsf);
223         }
224
225         if ( GetMenuItemCount (hmenu) == 0 )
226         { FileMenu_AppendItemA (hmenu, "(empty)", uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT);
227           NumberOfItems++;
228         }
229
230         menudata->bInitialized = TRUE;
231         SetMenuInfo(hmenu, &MenuInfo);
232
233         return NumberOfItems;
234 }
235 /*************************************************************************
236  * FileMenu_Create                              [SHELL32.114]
237  *
238  * NOTES
239  *  for non-root menus values are
240  *  (ffffffff,00000000,00000000,00000000,00000000)
241  */
242 HMENU WINAPI FileMenu_Create (
243         COLORREF crBorderColor,
244         int nBorderWidth,
245         HBITMAP hBorderBmp,
246         int nSelHeight,
247         UINT uFlags)
248 {
249         MENUINFO        MenuInfo;
250         LPFMINFO        menudata;
251
252         HMENU hMenu = CreatePopupMenu();
253
254         TRACE("0x%08lx 0x%08x %p 0x%08x 0x%08x  hMenu=%p\n",
255         crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu);
256
257         menudata = (LPFMINFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
258         menudata->crBorderColor = crBorderColor;
259         menudata->nBorderWidth = nBorderWidth;
260         menudata->hBorderBmp = hBorderBmp;
261
262         MenuInfo.cbSize = sizeof(MENUINFO);
263         MenuInfo.fMask = MIM_MENUDATA;
264         MenuInfo.dwMenuData = (DWORD) menudata;
265         SetMenuInfo (hMenu, &MenuInfo);
266
267         return hMenu;
268 }
269
270 /*************************************************************************
271  * FileMenu_Destroy                             [SHELL32.118]
272  *
273  * NOTES
274  *  exported by name
275  */
276 void WINAPI FileMenu_Destroy (HMENU hmenu)
277 {
278         LPFMINFO        menudata;
279
280         TRACE("%p\n", hmenu);
281
282         FileMenu_DeleteAllItems (hmenu);
283
284         menudata = FM_GetMenuInfo(hmenu);
285
286         if ( menudata->pidl)
287         { SHFree( menudata->pidl);
288         }
289         HeapFree(GetProcessHeap(), 0, menudata);
290
291         DestroyMenu (hmenu);
292 }
293
294 /*************************************************************************
295  * FileMenu_AppendItem                  [SHELL32.115]
296  *
297  */
298 static BOOL FileMenu_AppendItemA(
299         HMENU hMenu,
300         LPCSTR lpText,
301         UINT uID,
302         int icon,
303         HMENU hMenuPopup,
304         int nItemHeight)
305 {
306         LPSTR lpszText = (LPSTR)lpText;
307         MENUITEMINFOA   mii;
308         LPFMITEM        myItem;
309         LPFMINFO        menudata;
310         MENUINFO        MenuInfo;
311
312
313         TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n",
314         hMenu, (lpszText!=FM_SEPARATOR) ? lpText: NULL,
315         uID, icon, hMenuPopup, nItemHeight);
316
317         ZeroMemory (&mii, sizeof(MENUITEMINFOA));
318
319         mii.cbSize = sizeof(MENUITEMINFOA);
320
321         if (lpText != FM_SEPARATOR)
322         { int len = strlen (lpText);
323           myItem = (LPFMITEM) SHAlloc( sizeof(FMITEM) + len);
324           strcpy (myItem->szItemText, lpText);
325           myItem->cchItemText = len;
326           myItem->iIconIndex = icon;
327           myItem->hMenu = hMenu;
328           mii.fMask = MIIM_DATA;
329           mii.dwItemData = (DWORD) myItem;
330         }
331
332         if ( hMenuPopup )
333         { /* sub menu */
334           mii.fMask |= MIIM_TYPE | MIIM_SUBMENU;
335           mii.fType = MFT_OWNERDRAW;
336           mii.hSubMenu = hMenuPopup;
337         }
338         else if (lpText == FM_SEPARATOR )
339         { mii.fMask |= MIIM_ID | MIIM_TYPE;
340           mii.fType = MFT_SEPARATOR;
341         }
342         else
343         { /* normal item */
344           mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE;
345           mii.fState = MFS_ENABLED | MFS_DEFAULT;
346           mii.fType = MFT_OWNERDRAW;
347         }
348         mii.wID = uID;
349
350         InsertMenuItemA (hMenu, (UINT)-1, TRUE, &mii);
351
352         /* set bFixedItems to true */
353         MenuInfo.cbSize = sizeof(MENUINFO);
354         MenuInfo.fMask = MIM_MENUDATA;
355
356         if (! GetMenuInfo(hMenu, &MenuInfo))
357           return FALSE;
358
359         menudata = (LPFMINFO)MenuInfo.dwMenuData;
360         if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
361         {
362           ERR("menudata corrupt: %p %lu\n", menudata, MenuInfo.cbSize);
363           return 0;
364         }
365
366         menudata->bFixedItems = TRUE;
367         SetMenuInfo(hMenu, &MenuInfo);
368
369         return TRUE;
370
371 }
372
373 /**********************************************************************/
374
375 BOOL WINAPI FileMenu_AppendItemAW(
376         HMENU hMenu,
377         LPCVOID lpText,
378         UINT uID,
379         int icon,
380         HMENU hMenuPopup,
381         int nItemHeight)
382 {
383         BOOL ret;
384         LPSTR lpszText=NULL;
385
386         if (SHELL_OsIsUnicode() && (lpText!=FM_SEPARATOR))
387           lpszText = HEAP_strdupWtoA ( GetProcessHeap(),0, lpText);
388
389         ret = FileMenu_AppendItemA(hMenu, (lpszText) ? lpszText : lpText, uID, icon, hMenuPopup, nItemHeight);
390
391         if (lpszText)
392           HeapFree( GetProcessHeap(), 0, lpszText );
393
394         return ret;
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 wont 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    bAddSeperator)
470 {
471         LPFMINFO        menudata;
472
473         menudata = FM_GetMenuInfo(hmenu);
474
475         menudata->bInitialized = FALSE;
476
477         FM_InitMenuPopup(hmenu, pidl);
478
479         if (bAddSeperator)
480           FileMenu_AppendItemA (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT);
481
482         TRACE("%p %p 0x%08x\n",hmenu, pidl,bAddSeperator);
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, pMyItem->szItemText);
556
557         GetTextExtentPoint32A(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, BorderRect;
583         LPFMINFO menuinfo;
584
585         TRACE("%p %p %s\n", hWnd, lpdis, 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         BorderRect.right = menuinfo->nBorderWidth;
606 /*      FillRect(lpdis->hDC, &BorderRect, CreateSolidBrush( menuinfo->crBorderColor));
607 */
608         TextRect.left += FM_LEFTBORDER;
609         xi = TextRect.left + FM_SPACE1;
610         yi = TextRect.top + FM_Y_SPACE/2;
611         TextRect.bottom -= FM_Y_SPACE/2;
612
613         xt = xi + FM_ICON_SIZE + FM_SPACE2;
614         yt = yi;
615
616         ExtTextOutA (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL);
617
618         Shell_GetImageList(0, &hImageList);
619         ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL);
620
621         TRACE("-- 0x%04lx 0x%04lx 0x%04lx 0x%04lx\n", TextRect.left, TextRect.top, TextRect.right, TextRect.bottom);
622
623         SetTextColor(lpdis->hDC, clrPrevText);
624         SetBkColor(lpdis->hDC, clrPrevBkgnd);
625
626         return TRUE;
627 }
628
629 /*************************************************************************
630  * FileMenu_InitMenuPopup                       [SHELL32.109]
631  *
632  * NOTES
633  *  The filemenu is a ownerdrawn menu. Call this function responding to
634  *  WM_INITPOPUPMENU
635  *
636  */
637 BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu)
638 {
639         FM_InitMenuPopup(hmenu, NULL);
640         return TRUE;
641 }
642
643 /*************************************************************************
644  * FileMenu_HandleMenuChar                      [SHELL32.108]
645  */
646 LRESULT WINAPI FileMenu_HandleMenuChar(
647         HMENU   hMenu,
648         WPARAM  wParam)
649 {
650         FIXME("%p 0x%08x\n",hMenu,wParam);
651         return 0;
652 }
653
654 /*************************************************************************
655  * FileMenu_DeleteAllItems                      [SHELL32.104]
656  *
657  * NOTES
658  *  exported by name
659  */
660 BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu)
661 {
662         MENUITEMINFOA   mii;
663         LPFMINFO        menudata;
664
665         int i;
666
667         TRACE("%p\n", hmenu);
668
669         ZeroMemory ( &mii, sizeof(MENUITEMINFOA));
670         mii.cbSize = sizeof(MENUITEMINFOA);
671         mii.fMask = MIIM_SUBMENU|MIIM_DATA;
672
673         for (i = 0; i < GetMenuItemCount( hmenu ); i++)
674         { GetMenuItemInfoA(hmenu, i, TRUE, &mii );
675
676           if (mii.dwItemData)
677             SHFree((LPFMINFO)mii.dwItemData);
678
679           if (mii.hSubMenu)
680             FileMenu_Destroy(mii.hSubMenu);
681         }
682
683         while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){};
684
685         menudata = FM_GetMenuInfo(hmenu);
686
687         menudata->bInitialized = FALSE;
688
689         return TRUE;
690 }
691
692 /*************************************************************************
693  * FileMenu_DeleteItemByCmd                     [SHELL32.117]
694  *
695  */
696 BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID)
697 {
698         MENUITEMINFOA mii;
699
700         TRACE("%p 0x%08x\n", hMenu, uID);
701
702         ZeroMemory ( &mii, sizeof(MENUITEMINFOA));
703         mii.cbSize = sizeof(MENUITEMINFOA);
704         mii.fMask = MIIM_SUBMENU;
705
706         GetMenuItemInfoA(hMenu, uID, FALSE, &mii );
707         if ( mii.hSubMenu )
708         {
709           /* FIXME: Do what? */
710         }
711
712         DeleteMenu(hMenu, MF_BYCOMMAND, uID);
713         return TRUE;
714 }
715
716 /*************************************************************************
717  * FileMenu_DeleteItemByIndex                   [SHELL32.140]
718  */
719 BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos)
720 {
721         MENUITEMINFOA mii;
722
723         TRACE("%p 0x%08x\n", hMenu, uPos);
724
725         ZeroMemory ( &mii, sizeof(MENUITEMINFOA));
726         mii.cbSize = sizeof(MENUITEMINFOA);
727         mii.fMask = MIIM_SUBMENU;
728
729         GetMenuItemInfoA(hMenu, uPos, TRUE, &mii );
730         if ( mii.hSubMenu )
731         {
732           /* FIXME: Do what? */
733         }
734
735         DeleteMenu(hMenu, MF_BYPOSITION, uPos);
736         return TRUE;
737 }
738
739 /*************************************************************************
740  * FileMenu_DeleteItemByFirstID                 [SHELL32.141]
741  */
742 BOOL WINAPI FileMenu_DeleteItemByFirstID(
743         HMENU   hMenu,
744         UINT    uID)
745 {
746         TRACE("%p 0x%08x\n", hMenu, uID);
747         return 0;
748 }
749
750 /*************************************************************************
751  * FileMenu_DeleteSeparator                     [SHELL32.142]
752  */
753 BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu)
754 {
755         TRACE("%p\n", hMenu);
756         return 0;
757 }
758
759 /*************************************************************************
760  * FileMenu_EnableItemByCmd                     [SHELL32.143]
761  */
762 BOOL WINAPI FileMenu_EnableItemByCmd(
763         HMENU   hMenu,
764         UINT    uID,
765         BOOL    bEnable)
766 {
767         TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable);
768         return 0;
769 }
770
771 /*************************************************************************
772  * FileMenu_GetItemExtent                       [SHELL32.144]
773  *
774  * NOTES
775  *  if the menu is too big, entries are getting cut away!!
776  */
777 DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos)
778 {       RECT rect;
779
780         FIXME("%p 0x%08x\n", hMenu, uPos);
781
782         if (GetMenuItemRect(0, hMenu, uPos, &rect))
783         { FIXME("0x%04lx 0x%04lx 0x%04lx 0x%04lx\n",
784           rect.right, rect.left, rect.top, rect.bottom);
785           return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom);
786         }
787         return 0x00100010; /*FIXME*/
788 }
789
790 /*************************************************************************
791  * FileMenu_AbortInitMenu                       [SHELL32.120]
792  *
793  */
794 void WINAPI FileMenu_AbortInitMenu (void)
795 {       TRACE("\n");
796         bAbortInit = TRUE;
797 }
798
799 /*************************************************************************
800  * SHFind_InitMenuPopup                         [SHELL32.149]
801  *
802  *
803  * PARAMETERS
804  *  hMenu               [in] handle of menu previously created
805  *  hWndParent  [in] parent window
806  *  w                   [in] no pointer (0x209 over here) perhaps menu IDs ???
807  *  x                   [in] no pointer (0x226 over here)
808  *
809  * RETURNS
810  *  LPXXXXX                      pointer to struct containing a func addr at offset 8
811  *                                       or NULL at failure.
812  */
813 LPVOID WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, DWORD w, DWORD x)
814 {       FIXME("hmenu=%p hwnd=%p 0x%08lx 0x%08lx stub\n",
815                 hMenu,hWndParent,w,x);
816         return NULL; /* this is supposed to be a pointer */
817 }
818
819 /*************************************************************************
820  * Shell_MergeMenus                             [SHELL32.67]
821  *
822  */
823 BOOL _SHIsMenuSeparator(HMENU hm, int i)
824 {
825         MENUITEMINFOA mii;
826
827         mii.cbSize = sizeof(MENUITEMINFOA);
828         mii.fMask = MIIM_TYPE;
829         mii.cch = 0;    /* WARNING: We MUST initialize it to 0*/
830         if (!GetMenuItemInfoA(hm, i, TRUE, &mii))
831         {
832           return(FALSE);
833         }
834
835         if (mii.fType & MFT_SEPARATOR)
836         {
837           return(TRUE);
838         }
839
840         return(FALSE);
841 }
842
843 /**********************************************************************/
844
845 HRESULT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
846 {       int             nItem;
847         HMENU           hmSubMenu;
848         BOOL            bAlreadySeparated;
849         MENUITEMINFOA   miiSrc;
850         char            szName[256];
851         UINT            uTemp, uIDMax = uIDAdjust;
852
853         TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x  0x%04lx\n",
854                  hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);
855
856         if (!hmDst || !hmSrc)
857         { return uIDMax;
858         }
859
860         nItem = GetMenuItemCount(hmDst);
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(MENUITEMINFOA);
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);
891
892           if (!GetMenuItemInfoA(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 (!InsertMenuItemA(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               InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
981             }
982           }
983         }
984         return(uIDMax);
985 }