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