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