shlmenu.c 34.6 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 "shlwapi.h"
34 35 36
#include "shell32_main.h"

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

40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
/* FileMenu_Create nSelHeight constants */
#define FM_DEFAULT_SELHEIGHT  -1
#define FM_FULL_SELHEIGHT     0

/* FileMenu_Create flags */
#define FMF_SMALL_ICONS      0x00
#define FMF_LARGE_ICONS      0x08
#define FMF_NO_COLUMN_BREAK  0x10

/* FileMenu_AppendItem constants */
#define FM_SEPARATOR       ((const WCHAR *)1)
#define FM_BLANK_ICON      -1
#define FM_DEFAULT_HEIGHT  0

/* FileMenu_InsertUsingPidl flags */
#define FMF_NO_EMPTY_ITEM      0x01
#define FMF_NO_PROGRAM_GROUPS  0x04

/* FileMenu_InsertUsingPidl callback function */
typedef void (CALLBACK *LPFNFMCALLBACK)(LPCITEMIDLIST pidlFolder, LPCITEMIDLIST pidlFile);
60 61

static BOOL FileMenu_AppendItemW(HMENU hMenu, LPCWSTR lpText, UINT uID, int icon,
62
                                 HMENU hMenuPopup, int nItemHeight);
63
BOOL WINAPI FileMenu_DeleteAllItems(HMENU hMenu);
64 65

typedef struct
Juergen Schmied's avatar
Juergen Schmied committed
66 67 68
{
	BOOL		bInitialized;
	BOOL		bFixedItems;
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
	/* 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;
86
	WCHAR	szItemText[1];
87 88 89 90 91 92
} FMITEM, * LPFMITEM;

static BOOL bAbortInit;

#define	CCH_MAXITEMTEXT 256

93
WINE_DEFAULT_DEBUG_CHANNEL(shell);
94

Mike McCormack's avatar
Mike McCormack committed
95 96 97
static LPFMINFO FM_GetMenuInfo(HMENU hmenu)
{
	MENUINFO	MenuInfo;
98 99 100 101 102 103 104 105 106 107
	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
108 109
	if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
	{
110
	  ERR("menudata corrupt: %p %lu\n", menudata, MenuInfo.cbSize);
Juergen Schmied's avatar
Juergen Schmied committed
111 112
	  return 0;
	}
113

114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	return menudata;

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

131
	TRACE("\n");
132

133
	menudata = FM_GetMenuInfo(hmenu);
134

135
	SHFree(menudata->pidl);
136

137 138 139 140 141 142 143 144
	menudata->uID = uID;
	menudata->pidl = ILClone(pidl);
	menudata->uFlags = uFlags;
	menudata->uEnumFlags = uEnumFlags;
	menudata->lpfnCallback = lpfnCallback;

	return menudata;
}
145

146 147 148 149
/*************************************************************************
 * FM_InitMenuPopup				[internal]
 *
 */
150
static int FM_InitMenuPopup(HMENU hmenu, LPCITEMIDLIST pAlternatePidl)
151
{	IShellFolder	*lpsf, *lpsf2;
152
	ULONG		ulItemAttr = SFGAO_FOLDER;
153
	UINT		uID, uEnumFlags;
154
	LPFNFMCALLBACK	lpfnCallback;
155
	LPCITEMIDLIST	pidl;
156
	WCHAR		sTemp[MAX_PATH];
157 158 159 160
	int		NumberOfItems = 0, iIcon;
	MENUINFO	MenuInfo;
	LPFMINFO	menudata;

161
	TRACE("%p %p\n", hmenu, pAlternatePidl);
162 163 164 165 166 167 168 169

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

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

	menudata = (LPFMINFO)MenuInfo.dwMenuData;
170

Juergen Schmied's avatar
Juergen Schmied committed
171 172
	if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
	{
173
	  ERR("menudata corrupt: %p %lu\n", menudata, MenuInfo.cbSize);
Juergen Schmied's avatar
Juergen Schmied committed
174 175
	  return 0;
	}
176

177 178
	if (menudata->bInitialized)
	  return 0;
179

180
	pidl = (pAlternatePidl? pAlternatePidl: menudata->pidl);
Juergen Schmied's avatar
Juergen Schmied committed
181 182 183 184
	if (!pidl)
	  return 0;

	uID = menudata->uID;
185 186 187
	uEnumFlags = menudata->uEnumFlags;
	lpfnCallback = menudata->lpfnCallback;
	menudata->bInitialized = FALSE;
Juergen Schmied's avatar
Juergen Schmied committed
188

189
	SetMenuInfo(hmenu, &MenuInfo);
190

191 192
	if (SUCCEEDED (SHGetDesktopFolder(&lpsf)))
	{
193
	  if (SUCCEEDED(IShellFolder_BindToObject(lpsf, pidl,0,&IID_IShellFolder,(LPVOID *)&lpsf2)))
194 195 196 197 198 199 200 201 202
	  {
	    IEnumIDList	*lpe = NULL;

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

	      LPITEMIDLIST pidlTemp = NULL;
	      ULONG ulFetched;

203
	      while ((!bAbortInit) && (S_OK == IEnumIDList_Next(lpe,1,&pidlTemp,&ulFetched)))
204
	      {
205
		if (SUCCEEDED (IShellFolder_GetAttributesOf(lpsf, 1, (LPCITEMIDLIST*)&pidlTemp, &ulItemAttr)))
206
		{
207
		  ILGetDisplayNameExW(NULL, pidlTemp, sTemp, ILGDN_FORPARSING);
208
		  if (! (PidlToSicIndex(lpsf, pidlTemp, FALSE, 0, &iIcon)))
209 210 211 212 213 214
		    iIcon = FM_BLANK_ICON;
		  if ( SFGAO_FOLDER & ulItemAttr)
		  {
		    LPFMINFO lpFmMi;
		    MENUINFO MenuInfo;
		    HMENU hMenuPopup = CreatePopupMenu();
215

216
		    lpFmMi = heap_alloc_zero(sizeof(*lpFmMi));
217 218 219 220 221 222

		    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
223
		    MenuInfo.dwMenuData = (ULONG_PTR) lpFmMi;
224 225
		    SetMenuInfo (hMenuPopup, &MenuInfo);

226
		    FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, hMenuPopup, FM_DEFAULT_HEIGHT);
227 228 229
		  }
		  else
		  {
230 231 232 233
		    LPWSTR pExt = PathFindExtensionW(sTemp);
		    if (pExt)
		      *pExt = 0;
		    FileMenu_AppendItemW (hmenu, sTemp, uID, iIcon, 0, FM_DEFAULT_HEIGHT);
234 235 236 237 238
		  }
		}

		if (lpfnCallback)
		{
239
		  TRACE("enter callback\n");
240
		  lpfnCallback ( pidl, pidlTemp);
241
		  TRACE("leave callback\n");
242 243 244 245 246 247 248 249 250 251 252 253
		}

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

	if ( GetMenuItemCount (hmenu) == 0 )
254
	{
255
	  FileMenu_AppendItemW (hmenu, L"(empty)", uID, FM_BLANK_ICON, 0, FM_DEFAULT_HEIGHT);
Juergen Schmied's avatar
Juergen Schmied committed
256 257
	  NumberOfItems++;
	}
258 259 260 261 262 263

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

	return NumberOfItems;
}
264 265 266
/*************************************************************************
 * FileMenu_Create				[SHELL32.114]
 *
Juergen Schmied's avatar
Juergen Schmied committed
267 268
 * NOTES
 *  for non-root menus values are
269
 *  (ffffffff,00000000,00000000,00000000,00000000)
270 271 272 273 274 275 276 277
 */
HMENU WINAPI FileMenu_Create (
	COLORREF crBorderColor,
	int nBorderWidth,
	HBITMAP hBorderBmp,
	int nSelHeight,
	UINT uFlags)
{
278 279
	MENUINFO	MenuInfo;
	LPFMINFO	menudata;
280

281
	HMENU hMenu = CreatePopupMenu();
282

283
	TRACE("0x%08lx 0x%08x %p 0x%08x 0x%08x  hMenu=%p\n",
284 285
	crBorderColor, nBorderWidth, hBorderBmp, nSelHeight, uFlags, hMenu);

286
	menudata = heap_alloc_zero(sizeof(*menudata));
287 288 289 290 291 292
	menudata->crBorderColor = crBorderColor;
	menudata->nBorderWidth = nBorderWidth;
	menudata->hBorderBmp = hBorderBmp;

	MenuInfo.cbSize = sizeof(MENUINFO);
	MenuInfo.fMask = MIM_MENUDATA;
Kevin Koltzau's avatar
Kevin Koltzau committed
293
	MenuInfo.dwMenuData = (ULONG_PTR) menudata;
294 295 296
	SetMenuInfo (hMenu, &MenuInfo);

	return hMenu;
297 298 299 300 301 302 303 304
}

/*************************************************************************
 * FileMenu_Destroy				[SHELL32.118]
 *
 * NOTES
 *  exported by name
 */
305
void WINAPI FileMenu_Destroy (HMENU hmenu)
306
{
307 308
	LPFMINFO	menudata;

309
	TRACE("%p\n", hmenu);
310 311

	FileMenu_DeleteAllItems (hmenu);
312

313 314
	menudata = FM_GetMenuInfo(hmenu);

315
	SHFree( menudata->pidl);
316
	heap_free(menudata);
317 318

	DestroyMenu (hmenu);
319 320 321
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
322
 * FileMenu_AppendItem			[SHELL32.115]
323 324
 *
 */
325
static BOOL FileMenu_AppendItemW(
326
	HMENU hMenu,
327
	LPCWSTR lpText,
328 329 330 331 332
	UINT uID,
	int icon,
	HMENU hMenuPopup,
	int nItemHeight)
{
333
	MENUITEMINFOW	mii;
Juergen Schmied's avatar
Juergen Schmied committed
334 335 336 337
	LPFMITEM	myItem;
	LPFMINFO	menudata;
	MENUINFO        MenuInfo;

338

339
	TRACE("%p %s 0x%08x 0x%08x %p 0x%08x\n",
340 341
	  hMenu, (lpText!=FM_SEPARATOR) ? debugstr_w(lpText) : NULL,
	  uID, icon, hMenuPopup, nItemHeight);
342

343
	ZeroMemory (&mii, sizeof(MENUITEMINFOW));
344

345
	mii.cbSize = sizeof(MENUITEMINFOW);
346 347

	if (lpText != FM_SEPARATOR)
348
	{
349
	  int len = lstrlenW (lpText);
350
          myItem = SHAlloc(sizeof(FMITEM) + len*sizeof(WCHAR));
351
	  lstrcpyW (myItem->szItemText, lpText);
352 353 354 355
	  myItem->cchItemText = len;
	  myItem->iIconIndex = icon;
	  myItem->hMenu = hMenu;
	  mii.fMask = MIIM_DATA;
Kevin Koltzau's avatar
Kevin Koltzau committed
356
	  mii.dwItemData = (ULONG_PTR) myItem;
357
	}
358

359 360
	if ( hMenuPopup )
	{ /* sub menu */
361 362
	  mii.fMask |= MIIM_TYPE | MIIM_SUBMENU;
	  mii.fType = MFT_OWNERDRAW;
363 364 365
	  mii.hSubMenu = hMenuPopup;
	}
	else if (lpText == FM_SEPARATOR )
366
	{ mii.fMask |= MIIM_ID | MIIM_TYPE;
367 368 369 370
	  mii.fType = MFT_SEPARATOR;
	}
	else
	{ /* normal item */
371
	  mii.fMask |= MIIM_ID | MIIM_TYPE | MIIM_STATE;
372
	  mii.fState = MFS_ENABLED | MFS_DEFAULT;
373
	  mii.fType = MFT_OWNERDRAW;
374 375 376
	}
	mii.wID = uID;

377
	InsertMenuItemW (hMenu, (UINT)-1, TRUE, &mii);
378

Juergen Schmied's avatar
Juergen Schmied committed
379 380 381 382 383 384 385 386
	/* 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
387 388
	if ((menudata == 0) || (MenuInfo.cbSize != sizeof(MENUINFO)))
	{
389
	  ERR("menudata corrupt: %p %lu\n", menudata, MenuInfo.cbSize);
390
	  return FALSE;
Juergen Schmied's avatar
Juergen Schmied committed
391 392
	}

Juergen Schmied's avatar
Juergen Schmied committed
393 394 395
	menudata->bFixedItems = TRUE;
	SetMenuInfo(hMenu, &MenuInfo);

396 397 398
	return TRUE;

}
399 400 401

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

402 403 404 405 406 407 408 409 410 411
BOOL WINAPI FileMenu_AppendItemAW(
	HMENU hMenu,
	LPCVOID lpText,
	UINT uID,
	int icon,
	HMENU hMenuPopup,
	int nItemHeight)
{
	BOOL ret;

412 413 414
        if (!lpText) return FALSE;

	if (SHELL_OsIsUnicode() || lpText == FM_SEPARATOR)
415 416 417 418
	  ret = FileMenu_AppendItemW(hMenu, lpText, uID, icon, hMenuPopup, nItemHeight);
        else
	{
	  DWORD len = MultiByteToWideChar( CP_ACP, 0, lpText, -1, NULL, 0 );
419
	  LPWSTR lpszText = heap_alloc( len*sizeof(WCHAR) );
420
	  if (!lpszText) return FALSE;
421 422
	  MultiByteToWideChar( CP_ACP, 0, lpText, -1, lpszText, len );
	  ret = FileMenu_AppendItemW(hMenu, lpszText, uID, icon, hMenuPopup, nItemHeight);
423
	  heap_free( lpszText );
424
	}
425 426 427

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

429 430 431 432 433 434 435
/*************************************************************************
 * FileMenu_InsertUsingPidl			[SHELL32.110]
 *
 * NOTES
 *	uEnumFlags	any SHCONTF flag
 */
int WINAPI FileMenu_InsertUsingPidl (
436
	HMENU hmenu,
437 438 439 440 441
	UINT uID,
	LPCITEMIDLIST pidl,
	UINT uFlags,
	UINT uEnumFlags,
	LPFNFMCALLBACK lpfnCallback)
442
{
443
	TRACE("%p 0x%08x %p 0x%08x 0x%08x %p\n",
444
	hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
445 446 447

	pdump (pidl);

448
	bAbortInit = FALSE;
449

450
	FM_SetMenuParameter(hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
451 452

	return FM_InitMenuPopup(hmenu, NULL);
453 454 455 456 457
}

/*************************************************************************
 * FileMenu_ReplaceUsingPidl			[SHELL32.113]
 *
458
 * FIXME: the static items are deleted but won't be refreshed
459 460
 */
int WINAPI FileMenu_ReplaceUsingPidl(
461
	HMENU	hmenu,
462 463 464 465 466
	UINT	uID,
	LPCITEMIDLIST	pidl,
	UINT	uEnumFlags,
	LPFNFMCALLBACK lpfnCallback)
{
467
	TRACE("%p 0x%08x %p 0x%08x %p\n",
468
	hmenu, uID, pidl, uEnumFlags, lpfnCallback);
469

470 471
	FileMenu_DeleteAllItems (hmenu);

472
	FM_SetMenuParameter(hmenu, uID, pidl, 0, uEnumFlags, lpfnCallback);
473 474

	return FM_InitMenuPopup(hmenu, NULL);
475 476 477 478 479 480 481
}

/*************************************************************************
 * FileMenu_Invalidate			[SHELL32.111]
 */
void WINAPI FileMenu_Invalidate (HMENU hMenu)
{
482
	FIXME("%p\n",hMenu);
483 484 485 486 487 488 489 490 491
}

/*************************************************************************
 * FileMenu_FindSubMenuByPidl			[SHELL32.106]
 */
HMENU WINAPI FileMenu_FindSubMenuByPidl(
	HMENU	hMenu,
	LPCITEMIDLIST	pidl)
{
492
	FIXME("%p %p\n",hMenu, pidl);
493 494 495 496 497 498
	return 0;
}

/*************************************************************************
 * FileMenu_AppendFilesForPidl			[SHELL32.124]
 */
499
int WINAPI FileMenu_AppendFilesForPidl(
500
	HMENU	hmenu,
501
	LPCITEMIDLIST	pidl,
502
	BOOL	bAddSeparator)
503
{
504 505 506
	LPFMINFO	menudata;

	menudata = FM_GetMenuInfo(hmenu);
507

508
	menudata->bInitialized = FALSE;
509

510 511
	FM_InitMenuPopup(hmenu, pidl);

512
	if (bAddSeparator)
513
	  FileMenu_AppendItemW (hmenu, FM_SEPARATOR, 0, 0, 0, FM_DEFAULT_HEIGHT);
514

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

517 518 519 520 521 522 523 524 525
	return 0;
}
/*************************************************************************
 * FileMenu_AddFilesForPidl			[SHELL32.125]
 *
 * NOTES
 *	uEnumFlags	any SHCONTF flag
 */
int WINAPI FileMenu_AddFilesForPidl (
526
	HMENU	hmenu,
527 528 529 530 531 532 533
	UINT	uReserved,
	UINT	uID,
	LPCITEMIDLIST	pidl,
	UINT	uFlags,
	UINT	uEnumFlags,
	LPFNFMCALLBACK	lpfnCallback)
{
534
	TRACE("%p 0x%08x 0x%08x %p 0x%08x 0x%08x %p\n",
535 536 537
	hmenu, uReserved, uID, pidl, uFlags, uEnumFlags, lpfnCallback);

	return FileMenu_InsertUsingPidl ( hmenu, uID, pidl, uFlags, uEnumFlags, lpfnCallback);
538 539 540 541 542 543 544

}


/*************************************************************************
 * FileMenu_TrackPopupMenuEx			[SHELL32.116]
 */
545
BOOL WINAPI FileMenu_TrackPopupMenuEx (
546 547 548 549 550 551 552
	HMENU hMenu,
	UINT uFlags,
	int x,
	int y,
	HWND hWnd,
	LPTPMPARAMS lptpm)
{
553
	TRACE("%p 0x%08x 0x%x 0x%x %p %p\n",
554 555 556 557 558 559 560 561 562 563 564 565
	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)
{
566
	FIXME("0x%08x %p %p\n",uReserved, ppidlFolder, ppidlItem);
567
	return FALSE;
568 569
}

570 571 572 573 574 575
#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
576 577 578 579 580 581 582
/*************************************************************************
 * FileMenu_MeasureItem				[SHELL32.112]
 */
LRESULT WINAPI FileMenu_MeasureItem(
	HWND	hWnd,
	LPMEASUREITEMSTRUCT	lpmis)
{
583 584 585 586
	LPFMITEM pMyItem = (LPFMITEM)(lpmis->itemData);
	HDC hdc = GetDC(hWnd);
	SIZE size;
	LPFMINFO menuinfo;
587

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

590
	GetTextExtentPoint32W(hdc, pMyItem->szItemText, pMyItem->cchItemText, &size);
591

592 593 594 595 596
	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
597
	if (menuinfo->nBorderWidth)
598
	  lpmis->itemWidth += menuinfo->nBorderWidth;
599

600
	TRACE("-- 0x%04x 0x%04x\n", lpmis->itemWidth, lpmis->itemHeight);
601
	ReleaseDC (hWnd, hdc);
602 603 604 605 606 607 608 609 610
	return 0;
}
/*************************************************************************
 * FileMenu_DrawItem				[SHELL32.105]
 */
LRESULT WINAPI FileMenu_DrawItem(
	HWND			hWnd,
	LPDRAWITEMSTRUCT	lpdis)
{
611 612 613 614
	LPFMITEM pMyItem = (LPFMITEM)(lpdis->itemData);
	COLORREF clrPrevText, clrPrevBkgnd;
	int xi,yi,xt,yt;
	HIMAGELIST hImageList;
615
	RECT TextRect;
616
	LPFMINFO menuinfo;
617

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

620 621 622 623 624 625 626 627 628 629
	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));
	}
630

631
        TextRect = lpdis->rcItem;
632 633 634

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

638 639 640 641 642 643 644 645
	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;

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

648
	Shell_GetImageLists(0, &hImageList);
649
	ImageList_Draw(hImageList, pMyItem->iIconIndex, lpdis->hDC, xi, yi, ILD_NORMAL);
650

651
        TRACE("-- %s\n", wine_dbgstr_rect(&TextRect));
652

653 654 655 656
	SetTextColor(lpdis->hDC, clrPrevText);
	SetBkColor(lpdis->hDC, clrPrevBkgnd);

	return TRUE;
657 658 659 660 661 662
}

/*************************************************************************
 * FileMenu_InitMenuPopup			[SHELL32.109]
 *
 * NOTES
663
 *  The filemenu is an ownerdrawn menu. Call this function responding to
664 665 666
 *  WM_INITPOPUPMENU
 *
 */
667 668 669 670
BOOL WINAPI FileMenu_InitMenuPopup (HMENU hmenu)
{
	FM_InitMenuPopup(hmenu, NULL);
	return TRUE;
671 672 673 674 675 676 677 678 679
}

/*************************************************************************
 * FileMenu_HandleMenuChar			[SHELL32.108]
 */
LRESULT WINAPI FileMenu_HandleMenuChar(
	HMENU	hMenu,
	WPARAM	wParam)
{
680
	FIXME("%p 0x%08Ix\n",hMenu,wParam);
681 682 683 684 685 686 687 688 689
	return 0;
}

/*************************************************************************
 * FileMenu_DeleteAllItems			[SHELL32.104]
 *
 * NOTES
 *  exported by name
 */
690
BOOL WINAPI FileMenu_DeleteAllItems (HMENU hmenu)
691
{
692
	MENUITEMINFOW	mii;
693 694 695
	LPFMINFO	menudata;

	int i;
696

697
	TRACE("%p\n", hmenu);
698

699 700
	ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
	mii.cbSize = sizeof(MENUITEMINFOW);
701 702 703
	mii.fMask = MIIM_SUBMENU|MIIM_DATA;

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

706
	  SHFree((LPFMINFO)mii.dwItemData);
707 708 709 710

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

712 713 714
	while (DeleteMenu (hmenu, 0, MF_BYPOSITION)){};

	menudata = FM_GetMenuInfo(hmenu);
715

716
	menudata->bInitialized = FALSE;
717

718 719 720 721
	return TRUE;
}

/*************************************************************************
Patrik Stridvall's avatar
Patrik Stridvall committed
722
 * FileMenu_DeleteItemByCmd 			[SHELL32.117]
723 724 725 726
 *
 */
BOOL WINAPI FileMenu_DeleteItemByCmd (HMENU hMenu, UINT uID)
{
727
	MENUITEMINFOW mii;
728

729
	TRACE("%p 0x%08x\n", hMenu, uID);
730

731 732
	ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
	mii.cbSize = sizeof(MENUITEMINFOW);
733 734
	mii.fMask = MIIM_SUBMENU;

735
	GetMenuItemInfoW(hMenu, uID, FALSE, &mii );
736 737 738 739
	if ( mii.hSubMenu )
	{
	  /* FIXME: Do what? */
	}
740 741 742 743 744 745 746 747 748 749

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

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

752
	TRACE("%p 0x%08x\n", hMenu, uPos);
753

754 755
	ZeroMemory ( &mii, sizeof(MENUITEMINFOW));
	mii.cbSize = sizeof(MENUITEMINFOW);
756 757
	mii.fMask = MIIM_SUBMENU;

758
	GetMenuItemInfoW(hMenu, uPos, TRUE, &mii );
759 760 761 762
	if ( mii.hSubMenu )
	{
	  /* FIXME: Do what? */
	}
763

764 765 766 767 768 769 770 771 772 773 774
	DeleteMenu(hMenu, MF_BYPOSITION, uPos);
	return TRUE;
}

/*************************************************************************
 * FileMenu_DeleteItemByFirstID			[SHELL32.141]
 */
BOOL WINAPI FileMenu_DeleteItemByFirstID(
	HMENU	hMenu,
	UINT	uID)
{
775
	TRACE("%p 0x%08x\n", hMenu, uID);
776
	return FALSE;
777 778 779 780 781 782 783
}

/*************************************************************************
 * FileMenu_DeleteSeparator			[SHELL32.142]
 */
BOOL WINAPI FileMenu_DeleteSeparator(HMENU hMenu)
{
784
	TRACE("%p\n", hMenu);
785
	return FALSE;
786 787 788 789 790 791 792 793 794 795
}

/*************************************************************************
 * FileMenu_EnableItemByCmd			[SHELL32.143]
 */
BOOL WINAPI FileMenu_EnableItemByCmd(
	HMENU	hMenu,
	UINT	uID,
	BOOL	bEnable)
{
796
	TRACE("%p 0x%08x 0x%08x\n", hMenu, uID,bEnable);
797
	return FALSE;
798 799 800 801
}

/*************************************************************************
 * FileMenu_GetItemExtent			[SHELL32.144]
802
 *
803
 * NOTES
804
 *  if the menu is too big, entries are getting cut away!!
805 806 807
 */
DWORD WINAPI FileMenu_GetItemExtent (HMENU hMenu, UINT uPos)
{	RECT rect;
808

809
	FIXME("%p 0x%08x\n", hMenu, uPos);
810 811

	if (GetMenuItemRect(0, hMenu, uPos, &rect))
812 813
        {
          FIXME("%s\n", wine_dbgstr_rect(&rect));
814 815
	  return ((rect.right-rect.left)<<16) + (rect.top-rect.bottom);
	}
816
	return 0x00100010; /*FIXME*/
817 818 819 820 821 822 823
}

/*************************************************************************
 * FileMenu_AbortInitMenu 			[SHELL32.120]
 *
 */
void WINAPI FileMenu_AbortInitMenu (void)
824
{	TRACE("\n");
825
	bAbortInit = TRUE;
826 827 828 829 830
}

/*************************************************************************
 * SHFind_InitMenuPopup				[SHELL32.149]
 *
831 832
 * Get the IContextMenu instance for the submenu of options displayed
 * for the Search entry in the Classic style Start menu.
833 834
 *
 * PARAMETERS
835
 *  hMenu		[in] handle of menu previously created
836
 *  hWndParent	[in] parent window
837 838 839 840 841 842
 *  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.
843
 */
844
LPVOID WINAPI SHFind_InitMenuPopup (HMENU hMenu, HWND hWndParent, DWORD w, DWORD x)
Mike McCormack's avatar
Mike McCormack committed
845
{
846
	FIXME("hmenu=%p hwnd=%p 0x%08lx 0x%08lx stub\n",
847
		hMenu,hWndParent,w,x);
848
	return NULL; /* this is supposed to be a pointer */
849 850 851
}

/*************************************************************************
Mike McCormack's avatar
Mike McCormack committed
852
 * _SHIsMenuSeparator   (internal)
853
 */
Mike McCormack's avatar
Mike McCormack committed
854
static BOOL _SHIsMenuSeparator(HMENU hm, int i)
855
{
856
	MENUITEMINFOW mii;
857

858
	mii.cbSize = sizeof(MENUITEMINFOW);
859 860
	mii.fMask = MIIM_TYPE;
	mii.cch = 0;    /* WARNING: We MUST initialize it to 0*/
861
	if (!GetMenuItemInfoW(hm, i, TRUE, &mii))
862 863
	{
	  return(FALSE);
864 865 866
	}

	if (mii.fType & MFT_SEPARATOR)
867 868
	{
	  return(TRUE);
869 870
	}

871
	return(FALSE);
872
}
873

Mike McCormack's avatar
Mike McCormack committed
874 875 876
/*************************************************************************
 * Shell_MergeMenus				[SHELL32.67]
 */
877
UINT WINAPI Shell_MergeMenus (HMENU hmDst, HMENU hmSrc, UINT uInsert, UINT uIDAdjust, UINT uIDAdjustMax, ULONG uFlags)
878 879 880
{	int		nItem;
	HMENU		hmSubMenu;
	BOOL		bAlreadySeparated;
881 882
	MENUITEMINFOW	miiSrc;
	WCHAR		szName[256];
883 884
	UINT		uTemp, uIDMax = uIDAdjust;

885
	TRACE("hmenu1=%p hmenu2=%p 0x%04x 0x%04x 0x%04x  0x%04lx\n",
886 887 888
		 hmDst, hmSrc, uInsert, uIDAdjust, uIDAdjustMax, uFlags);

	if (!hmDst || !hmSrc)
889
	  return uIDMax;
890 891

	nItem = GetMenuItemCount(hmDst);
892 893
        if (nItem == -1)
	  return uIDMax;
894 895 896 897

	if (uInsert >= (UINT)nItem)	/* insert position inside menu? */
	{
	  uInsert = (UINT)nItem;	/* append on the end */
898 899 900
	  bAlreadySeparated = TRUE;
	}
	else
901
	{
902
	  bAlreadySeparated = _SHIsMenuSeparator(hmDst, uInsert);
903
	}
904

905
	if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
906 907
	{
	  /* Add a separator between the menus */
908 909 910 911 912 913 914
	  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--)
915
	{
916
	  miiSrc.cbSize = sizeof(MENUITEMINFOW);
917 918 919
	  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*/
920 921 922
	  miiSrc.fType = MFT_STRING;
	  miiSrc.dwTypeData = szName;
	  miiSrc.dwItemData = 0;
923
	  miiSrc.cch = ARRAY_SIZE(szName);
924

925
	  if (!GetMenuItemInfoW(hmSrc, nItem, TRUE, &miiSrc))
926 927
	  {
	    continue;
928
	  }
929 930 931

/*	  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);
*/
932
	  if (miiSrc.fType & MFT_SEPARATOR)
933 934
	  {
	    /* This is a separator; don't put two of them in a row */
935
	    if (bAlreadySeparated)
936 937
	      continue;

938 939 940
	    bAlreadySeparated = TRUE;
	  }
	  else if (miiSrc.hSubMenu)
941 942 943 944 945
	  {
	    if (uFlags & MM_SUBMENUSHAVEIDS)
	    {
	      miiSrc.wID += uIDAdjust;			/* add uIDAdjust to the ID */

946
	      if (miiSrc.wID > uIDAdjustMax)		/* skip IDs higher than uIDAdjustMax */
947 948 949 950
	        continue;

	      if (uIDMax <= miiSrc.wID)			/* remember the highest ID */
	        uIDMax = miiSrc.wID + 1;
951 952
	    }
	    else
953 954
	    {
	      miiSrc.fMask &= ~MIIM_ID;			/* Don't set IDs for submenus that didn't have them already */
955 956
	    }
	    hmSubMenu = miiSrc.hSubMenu;
957

958
	    miiSrc.hSubMenu = CreatePopupMenu();
959 960 961 962 963

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

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

964
	    if (uIDMax <= uTemp)
965 966
	      uIDMax = uTemp;

967 968
	    bAlreadySeparated = FALSE;
	  }
969 970 971 972
	  else						/* normal menu item */
	  {
	    miiSrc.wID += uIDAdjust;			/* add uIDAdjust to the ID */

973
	    if (miiSrc.wID > uIDAdjustMax)		/* skip IDs higher than uIDAdjustMax */
974 975 976 977 978
	      continue;

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

979 980
	    bAlreadySeparated = FALSE;
	  }
981 982 983

/*	  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);
*/
984
	  if (!InsertMenuItemW(hmDst, uInsert, TRUE, &miiSrc))
985 986
	  {
	    return(uIDMax);
987 988 989 990 991 992
	  }
	}

	/* Ensure the correct number of separators at the beginning of the
	inserted menu items*/
	if (uInsert == 0)
993 994 995 996
	{
	  if (bAlreadySeparated)
	  {
	    DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
997 998 999
	  }
	}
	else
1000 1001 1002 1003 1004 1005
	{
	  if (_SHIsMenuSeparator(hmDst, uInsert-1))
	  {
	    if (bAlreadySeparated)
	    {
	      DeleteMenu(hmDst, uInsert, MF_BYPOSITION);
1006 1007 1008
	    }
	  }
	  else
1009 1010 1011 1012
	  {
	    if ((uFlags & MM_ADDSEPARATOR) && !bAlreadySeparated)
	    {
	      /* Add a separator between the menus*/
1013
	      InsertMenuW(hmDst, uInsert, MF_BYPOSITION | MF_SEPARATOR, 0, NULL);
1014 1015 1016 1017 1018
	    }
	  }
	}
	return(uIDMax);
}
1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037

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)
{
1038
    CompositeCMenu *ret;
1039
    UINT i;
1040

1041
    TRACE("(%p,%u,%s,%p)\n",menus,menu_count,shdebugstr_guid(riid),ppv);
1042 1043

    ret = heap_alloc(sizeof(*ret));
1044 1045 1046 1047
    if(!ret)
        return E_OUTOFMEMORY;
    ret->IContextMenu3_iface.lpVtbl = &CompositeCMenuVtbl;
    ret->menu_count = menu_count;
1048
    ret->menus = heap_alloc(menu_count*sizeof(IContextMenu*));
1049 1050
    if(!ret->menus)
    {
1051
        heap_free(ret);
1052 1053
        return E_OUTOFMEMORY;
    }
1054
    ret->offsets = heap_alloc_zero(menu_count*sizeof(UINT));
1055 1056
    if(!ret->offsets)
    {
1057 1058
        heap_free(ret->menus);
        heap_free(ret);
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072
        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]);
1073 1074 1075
    heap_free(This->menus);
    heap_free(This->offsets);
    heap_free(This);
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108
}

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;
}

1109
static UINT CompositeCMenu_GetIndexForCommandId(CompositeCMenu *This,UINT id)
1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127
{
    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);
1128
    TRACE("(%p)->(%Ix,%x,%p,%s,%u)\n",iface,idCmd,uFlags,pwReserved,pszName,cchMax);
1129 1130 1131 1132 1133 1134
    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);
1135 1136 1137 1138 1139 1140 1141 1142 1143 1144

    TRACE("(%p)->(%p)\n", iface, pici);

    if (IS_INTRESOURCE(pici->lpVerb))
    {
        UINT id = (UINT_PTR)pici->lpVerb;
        UINT index = CompositeCMenu_GetIndexForCommandId(This, id);
        return IContextMenu_InvokeCommand(This->menus[index], pici);
    }
    else
1145 1146
    {
        /*call each handler until one of them succeeds*/
1147 1148 1149
        UINT i;

        for (i = 0; i < This->menu_count; i++)
1150 1151
        {
            HRESULT hres;
1152
            if (SUCCEEDED(hres = IContextMenu_InvokeCommand(This->menus[i], pici)))
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
                return hres;
        }
        return E_FAIL;
    }
}

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;
1184
    TRACE("(%p)->(%x,%Ix,%Ix)\n",iface,uMsg,wParam,lParam);
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
    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;
1218
    TRACE("(%p)->(%x,%Ix,%Ix,%p)\n",iface,uMsg,wParam,lParam,plResult);
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 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
    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
};

1270
static HRESULT SHELL_CreateContextMenu(HWND hwnd, IContextMenu* system_menu,
1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298
                                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);
1299 1300

    ItemMenu_Constructor(psf, folder_pidl, (const LPCITEMIDLIST*)apidl, cidl, &IID_IContextMenu, (void**)&system_menu);
1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324
    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");
1325 1326

    ItemMenu_Constructor(folder, folder_pidl, (const LPCITEMIDLIST*)pdcm->apidl, pdcm->cidl, &IID_IContextMenu, (void**)&system_menu);
1327 1328 1329 1330 1331
    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;
}