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)
13 //fixme: this isn't in wine's shlwapi header, and the definition doesnt match the
14 // windows headers. When wine's header and lib are fixed this can be removed.
15 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
);
16 INT WINAPI
SHUnicodeToAnsi(LPCWSTR lpSrcStr
, LPSTR lpDstStr
, INT iLen
);
19 WINE_DEFAULT_DEBUG_CHANNEL(dmenu
);
21 typedef struct _DynamicShellEntry_
27 struct _DynamicShellEntry_
*pNext
;
28 } DynamicShellEntry
, *PDynamicShellEntry
;
30 typedef struct _StaticShellEntry_
34 struct _StaticShellEntry_
*pNext
;
35 } StaticShellEntry
, *PStaticShellEntry
;
39 // verbs for InvokeCommandInfo
41 struct _StaticInvokeCommandMap_
45 } g_StaticInvokeCmdMap
[] =
47 { "RunAs", 0 }, // Unimplemented
48 { "Print", 0 }, // Unimplemented
49 { "Preview", 0 }, // Unimplemented
50 { "Open", FCIDM_SHVIEW_OPEN
},
51 { CMDSTR_NEWFOLDERA
, FCIDM_SHVIEW_NEWFOLDER
},
52 { "cut", FCIDM_SHVIEW_CUT
},
53 { "copy", FCIDM_SHVIEW_COPY
},
54 { "paste", FCIDM_SHVIEW_INSERT
},
55 { "link", FCIDM_SHVIEW_CREATELINK
},
56 { "delete", FCIDM_SHVIEW_DELETE
},
57 { "properties", FCIDM_SHVIEW_PROPERTIES
},
58 { "rename", FCIDM_SHVIEW_RENAME
},
62 class CDefaultContextMenu
:
63 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
65 public IObjectWithSite
68 CComPtr
<IUnknown
> m_site
;
69 CComPtr
<IShellFolder
> m_psf
;
70 CComPtr
<IContextMenuCB
> m_pmcb
;
71 LPFNDFMCALLBACK m_pfnmcb
;
73 PCUITEMID_CHILD_ARRAY m_apidl
;
74 CComPtr
<IDataObject
> m_pDataObj
;
77 PIDLIST_ABSOLUTE m_pidlFolder
;
78 DWORD m_bGroupPolicyActive
;
79 PDynamicShellEntry m_pDynamicEntries
; /* first dynamic shell extension entry */
80 UINT m_iIdSHEFirst
; /* first used id */
81 UINT m_iIdSHELast
; /* last used id */
82 PStaticShellEntry m_pStaticEntries
; /* first static shell extension entry */
83 UINT m_iIdSCMFirst
; /* first static used id */
84 UINT m_iIdSCMLast
; /* last static used id */
85 UINT m_iIdCBFirst
; /* first callback used id */
86 UINT m_iIdCBLast
; /* last callback used id */
87 UINT m_iIdDfltFirst
; /* first default part id */
88 UINT m_iIdDfltLast
; /* last default part id */
90 HRESULT
_DoCallback(UINT uMsg
, WPARAM wParam
, LPVOID lParam
);
91 void AddStaticEntry(const HKEY hkeyClass
, const WCHAR
*szVerb
);
92 void AddStaticEntriesForKey(HKEY hKey
);
93 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
);
94 HRESULT
LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
);
95 BOOL
EnumerateDynamicContextHandlerForKey(HKEY hRootKey
);
96 UINT
AddShellExtensionsToMenu(HMENU hMenu
, UINT
* pIndexMenu
, UINT idCmdFirst
, UINT idCmdLast
);
97 UINT
AddStaticContextMenusToMenu(HMENU hMenu
, UINT
* IndexMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
);
98 HRESULT
DoPaste(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
);
99 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
100 HRESULT
DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
);
101 HRESULT
DoDelete(LPCMINVOKECOMMANDINFO lpcmi
);
102 HRESULT
DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
);
103 HRESULT
DoRename(LPCMINVOKECOMMANDINFO lpcmi
);
104 HRESULT
DoProperties(LPCMINVOKECOMMANDINFO lpcmi
);
105 HRESULT
DoCreateNewFolder(LPCMINVOKECOMMANDINFO lpici
);
106 HRESULT
InvokeShellExt(LPCMINVOKECOMMANDINFO lpcmi
);
107 HRESULT
InvokeRegVerb(LPCMINVOKECOMMANDINFO lpcmi
);
108 DWORD
BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
);
109 HRESULT
TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
);
110 HRESULT
InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
);
111 PDynamicShellEntry
GetDynamicEntry(UINT idCmd
);
112 BOOL
MapVerbToCmdId(PVOID Verb
, PUINT idCmd
, BOOL IsUnicode
);
115 CDefaultContextMenu();
116 ~CDefaultContextMenu();
117 HRESULT WINAPI
Initialize(const DEFCONTEXTMENU
*pdcm
, LPFNDFMCALLBACK lpfn
);
120 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
121 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
122 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
125 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
128 virtual HRESULT WINAPI
HandleMenuMsg2(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*plResult
);
131 virtual HRESULT STDMETHODCALLTYPE
SetSite(IUnknown
*pUnkSite
);
132 virtual HRESULT STDMETHODCALLTYPE
GetSite(REFIID riid
, void **ppvSite
);
134 BEGIN_COM_MAP(CDefaultContextMenu
)
135 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
136 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
137 COM_INTERFACE_ENTRY_IID(IID_IContextMenu3
, IContextMenu3
)
138 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite
, IObjectWithSite
)
142 CDefaultContextMenu::CDefaultContextMenu() :
152 m_bGroupPolicyActive(0),
153 m_pDynamicEntries(NULL
),
156 m_pStaticEntries(NULL
),
167 CDefaultContextMenu::~CDefaultContextMenu()
169 /* Free dynamic shell extension entries */
170 PDynamicShellEntry pDynamicEntry
= m_pDynamicEntries
, pNextDynamic
;
171 while (pDynamicEntry
)
173 pNextDynamic
= pDynamicEntry
->pNext
;
174 pDynamicEntry
->pCM
->Release();
175 HeapFree(GetProcessHeap(), 0, pDynamicEntry
);
176 pDynamicEntry
= pNextDynamic
;
179 /* Free static shell extension entries */
180 PStaticShellEntry pStaticEntry
= m_pStaticEntries
, pNextStatic
;
183 pNextStatic
= pStaticEntry
->pNext
;
184 HeapFree(GetProcessHeap(), 0, pStaticEntry
->szVerb
);
185 HeapFree(GetProcessHeap(), 0, pStaticEntry
);
186 pStaticEntry
= pNextStatic
;
189 for (UINT i
= 0; i
< m_cKeys
; i
++)
190 RegCloseKey(m_aKeys
[i
]);
191 HeapFree(GetProcessHeap(), 0, m_aKeys
);
194 CoTaskMemFree(m_pidlFolder
);
195 _ILFreeaPidl(const_cast<PITEMID_CHILD
*>(m_apidl
), m_cidl
);
198 HRESULT WINAPI
CDefaultContextMenu::Initialize(const DEFCONTEXTMENU
*pdcm
, LPFNDFMCALLBACK lpfn
)
200 TRACE("cidl %u\n", pdcm
->cidl
);
202 if (!pdcm
->pcmcb
&& !lpfn
)
204 ERR("CDefaultContextMenu needs a callback!\n");
209 m_apidl
= const_cast<PCUITEMID_CHILD_ARRAY
>(_ILCopyaPidl(pdcm
->apidl
, m_cidl
));
210 if (m_cidl
&& !m_apidl
)
211 return E_OUTOFMEMORY
;
213 m_pmcb
= pdcm
->pcmcb
;
216 m_cKeys
= pdcm
->cKeys
;
219 m_aKeys
= (HKEY
*)HeapAlloc(GetProcessHeap(), 0, sizeof(HKEY
) * pdcm
->cKeys
);
221 return E_OUTOFMEMORY
;
222 memcpy(m_aKeys
, pdcm
->aKeys
, sizeof(HKEY
) * pdcm
->cKeys
);
225 m_psf
->GetUIObjectOf(pdcm
->hwnd
, m_cidl
, m_apidl
, IID_NULL_PPV_ARG(IDataObject
, &m_pDataObj
));
227 if (pdcm
->pidlFolder
)
229 m_pidlFolder
= ILClone(pdcm
->pidlFolder
);
233 CComPtr
<IPersistFolder2
> pf
= NULL
;
234 if (SUCCEEDED(m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
236 if (FAILED(pf
->GetCurFolder(&m_pidlFolder
)))
237 ERR("GetCurFolder failed\n");
239 TRACE("pidlFolder %p\n", m_pidlFolder
);
245 HRESULT
CDefaultContextMenu::_DoCallback(UINT uMsg
, WPARAM wParam
, LPVOID lParam
)
249 return m_pmcb
->CallBack(m_psf
, NULL
, m_pDataObj
, uMsg
, wParam
, (LPARAM
)lParam
);
253 return m_pfnmcb(m_psf
, NULL
, m_pDataObj
, uMsg
, wParam
, (LPARAM
)lParam
);
259 void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass
, const WCHAR
*szVerb
)
261 PStaticShellEntry pEntry
= m_pStaticEntries
, pLastEntry
= NULL
;
264 if (!wcsicmp(pEntry
->szVerb
, szVerb
))
266 /* entry already exists */
270 pEntry
= pEntry
->pNext
;
273 TRACE("adding verb %s\n", debugstr_w(szVerb
));
275 pEntry
= (StaticShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry
));
278 pEntry
->pNext
= NULL
;
279 pEntry
->szVerb
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb
) + 1) * sizeof(WCHAR
));
281 wcscpy(pEntry
->szVerb
, szVerb
);
282 pEntry
->hkClass
= hkeyClass
;
285 if (!wcsicmp(szVerb
, L
"open"))
287 /* open verb is always inserted in front */
288 pEntry
->pNext
= m_pStaticEntries
;
289 m_pStaticEntries
= pEntry
;
292 pLastEntry
->pNext
= pEntry
;
294 m_pStaticEntries
= pEntry
;
297 void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey
)
300 DWORD cchName
, dwIndex
= 0;
303 LRESULT lres
= RegOpenKeyExW(hKey
, L
"shell", 0, KEY_READ
, &hShellKey
);
304 if (lres
!= STATUS_SUCCESS
)
309 cchName
= _countof(wszName
);
310 if (RegEnumKeyExW(hShellKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
313 AddStaticEntry(hKey
, wszName
);
316 RegCloseKey(hShellKey
);
324 CComPtr
<IDataObject
> pDataObj
;
326 if (SUCCEEDED(OleGetClipboard(&pDataObj
)))
331 TRACE("pDataObj=%p\n", pDataObj
.p
);
333 /* Set the FORMATETC structure*/
334 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
335 if (SUCCEEDED(pDataObj
->GetData(&formatetc
, &medium
)))
338 ReleaseStgMedium(&medium
);
346 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
)
348 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
352 if (!memcmp(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
)))
354 pEntry
= pEntry
->pNext
;
361 CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
)
365 TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey
, wine_dbgstr_guid(pclsid
));
367 if (IsShellExtensionAlreadyLoaded(pclsid
))
370 CComPtr
<IContextMenu
> pcm
;
371 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IContextMenu
, &pcm
));
374 ERR("SHCoCreateInstance(IContextMenu) failed.clsid %s hr 0x%x\n", wine_dbgstr_guid(pclsid
), hr
);
378 CComPtr
<IShellExtInit
> pExtInit
;
379 hr
= pcm
->QueryInterface(IID_PPV_ARG(IShellExtInit
, &pExtInit
));
382 ERR("IContextMenu->QueryInterface(IShellExtInit) failed.clsid %s hr 0x%x\n", wine_dbgstr_guid(pclsid
), hr
);
386 hr
= pExtInit
->Initialize(m_pidlFolder
, m_pDataObj
, hKey
);
389 ERR("IShellExtInit::Initialize failed.clsid %s hr 0x%x\n", wine_dbgstr_guid(pclsid
), hr
);
394 IUnknown_SetSite(pcm
, m_site
);
396 PDynamicShellEntry pEntry
= (DynamicShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
398 return E_OUTOFMEMORY
;
400 pEntry
->iIdCmdFirst
= 0;
401 pEntry
->pNext
= NULL
;
403 pEntry
->pCM
= pcm
.Detach();
404 memcpy(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
));
406 if (m_pDynamicEntries
)
408 PDynamicShellEntry pLastEntry
= m_pDynamicEntries
;
410 while (pLastEntry
->pNext
)
411 pLastEntry
= pLastEntry
->pNext
;
413 pLastEntry
->pNext
= pEntry
;
416 m_pDynamicEntries
= pEntry
;
422 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey
)
424 WCHAR wszName
[MAX_PATH
], wszBuf
[MAX_PATH
], *pwszClsid
;
429 if (RegOpenKeyExW(hRootKey
, L
"shellex\\ContextMenuHandlers", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
431 TRACE("RegOpenKeyExW failed\n");
438 cchName
= _countof(wszName
);
439 if (RegEnumKeyExW(hKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
442 /* Key name or key value is CLSID */
444 hr
= CLSIDFromString(wszName
, &clsid
);
449 DWORD cchBuf
= _countof(wszBuf
);
450 if (RegGetValueW(hKey
, wszName
, NULL
, RRF_RT_REG_SZ
, NULL
, wszBuf
, &cchBuf
) == ERROR_SUCCESS
)
451 hr
= CLSIDFromString(wszBuf
, &clsid
);
457 ERR("CLSIDFromString failed for clsid %S hr 0x%x\n", pwszClsid
, hr
);
461 if (m_bGroupPolicyActive
)
463 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
464 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
469 NULL
) != ERROR_SUCCESS
)
471 ERR("Shell extension %s not approved!\n", pwszClsid
);
476 hr
= LoadDynamicContextMenuHandler(hKey
, &clsid
);
478 WARN("Failed to get context menu entires from shell extension! clsid: %S\n", pwszClsid
);
486 CDefaultContextMenu::AddShellExtensionsToMenu(HMENU hMenu
, UINT
* pIndexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
490 if (!m_pDynamicEntries
)
493 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
496 HRESULT hr
= pEntry
->pCM
->QueryContextMenu(hMenu
, *pIndexMenu
, idCmdFirst
+ cIds
, idCmdLast
, CMF_NORMAL
);
499 pEntry
->iIdCmdFirst
= cIds
;
500 pEntry
->NumIds
= LOWORD(hr
);
501 (*pIndexMenu
) += pEntry
->NumIds
;
503 cIds
+= pEntry
->NumIds
;
504 if(idCmdFirst
+ cIds
>= idCmdLast
)
507 TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry
, hr
, pEntry
->pCM
, pEntry
->iIdCmdFirst
, pEntry
->NumIds
);
508 pEntry
= pEntry
->pNext
;
515 CDefaultContextMenu::AddStaticContextMenusToMenu(
527 mii
.cbSize
= sizeof(mii
);
528 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
529 mii
.fType
= MFT_STRING
;
530 mii
.dwTypeData
= NULL
;
532 PStaticShellEntry pEntry
= m_pStaticEntries
;
536 fState
= MFS_ENABLED
;
537 mii
.dwTypeData
= NULL
;
539 /* set first entry as default */
540 if (pEntry
== m_pStaticEntries
)
541 fState
|= MFS_DEFAULT
;
543 if (!wcsicmp(pEntry
->szVerb
, L
"open"))
545 /* override default when open verb is found */
546 fState
|= MFS_DEFAULT
;
547 idResource
= IDS_OPEN_VERB
;
549 else if (!wcsicmp(pEntry
->szVerb
, L
"explore"))
550 idResource
= IDS_EXPLORE_VERB
;
551 else if (!wcsicmp(pEntry
->szVerb
, L
"runas"))
552 idResource
= IDS_RUNAS_VERB
;
553 else if (!wcsicmp(pEntry
->szVerb
, L
"edit"))
554 idResource
= IDS_EDIT_VERB
;
555 else if (!wcsicmp(pEntry
->szVerb
, L
"find"))
556 idResource
= IDS_FIND_VERB
;
557 else if (!wcsicmp(pEntry
->szVerb
, L
"print"))
558 idResource
= IDS_PRINT_VERB
;
559 else if (!wcsicmp(pEntry
->szVerb
, L
"printto"))
561 pEntry
= pEntry
->pNext
;
567 /* By default use verb for menu item name */
568 mii
.dwTypeData
= pEntry
->szVerb
;
572 if (LoadStringW(shell32_hInstance
, idResource
, wszVerb
, _countof(wszVerb
)))
573 mii
.dwTypeData
= wszVerb
; /* use translated verb */
575 ERR("Failed to load string\n");
580 HRESULT hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"shell\\%s", pEntry
->szVerb
);
585 DWORD cbVerb
= sizeof(wszVerb
);
586 LONG res
= RegOpenKeyW(pEntry
->hkClass
, wszKey
, &hkVerb
);
587 if (res
== ERROR_SUCCESS
)
589 res
= RegLoadMUIStringW(hkVerb
,
596 if (res
== ERROR_SUCCESS
)
598 /* use description for the menu entry */
599 mii
.dwTypeData
= wszVerb
;
607 mii
.cch
= wcslen(mii
.dwTypeData
);
609 mii
.wID
= iIdCmdFirst
+ cIds
;
610 InsertMenuItemW(hMenu
, *pIndexMenu
, TRUE
, &mii
);
614 pEntry
= pEntry
->pNext
;
616 if (mii
.wID
>= iIdCmdLast
)
623 void WINAPI
_InsertMenuItemW(
635 ZeroMemory(&mii
, sizeof(mii
));
636 mii
.cbSize
= sizeof(mii
);
637 if (fType
== MFT_SEPARATOR
)
638 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
639 else if (fType
== MFT_STRING
)
641 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
642 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
644 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), wszText
, _countof(wszText
)))
645 mii
.dwTypeData
= wszText
;
648 ERR("failed to load string %p\n", dwTypeData
);
653 mii
.dwTypeData
= (LPWSTR
)dwTypeData
;
659 InsertMenuItemW(hMenu
, indexMenu
, fByPosition
, &mii
);
664 CDefaultContextMenu::QueryContextMenu(
672 UINT idCmdNext
= idCmdFirst
;
675 TRACE("BuildShellItemContextMenu entered\n");
677 /* Load static verbs and shell extensions from registry */
678 for (UINT i
= 0; i
< m_cKeys
; i
++)
680 AddStaticEntriesForKey(m_aKeys
[i
]);
681 EnumerateDynamicContextHandlerForKey(m_aKeys
[i
]);
684 /* Add static context menu handlers */
685 cIds
= AddStaticContextMenusToMenu(hMenu
, &IndexMenu
, idCmdFirst
, idCmdLast
);
688 idCmdNext
= idCmdFirst
+ cIds
;
690 /* Add dynamic context menu handlers */
691 cIds
+= AddShellExtensionsToMenu(hMenu
, &IndexMenu
, idCmdNext
, idCmdLast
);
692 m_iIdSHEFirst
= m_iIdSCMLast
;
694 idCmdNext
= idCmdFirst
+ cIds
;
695 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst
, m_iIdSHELast
);
697 /* Now let the callback add its own items */
698 QCMINFO qcminfo
= {hMenu
, IndexMenu
, idCmdNext
, idCmdLast
, NULL
};
699 if (SUCCEEDED(_DoCallback(DFM_MERGECONTEXTMENU
, uFlags
, &qcminfo
)))
701 cIds
+= qcminfo
.idCmdFirst
;
702 IndexMenu
+= qcminfo
.idCmdFirst
;
703 m_iIdCBFirst
= m_iIdSHELast
;
705 idCmdNext
= idCmdFirst
+ cIds
;
708 if (uFlags
& CMF_VERBSONLY
)
709 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, cIds
);
711 /* If this is a background context menu we are done */
713 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, cIds
);
715 /* Get the attributes of the items */
716 SFGAOF rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
717 hr
= m_psf
->GetAttributesOf(m_cidl
, m_apidl
, &rfg
);
718 if (FAILED_UNEXPECTEDLY(hr
))
719 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, cIds
);
721 /* Add the default part of the menu */
722 HMENU hmenuDefault
= LoadMenu(_AtlBaseModule
.GetResourceInstance(), L
"MENU_SHV_FILE");
724 /* Remove uneeded entries */
725 if (!(rfg
& SFGAO_CANMOVE
))
726 DeleteMenu(hmenuDefault
, IDM_CUT
, MF_BYCOMMAND
);
727 if (!(rfg
& SFGAO_CANCOPY
))
728 DeleteMenu(hmenuDefault
, IDM_COPY
, MF_BYCOMMAND
);
729 if (!((rfg
& SFGAO_FILESYSTEM
) && HasClipboardData()))
730 DeleteMenu(hmenuDefault
, IDM_INSERT
, MF_BYCOMMAND
);
731 if (!(rfg
& SFGAO_CANLINK
))
732 DeleteMenu(hmenuDefault
, IDM_CREATELINK
, MF_BYCOMMAND
);
733 if (!(rfg
& SFGAO_CANDELETE
))
734 DeleteMenu(hmenuDefault
, IDM_DELETE
, MF_BYCOMMAND
);
735 if (!(rfg
& SFGAO_CANRENAME
))
736 DeleteMenu(hmenuDefault
, IDM_RENAME
, MF_BYCOMMAND
);
737 if (!(rfg
& SFGAO_HASPROPSHEET
))
738 DeleteMenu(hmenuDefault
, IDM_PROPERTIES
, MF_BYCOMMAND
);
740 UINT idMax
= Shell_MergeMenus(hMenu
, GetSubMenu(hmenuDefault
, 0), IndexMenu
, idCmdNext
, idCmdLast
, 0);
741 m_iIdDfltFirst
= cIds
;
742 cIds
+= idMax
- idCmdNext
;
743 m_iIdDfltLast
= cIds
;
745 DestroyMenu(hmenuDefault
);
747 return MAKE_HRESULT(SEVERITY_SUCCESS
, 0, cIds
);
750 HRESULT
CDefaultContextMenu::DoPaste(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
)
754 CComPtr
<IDataObject
> pda
;
755 hr
= OleGetClipboard(&pda
);
756 if (FAILED_UNEXPECTEDLY(hr
))
759 FORMATETC formatetc2
;
761 InitFormatEtc(formatetc2
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
765 if (SUCCEEDED(pda
->GetData(&formatetc2
, &medium2
)))
767 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium2
.hGlobal
);
770 if (*pdwFlag
== DROPEFFECT_COPY
)
776 ERR("No drop effect obtained");
778 GlobalUnlock(medium2
.hGlobal
);
783 dwKey
= MK_CONTROL
|MK_SHIFT
;
786 CComPtr
<IDropTarget
> pdrop
;
788 hr
= m_psf
->GetUIObjectOf(NULL
, 1, &m_apidl
[0], IID_NULL_PPV_ARG(IDropTarget
, &pdrop
));
790 hr
= m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pdrop
));
792 if (FAILED_UNEXPECTEDLY(hr
))
795 SHSimulateDrop(pdrop
, pda
, dwKey
, NULL
, NULL
);
797 TRACE("CP result %x\n", hr
);
802 CDefaultContextMenu::DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
)
808 HRESULT
CDefaultContextMenu::DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
)
810 if (!m_cidl
|| !m_pDataObj
)
813 CComPtr
<IDropTarget
> pDT
;
814 HRESULT hr
= m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pDT
));
815 if (FAILED_UNEXPECTEDLY(hr
))
818 SHSimulateDrop(pDT
, m_pDataObj
, MK_CONTROL
|MK_SHIFT
, NULL
, NULL
);
823 HRESULT
CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi
)
825 if (!m_cidl
|| !m_pDataObj
)
828 CComPtr
<IDropTarget
> pDT
;
829 HRESULT hr
= CRecyclerDropTarget_CreateInstance(IID_PPV_ARG(IDropTarget
, &pDT
));
830 if (FAILED_UNEXPECTEDLY(hr
))
833 SHSimulateDrop(pDT
, m_pDataObj
, 0, NULL
, NULL
);
838 HRESULT
CDefaultContextMenu::DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
)
840 if (!m_cidl
|| !m_pDataObj
)
847 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
848 m_pDataObj
->GetData(&formatetc
, &medium
);
849 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium
.hGlobal
);
851 *pdwFlag
= DROPEFFECT_MOVE
;
852 GlobalUnlock(medium
.hGlobal
);
853 m_pDataObj
->SetData(&formatetc
, &medium
, TRUE
);
856 HRESULT hr
= OleSetClipboard(m_pDataObj
);
857 if (FAILED_UNEXPECTEDLY(hr
))
863 HRESULT
CDefaultContextMenu::DoRename(LPCMINVOKECOMMANDINFO lpcmi
)
865 CComPtr
<IShellBrowser
> psb
;
868 if (!m_site
|| !m_cidl
)
871 /* Get a pointer to the shell browser */
872 hr
= IUnknown_QueryService(m_site
, SID_IShellBrowser
, IID_PPV_ARG(IShellBrowser
, &psb
));
873 if (FAILED_UNEXPECTEDLY(hr
))
876 CComPtr
<IShellView
> lpSV
;
877 hr
= psb
->QueryActiveShellView(&lpSV
);
878 if (FAILED_UNEXPECTEDLY(hr
))
881 SVSIF selFlags
= SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
;
882 hr
= lpSV
->SelectItem(m_apidl
[0], selFlags
);
883 if (FAILED_UNEXPECTEDLY(hr
))
890 CDefaultContextMenu::DoProperties(
891 LPCMINVOKECOMMANDINFO lpcmi
)
893 _DoCallback(DFM_INVOKECOMMAND
, DFM_CMD_PROPERTIES
, NULL
);
898 // This code is taken from CNewMenu and should be shared between the 2 classes
900 CDefaultContextMenu::DoCreateNewFolder(
901 LPCMINVOKECOMMANDINFO lpici
)
903 WCHAR wszPath
[MAX_PATH
];
904 WCHAR wszName
[MAX_PATH
];
905 WCHAR wszNewFolder
[25];
908 /* Get folder path */
909 hr
= SHGetPathFromIDListW(m_pidlFolder
, wszPath
);
910 if (FAILED_UNEXPECTEDLY(hr
))
913 if (!LoadStringW(shell32_hInstance
, IDS_NEWFOLDER
, wszNewFolder
, _countof(wszNewFolder
)))
916 /* Create the name of the new directory */
917 if (!PathYetAnotherMakeUniqueName(wszName
, wszPath
, NULL
, wszNewFolder
))
920 /* Create the new directory and show the appropriate dialog in case of error */
921 if (SHCreateDirectory(lpici
->hwnd
, wszName
) != ERROR_SUCCESS
)
924 /* Show and select the new item in the def view */
926 PITEMID_CHILD pidlNewItem
;
927 CComPtr
<IShellView
> psv
;
929 /* Notify the view object about the new item */
930 SHChangeNotify(SHCNE_MKDIR
, SHCNF_PATHW
, (LPCVOID
)wszName
, NULL
);
935 /* Get a pointer to the shell view */
936 hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
937 if (FAILED_UNEXPECTEDLY(hr
))
940 /* Attempt to get the pidl of the new item */
941 hr
= SHILCreateFromPathW(wszName
, &pidl
, NULL
);
942 if (FAILED_UNEXPECTEDLY(hr
))
945 pidlNewItem
= ILFindLastID(pidl
);
947 hr
= psv
->SelectItem(pidlNewItem
, SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
|
948 SVSI_FOCUSED
| SVSI_SELECT
);
949 if (FAILED_UNEXPECTEDLY(hr
))
957 PDynamicShellEntry
CDefaultContextMenu::GetDynamicEntry(UINT idCmd
)
959 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
961 while(pEntry
&& idCmd
>= pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
962 pEntry
= pEntry
->pNext
;
967 if (idCmd
< pEntry
->iIdCmdFirst
|| idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
973 // FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
977 CDefaultContextMenu::MapVerbToCmdId(PVOID Verb
, PUINT idCmd
, BOOL IsUnicode
)
979 WCHAR UnicodeStr
[MAX_VERB
];
981 /* Loop through all the static verbs looking for a match */
982 for (UINT i
= 0; i
< _countof(g_StaticInvokeCmdMap
); i
++)
984 /* We can match both ANSI and unicode strings */
987 /* The static verbs are ANSI, get a unicode version before doing the compare */
988 SHAnsiToUnicode(g_StaticInvokeCmdMap
[i
].szStringVerb
, UnicodeStr
, MAX_VERB
);
989 if (!wcscmp(UnicodeStr
, (LPWSTR
)Verb
))
991 /* Return the Corresponding Id */
992 *idCmd
= g_StaticInvokeCmdMap
[i
].IntVerb
;
998 if (!strcmp(g_StaticInvokeCmdMap
[i
].szStringVerb
, (LPSTR
)Verb
))
1000 *idCmd
= g_StaticInvokeCmdMap
[i
].IntVerb
;
1010 CDefaultContextMenu::InvokeShellExt(
1011 LPCMINVOKECOMMANDINFO lpcmi
)
1013 TRACE("verb %p first %x last %x\n", lpcmi
->lpVerb
, m_iIdSHEFirst
, m_iIdSHELast
);
1015 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
1016 PDynamicShellEntry pEntry
= GetDynamicEntry(idCmd
);
1020 /* invoke the dynamic context menu */
1021 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
- pEntry
->iIdCmdFirst
);
1022 return pEntry
->pCM
->InvokeCommand(lpcmi
);
1026 CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
)
1028 CComPtr
<IShellBrowser
> psb
;
1039 /* Get a pointer to the shell browser */
1040 hr
= IUnknown_QueryService(m_site
, SID_IShellBrowser
, IID_PPV_ARG(IShellBrowser
, &psb
));
1041 if (FAILED_UNEXPECTEDLY(hr
))
1044 /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
1045 if (SUCCEEDED(psb
->GetControlWindow(FCW_TREE
, &hwndTree
)) && hwndTree
)
1046 FlagsName
= L
"ExplorerFlags";
1048 FlagsName
= L
"BrowserFlags";
1050 /* Try to get the flag from the verb */
1051 hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"shell\\%s", pEntry
->szVerb
);
1052 if (FAILED_UNEXPECTEDLY(hr
))
1055 cbVerb
= sizeof(wFlags
);
1056 if (RegGetValueW(pEntry
->hkClass
, wszKey
, FlagsName
, RRF_RT_REG_DWORD
, NULL
, &wFlags
, &cbVerb
) == ERROR_SUCCESS
)
1065 CDefaultContextMenu::TryToBrowse(
1066 LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
)
1068 CComPtr
<IShellBrowser
> psb
;
1074 /* Get a pointer to the shell browser */
1075 hr
= IUnknown_QueryService(m_site
, SID_IShellBrowser
, IID_PPV_ARG(IShellBrowser
, &psb
));
1076 if (FAILED_UNEXPECTEDLY(hr
))
1079 return psb
->BrowseObject(ILCombine(m_pidlFolder
, pidl
), wFlags
);
1083 CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
)
1085 LPITEMIDLIST pidlFull
= ILCombine(m_pidlFolder
, pidl
);
1086 if (pidlFull
== NULL
)
1091 WCHAR wszPath
[MAX_PATH
];
1092 BOOL bHasPath
= SHGetPathFromIDListW(pidlFull
, wszPath
);
1094 WCHAR wszDir
[MAX_PATH
];
1097 wcscpy(wszDir
, wszPath
);
1098 PathRemoveFileSpec(wszDir
);
1102 SHGetPathFromIDListW(m_pidlFolder
, wszDir
);
1105 SHELLEXECUTEINFOW sei
;
1106 ZeroMemory(&sei
, sizeof(sei
));
1107 sei
.cbSize
= sizeof(sei
);
1108 sei
.hwnd
= lpcmi
->hwnd
;
1109 sei
.nShow
= SW_SHOWNORMAL
;
1110 sei
.lpVerb
= pEntry
->szVerb
;
1111 sei
.lpDirectory
= wszDir
;
1112 sei
.lpIDList
= pidlFull
;
1113 sei
.hkeyClass
= pEntry
->hkClass
;
1114 sei
.fMask
= SEE_MASK_CLASSKEY
| SEE_MASK_IDLIST
;
1117 sei
.lpFile
= wszPath
;
1120 ShellExecuteExW(&sei
);
1128 CDefaultContextMenu::InvokeRegVerb(
1129 LPCMINVOKECOMMANDINFO lpcmi
)
1131 PStaticShellEntry pEntry
= m_pStaticEntries
;
1132 INT iCmd
= LOWORD(lpcmi
->lpVerb
) - m_iIdSCMFirst
;
1136 while (pEntry
&& (iCmd
--) > 0)
1137 pEntry
= pEntry
->pNext
;
1142 /* Get the browse flags to see if we need to browse */
1143 DWORD wFlags
= BrowserFlagsFromVerb(lpcmi
, pEntry
);
1144 BOOL bBrowsed
= FALSE
;
1146 for (i
=0; i
< m_cidl
; i
++)
1148 /* Check if we need to browse */
1151 /* In xp if we have browsed, we don't open any more folders.
1152 * In win7 we browse to the first folder we find and
1153 * open new windows for each of the rest of the folders */
1157 hr
= TryToBrowse(lpcmi
, m_apidl
[i
], wFlags
);
1165 InvokePidl(lpcmi
, m_apidl
[i
], pEntry
);
1173 CDefaultContextMenu::InvokeCommand(
1174 LPCMINVOKECOMMANDINFO lpcmi
)
1176 CMINVOKECOMMANDINFO LocalInvokeInfo
;
1180 /* Take a local copy of the fixed members of the
1181 struct as we might need to modify the verb */
1182 LocalInvokeInfo
= *lpcmi
;
1184 /* Check if this is a string verb */
1185 if (HIWORD(LocalInvokeInfo
.lpVerb
))
1187 /* Get the ID which corresponds to this verb, and update our local copy */
1188 if (MapVerbToCmdId((LPVOID
)LocalInvokeInfo
.lpVerb
, &CmdId
, FALSE
))
1189 LocalInvokeInfo
.lpVerb
= MAKEINTRESOURCEA(CmdId
);
1192 CmdId
= LOWORD(LocalInvokeInfo
.lpVerb
);
1194 if (m_pDynamicEntries
&& CmdId
>= m_iIdSHEFirst
&& CmdId
< m_iIdSHELast
)
1196 LocalInvokeInfo
.lpVerb
-= m_iIdSHEFirst
;
1197 Result
= InvokeShellExt(&LocalInvokeInfo
);
1201 if (m_pStaticEntries
&& CmdId
>= m_iIdSCMFirst
&& CmdId
< m_iIdSCMLast
)
1203 LocalInvokeInfo
.lpVerb
-= m_iIdSCMFirst
;
1204 Result
= InvokeRegVerb(&LocalInvokeInfo
);
1208 if (m_iIdCBFirst
!= m_iIdCBLast
&& CmdId
>= m_iIdCBFirst
&& CmdId
< m_iIdCBLast
)
1210 Result
= _DoCallback(DFM_INVOKECOMMAND
, CmdId
- m_iIdCBFirst
, NULL
);
1214 if (m_iIdDfltFirst
!= m_iIdDfltLast
&& CmdId
>= m_iIdDfltFirst
&& CmdId
< m_iIdDfltLast
)
1216 CmdId
-= m_iIdDfltFirst
;
1217 /* See the definitions of IDM_CUT and co to see how this works */
1221 /* Check if this is a Id */
1224 case FCIDM_SHVIEW_INSERT
:
1225 Result
= DoPaste(&LocalInvokeInfo
, FALSE
);
1227 case FCIDM_SHVIEW_INSERTLINK
:
1228 Result
= DoPaste(&LocalInvokeInfo
, TRUE
);
1230 case FCIDM_SHVIEW_OPEN
:
1231 case FCIDM_SHVIEW_EXPLORE
:
1232 Result
= DoOpenOrExplore(&LocalInvokeInfo
);
1234 case FCIDM_SHVIEW_COPY
:
1235 case FCIDM_SHVIEW_CUT
:
1236 Result
= DoCopyOrCut(&LocalInvokeInfo
, CmdId
== FCIDM_SHVIEW_COPY
);
1238 case FCIDM_SHVIEW_CREATELINK
:
1239 Result
= DoCreateLink(&LocalInvokeInfo
);
1241 case FCIDM_SHVIEW_DELETE
:
1242 Result
= DoDelete(&LocalInvokeInfo
);
1244 case FCIDM_SHVIEW_RENAME
:
1245 Result
= DoRename(&LocalInvokeInfo
);
1247 case FCIDM_SHVIEW_PROPERTIES
:
1248 Result
= DoProperties(&LocalInvokeInfo
);
1250 case FCIDM_SHVIEW_NEWFOLDER
:
1251 Result
= DoCreateNewFolder(&LocalInvokeInfo
);
1254 Result
= E_INVALIDARG
;
1255 ERR("Unhandled Verb %xl\n", LOWORD(LocalInvokeInfo
.lpVerb
));
1264 CDefaultContextMenu::GetCommandString(
1271 /* We don't handle the help text yet */
1272 if (uFlags
== GCS_HELPTEXTA
||
1273 uFlags
== GCS_HELPTEXTW
||
1274 HIWORD(idCommand
) != 0)
1279 UINT CmdId
= LOWORD(idCommand
);
1281 if (m_pDynamicEntries
&& CmdId
>= m_iIdSHEFirst
&& CmdId
< m_iIdSHELast
)
1283 idCommand
-= m_iIdSHEFirst
;
1284 PDynamicShellEntry pEntry
= GetDynamicEntry(idCommand
);
1288 idCommand
-= pEntry
->iIdCmdFirst
;
1289 return pEntry
->pCM
->GetCommandString(idCommand
,
1296 if (m_pStaticEntries
&& CmdId
>= m_iIdSCMFirst
&& CmdId
< m_iIdSCMLast
)
1298 /* Validation just returns S_OK on a match. The id exists. */
1299 if (uFlags
== GCS_VALIDATEA
|| uFlags
== GCS_VALIDATEW
)
1302 CmdId
-= m_iIdSCMFirst
;
1304 PStaticShellEntry pEntry
= m_pStaticEntries
;
1305 while (pEntry
&& (CmdId
--) > 0)
1306 pEntry
= pEntry
->pNext
;
1309 return E_INVALIDARG
;
1311 if (uFlags
== GCS_VERBW
)
1312 return StringCchCopyW((LPWSTR
)lpszName
, uMaxNameLen
, pEntry
->szVerb
);
1314 if (uFlags
== GCS_VERBA
)
1316 if (SHUnicodeToAnsi(pEntry
->szVerb
, lpszName
, uMaxNameLen
))
1320 return E_INVALIDARG
;
1323 //FIXME: Should we handle callbacks here?
1324 if (m_iIdDfltFirst
!= m_iIdDfltLast
&& CmdId
>= m_iIdDfltFirst
&& CmdId
< m_iIdDfltLast
)
1326 CmdId
-= m_iIdDfltFirst
;
1327 /* See the definitions of IDM_CUT and co to see how this works */
1331 /* Loop looking for a matching Id */
1332 for (UINT i
= 0; i
< _countof(g_StaticInvokeCmdMap
); i
++)
1334 if (g_StaticInvokeCmdMap
[i
].IntVerb
== CmdId
)
1336 /* Validation just returns S_OK on a match */
1337 if (uFlags
== GCS_VALIDATEA
|| uFlags
== GCS_VALIDATEW
)
1340 /* Return a copy of the ANSI verb */
1341 if (uFlags
== GCS_VERBA
)
1342 return StringCchCopyA(lpszName
, uMaxNameLen
, g_StaticInvokeCmdMap
[i
].szStringVerb
);
1344 /* Convert the ANSI verb to unicode and return that */
1345 if (uFlags
== GCS_VERBW
)
1347 if (SHAnsiToUnicode(g_StaticInvokeCmdMap
[i
].szStringVerb
, (LPWSTR
)lpszName
, uMaxNameLen
))
1353 return E_INVALIDARG
;
1358 CDefaultContextMenu::HandleMenuMsg(
1363 /* FIXME: Should we implement this as well? */
1367 HRESULT
SHGetMenuIdFromMenuMsg(UINT uMsg
, LPARAM lParam
, UINT
*CmdId
)
1369 if (uMsg
== WM_DRAWITEM
)
1371 DRAWITEMSTRUCT
* pDrawStruct
= reinterpret_cast<DRAWITEMSTRUCT
*>(lParam
);
1372 *CmdId
= pDrawStruct
->itemID
;
1375 else if (uMsg
== WM_MEASUREITEM
)
1377 MEASUREITEMSTRUCT
* pMeasureStruct
= reinterpret_cast<MEASUREITEMSTRUCT
*>(lParam
);
1378 *CmdId
= pMeasureStruct
->itemID
;
1385 HRESULT
SHSetMenuIdInMenuMsg(UINT uMsg
, LPARAM lParam
, UINT CmdId
)
1387 if (uMsg
== WM_DRAWITEM
)
1389 DRAWITEMSTRUCT
* pDrawStruct
= reinterpret_cast<DRAWITEMSTRUCT
*>(lParam
);
1390 pDrawStruct
->itemID
= CmdId
;
1393 else if (uMsg
== WM_MEASUREITEM
)
1395 MEASUREITEMSTRUCT
* pMeasureStruct
= reinterpret_cast<MEASUREITEMSTRUCT
*>(lParam
);
1396 pMeasureStruct
->itemID
= CmdId
;
1405 CDefaultContextMenu::HandleMenuMsg2(
1411 if (uMsg
== WM_INITMENUPOPUP
)
1413 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1416 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1417 pEntry
= pEntry
->pNext
;
1423 HRESULT hr
= SHGetMenuIdFromMenuMsg(uMsg
, lParam
, &CmdId
);
1427 if (CmdId
< m_iIdSHEFirst
|| CmdId
>= m_iIdSHELast
)
1430 CmdId
-= m_iIdSHEFirst
;
1431 PDynamicShellEntry pEntry
= GetDynamicEntry(CmdId
);
1434 SHSetMenuIdInMenuMsg(uMsg
, lParam
, CmdId
- pEntry
->iIdCmdFirst
);
1435 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1443 CDefaultContextMenu::SetSite(IUnknown
*pUnkSite
)
1451 CDefaultContextMenu::GetSite(REFIID riid
, void **ppvSite
)
1456 return m_site
->QueryInterface(riid
, ppvSite
);
1461 CDefaultContextMenu_CreateInstance(const DEFCONTEXTMENU
*pdcm
, LPFNDFMCALLBACK lpfn
, REFIID riid
, void **ppv
)
1463 return ShellObjectCreatorInit
<CDefaultContextMenu
>(pdcm
, lpfn
, riid
, ppv
);
1466 /*************************************************************************
1467 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1473 SHCreateDefaultContextMenu(const DEFCONTEXTMENU
*pdcm
, REFIID riid
, void **ppv
)
1478 return E_INVALIDARG
;
1480 hr
= CDefaultContextMenu_CreateInstance(pdcm
, NULL
, riid
, ppv
);
1481 if (FAILED_UNEXPECTEDLY(hr
))
1487 /*************************************************************************
1488 * CDefFolderMenu_Create2 [SHELL32.701]
1494 CDefFolderMenu_Create2(
1495 PCIDLIST_ABSOLUTE pidlFolder
,
1498 PCUITEMID_CHILD_ARRAY apidl
,
1500 LPFNDFMCALLBACK lpfn
,
1502 const HKEY
*ahkeyClsKeys
,
1503 IContextMenu
**ppcm
)
1508 dcm
.pidlFolder
= pidlFolder
;
1512 dcm
.punkAssociationInfo
= NULL
;
1514 dcm
.aKeys
= ahkeyClsKeys
;
1516 HRESULT hr
= CDefaultContextMenu_CreateInstance(&dcm
, lpfn
, IID_PPV_ARG(IContextMenu
, ppcm
));
1517 if (FAILED_UNEXPECTEDLY(hr
))