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