shlmenu.c 34.4 KB
Newer Older
1
/*
2
 * see www.geocities.com/SiliconValley/4942/filemenu.html
3 4
 *
 * Copyright 1999, 2000 Juergen Schmied
5
 * Copyright 2011 Jay Yang
6 7 8 9 10 11 12 13 14 15 16 17 18
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
19
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20
 */
21

22
#include <stdarg.h>
23 24
#include <string.h>

25 26
#define COBJMACROS

27 28
#include "windef.h"
#include "winbase.h"
29
#include "winreg.h"
30 31
#include "wingdi.h"
#include "winuser.h"
32
#include "shlobj.h"
33
#include "undocshell.h"
34
#include "shlwapi.h"
35 36 37
#include "shell32_main.h"

#include "pidl.h"
38
#include "wine/debug.h"
39
#include "debughlp.h"
40

41 42 43 44 45 46
#ifdef FM_SEPARATOR
#undef FM_SEPARATOR
#endif
#define FM_SEPARATOR (LPCWSTR)1

static BOOL FileMenu_AppendItemW(HMENU hMenu, LPCWSTR lpText, UINT uID, int icon,
47
                                 HMENU hMenuPopup, int nItemHeight);
48 49

typedef struct
Juergen Schmied's avatar
Juergen Schmied committed
50 51 52
{
	BOOL		bInitialized;
	BOOL		bFixedItems;
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
	/* create */
	COLORREF	crBorderColor;
	int		nBorderWidth;
	HBITMAP		hBorderBmp;

	/* insert using pidl */
	LPITEMIDLIST	pidl;
	UINT		uID;
	UINT		uFlags;
	UINT		uEnumFlags;
	LPFNFMCALLBACK lpfnCallback;
} FMINFO, *LPFMINFO;

typedef struct
{	int	cchItemText;
	int	iIconIndex;
	HMENU	hMenu;
70
	WCHAR	szItemText[1];
71 72 73 74 75 76
} FMITEM, * LPFMITEM;

static BOOL bAbortInit;

#define	CCH_MAXITEMTEXT 256

77
WINE_DEFAULT_DEBUG_CHANNEL(shell);
78

Mike McCormack's avatar
Mike McCormack committed
79 80 81
static LPFMINFO FM_GetMenuInfo(HMENU hmenu)
{
	MENUINFO	MenuInfo;
82 83 84 85 86 87 88 89 90 91
	LPFMINFO	menudata;

	MenuInfo.cbSize = sizeof(MENUINFO);
	MenuInfo.fMask = MIM_MENUDATA;

	if (! GetMenuInfo(hmenu, &MenuInfo))
	  return NULL;

	menudata = (LPFMINFO)MenuInfo.dwMenuData;

Juergen Schmied's avatar
Juergen Schmied committed
92 93
	if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
	{
94
	  ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
Juergen Schmied's avatar
Juergen Schmied committed
95 96
	  return 0;
	}
97

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
	return menudata;

}
/*************************************************************************
 * FM_SetMenuParameter				[internal]
 *
 */
static LPFMINFO FM_SetMenuParameter(
	HMENU hmenu,
	UINT uID,
	LPCITEMIDLIST pidl,
	UINT uFlags,
	UINT uEnumFlags,
	LPFNFMCALLBACK lpfnCallback)
{
	LPFMINFO	menudata;

115
	TRACE("\n");
116

117
	menudata = FM_GetMenuInfo(hmenu);
118

119
	SHFree(menudata->pidl);
120

121 122 123 124 125 126 127 128
	menudata->uID = uID;
	menudata->pidl = ILClone(pidl);
	menudata->uFlags = uFlags;
	menudata->uEnumFlags = uEnumFlags;
	menudata->lpfnCallback = lpfnCallback;

	return menudata;
}
129

130 131 132 133
/*************************************************************************
 * FM_InitMenuPopup				[internal]
 *
 */
134
static int FM_InitMenuPopup(HMENU hmenu, LPCITEMIDLIST pAlternatePidl)
135
{	IShellFolder	*lpsf, *lpsf2;
136
	ULONG		ulItemAttr = SFGAO_FOLDER;
137
	UINT		uID, uEnumFlags;
138
	LPFNFMCALLBACK	lpfnCallback;
139
	LPCITEMIDLIST	pidl;
140
	WCHAR		sTemp[MAX_PATH];
141 142 143 144
	int		NumberOfItems = 0, iIcon;
	MENUINFO	MenuInfo;
	LPFMINFO	menudata;

145
	TRACE("%p %p\n", hmenu, pAlternatePidl);
146 147 148 149 150 151 152 153

	MenuInfo.cbSize = sizeof(MENUINFO);
	MenuInfo.fMask = MIM_MENUDATA;

	if (! GetMenuInfo(hmenu, &MenuInfo))
	  return FALSE;

	menudata = (LPFMINFO)MenuInfo.dwMenuData;
154

Juergen Schmied's avatar
Juergen Schmied committed
155 156
	if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
	{
157
	  ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
Juergen Schmied's avatar
Juergen Schmied committed
158 159
	  return 0;
	}
160

161 162
	if (menudata->bInitialized)
	  return 0;
163

164
	pidl = (pAlternatePidl? pAlternatePidl: menudata->pidl);
Juergen Schmied's avatar
Juergen Schmied committed
165 166 167 168
	if (!pidl)
	  return 0;

	uID = menudata->uID;
169 170 171
	uEnumFlags = menudata->uEnumFlags;
	lpfnCallback = menudata->lpfnCallback;
	menudata->bInitialized = FALSE;
Juergen Schmied's avatar
Juergen Schmied committed
172

173
	SetMenuInfo(hmenu, &MenuInfo);
174

175 176
	if (SUCCEEDED (SHGetDesktopFolder(&lpsf)))
	{
177
	  if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,&IID_IShellFolder,(LPVOID *)&lpsf2)))
178 179 180 181 182 183 184 185 186
	  {
	    IEnumIDList	*lpe = NULL;

	    if (SUCCEEDED (IShellFolder_EnumObjects(lpsf2, 0, uEnumFlags, &lpe )))
	    {

	      LPITEMIDLIST pidlTemp = NULL;
	      ULONG ulFetched;

187
	      while ((!bAbortInit) && (S_OK == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched)))
188
	      {
189
		if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, (LPCITEMIDLIST*)&pidlTemp, &ulItemAttr)))
190
		{
191
		  ILGetDisplayNameExW(NULL, pidlTemp, sTemp, ILGDN_FORPARSING);
192
		  if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon)))
193 194 195 196 197 198
		    iIcon = FM_BLANK_ICON;
		  if ( SFGAO_FOLDER & ulItemAttr)
		  {
		    LPFMINFO lpFmMi;
		    MENUINFO MenuInfo;
		    HMENU hMenuPopup = CreatePopupMenu();
199

200
		    lpFmMi = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
201 202 203 204 205 206

		    lpFmMi->pidl = ILCombine(pidl, pidlTemp);
		    lpFmMi->uEnumFlags = SHCONTF_FOLDERS | SHCONTF_NONFOLDERS;

		    MenuInfo.cbSize = sizeof(MENUINFO);
		    MenuInfo.fMask = MIM_MENUDATA;
Kevin Koltzau's avatar
Kevin Koltzau committed
207
		    MenuInfo.dwMenuData = (ULONG_PTR) lpFmMi;
208 209
		    SetMenuInfo (hMenuPopup, &MenuInfo);

210
		    FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT);
211 212 213
		  }
		  else
		  {
214 215 216 217
		    LPWSTR pExt = PathFindExtensionW(sTemp);
		    if (pExt)
		      *pExt = 0;
		    FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT);
218 219 220 221 222
		  }
		}

		if (lpfnCallback)
		{
223
		  TRACE("enter callback\n");
224
		  lpfnCallback ( pidl, pidlTemp);
225
		  TRACE("leave callback\n");
226 227 228 229 230 231 232 233 234 235 236 237
		}

		NumberOfItems++;
	      }
	      IEnumIDList_Release (lpe);
	    }
	    IShellFolder_Release(lpsf2);
	  }
	  IShellFolder_Release(lpsf);
	}

	if ( GetMenuItemCount (hmenu) == 0 )
238 239 240
	{
          static const WCHAR szEmpty[] = { '(','e','m','p','t','y',')',0 };
	  FileMenu_AppendItemW (hmenu, szEmpty, uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT);
Juergen Schmied's avatar
Juergen Schmied committed
241 242
	  NumberOfItems++;
	}
243 244 245 246 247 248

	menudata->bInitialized = TRUE;
	SetMenuInfo(hmenu, &MenuInfo);

	return NumberOfItems;
}
249 250 251
/*************************************************************************
 * FileMenu_Create				[SHELL32.114]
 *
Juergen Schmied's avatar
Juergen Schmied committed
252 253
 * NOTES
 *  for non-root menus values are
254
 *  (ffffffff,00000000,00000000,00000000,00000000)
255 256 257 258 259 260 261 262
 */
HMENU WINAPI FileMenu_Create (
	COLORREF crBorderColor,
	int nBorderWidth,
	HBITMAP hBorderBmp,
	int nSelHeight,
	UINT uFlags)
{
263 264
	MENUINFO	MenuInfo;
	LPFMINFO	menudata;
265

266
	HMENU hMenu = CreatePopupMenu();
267

268
	TRACE("0x%08x 0x%08x %p 0x%08x 0x%08x  hMenu=%p\n",
269 270
	crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu);

271
	menudata = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(FMINFO));
272 273 274 275 276 277
	menudata->crBorderColor = crBorderColor;
	menudata->nBorderWidth = nBorderWidth;
	menudata->hBorderBmp = hBorderBmp;

	MenuInfo.cbSize = sizeof(MENUINFO);
	MenuInfo.fMask = MIM_MENUDATA;
Kevin Koltzau's avatar
Kevin Koltzau committed
278
	MenuInfo.dwMenuData = (ULONG_PTR) menudata;
279 280 281
	SetMenuInfo (hMenu, &MenuInfo);

	return hMenu;
282 283 284 285 286 287 288 289
}

/*************************************************************************
 * FileMenu_Destroy				[SHELL32.118]
 *
 * NOTES
 *  exported by name
 */
290
void WINAPI FileMenu_Destroy (HMENU hmenu)
291
{
292 293
	LPFMINFO	menudata;

294
	TRACE("%p\n", hmenu);
295 296

	FileMenu_DeleteAllItems (hmenu);
297

298 299
	menudata = FM_GetMenuInfo(hmenu);

300
	SHFree( menudata->pidl);
301 302 303
	HeapFree(GetProcessHeap(), 0, menudata);

	DestroyMenu (hmenu);
304 305 306
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
307
 * FileMenu_AppendItem			[SHELL32.115]
308 309
 *
 */
310
static BOOL FileMenu_AppendItemW(
311
	HMENU hMenu,
312
	LPCWSTR lpText,
313 314 315 316 317
	UINT uID,
	int icon,
	HMENU hMenuPopup,
	int nItemHeight)
{
318
	MENUITEMINFOW	mii;
Juergen Schmied's avatar
Juergen Schmied committed
319 320 321 322
	LPFMITEM	myItem;
	LPFMINFO	menudata;
	MENUINFO        MenuInfo;

323

324
	TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n",
325 326
	  hMenu, (lpText!=FM_SEPARATOR) ? debugstr_w(lpText) : NULL,
	  uID, icon, hMenuPopup, nItemHeight);
327

328
	ZeroMemory (&mii, sizeof(MENUITEMINFOW));
329

330
	mii.cbSize = sizeof(MENUITEMINFOW);
331 332

	if (lpText != FM_SEPARATOR)
333 334
	{
	  int len = strlenW (lpText);
335
          myItem = SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR));
336
	  strcpyW (myItem->szItemText, lpText);
337 338 339 340
	  myItem->cchItemText = len;
	  myItem->iIconIndex = icon;
	  myItem->hMenu = hMenu;
	  mii.fMask = MIIM_DATA;
Kevin Koltzau's avatar
Kevin Koltzau committed
341
	  mii.dwItemData = (ULONG_PTR) myItem;
342
	}
343

344 345
	if ( hMenuPopup )
	{ /* sub menu */
346 347
	  mii.fMask |= MIIM_TYPE | MIIM_SUBMENU;
	  mii.fType = MFT_OWNERDRAW;
348 349 350
	  mii.hSubMenu = hMenuPopup;
	}
	else if (lpText == FM_SEPARATOR )
351
	{ mii.fMask |= MIIM_ID | MIIM_TYPE;
352 353 354 355
	  mii.fType = MFT_SEPARATOR;
	}
	else
	{ /* normal item */
356
	  mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE;
357
	  mii.fState = MFS_ENABLED | MFS_DEFAULT;
358
	  mii.fType = MFT_OWNERDRAW;
359 360 361
	}
	mii.wID = uID;

362
	InsertMenuItemW (hMenu, (UINT)-1, TRUE, &mii);
363

Juergen Schmied's avatar
Juergen Schmied committed
364 365 366 367 368 369 370 371
	/* set bFixedItems to true */
	MenuInfo.cbSize = sizeof(MENUINFO);
	MenuInfo.fMask = MIM_MENUDATA;

	if (! GetMenuInfo(hMenu, &MenuInfo))
	  return FALSE;

	menudata = (LPFMINFO)MenuInfo.dwMenuData;
Juergen Schmied's avatar
Juergen Schmied committed
372 373
	if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
	{
374
	  ERR("menudata corrupt: %p %u\n", menudata, MenuInfo.cbSize);
375
	  return FALSE;
Juergen Schmied's avatar
Juergen Schmied committed
376 377
	}

Juergen Schmied's avatar
Juergen Schmied committed
378 379 380
	menudata->bFixedItems = TRUE;
	SetMenuInfo(hMenu, &MenuInfo);

381 382 383
	return TRUE;

}
384 385 386

/**********************************************************************/

387 388 389 390 391 392 393 394 395 396
BOOL WINAPI FileMenu_AppendItemAW(
	HMENU hMenu,
	LPCVOID lpText,
	UINT uID,
	int icon,
	HMENU hMenuPopup,
	int nItemHeight)
{
	BOOL ret;

397 398 399
        if (!lpText) return FALSE;

	if (SHELL_OsIsUnicode() || lpText == FM_SEPARATOR)
400 401 402 403 404
	  ret = FileMenu_AppendItemW(hMenu, lpText, uID, icon, hMenuPopup, nItemHeight);
        else
	{
	  DWORD len = MultiByteToWideChar( CP_ACP, 0, lpText, -1, NULL, 0 );
	  LPWSTR lpszText = HeapAlloc ( GetProcessHeap(), 0, len*sizeof(WCHAR) );
405
	  if (!lpszText) return FALSE;
406 407
	  MultiByteToWideChar( CP_ACP, 0, lpText, -1, lpszText, len );
	  ret = FileMenu_AppendItemW(hMenu, lpszText, uID, icon, hMenuPopup, nItemHeight);
408
	  HeapFree( GetProcessHeap(), 0, lpszText );
409
	}
410 411 412

	return ret;
}
Mike McCormack's avatar
Mike McCormack committed
413

414 415 416 417 418 419 420
/*************************************************************************
 * FileMenu_InsertUsingPidl			[SHELL32.110]
 *
 * NOTES
 *	uEnumFlags	any SHCONTF flag
 */
int WINAPI FileMenu_InsertUsingPidl (
421
	HMENU hmenu,
422 423 424 425 426
	UINT uID,
	LPCITEMIDLIST pidl,
	UINT uFlags,
	UINT uEnumFlags,
	LPFNFMCALLBACK lpfnCallback)
427
{
428
	TRACE("%p 0x%08x %p 0x%08x 0x%08x %p\n",
429
	hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
430 431 432

	pdump (pidl);

433
	bAbortInit = FALSE;
434

435
	FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
436 437

	return FM_InitMenuPopup(hmenu, NULL);
438 439 440 441 442
}

/*************************************************************************
 * FileMenu_ReplaceUsingPidl			[SHELL32.113]
 *
443
 * FIXME: the static items are deleted but won't be refreshed
444 445
 */
int WINAPI FileMenu_ReplaceUsingPidl(
446
	HMENU	hmenu,
447 448 449 450 451
	UINT	uID,
	LPCITEMIDLIST	pidl,
	UINT	uEnumFlags,
	LPFNFMCALLBACK lpfnCallback)
{
452
	TRACE("%p 0x%08x %p 0x%08x %p\n",
453
	hmenu, uID, pidl, uEnumFlags, lpfnCallback);
454

455 456
	FileMenu_DeleteAllItems (hmenu);

457
	FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback);
458 459

	return FM_InitMenuPopup(hmenu, NULL);
460 461 462 463 464 465 466
}

/*************************************************************************
 * FileMenu_Invalidate			[SHELL32.111]
 */
void WINAPI FileMenu_Invalidate (HMENU hMenu)
{
467
	FIXME("%p\n",hMenu);
468 469 470 471 472 473 474 475 476
}

/*************************************************************************
 * FileMenu_FindSubMenuByPidl			[SHELL32.106]
 */
HMENU WINAPI FileMenu_FindSubMenuByPidl(
	HMENU	hMenu,
	LPCITEMIDLIST	pidl)
{
477
	FIXME("%p %p\n",hMenu, pidl);
478 479 480 481 482 483
	return 0;
}

/*************************************************************************
 * FileMenu_AppendFilesForPidl			[SHELL32.124]
 */
484
int WINAPI FileMenu_AppendFilesForPidl(
485
	HMENU	hmenu,
486
	LPCITEMIDLIST	pidl,
487
	BOOL	bAddSeparator)
488
{
489 490 491
	LPFMINFO	menudata;

	menudata = FM_GetMenuInfo(hmenu);
492

493
	menudata->bInitialized = FALSE;
494

495 496
	FM_InitMenuPopup(hmenu, pidl);

497
	if (bAddSeparator)
498
	  FileMenu_AppendItemW (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT);
499

500
	TRACE("%p %p 0x%08x\n",hmenu, pidl,bAddSeparator);
501

502 503 504 505 506 507 508 509 510
	return 0;
}
/*************************************************************************
 * FileMenu_AddFilesForPidl			[SHELL32.125]
 *
 * NOTES
 *	uEnumFlags	any SHCONTF flag
 */
int WINAPI FileMenu_AddFilesForPidl (
511
	HMENU	hmenu,
512 513 514 515 516 517 518
	UINT	uReserved,
	UINT	uID,
	LPCITEMIDLIST	pidl,
	UINT	uFlags,
	UINT	uEnumFlags,
	LPFNFMCALLBACK	lpfnCallback)
{
519
	TRACE("%p 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n",
520 521 522
	hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback);

	return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
523 524 525 526 527 528 529

}


/*************************************************************************
 * FileMenu_TrackPopupMenuEx			[SHELL32.116]
 */
530
BOOL WINAPI FileMenu_TrackPopupMenuEx (
531 532 533 534 535 536 537
	HMENU hMenu,
	UINT uFlags,
	int x,
	int y,
	HWND hWnd,
	LPTPMPARAMS lptpm)
{
538
	TRACE("%p 0x%08x 0x%x 0x%x %p %p\n",
539 540 541 542 543 544 545 546 547 548 549 550
	hMenu, uFlags, x, y, hWnd, lptpm);
	return TrackPopupMenuEx(hMenu, uFlags, x, y, hWnd, lptpm);
}

/*************************************************************************
 * FileMenu_GetLastSelectedItemPidls		[SHELL32.107]
 */
BOOL WINAPI FileMenu_GetLastSelectedItemPidls(
	UINT	uReserved,
	LPCITEMIDLIST	*ppidlFolder,
	LPCITEMIDLIST	*ppidlItem)
{
551
	FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem);
552
	return FALSE;
553 554
}

555 556 557 558 559 560
#define FM_ICON_SIZE	16
#define FM_Y_SPACE	4
#define FM_SPACE1	4
#define FM_SPACE2	2
#define FM_LEFTBORDER	2
#define FM_RIGHTBORDER	8
561 562 563 564 565 566 567
/*************************************************************************
 * FileMenu_MeasureItem				[SHELL32.112]
 */
LRESULT WINAPI FileMenu_MeasureItem(
	HWND	hWnd,
	LPMEASUREITEMSTRUCT	lpmis)
{
568 569 570 571
	LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData);
	HDC hdc = GetDC(hWnd);
	SIZE size;
	LPFMINFO menuinfo;
572

573
	TRACE("%p %p %s\n", hWnd, lpmis, debugstr_w(pMyItem->szItemText));
574

575
	GetTextExtentPoint32W(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size);
576

577 578 579 580 581
	lpmis->itemWidth = size.cx + FM_LEFTBORDER + FM_ICON_SIZE + FM_SPACE1 + FM_SPACE2 + FM_RIGHTBORDER;
	lpmis->itemHeight = (size.cy > (FM_ICON_SIZE + FM_Y_SPACE)) ? size.cy : (FM_ICON_SIZE + FM_Y_SPACE);

	/* add the menubitmap */
	menuinfo = FM_GetMenuInfo(pMyItem->hMenu);
Juergen Schmied's avatar
Juergen Schmied committed
582
	if (menuinfo->nBorderWidth)
583
	  lpmis->itemWidth += menuinfo->nBorderWidth;
584

585
	TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight);
586
	ReleaseDC (hWnd, hdc);
587 588 589 590 591 592 593 594 595
	return 0;
}
/*************************************************************************
 * FileMenu_DrawItem				[SHELL32.105]
 */
LRESULT WINAPI FileMenu_DrawItem(
	HWND			hWnd,
	LPDRAWITEMSTRUCT	lpdis)
{
596 597 598 599
	LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData);
	COLORREF clrPrevText, clrPrevBkgnd;
	int xi,yi,xt,yt;
	HIMAGELIST hImageList;
600
	RECT TextRect;
601
	LPFMINFO menuinfo;
602

603
	TRACE("%p %p %s\n", hWnd, lpdis, debugstr_w(pMyItem->szItemText));
604

605 606 607 608 609 610 611 612 613 614
	if (lpdis->itemState & ODS_SELECTED)
	{
	  clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHTTEXT));
	  clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_HIGHLIGHT));
	}
	else
	{
	  clrPrevText = SetTextColor(lpdis->hDC, GetSysColor (COLOR_MENUTEXT));
	  clrPrevBkgnd = SetBkColor(lpdis->hDC, GetSysColor (COLOR_MENU));
	}
615

616
        TextRect = lpdis->rcItem;
617 618 619

	/* add the menubitmap */
	menuinfo = FM_GetMenuInfo(pMyItem->hMenu);
Juergen Schmied's avatar
Juergen Schmied committed
620
	if (menuinfo->nBorderWidth)
621
	  TextRect.left += menuinfo->nBorderWidth;
622

623 624 625 626 627 628 629 630
	TextRect.left += FM_LEFTBORDER;
	xi = TextRect.left + FM_SPACE1;
	yi = TextRect.top + FM_Y_SPACE/2;
	TextRect.bottom -= FM_Y_SPACE/2;

	xt = xi + FM_ICON_SIZE + FM_SPACE2;
	yt = yi;

631
	ExtTextOutW (lpdis->hDC, xt , yt, ETO_OPAQUE, &TextRect, pMyItem->szItemText, pMyItem->cchItemText, NULL);
632

633
	Shell_GetImageLists(0, &hImageList);
634
	ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL);
635

636
        TRACE("-- %s\n", wine_dbgstr_rect(&TextRect));
637

638 639 640 641
	SetTextColor(lpdis->hDC, clrPrevText);
	SetBkColor(lpdis->hDC, clrPrevBkgnd);

	return TRUE;
642 643 644 645 646 647
}

/*************************************************************************
 * FileMenu_InitMenuPopup			[SHELL32.109]
 *
 * NOTES
648
 *  The filemenu is an ownerdrawn menu. Call this function responding to
649 650 651
 *  WM_INITPOPUPMENU
 *
 */
652 653 654 655
BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu)
{
	FM_InitMenuPopup(hmenu, NULL);
	return TRUE;
656 657 658 659 660 661 662 663 664
}

/*************************************************************************
 * FileMenu_HandleMenuChar			[SHELL32.108]
 */
LRESULT WINAPI FileMenu_HandleMenuChar(
	HMENU	hMenu,
	WPARAM	wParam)
{
665
	FIXME("%p 0x%08lx\n",hMenu,wParam);
666 667 668 669 670 671 672 673 674
	return 0;
}

/*************************************************************************
 * FileMenu_DeleteAllItems			[SHELL32.104]
 *
 * NOTES
 *  exported by name
 */
675
BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu)
676
{
677
	MENUITEMINFOW	mii;
678 679 680
	LPFMINFO	menudata;

	int i;
681

682
	TRACE("%p\n", hmenu);
683

684 685
	ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
	mii.cbSize = sizeof(MENUITEMINFOW);
686 687 688
	mii.fMask = MIIM_SUBMENU|MIIM_DATA;

	for (i = 0; i < GetMenuItemCount( hmenu ); i++)
689
	{ GetMenuItemInfoW(hmenu, i, TRUE, &mii );
690

691
	  SHFree((LPFMINFO)mii.dwItemData);
692 693 694 695

	  if (mii.hSubMenu)
	    FileMenu_Destroy(mii.hSubMenu);
	}
696

697 698 699
	while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){};

	menudata = FM_GetMenuInfo(hmenu);
700

701
	menudata->bInitialized = FALSE;
702

703 704 705 706
	return TRUE;
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
707
 * FileMenu_DeleteItemByCmd 			[SHELL32.117]
708 709 710 711
 *
 */
BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID)
{
712
	MENUITEMINFOW mii;
713

714
	TRACE("%p 0x%08x\n", hMenu, uID);
715

716 717
	ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
	mii.cbSize = sizeof(MENUITEMINFOW);
718 719
	mii.fMask = MIIM_SUBMENU;

720
	GetMenuItemInfoW(hMenu, uID, FALSE, &mii );
721 722 723 724
	if ( mii.hSubMenu )
	{
	  /* FIXME: Do what? */
	}
725 726 727 728 729 730 731 732 733 734

	DeleteMenu(hMenu, MF_BYCOMMAND, uID);
	return TRUE;
}

/*************************************************************************
 * FileMenu_DeleteItemByIndex			[SHELL32.140]
 */
BOOL WINAPI FileMenu_DeleteItemByIndex ( HMENU hMenu, UINT uPos)
{
735
	MENUITEMINFOW mii;
736

737
	TRACE("%p 0x%08x\n", hMenu, uPos);
738

739 740
	ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
	mii.cbSize = sizeof(MENUITEMINFOW);
741 742
	mii.fMask = MIIM_SUBMENU;

743
	GetMenuItemInfoW(hMenu, uPos, TRUE, &mii );
744 745 746 747
	if ( mii.hSubMenu )
	{
	  /* FIXME: Do what? */
	}
748

749 750 751 752 753 754 755 756 757 758 759
	DeleteMenu(hMenu, MF_BYPOSITION, uPos);
	return TRUE;
}

/*************************************************************************
 * FileMenu_DeleteItemByFirstID			[SHELL32.141]
 */
BOOL WINAPI FileMenu_DeleteItemByFirstID(
	HMENU	hMenu,
	UINT	uID)
{
760
	TRACE("%p 0x%08x\n", hMenu, uID);
761
	return FALSE;
762 763 764 765 766 767 768
}

/*************************************************************************
 * FileMenu_DeleteSeparator			[SHELL32.142]
 */
BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu)
{
769
	TRACE("%p\n", hMenu);
770
	return FALSE;
771 772 773 774 775 776 777 778 779 780
}

/*************************************************************************
 * FileMenu_EnableItemByCmd			[SHELL32.143]
 */
BOOL WINAPI FileMenu_EnableItemByCmd(
	HMENU	hMenu,
	UINT	uID,
	BOOL	bEnable)
{
781
	TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable);
782
	return FALSE;
783 784 785 786
}

/*************************************************************************
 * FileMenu_GetItemExtent			[SHELL32.144]
787
 *
788
 * NOTES
789
 *  if the menu is too big, entries are getting cut away!!
790 791 792
 */
DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos)
{	RECT rect;
793

794
	FIXME("%p 0x%08x\n", hMenu, uPos);
795 796

	if (GetMenuItemRect(0, hMenu, uPos, &rect))
797 798
        {
          FIXME("%s\n", wine_dbgstr_rect(&rect));
799 800
	  return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom);
	}
801
	return 0x00100010; /*FIXME*/
802 803 804 805 806 807 808
}

/*************************************************************************
 * FileMenu_AbortInitMenu 			[SHELL32.120]
 *
 */
void WINAPI FileMenu_AbortInitMenu (void)
809
{	TRACE("\n");
810
	bAbortInit = TRUE;
811 812 813 814 815
}

/*************************************************************************
 * SHFind_InitMenuPopup				[SHELL32.149]
 *
816 817
 * Get the IContextMenu instance for the submenu of options displayed
 * for the Search entry in the Classic style Start menu.
818 819
 *
 * PARAMETERS
820
 *  hMenu		[in] handle of menu previously created
821
 *  hWndParent	[in] parent window
822 823 824 825 826 827
 *  w			[in] no pointer (0x209 over here) perhaps menu IDs ???
 *  x			[in] no pointer (0x226 over here)
 *
 * RETURNS
 *  LPXXXXX			 pointer to struct containing a func addr at offset 8
 *					 or NULL at failure.
828
 */
829
LPVOID WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, DWORD w, DWORD x)
Mike McCormack's avatar
Mike McCormack committed
830
{
831
	FIXME("hmenu=%p hwnd=%p 0x%08x 0x%08x stub\n",
832
		hMenu,hWndParent,w,x);
833
	return NULL; /* this is supposed to be a pointer */
834 835 836
}

/*************************************************************************
Mike McCormack's avatar
Mike McCormack committed
837
 * _SHIsMenuSeparator   (internal)
838
 */
Mike McCormack's avatar
Mike McCormack committed
839
static BOOL _SHIsMenuSeparator(HMENU hm, int i)
840
{
841
	MENUITEMINFOW mii;
842

843
	mii.cbSize = sizeof(MENUITEMINFOW);
844 845
	mii.fMask = MIIM_TYPE;
	mii.cch = 0;    /* WARNING: We MUST initialize it to 0*/
846
	if (!GetMenuItemInfoW(hm, i, TRUE, &mii))
847 848
	{
	  return(FALSE);
849 850 851
	}

	if (mii.fType & MFT_SEPARATOR)
852 853
	{
	  return(TRUE);
854 855
	}

856
	return(FALSE);
857
}
858

Mike McCormack's avatar
Mike McCormack committed
859 860 861
/*************************************************************************
 * Shell_MergeMenus				[SHELL32.67]
 */
862
UINT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
863 864 865
{	int		nItem;
	HMENU		hmSubMenu;
	BOOL		bAlreadySeparated;
866 867
	MENUITEMINFOW	miiSrc;
	WCHAR		szName[256];
868 869
	UINT		uTemp, uIDMax = uIDAdjust;

870
	TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x  0x%04x\n",
871 872 873
		 hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);

	if (!hmDst || !hmSrc)
874
	  return uIDMax;
875 876

	nItem = GetMenuItemCount(hmDst);
877 878
        if (nItem == -1)
	  return uIDMax;
879 880 881 882

	if (uInsert >= (UINT)nItem)	/* insert position inside menu? */
	{
	  uInsert = (UINT)nItem;	/* append on the end */
883 884 885
	  bAlreadySeparated = TRUE;
	}
	else
886
	{
887
	  bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);
888
	}
889

890
	if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
891 892
	{
	  /* Add a separator between the menus */
893 894 895 896 897 898 899
	  InsertMenuA(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
	  bAlreadySeparated = TRUE;
	}


	/* Go through the menu items and clone them*/
	for (nItem = GetMenuItemCount(hmSrc) - 1; nItem >= 0; nItem--)
900
	{
901
	  miiSrc.cbSize = sizeof(MENUITEMINFOW);
902 903 904
	  miiSrc.fMask =  MIIM_STATE | MIIM_ID | MIIM_SUBMENU | MIIM_CHECKMARKS | MIIM_TYPE | MIIM_DATA;

	  /* We need to reset this every time through the loop in case menus DON'T have IDs*/
905 906 907
	  miiSrc.fType = MFT_STRING;
	  miiSrc.dwTypeData = szName;
	  miiSrc.dwItemData = 0;
908
	  miiSrc.cch = sizeof(szName)/sizeof(WCHAR);
909

910
	  if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc))
911 912
	  {
	    continue;
913
	  }
914 915 916

/*	  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);
*/
917
	  if (miiSrc.fType & MFT_SEPARATOR)
918 919
	  {
	    /* This is a separator; don't put two of them in a row */
920
	    if (bAlreadySeparated)
921 922
	      continue;

923 924 925
	    bAlreadySeparated = TRUE;
	  }
	  else if (miiSrc.hSubMenu)
926 927 928 929 930
	  {
	    if (uFlags & MM_SUBMENUSHAVEIDS)
	    {
	      miiSrc.wID += uIDAdjust;			/* add uIDAdjust to the ID */

931
	      if (miiSrc.wID > uIDAdjustMax)		/* skip IDs higher than uIDAdjustMax */
932 933 934 935
	        continue;

	      if (uIDMax <= miiSrc.wID)			/* remember the highest ID */
	        uIDMax = miiSrc.wID + 1;
936 937
	    }
	    else
938 939
	    {
	      miiSrc.fMask &= ~MIIM_ID;			/* Don't set IDs for submenus that didn't have them already */
940 941
	    }
	    hmSubMenu = miiSrc.hSubMenu;
942

943
	    miiSrc.hSubMenu = CreatePopupMenu();
944 945 946 947 948

	    if (!miiSrc.hSubMenu) return(uIDMax);

	    uTemp = Shell_MergeMenus(miiSrc.hSubMenu, hmSubMenu, 0, uIDAdjust, uIDAdjustMax, uFlags & MM_SUBMENUSHAVEIDS);

949
	    if (uIDMax <= uTemp)
950 951
	      uIDMax = uTemp;

952 953
	    bAlreadySeparated = FALSE;
	  }
954 955 956 957
	  else						/* normal menu item */
	  {
	    miiSrc.wID += uIDAdjust;			/* add uIDAdjust to the ID */

958
	    if (miiSrc.wID > uIDAdjustMax)		/* skip IDs higher than uIDAdjustMax */
959 960 961 962 963
	      continue;

	    if (uIDMax <= miiSrc.wID)			/* remember the highest ID */
	      uIDMax = miiSrc.wID + 1;

964 965
	    bAlreadySeparated = FALSE;
	  }
966 967 968

/*	  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);
*/
969
	  if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc))
970 971
	  {
	    return(uIDMax);
972 973 974 975 976 977
	  }
	}

	/* Ensure the correct number of separators at the beginning of the
	inserted menu items*/
	if (uInsert == 0)
978 979 980 981
	{
	  if (bAlreadySeparated)
	  {
	    DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
982 983 984
	  }
	}
	else
985 986 987 988 989 990
	{
	  if (_SHIsMenuSeparator(hmDst, uInsert-1))
	  {
	    if (bAlreadySeparated)
	    {
	      DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
991 992 993
	    }
	  }
	  else
994 995 996 997
	  {
	    if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
	    {
	      /* Add a separator between the menus*/
998
	      InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
999 1000 1001 1002 1003
	    }
	  }
	}
	return(uIDMax);
}
1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090

typedef struct
{
    IContextMenu3 IContextMenu3_iface;
    IContextMenu **menus;
    UINT *offsets;
    UINT menu_count;
    ULONG refCount;
}CompositeCMenu;

static const IContextMenu3Vtbl CompositeCMenuVtbl;

static CompositeCMenu* impl_from_IContextMenu3(IContextMenu3* iface)
{
    return CONTAINING_RECORD(iface, CompositeCMenu, IContextMenu3_iface);
}

static HRESULT CompositeCMenu_Constructor(IContextMenu **menus,UINT menu_count, REFIID riid, void **ppv)
{
    CompositeCMenu *ret = HeapAlloc(GetProcessHeap(),0,sizeof(CompositeCMenu));
    UINT i;
    TRACE("(%p,%u,%s,%p)\n",menus,menu_count,shdebugstr_guid(riid),ppv);
    if(!ret)
        return E_OUTOFMEMORY;
    ret->IContextMenu3_iface.lpVtbl = &CompositeCMenuVtbl;
    ret->menu_count = menu_count;
    ret->menus = HeapAlloc(GetProcessHeap(),0,menu_count*sizeof(IContextMenu*));
    if(!ret->menus)
    {
        HeapFree(GetProcessHeap(),0,ret);
        return E_OUTOFMEMORY;
    }
    ret->offsets = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,menu_count*sizeof(UINT));
    if(!ret->offsets)
    {
        HeapFree(GetProcessHeap(),0,ret->menus);
        HeapFree(GetProcessHeap(),0,ret);
        return E_OUTOFMEMORY;
    }
    ret->refCount=0;
    memcpy(ret->menus,menus,menu_count*sizeof(IContextMenu*));
    for(i=0;i<menu_count;i++)
        IContextMenu_AddRef(menus[i]);
    return IContextMenu3_QueryInterface(&(ret->IContextMenu3_iface),riid,ppv);
}

static void CompositeCMenu_Destroy(CompositeCMenu *This)
{
    UINT i;
    for(i=0;i<This->menu_count;i++)
        IContextMenu_Release(This->menus[i]);
    HeapFree(GetProcessHeap(),0,This->menus);
    HeapFree(GetProcessHeap(),0,This->offsets);
    HeapFree(GetProcessHeap(),0,This);
}

static HRESULT WINAPI CompositeCMenu_QueryInterface(IContextMenu3 *iface, REFIID riid, void **ppv)
{
    TRACE("(%p)->(%s,%p)\n",iface,shdebugstr_guid(riid),ppv);
    if(!ppv)
        return E_INVALIDARG;
    if(IsEqualIID(riid,&IID_IUnknown) || IsEqualIID(riid,&IID_IContextMenu) ||
       IsEqualIID(riid,&IID_IContextMenu2) || IsEqualIID(riid,&IID_IContextMenu3))
        *ppv=iface;
    else
        return E_NOINTERFACE;
    IContextMenu3_AddRef(iface);
    return S_OK;
}

static ULONG WINAPI CompositeCMenu_AddRef(IContextMenu3 *iface)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    TRACE("(%p)->()\n",iface);
    return ++This->refCount;
}

static ULONG WINAPI CompositeCMenu_Release(IContextMenu3 *iface)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    TRACE("(%p)->()\n",iface);
    if(--This->refCount)
        return This->refCount;
    CompositeCMenu_Destroy(This);
    return 0;
}

1091
static UINT CompositeCMenu_GetIndexForCommandId(CompositeCMenu *This,UINT id)
1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
{
    UINT low=0;
    UINT high=This->menu_count;
    while(high-low!=1)
    {
        UINT i=(high+low)/2;
        if(This->offsets[i]<=id)
            low=i;
        else
            high=i;
    }
    return low;
}

static HRESULT WINAPI CompositeCMenu_GetCommandString(IContextMenu3* iface, UINT_PTR idCmd, UINT uFlags, UINT *pwReserved, LPSTR pszName, UINT cchMax)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    UINT index = CompositeCMenu_GetIndexForCommandId(This,idCmd);
    TRACE("(%p)->(%lx,%x,%p,%s,%u)\n",iface,idCmd,uFlags,pwReserved,pszName,cchMax);
    return IContextMenu_GetCommandString(This->menus[index],idCmd,uFlags,pwReserved,pszName,cchMax);
}

static HRESULT WINAPI CompositeCMenu_InvokeCommand(IContextMenu3* iface,LPCMINVOKECOMMANDINFO pici)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    TRACE("(%p)->(%p)\n",iface,pici);
    if(HIWORD(pici->lpVerb))
    {
        /*call each handler until one of them succeeds*/
        UINT i=0;
        for(;i<This->menu_count;i++)
        {
            HRESULT hres;
            if(SUCCEEDED(hres=IContextMenu_InvokeCommand(This->menus[i],pici)))
                return hres;
        }
        return E_FAIL;
    }
    else
    {
        UINT id = (UINT_PTR)pici->lpVerb;
        UINT index = CompositeCMenu_GetIndexForCommandId(This,id);
        return IContextMenu_InvokeCommand(This->menus[index],pici);
    }
}

static HRESULT WINAPI CompositeCMenu_QueryContextMenu(IContextMenu3 *iface, HMENU hmenu,UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    UINT i=0;
    UINT id_offset=idCmdFirst;
    TRACE("(%p)->(%p,%u,%u,%u,%x)\n",iface,hmenu,indexMenu,idCmdFirst,idCmdLast,uFlags);
    for(;i<This->menu_count;i++)
    {
        HRESULT hres;
        This->offsets[i]=id_offset;
        hres = IContextMenu_QueryContextMenu(This->menus[i],hmenu,indexMenu,id_offset,idCmdLast,uFlags);
        if(SUCCEEDED(hres))
            id_offset+=hres;
    }
    return MAKE_HRESULT(SEVERITY_SUCCESS, FACILITY_NULL, id_offset-idCmdFirst);
}

static HRESULT WINAPI CompositeCMenu_HandleMenuMsg(IContextMenu3 *iface, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    HMENU menu;
    UINT id;
    UINT index;
    IContextMenu2 *handler;
    HRESULT hres;
    TRACE("(%p)->(%x,%lx,%lx)\n",iface,uMsg,wParam,lParam);
    switch(uMsg)
    {
    case WM_INITMENUPOPUP:
        menu = (HMENU)wParam;
        id = GetMenuItemID(menu,LOWORD(lParam));
        break;
    case WM_DRAWITEM:
        id = ((DRAWITEMSTRUCT*)lParam)->itemID;
        break;
    case WM_MEASUREITEM:
        id = ((MEASUREITEMSTRUCT*)lParam)->itemID;
        break;
    default:
        WARN("Unimplemented uMsg: 0x%x\n",uMsg);
        return E_NOTIMPL;
    }
    index = CompositeCMenu_GetIndexForCommandId(This,id);
    hres = IContextMenu_QueryInterface(This->menus[index],&IID_IContextMenu2,
                                       (void**)&handler);
    if(SUCCEEDED(hres))
        return IContextMenu2_HandleMenuMsg(handler,uMsg,wParam,lParam);
    return S_OK;
}

static HRESULT WINAPI CompositeCMenu_HandleMenuMsg2(IContextMenu3 *iface, UINT uMsg, WPARAM wParam, LPARAM lParam,LRESULT *plResult)
{
    CompositeCMenu *This = impl_from_IContextMenu3(iface);
    HMENU menu;
    UINT id;
    UINT index;
    IContextMenu3 *handler;
    HRESULT hres;
    LRESULT lres;
    TRACE("(%p)->(%x,%lx,%lx,%p)\n",iface,uMsg,wParam,lParam,plResult);
    if(!plResult)
        plResult=&lres;
    switch(uMsg)
    {
    case WM_INITMENUPOPUP:
        menu = (HMENU)wParam;
        id = GetMenuItemID(menu,LOWORD(lParam));
        break;
    case WM_DRAWITEM:
        id = ((DRAWITEMSTRUCT*)lParam)->itemID;
        break;
    case WM_MEASUREITEM:
        id = ((MEASUREITEMSTRUCT*)lParam)->itemID;
        break;
    case WM_MENUCHAR:
        {
            UINT i=0;
            for(;i<This->menu_count;i++)
            {
                hres = IContextMenu_QueryInterface(This->menus[i],&IID_IContextMenu3,(void**)&handler);
                if(SUCCEEDED(hres))
                {
                    hres = IContextMenu3_HandleMenuMsg2(handler,uMsg,wParam,lParam,plResult);
                    if(SUCCEEDED(hres) && HIWORD(*plResult))
                        return hres;
                }
            }
        }
    default:
        WARN("Unimplemented uMsg: 0x%x\n",uMsg);
        return E_NOTIMPL;
    }
    index = CompositeCMenu_GetIndexForCommandId(This,id);
    hres = IContextMenu_QueryInterface(This->menus[index],&IID_IContextMenu3,(void**)&handler);
    if(SUCCEEDED(hres))
        return IContextMenu3_HandleMenuMsg2(handler,uMsg,wParam,lParam,plResult);
    return S_OK;
}

static const IContextMenu3Vtbl CompositeCMenuVtbl=
{
    CompositeCMenu_QueryInterface,
    CompositeCMenu_AddRef,
    CompositeCMenu_Release,
    CompositeCMenu_QueryContextMenu,
    CompositeCMenu_InvokeCommand,
    CompositeCMenu_GetCommandString,
    CompositeCMenu_HandleMenuMsg,
    CompositeCMenu_HandleMenuMsg2
};

1249
static HRESULT SHELL_CreateContextMenu(HWND hwnd, IContextMenu* system_menu,
1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277
                                IShellFolder *folder, LPCITEMIDLIST folder_pidl,
                                LPCITEMIDLIST *apidl, UINT cidl, const HKEY *aKeys,
                                UINT cKeys,REFIID riid, void** ppv)
{
    HRESULT ret;
    TRACE("(%p,%p,%p,%p,%p,%u,%p,%u,%s,%p)\n",hwnd,system_menu,folder,folder_pidl,apidl,cidl,aKeys,cKeys,shdebugstr_guid(riid),ppv);
    ret = CompositeCMenu_Constructor(&system_menu,1,riid,ppv);
    return ret;
}

HRESULT WINAPI CDefFolderMenu_Create2(LPCITEMIDLIST pidlFolder, HWND hwnd, UINT cidl,
                                      LPCITEMIDLIST *apidl, IShellFolder *psf,
                                      LPFNDFMCALLBACK lpfn, UINT nKeys, const HKEY *ahkeys,
                                      IContextMenu **ppcm)
{
    IContextMenu *system_menu;
    HRESULT hres;
    LPITEMIDLIST folder_pidl;
    TRACE("(%p,%p,%u,%p,%p,%u,%p,%p)\n",pidlFolder,hwnd,cidl,apidl,psf,nKeys,ahkeys,ppcm);
    if(!pidlFolder)
    {
        IPersistFolder2 *persist;
        IShellFolder_QueryInterface(psf,&IID_IPersistFolder2,(void**)&persist);
        IPersistFolder2_GetCurFolder(persist,&folder_pidl);
        IPersistFolder2_Release(persist);
    }
    else
        folder_pidl=ILClone(pidlFolder);
1278 1279

    ItemMenu_Constructor(psf, folder_pidl, (const LPCITEMIDLIST*)apidl, cidl, &IID_IContextMenu, (void**)&system_menu);
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303
    hres= SHELL_CreateContextMenu(hwnd,system_menu,psf,folder_pidl,apidl,cidl,ahkeys,nKeys,&IID_IContextMenu,(void**)ppcm);
    IContextMenu_Release(system_menu);
    ILFree(folder_pidl);
    return hres;
}

HRESULT WINAPI SHCreateDefaultContextMenu(const DEFCONTEXTMENU *pdcm, REFIID riid, void **ppv)
{
    IShellFolder *folder=pdcm->psf;
    LPITEMIDLIST folder_pidl;
    HRESULT ret;
    IContextMenu *system_menu;
    TRACE("(%p,%s,%p)\n",pdcm,shdebugstr_guid(riid),ppv);
    if(!pdcm->pidlFolder)
    {
        IPersistFolder2 *persist;
        IShellFolder_QueryInterface(folder,&IID_IPersistFolder2,(void**)&persist);
        IPersistFolder2_GetCurFolder(persist,&folder_pidl);
        IPersistFolder2_Release(persist);
    }
    else
        folder_pidl=ILClone(pdcm->pidlFolder);
    if(pdcm->cKeys==0)
        FIXME("Loading shell extensions using IQueryAssociations not yet supported\n");
1304 1305

    ItemMenu_Constructor(folder, folder_pidl, (const LPCITEMIDLIST*)pdcm->apidl, pdcm->cidl, &IID_IContextMenu, (void**)&system_menu);
1306 1307 1308 1309 1310
    ret = SHELL_CreateContextMenu(pdcm->hwnd,system_menu,folder,folder_pidl,(LPCITEMIDLIST*)pdcm->apidl,pdcm->cidl,pdcm->aKeys,pdcm->cKeys,riid,ppv);
    IContextMenu_Release(system_menu);
    ILFree(folder_pidl);
    return ret;
}