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