99810dc45a845add995536d968d34cd5a49e6f10
[reactos.git] / reactos / lib / 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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 *
822 * PARAMETERS
823 * hMenu [in] handle of menu previously created
824 * hWndParent [in] parent window
825 * w [in] no pointer (0x209 over here) perhaps menu IDs ???
826 * x [in] no pointer (0x226 over here)
827 *
828 * RETURNS
829 * LPXXXXX pointer to struct containing a func addr at offset 8
830 * or NULL at failure.
831 */
832 LPVOID WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, DWORD w, DWORD x)
833 {
834 FIXME("hmenu=%p hwnd=%p 0x%08lx 0x%08lx stub\n",
835 hMenu,hWndParent,w,x);
836 return NULL; /* this is supposed to be a pointer */
837 }
838
839 /*************************************************************************
840 * _SHIsMenuSeparator (internal)
841 */
842 static BOOL _SHIsMenuSeparator(HMENU hm, int i)
843 {
844 MENUITEMINFOW mii;
845
846 mii.cbSize = sizeof(MENUITEMINFOW);
847 mii.fMask = MIIM_TYPE;
848 mii.cch = 0; /* WARNING: We MUST initialize it to 0*/
849 if (!GetMenuItemInfoW(hm, i, TRUE, &mii))
850 {
851 return(FALSE);
852 }
853
854 if (mii.fType & MFT_SEPARATOR)
855 {
856 return(TRUE);
857 }
858
859 return(FALSE);
860 }
861
862 /*************************************************************************
863 * Shell_MergeMenus [SHELL32.67]
864 */
865 HRESULT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
866 { int nItem;
867 HMENU hmSubMenu;
868 BOOL bAlreadySeparated;
869 MENUITEMINFOW miiSrc;
870 WCHAR szName[256];
871 UINT uTemp, uIDMax = uIDAdjust;
872
873 TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x 0x%04lx\n",
874 hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);
875
876 if (!hmDst || !hmSrc)
877 { return uIDMax;
878 }
879
880 nItem = GetMenuItemCount(hmDst);
881
882 if (uInsert >= (UINT)nItem) /* insert position inside menu? */
883 {
884 uInsert = (UINT)nItem; /* append on the end */
885 bAlreadySeparated = TRUE;
886 }
887 else
888 {
889 bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);
890 }
891
892 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
893 {
894 /* Add a separator between the menus */
895 InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
896 bAlreadySeparated = TRUE;
897 }
898
899
900 /* Go through the menu items and clone them*/
901 for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--)
902 {
903 miiSrc.cbSize = sizeof(MENUITEMINFOW);
904 miiSrc.fMask = MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;
905
906 /* We need to reset this every time through the loop in case menus DON'T have IDs*/
907 miiSrc.fType = MFT_STRING;
908 miiSrc.dwTypeData = szName;
909 miiSrc.dwItemData = 0;
910 miiSrc.cch = sizeof(szName)/sizeof(WCHAR);
911
912 if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc))
913 {
914 continue;
915 }
916
917 /* 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);
918 */
919 if (miiSrc.fType & MFT_SEPARATOR)
920 {
921 /* This is a separator; don't put two of them in a row */
922 if (bAlreadySeparated)
923 continue;
924
925 bAlreadySeparated = TRUE;
926 }
927 else if (miiSrc.hSubMenu)
928 {
929 if (uFlags & MM_SUBMENUSHAVEIDS)
930 {
931 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */
932
933 if (miiSrc.wID > uIDAdjustMax) /* skip ID's higher uIDAdjustMax */
934 continue;
935
936 if (uIDMax <= miiSrc.wID) /* remember the highest ID */
937 uIDMax = miiSrc.wID + 1;
938 }
939 else
940 {
941 miiSrc.fMask &= ~MIIM_ID; /* Don't set IDs for submenus that didn't have them already */
942 }
943 hmSubMenu = miiSrc.hSubMenu;
944
945 miiSrc.hSubMenu = CreatePopupMenu();
946
947 if (!miiSrc.hSubMenu) return(uIDMax);
948
949 uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS);
950
951 if (uIDMax <= uTemp)
952 uIDMax = uTemp;
953
954 bAlreadySeparated = FALSE;
955 }
956 else /* normal menu item */
957 {
958 miiSrc.wID += uIDAdjust; /* add uIDAdjust to the ID */
959
960 if (miiSrc.wID > uIDAdjustMax) /* skip ID's higher uIDAdjustMax */
961 continue;
962
963 if (uIDMax <= miiSrc.wID) /* remember the highest ID */
964 uIDMax = miiSrc.wID + 1;
965
966 bAlreadySeparated = FALSE;
967 }
968
969 /* 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);
970 */
971 if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc))
972 {
973 return(uIDMax);
974 }
975 }
976
977 /* Ensure the correct number of separators at the beginning of the
978 inserted menu items*/
979 if (uInsert == 0)
980 {
981 if (bAlreadySeparated)
982 {
983 DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
984 }
985 }
986 else
987 {
988 if (_SHIsMenuSeparator(hmDst, uInsert-1))
989 {
990 if (bAlreadySeparated)
991 {
992 DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
993 }
994 }
995 else
996 {
997 if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
998 {
999 /* Add a separator between the menus*/
1000 InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
1001 }
1002 }
1003 }
1004 return(uIDMax);
1005 }