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