3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/shell32/shv_item_new.c
5 * PURPOSE: provides default context menu implementation
6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
11 The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
12 example of the wrong way to do it.
17 WINE_DEFAULT_DEBUG_CHANNEL(dmenu
);
19 typedef struct _DynamicShellEntry_
25 struct _DynamicShellEntry_
*pNext
;
26 } DynamicShellEntry
, *PDynamicShellEntry
;
28 typedef struct _StaticShellEntry_
32 struct _StaticShellEntry_
*pNext
;
33 } StaticShellEntry
, *PStaticShellEntry
;
35 class CDefaultContextMenu
:
36 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
41 IDataObject
*m_pDataObj
;
42 LPCITEMIDLIST m_pidlFolder
;
43 DWORD m_bGroupPolicyActive
;
44 PDynamicShellEntry m_pDynamicEntries
; /* first dynamic shell extension entry */
45 UINT m_iIdSHEFirst
; /* first used id */
46 UINT m_iIdSHELast
; /* last used id */
47 PStaticShellEntry m_pStaticEntries
; /* first static shell extension entry */
48 UINT m_iIdSCMFirst
; /* first static used id */
49 UINT m_iIdSCMLast
; /* last static used id */
51 void AddStaticEntry(LPCWSTR pwszVerb
, LPCWSTR pwszClass
);
52 void AddStaticEntryForKey(HKEY hKey
, LPCWSTR pwszClass
);
53 void AddStaticEntryForFileClass(LPCWSTR pwszExt
);
54 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
);
55 HRESULT
LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
);
56 BOOL
EnumerateDynamicContextHandlerForKey(HKEY hRootKey
);
57 UINT
InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
);
58 UINT
BuildBackgroundContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
59 UINT
AddStaticContextMenusToMenu(HMENU hMenu
, UINT IndexMenu
);
60 UINT
BuildShellItemContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
61 HRESULT
DoPaste(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
);
62 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
63 HRESULT
DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
);
64 HRESULT
DoDelete(LPCMINVOKECOMMANDINFO lpcmi
);
65 HRESULT
DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
);
66 HRESULT
DoRename(LPCMINVOKECOMMANDINFO lpcmi
);
67 HRESULT
DoProperties(LPCMINVOKECOMMANDINFO lpcmi
);
68 HRESULT
DoFormat(LPCMINVOKECOMMANDINFO lpcmi
);
69 HRESULT
DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
70 HRESULT
DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
71 DWORD
BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
);
72 HRESULT
TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
);
73 HRESULT
InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
);
76 CDefaultContextMenu();
77 ~CDefaultContextMenu();
78 HRESULT WINAPI
Initialize(const DEFCONTEXTMENU
*pdcm
);
81 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
82 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
83 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
86 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
88 BEGIN_COM_MAP(CDefaultContextMenu
)
89 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
90 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
94 CDefaultContextMenu::CDefaultContextMenu()
96 memset(&m_Dcm
, 0, sizeof(m_Dcm
));
99 m_bGroupPolicyActive
= 0;
100 m_pDynamicEntries
= NULL
;
103 m_pStaticEntries
= NULL
;
108 CDefaultContextMenu::~CDefaultContextMenu()
110 /* Free dynamic shell extension entries */
111 PDynamicShellEntry pDynamicEntry
= m_pDynamicEntries
, pNextDynamic
;
112 while (pDynamicEntry
)
114 pNextDynamic
= pDynamicEntry
->pNext
;
115 pDynamicEntry
->pCM
->Release();
116 HeapFree(GetProcessHeap(), 0, pDynamicEntry
);
117 pDynamicEntry
= pNextDynamic
;
120 /* Free static shell extension entries */
121 PStaticShellEntry pStaticEntry
= m_pStaticEntries
, pNextStatic
;
124 pNextStatic
= pStaticEntry
->pNext
;
125 HeapFree(GetProcessHeap(), 0, pStaticEntry
->szClass
);
126 HeapFree(GetProcessHeap(), 0, pStaticEntry
->szVerb
);
127 HeapFree(GetProcessHeap(), 0, pStaticEntry
);
128 pStaticEntry
= pNextStatic
;
132 ILFree((_ITEMIDLIST
*)m_pidlFolder
);
134 m_pDataObj
->Release();
137 HRESULT WINAPI
CDefaultContextMenu::Initialize(const DEFCONTEXTMENU
*pdcm
)
139 IDataObject
*pDataObj
;
141 TRACE("cidl %u\n", pdcm
->cidl
);
142 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
))))
143 m_pDataObj
= pDataObj
;
147 /* Init pidlFolder only if it is background context menu. See IShellExtInit::Initialize */
148 if (pdcm
->pidlFolder
)
149 m_pidlFolder
= ILClone(pdcm
->pidlFolder
);
152 IPersistFolder2
*pf
= NULL
;
153 if (SUCCEEDED(pdcm
->psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
155 if (FAILED(pf
->GetCurFolder((_ITEMIDLIST
**)&m_pidlFolder
)))
156 ERR("GetCurFolder failed\n");
160 TRACE("pidlFolder %p\n", m_pidlFolder
);
163 CopyMemory(&m_Dcm
, pdcm
, sizeof(DEFCONTEXTMENU
));
168 CDefaultContextMenu::AddStaticEntry(const WCHAR
*szVerb
, const WCHAR
*szClass
)
170 PStaticShellEntry pEntry
= m_pStaticEntries
, pLastEntry
= NULL
;
173 if (!wcsicmp(pEntry
->szVerb
, szVerb
))
175 /* entry already exists */
179 pEntry
= pEntry
->pNext
;
182 TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb
), debugstr_w(szClass
));
184 pEntry
= (StaticShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry
));
187 pEntry
->pNext
= NULL
;
188 pEntry
->szVerb
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb
) + 1) * sizeof(WCHAR
));
190 wcscpy(pEntry
->szVerb
, szVerb
);
191 pEntry
->szClass
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass
) + 1) * sizeof(WCHAR
));
193 wcscpy(pEntry
->szClass
, szClass
);
196 if (!wcsicmp(szVerb
, L
"open"))
198 /* open verb is always inserted in front */
199 pEntry
->pNext
= m_pStaticEntries
;
200 m_pStaticEntries
= pEntry
;
203 pLastEntry
->pNext
= pEntry
;
205 m_pStaticEntries
= pEntry
;
209 CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey
, const WCHAR
*pwszClass
)
212 DWORD cchName
, dwIndex
= 0;
214 TRACE("AddStaticEntryForKey %x %ls\n", hKey
, pwszClass
);
218 cchName
= _countof(wszName
);
219 if (RegEnumKeyExW(hKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
222 AddStaticEntry(wszName
, pwszClass
);
227 CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR
* szExt
)
234 static WCHAR szShell
[] = L
"\\shell";
235 static WCHAR szShellAssoc
[] = L
"SystemFileAssociations\\";
237 TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt
));
239 Length
= wcslen(szExt
);
240 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
242 wcscpy(szBuffer
, szExt
);
243 wcscpy(&szBuffer
[Length
], szShell
);
244 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
245 if (result
== ERROR_SUCCESS
)
247 szBuffer
[Length
] = 0;
248 AddStaticEntryForKey(hKey
, szExt
);
253 dwBuffer
= sizeof(szBuffer
);
254 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, (LPBYTE
)szBuffer
, &dwBuffer
);
255 if (result
== ERROR_SUCCESS
)
257 Length
= wcslen(szBuffer
);
258 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
260 wcscpy(&szBuffer
[Length
], szShell
);
261 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
263 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
264 if (result
== ERROR_SUCCESS
)
266 szBuffer
[Length
] = 0;
267 AddStaticEntryForKey(hKey
, szBuffer
);
273 wcscpy(szBuffer
, szShellAssoc
);
274 dwBuffer
= sizeof(szBuffer
) - sizeof(szShellAssoc
) - sizeof(WCHAR
);
275 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, L
"PerceivedType", RRF_RT_REG_SZ
, NULL
, (LPBYTE
)&szBuffer
[_countof(szShellAssoc
) - 1], &dwBuffer
);
276 if (result
== ERROR_SUCCESS
)
278 Length
= wcslen(&szBuffer
[_countof(szShellAssoc
)]) + _countof(szShellAssoc
);
279 wcscat(szBuffer
, L
"\\shell");
280 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
282 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
283 if (result
== ERROR_SUCCESS
)
285 szBuffer
[Length
] = 0;
286 AddStaticEntryForKey(hKey
, szBuffer
);
297 IDataObject
*pDataObj
;
299 if(SUCCEEDED(OleGetClipboard(&pDataObj
)))
304 TRACE("pDataObj=%p\n", pDataObj
);
306 /* Set the FORMATETC structure*/
307 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
308 if(SUCCEEDED(pDataObj
->GetData(&formatetc
, &medium
)))
311 ReleaseStgMedium(&medium
);
322 DisablePasteOptions(HMENU hMenu
)
326 mii
.cbSize
= sizeof(mii
);
327 mii
.fMask
= MIIM_STATE
;
328 mii
.fState
= MFS_DISABLED
;
330 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
));
331 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
));
335 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
)
337 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
341 if (!memcmp(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
)))
343 pEntry
= pEntry
->pNext
;
350 CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
)
354 TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey
, wine_dbgstr_guid(pclsid
));
356 if (IsShellExtensionAlreadyLoaded(pclsid
))
360 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IContextMenu
, &pcm
));
363 ERR("SHCoCreateInstance failed %x\n", GetLastError());
367 IShellExtInit
*pExtInit
;
368 hr
= pcm
->QueryInterface(IID_PPV_ARG(IShellExtInit
, &pExtInit
));
371 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));
376 hr
= pExtInit
->Initialize(m_pidlFolder
, m_pDataObj
, hKey
);
380 TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));
385 PDynamicShellEntry pEntry
= (DynamicShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
389 return E_OUTOFMEMORY
;
392 pEntry
->iIdCmdFirst
= 0;
393 pEntry
->pNext
= NULL
;
396 memcpy(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
));
398 if (m_pDynamicEntries
)
400 PDynamicShellEntry pLastEntry
= m_pDynamicEntries
;
402 while (pLastEntry
->pNext
)
403 pLastEntry
= pLastEntry
->pNext
;
405 pLastEntry
->pNext
= pEntry
;
408 m_pDynamicEntries
= pEntry
;
414 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey
)
417 WCHAR wszName
[MAX_PATH
], wszBuf
[MAX_PATH
], *pwszClsid
;
422 if (RegOpenKeyExW(hRootKey
, L
"shellex\\ContextMenuHandlers", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
424 TRACE("RegOpenKeyExW failed\n");
431 cchName
= _countof(wszName
);
432 if (RegEnumKeyExW(hKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
435 /* Key name or key value is CLSID */
437 hr
= CLSIDFromString(wszName
, &clsid
);
442 DWORD cchBuf
= _countof(wszBuf
);
443 if (RegGetValueW(hKey
, wszName
, NULL
, RRF_RT_REG_SZ
, NULL
, wszBuf
, &cchBuf
) == ERROR_SUCCESS
)
444 hr
= CLSIDFromString(wszBuf
, &clsid
);
449 if (m_bGroupPolicyActive
)
451 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
452 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
457 NULL
) == ERROR_SUCCESS
)
459 LoadDynamicContextMenuHandler(hKey
, &clsid
);
463 LoadDynamicContextMenuHandler(hKey
, &clsid
);
472 CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
474 if (!m_pDynamicEntries
)
481 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
484 m_iIdSHEFirst
= idCmdFirst
;
487 HRESULT hr
= pEntry
->pCM
->QueryContextMenu(hMenu
, IndexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
490 pEntry
->iIdCmdFirst
= idCmdFirst
;
491 pEntry
->NumIds
= LOWORD(hr
);
492 IndexMenu
+= pEntry
->NumIds
;
493 idCmdFirst
+= pEntry
->NumIds
+ 0x10;
495 TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry
, hr
, pEntry
->pCM
, pEntry
->iIdCmdFirst
, pEntry
->NumIds
);
496 pEntry
= pEntry
->pNext
;
499 m_iIdSHELast
= idCmdFirst
;
500 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst
, m_iIdSHELast
);
505 CDefaultContextMenu::BuildBackgroundContextMenu(
514 TRACE("BuildBackgroundContextMenu entered\n");
516 if (!_ILIsDesktop(m_pidlFolder
))
518 WCHAR wszBuf
[MAX_PATH
];
520 /* view option is only available in browsing mode */
521 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_001");
522 if (hSubMenu
&& LoadStringW(shell32_hInstance
, FCIDM_SHVIEW_VIEW
, wszBuf
, _countof(wszBuf
)))
524 TRACE("wszBuf %s\n", debugstr_w(wszBuf
));
527 ZeroMemory(&mii
, sizeof(mii
));
528 mii
.cbSize
= sizeof(mii
);
529 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_ID
;
530 mii
.fType
= MFT_STRING
;
531 mii
.wID
= iIdCmdFirst
++;
532 mii
.dwTypeData
= wszBuf
;
533 mii
.cch
= wcslen(mii
.dwTypeData
);
534 mii
.fState
= MFS_ENABLED
;
535 mii
.hSubMenu
= hSubMenu
;
536 InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, &mii
);
537 DestroyMenu(hSubMenu
);
541 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
544 /* merge general background context menu in */
545 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), IndexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
546 DestroyMenu(hSubMenu
);
549 if (!HasClipboardData())
551 TRACE("disabling paste options\n");
552 DisablePasteOptions(hMenu
);
555 /* Directory is progid of filesystem folders only */
556 LPITEMIDLIST pidlFolderLast
= ILFindLastID(m_pidlFolder
);
557 if (_ILIsDesktop(pidlFolderLast
) || _ILIsDrive(pidlFolderLast
) || _ILIsFolder(pidlFolderLast
))
559 /* Load context menu handlers */
560 TRACE("Add background handlers: %p\n", m_pidlFolder
);
562 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory\\Background", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
564 EnumerateDynamicContextHandlerForKey(hKey
);
568 if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, GetMenuItemCount(hMenu
) - 1, iIdCmdFirst
, iIdCmdLast
))
570 /* seperate dynamic context menu items */
571 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
) - 1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
579 CDefaultContextMenu::AddStaticContextMenusToMenu(
588 mii
.cbSize
= sizeof(mii
);
589 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
590 mii
.fType
= MFT_STRING
;
592 mii
.dwTypeData
= NULL
;
593 m_iIdSCMFirst
= mii
.wID
;
595 PStaticShellEntry pEntry
= m_pStaticEntries
;
599 fState
= MFS_ENABLED
;
600 mii
.dwTypeData
= NULL
;
602 if (!wcsicmp(pEntry
->szVerb
, L
"open"))
604 fState
|= MFS_DEFAULT
;
605 idResource
= IDS_OPEN_VERB
;
607 else if (!wcsicmp(pEntry
->szVerb
, L
"explore"))
608 idResource
= IDS_EXPLORE_VERB
;
609 else if (!wcsicmp(pEntry
->szVerb
, L
"runas"))
610 idResource
= IDS_RUNAS_VERB
;
611 else if (!wcsicmp(pEntry
->szVerb
, L
"edit"))
612 idResource
= IDS_EDIT_VERB
;
613 else if (!wcsicmp(pEntry
->szVerb
, L
"find"))
614 idResource
= IDS_FIND_VERB
;
615 else if (!wcsicmp(pEntry
->szVerb
, L
"print"))
616 idResource
= IDS_PRINT_VERB
;
617 else if (!wcsicmp(pEntry
->szVerb
, L
"printto"))
619 pEntry
= pEntry
->pNext
;
625 /* By default use verb for menu item name */
626 mii
.dwTypeData
= pEntry
->szVerb
;
630 if (LoadStringW(shell32_hInstance
, idResource
, wszVerb
, _countof(wszVerb
)))
631 mii
.dwTypeData
= wszVerb
; /* use translated verb */
633 ERR("Failed to load string\n");
638 HRESULT hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"%s\\shell\\%s", pEntry
->szClass
, pEntry
->szVerb
);
642 DWORD cbVerb
= sizeof(wszVerb
);
644 if (RegGetValueW(HKEY_CLASSES_ROOT
, wszKey
, NULL
, RRF_RT_REG_SZ
, NULL
, wszVerb
, &cbVerb
) == ERROR_SUCCESS
)
645 mii
.dwTypeData
= wszVerb
; /* use description for the menu entry */
649 mii
.cch
= wcslen(mii
.dwTypeData
);
651 InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, &mii
);
654 pEntry
= pEntry
->pNext
;
657 m_iIdSCMLast
= mii
.wID
- 1;
661 void WINAPI
_InsertMenuItemW(
673 ZeroMemory(&mii
, sizeof(mii
));
674 mii
.cbSize
= sizeof(mii
);
675 if (fType
== MFT_SEPARATOR
)
676 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
677 else if (fType
== MFT_STRING
)
679 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
680 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
682 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), wszText
, _countof(wszText
)))
683 mii
.dwTypeData
= wszText
;
686 ERR("failed to load string %p\n", dwTypeData
);
691 mii
.dwTypeData
= (LPWSTR
)dwTypeData
;
697 InsertMenuItemW(hMenu
, indexMenu
, fByPosition
, &mii
);
701 CDefaultContextMenu::BuildShellItemContextMenu(
710 TRACE("BuildShellItemContextMenu entered\n");
711 ASSERT(m_Dcm
.cidl
>= 1);
714 hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
);
717 WCHAR wszPath
[MAX_PATH
];
718 hr
= StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], wszPath
, _countof(wszPath
));
721 LPCWSTR pwszExt
= PathFindExtensionW(wszPath
);
724 /* enumerate dynamic/static for a given file class */
725 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pwszExt
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
727 /* add static verbs */
728 AddStaticEntryForFileClass(pwszExt
);
730 /* load dynamic extensions from file extension key */
731 EnumerateDynamicContextHandlerForKey(hKey
);
736 DWORD dwSize
= sizeof(wszTemp
);
737 if (RegGetValueW(HKEY_CLASSES_ROOT
, pwszExt
, NULL
, RRF_RT_REG_SZ
, NULL
, wszTemp
, &dwSize
) == ERROR_SUCCESS
)
739 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
741 /* add static verbs from progid key */
742 AddStaticEntryForFileClass(wszTemp
);
744 /* load dynamic extensions from progid key */
745 EnumerateDynamicContextHandlerForKey(hKey
);
751 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
753 /* load default extensions */
754 EnumerateDynamicContextHandlerForKey(hKey
);
760 ERR("GetDisplayNameOf failed: %x\n", hr
);
762 GUID
*pGuid
= _ILGetGUIDPointer(m_Dcm
.apidl
[0]);
768 wcscpy(buffer
, L
"CLSID\\");
769 hr
= StringFromCLSID(*pGuid
, &pwszCLSID
);
772 wcscpy(&buffer
[6], pwszCLSID
);
773 TRACE("buffer %s\n", debugstr_w(buffer
));
774 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
776 EnumerateDynamicContextHandlerForKey(hKey
);
777 AddStaticEntryForFileClass(buffer
);
780 CoTaskMemFree(pwszCLSID
);
784 if (_ILIsDrive(m_Dcm
.apidl
[0]))
786 AddStaticEntryForFileClass(L
"Drive");
787 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
789 EnumerateDynamicContextHandlerForKey(hKey
);
795 /* add static actions */
796 SFGAOF rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
797 hr
= m_Dcm
.psf
->GetAttributesOf(m_Dcm
.cidl
, m_Dcm
.apidl
, &rfg
);
800 ERR("GetAttributesOf failed: %x\n", hr
);
804 if (rfg
& SFGAO_FOLDER
)
806 /* add the default verbs open / explore */
807 AddStaticEntryForFileClass(L
"Folder");
808 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
810 EnumerateDynamicContextHandlerForKey(hKey
);
814 /* Directory is only loaded for real filesystem directories */
815 if (_ILIsFolder(m_Dcm
.apidl
[0]))
817 AddStaticEntryForFileClass(L
"Directory");
818 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
820 EnumerateDynamicContextHandlerForKey(hKey
);
826 /* AllFilesystemObjects class is loaded only for files and directories */
827 if (_ILIsFolder(m_Dcm
.apidl
[0]) || _ILIsValue(m_Dcm
.apidl
[0]))
829 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
831 /* sendto service is registered here */
832 EnumerateDynamicContextHandlerForKey(hKey
);
837 /* add static context menu handlers */
838 UINT IndexMenu
= AddStaticContextMenusToMenu(hMenu
, 0);
840 /* now process dynamic context menu handlers */
841 BOOL bAddSep
= FALSE
;
842 IndexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, IndexMenu
, iIdCmdFirst
, iIdCmdLast
);
843 TRACE("IndexMenu %d\n", IndexMenu
);
845 if (_ILIsDrive(m_Dcm
.apidl
[0]))
847 /* The 'Format' option must be always available,
848 * thus it is not registered as a static shell extension */
849 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
850 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
854 BOOL bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
855 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
857 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
858 if (rfg
& SFGAO_CANMOVE
)
859 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
860 if (rfg
& SFGAO_CANCOPY
)
861 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
863 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_INSERT
), MFS_ENABLED
);
868 if (rfg
& SFGAO_CANLINK
)
871 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
872 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
875 if (rfg
& SFGAO_CANDELETE
)
880 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
882 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
885 if (rfg
& SFGAO_CANRENAME
)
889 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
891 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
895 if (rfg
& SFGAO_HASPROPSHEET
)
897 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
898 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
906 CDefaultContextMenu::QueryContextMenu(
914 idCmdFirst
= BuildShellItemContextMenu(hMenu
, idCmdFirst
, idCmdLast
, uFlags
);
916 idCmdFirst
= BuildBackgroundContextMenu(hMenu
, idCmdFirst
, idCmdLast
, uFlags
);
923 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
925 /* Note: CWM_GETISHELLBROWSER returns not referenced object */
926 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
930 LPSHELLVIEW lpSV
= NULL
;
931 if (FAILED(lpSB
->QueryActiveShellView(&lpSV
)))
934 if (LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_REFRESH
|| bRefresh
)
939 if (SUCCEEDED(lpSV
->GetWindow(&hwndSV
)))
940 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
948 CDefaultContextMenu::DoPaste(
949 LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
)
953 CComPtr
<IDataObject
> pda
;
954 hr
= OleGetClipboard(&pda
);
958 CComPtr
<IShellFolder
> psfDesktop
;
959 CComPtr
<IShellFolder
> psfTarget
= NULL
;
961 hr
= SHGetDesktopFolder(&psfDesktop
);
965 /* Find target folder */
968 hr
= m_Dcm
.psf
->BindToObject(m_Dcm
.apidl
[0], NULL
, IID_PPV_ARG(IShellFolder
, &psfTarget
));
972 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
975 /* cidl is zero due to explorer view */
976 hr
= m_Dcm
.psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &ppf2
));
979 hr
= ppf2
->GetCurFolder(&pidl
);
982 if (_ILIsDesktop(pidl
))
984 /* use desktop shellfolder */
985 psfTarget
= psfDesktop
;
989 /* retrieve target desktop folder */
990 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfTarget
));
992 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
.p
, _ILIsDesktop(pidl
));
1000 ERR("no IShellFolder\n");
1004 FORMATETC formatetc2
;
1006 InitFormatEtc(formatetc2
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
1010 if (SUCCEEDED(pda
->GetData(&formatetc2
, &medium2
)))
1012 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium2
.hGlobal
);
1015 if (*pdwFlag
== DROPEFFECT_COPY
)
1021 ERR("No drop effect obtained");
1023 GlobalUnlock(medium2
.hGlobal
);
1028 dwKey
= MK_CONTROL
|MK_SHIFT
;
1032 hr
= psfTarget
->QueryInterface(IID_PPV_ARG(IDropTarget
, &pdrop
));
1035 ERR("Error getting IDropTarget interface\n");
1039 SHSimulateDrop(pdrop
, pda
, dwKey
, NULL
, NULL
);
1040 NotifyShellViewWindow(lpcmi
, TRUE
);
1042 TRACE("CP result %x\n", hr
);
1047 CDefaultContextMenu::DoOpenOrExplore(
1048 LPCMINVOKECOMMANDINFO lpcmi
)
1055 CDefaultContextMenu::DoCreateLink(
1056 LPCMINVOKECOMMANDINFO lpcmi
)
1058 LPDATAOBJECT pDataObj
;
1061 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
1063 CComPtr
<IShellFolder
> psfDesktop
;
1064 CComPtr
<IShellFolder
> psfTarget
= NULL
;
1066 hr
= SHGetDesktopFolder(&psfDesktop
);
1070 if (SUCCEEDED(hr
= SHCreateDataObject(m_Dcm
.pidlFolder
, m_Dcm
.cidl
, m_Dcm
.apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
))))
1072 hr
= m_Dcm
.psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &ppf2
));
1075 hr
= ppf2
->GetCurFolder(&pidl
);
1078 if (_ILIsDesktop(pidl
))
1080 /* use desktop shellfolder */
1081 psfTarget
= psfDesktop
;
1085 /* retrieve target desktop folder */
1086 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfTarget
));
1088 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
.p
, _ILIsDesktop(pidl
));
1097 ERR("no IShellFolder\n");
1101 psfTarget
->QueryInterface(IID_PPV_ARG(IDropTarget
, &pDT
));
1104 ERR("no IDropTarget Interface\n");
1107 //DWORD link = DROPEFFECT_LINK;
1108 SHSimulateDrop(pDT
, pDataObj
, MK_CONTROL
|MK_SHIFT
, NULL
, NULL
);
1109 NotifyShellViewWindow(lpcmi
, TRUE
);
1115 CDefaultContextMenu::DoDelete(
1116 LPCMINVOKECOMMANDINFO lpcmi
)
1119 HRESULT hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1122 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1126 WCHAR wszPath
[MAX_PATH
];
1127 hr
= StrRetToBufW(&strTemp
, m_Dcm
.apidl
[0], wszPath
, _countof(wszPath
));
1130 ERR("StrRetToBufW failed with %x\n", hr
);
1134 /* Only keep the base path */
1135 LPWSTR pwszFilename
= PathFindFileNameW(wszPath
);
1136 *pwszFilename
= L
'\0';
1138 /* Build paths list */
1139 LPWSTR pwszPaths
= BuildPathsList(wszPath
, m_Dcm
.cidl
, m_Dcm
.apidl
);
1144 SHFILEOPSTRUCTW FileOp
;
1145 ZeroMemory(&FileOp
, sizeof(FileOp
));
1146 FileOp
.hwnd
= GetActiveWindow();
1147 FileOp
.wFunc
= FO_DELETE
;
1148 FileOp
.pFrom
= pwszPaths
;
1149 FileOp
.fFlags
= FOF_ALLOWUNDO
;
1151 if (SHFileOperationW(&FileOp
) != 0)
1153 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths
));
1157 /* Get the active IShellView */
1158 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageW(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1161 /* Is the treeview focused */
1163 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1165 /* Remove selected items from treeview */
1166 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1168 (void)TreeView_DeleteItem(hwnd
, hItem
);
1171 NotifyShellViewWindow(lpcmi
, TRUE
);
1173 HeapFree(GetProcessHeap(), 0, pwszPaths
);
1179 CDefaultContextMenu::DoCopyOrCut(
1180 LPCMINVOKECOMMANDINFO lpcmi
,
1183 LPDATAOBJECT pDataObj
;
1186 if (SUCCEEDED(SHCreateDataObject(m_Dcm
.pidlFolder
, m_Dcm
.cidl
, m_Dcm
.apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
))))
1190 FORMATETC formatetc
;
1192 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
1193 pDataObj
->GetData(&formatetc
, &medium
);
1194 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium
.hGlobal
);
1196 *pdwFlag
= DROPEFFECT_MOVE
;
1197 GlobalUnlock(medium
.hGlobal
);
1198 pDataObj
->SetData(&formatetc
, &medium
, TRUE
);
1201 hr
= OleSetClipboard(pDataObj
);
1202 pDataObj
->Release();
1206 /* Note: CWM_GETISHELLBROWSER returns not referenced object */
1207 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1210 ERR("failed to get shellbrowser\n");
1215 hr
= lpSB
->QueryActiveShellView(&lpSV
);
1218 ERR("failed to query the active shellview\n");
1222 hr
= lpSV
->GetItemObject(SVGIO_SELECTION
, IID_IDataObject
, (LPVOID
*)&pDataObj
);
1225 hr
= OleSetClipboard(pDataObj
);
1227 ERR("OleSetClipboard failed");
1228 pDataObj
->Release();
1230 ERR("failed to get item object\n");
1237 CDefaultContextMenu::DoRename(
1238 LPCMINVOKECOMMANDINFO lpcmi
)
1240 /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
1241 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1244 ERR("CWM_GETISHELLBROWSER failed\n");
1248 /* is the treeview focused */
1250 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1252 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1254 (void)TreeView_EditLabel(hwnd
, hItem
);
1258 HRESULT hr
= lpSB
->QueryActiveShellView(&lpSV
);
1261 ERR("CWM_GETISHELLBROWSER failed\n");
1265 lpSV
->SelectItem(m_Dcm
.apidl
[0],
1266 SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
);
1272 CDefaultContextMenu::DoProperties(
1273 LPCMINVOKECOMMANDINFO lpcmi
)
1276 const ITEMIDLIST
*pidlParent
= m_Dcm
.pidlFolder
, *pidlChild
;
1280 IPersistFolder2
*pf
;
1282 /* pidlFolder is optional */
1283 if (SUCCEEDED(m_Dcm
.psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
1285 pf
->GetCurFolder((_ITEMIDLIST
**)&pidlParent
);
1291 pidlChild
= m_Dcm
.apidl
[0];
1294 /* Set pidlChild to last pidl of current folder */
1295 if (pidlParent
== m_Dcm
.pidlFolder
)
1296 pidlParent
= (ITEMIDLIST
*)ILClone(pidlParent
);
1298 pidlChild
= (ITEMIDLIST
*)ILClone(ILFindLastID(pidlParent
));
1299 ILRemoveLastID((ITEMIDLIST
*)pidlParent
);
1302 if (_ILIsMyComputer(pidlChild
))
1304 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1307 else if (_ILIsDesktop(pidlChild
))
1309 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1312 else if (_ILIsDrive(pidlChild
))
1314 WCHAR wszBuf
[MAX_PATH
];
1315 ILGetDisplayName(pidlChild
, wszBuf
);
1316 if (!SH_ShowDriveProperties(wszBuf
, pidlParent
, &pidlChild
))
1319 else if (_ILIsNetHood(pidlChild
))
1322 if (32 >= (UINT
)ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1323 L
"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1324 NULL
, SW_SHOWDEFAULT
))
1327 else if (_ILIsBitBucket(pidlChild
))
1329 /* FIXME: detect the drive path of bitbucket if appropiate */
1330 if(!SH_ShowRecycleBinProperties(L
'C'))
1336 WARN("SHMultiFileProperties is not yet implemented\n");
1339 hr
= m_Dcm
.psf
->GetDisplayNameOf(pidlChild
, SHGDN_FORPARSING
, &strFile
);
1342 WCHAR wszBuf
[MAX_PATH
];
1343 hr
= StrRetToBufW(&strFile
, pidlChild
, wszBuf
, _countof(wszBuf
));
1345 hr
= SH_ShowPropertiesDialog(wszBuf
, pidlParent
, &pidlChild
);
1347 ERR("StrRetToBufW failed\n");
1350 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1353 /* Free allocated PIDLs */
1354 if (pidlParent
!= m_Dcm
.pidlFolder
)
1355 ILFree((ITEMIDLIST
*)pidlParent
);
1356 if (m_Dcm
.cidl
< 1 || pidlChild
!= m_Dcm
.apidl
[0])
1357 ILFree((ITEMIDLIST
*)pidlChild
);
1363 CDefaultContextMenu::DoFormat(
1364 LPCMINVOKECOMMANDINFO lpcmi
)
1366 char szDrive
[8] = {0};
1368 if (!_ILGetDrive(m_Dcm
.apidl
[0], szDrive
, sizeof(szDrive
)))
1370 ERR("pidl is not a drive\n");
1374 SHFormatDrive(lpcmi
->hwnd
, szDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1379 CDefaultContextMenu::DoDynamicShellExtensions(
1380 LPCMINVOKECOMMANDINFO lpcmi
)
1382 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
1383 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1385 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, m_iIdSHEFirst
, m_iIdSHELast
);
1387 while(pEntry
&& idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1388 pEntry
= pEntry
->pNext
;
1393 if (idCmd
>= pEntry
->iIdCmdFirst
&& idCmd
<= pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1395 /* invoke the dynamic context menu */
1396 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
- pEntry
->iIdCmdFirst
);
1397 return pEntry
->pCM
->InvokeCommand(lpcmi
);
1404 CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
)
1406 LPSHELLBROWSER lpSB
;
1414 /* Get a pointer to the shell browser */
1415 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1419 /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
1420 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwndTree
)) && hwndTree
)
1421 FlagsName
= L
"ExplorerFlags";
1423 FlagsName
= L
"BrowserFlags";
1425 /* Try to get the flag from the verb */
1426 hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"%s\\shell\\%s", pEntry
->szClass
, pEntry
->szVerb
);
1430 cbVerb
= sizeof(wFlags
);
1431 if (RegGetValueW(HKEY_CLASSES_ROOT
, wszKey
, FlagsName
, RRF_RT_REG_DWORD
, NULL
, &wFlags
, &cbVerb
) == ERROR_SUCCESS
)
1440 CDefaultContextMenu::TryToBrowse(
1441 LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
)
1443 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageW(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1449 hr
= lpSB
->BrowseObject(ILCombine(m_Dcm
.pidlFolder
, pidl
), wFlags
);
1455 CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
)
1457 LPITEMIDLIST pidlFull
= ILCombine(m_Dcm
.pidlFolder
, pidl
);
1458 if (pidlFull
== NULL
)
1463 WCHAR wszPath
[MAX_PATH
];
1464 BOOL bHasPath
= SHGetPathFromIDListW(pidlFull
, wszPath
);
1466 WCHAR wszDir
[MAX_PATH
];
1469 wcscpy(wszDir
, wszPath
);
1470 PathRemoveFileSpec(wszDir
);
1474 SHGetPathFromIDListW(m_Dcm
.pidlFolder
, wszDir
);
1478 RegOpenKeyExW(HKEY_CLASSES_ROOT
, pEntry
->szClass
, 0, KEY_READ
, &hkeyClass
);
1480 SHELLEXECUTEINFOW sei
;
1481 ZeroMemory(&sei
, sizeof(sei
));
1482 sei
.cbSize
= sizeof(sei
);
1483 sei
.hwnd
= lpcmi
->hwnd
;
1484 sei
.nShow
= SW_SHOWNORMAL
;
1485 sei
.lpVerb
= pEntry
->szVerb
;
1486 sei
.lpDirectory
= wszDir
;
1487 sei
.lpIDList
= pidlFull
;
1488 sei
.hkeyClass
= hkeyClass
;
1489 sei
.fMask
= SEE_MASK_CLASSKEY
| SEE_MASK_IDLIST
;
1492 sei
.lpFile
= wszPath
;
1495 ShellExecuteExW(&sei
);
1497 RegCloseKey(hkeyClass
);
1505 CDefaultContextMenu::DoStaticShellExtensions(
1506 LPCMINVOKECOMMANDINFO lpcmi
)
1508 PStaticShellEntry pEntry
= m_pStaticEntries
;
1509 INT iCmd
= LOWORD(lpcmi
->lpVerb
) - m_iIdSCMFirst
;
1513 while (pEntry
&& (iCmd
--) > 0)
1514 pEntry
= pEntry
->pNext
;
1519 /* Get the browse flags to see if we need to browse */
1520 DWORD wFlags
= BrowserFlagsFromVerb(lpcmi
, pEntry
);
1521 BOOL bBrowsed
= FALSE
;
1523 for (i
=0; i
< m_Dcm
.cidl
; i
++)
1525 /* Check if we need to browse */
1528 /* In xp if we have browsed, we don't open any more folders .
1529 * In win7 we browse to the first folder we find and
1530 * open new windows fo for each of the rest of the folders */
1534 hr
= TryToBrowse(lpcmi
, m_Dcm
.apidl
[i
], wFlags
);
1542 InvokePidl(lpcmi
, m_Dcm
.apidl
[i
], pEntry
);
1550 CDefaultContextMenu::InvokeCommand(
1551 LPCMINVOKECOMMANDINFO lpcmi
)
1553 switch(LOWORD(lpcmi
->lpVerb
))
1555 case FCIDM_SHVIEW_BIGICON
:
1556 case FCIDM_SHVIEW_SMALLICON
:
1557 case FCIDM_SHVIEW_LISTVIEW
:
1558 case FCIDM_SHVIEW_REPORTVIEW
:
1559 case 0x30: /* FIX IDS in resource files */
1563 case FCIDM_SHVIEW_AUTOARRANGE
:
1564 case FCIDM_SHVIEW_SNAPTOGRID
:
1565 case FCIDM_SHVIEW_REFRESH
:
1566 return NotifyShellViewWindow(lpcmi
, FALSE
);
1567 case FCIDM_SHVIEW_INSERT
:
1568 return DoPaste(lpcmi
, FALSE
);
1569 case FCIDM_SHVIEW_INSERTLINK
:
1570 return DoPaste(lpcmi
, TRUE
);
1571 case FCIDM_SHVIEW_OPEN
:
1572 case FCIDM_SHVIEW_EXPLORE
:
1573 return DoOpenOrExplore(lpcmi
);
1574 case FCIDM_SHVIEW_COPY
:
1575 case FCIDM_SHVIEW_CUT
:
1576 return DoCopyOrCut(lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1577 case FCIDM_SHVIEW_CREATELINK
:
1578 return DoCreateLink(lpcmi
);
1579 case FCIDM_SHVIEW_DELETE
:
1580 return DoDelete(lpcmi
);
1581 case FCIDM_SHVIEW_RENAME
:
1582 return DoRename(lpcmi
);
1583 case FCIDM_SHVIEW_PROPERTIES
:
1584 return DoProperties(lpcmi
);
1586 return DoFormat(lpcmi
);
1589 if (m_iIdSHEFirst
&& m_iIdSHELast
)
1591 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSHELast
)
1592 return DoDynamicShellExtensions(lpcmi
);
1595 if (m_iIdSCMFirst
&& m_iIdSCMLast
)
1597 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSCMLast
)
1598 return DoStaticShellExtensions(lpcmi
);
1601 FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi
->lpVerb
));
1602 return E_UNEXPECTED
;
1607 CDefaultContextMenu::GetCommandString(
1619 CDefaultContextMenu::HandleMenuMsg(
1629 IDefaultContextMenu_Constructor(
1630 const DEFCONTEXTMENU
*pdcm
,
1638 CComObject
<CDefaultContextMenu
> *pCM
;
1639 HRESULT hr
= CComObject
<CDefaultContextMenu
>::CreateInstance(&pCM
);
1642 pCM
->AddRef(); // CreateInstance returns object with 0 ref count */
1644 CComPtr
<IUnknown
> pResult
;
1645 hr
= pCM
->QueryInterface(riid
, (void **)&pResult
);
1652 hr
= pCM
->Initialize(pdcm
);
1659 *ppv
= pResult
.Detach();
1661 TRACE("This(%p) cidl %u\n", *ppv
, pdcm
->cidl
);
1665 /*************************************************************************
1666 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1672 SHCreateDefaultContextMenu(
1673 const DEFCONTEXTMENU
*pdcm
,
1678 HRESULT hr
= IDefaultContextMenu_Constructor(pdcm
, riid
, ppv
);
1680 ERR("IDefaultContextMenu_Constructor failed: %x\n", hr
);
1681 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1685 /*************************************************************************
1686 * CDefFolderMenu_Create2 [SHELL32.701]
1692 CDefFolderMenu_Create2(
1693 LPCITEMIDLIST pidlFolder
,
1696 LPCITEMIDLIST
*apidl
,
1698 LPFNDFMCALLBACK lpfn
,
1700 const HKEY
*ahkeyClsKeys
,
1701 IContextMenu
**ppcm
)
1703 DEFCONTEXTMENU pdcm
;
1706 pdcm
.pidlFolder
= pidlFolder
;
1710 pdcm
.punkAssociationInfo
= NULL
;
1712 pdcm
.aKeys
= ahkeyClsKeys
;
1714 HRESULT hr
= SHCreateDefaultContextMenu(&pdcm
, IID_PPV_ARG(IContextMenu
, ppcm
));