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