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