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