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
>,
40 CComPtr
<IShellFolder
> m_psf
;
42 PCUITEMID_CHILD_ARRAY m_apidl
;
43 CComPtr
<IDataObject
> m_pDataObj
;
44 PIDLIST_ABSOLUTE m_pidlFolder
;
45 DWORD m_bGroupPolicyActive
;
46 PDynamicShellEntry m_pDynamicEntries
; /* first dynamic shell extension entry */
47 UINT m_iIdSHEFirst
; /* first used id */
48 UINT m_iIdSHELast
; /* last used id */
49 PStaticShellEntry m_pStaticEntries
; /* first static shell extension entry */
50 UINT m_iIdSCMFirst
; /* first static used id */
51 UINT m_iIdSCMLast
; /* last static used id */
53 void AddStaticEntry(LPCWSTR pwszVerb
, LPCWSTR pwszClass
);
54 void AddStaticEntryForKey(HKEY hKey
, LPCWSTR pwszClass
);
55 void AddStaticEntryForFileClass(LPCWSTR pwszExt
);
56 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
);
57 HRESULT
LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
);
58 BOOL
EnumerateDynamicContextHandlerForKey(HKEY hRootKey
);
59 UINT
InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
);
60 UINT
BuildBackgroundContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
61 UINT
AddStaticContextMenusToMenu(HMENU hMenu
, UINT IndexMenu
);
62 UINT
BuildShellItemContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
63 HRESULT
DoPaste(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
);
64 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
65 HRESULT
DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
);
66 HRESULT
DoRefresh(LPCMINVOKECOMMANDINFO lpcmi
);
67 HRESULT
DoDelete(LPCMINVOKECOMMANDINFO lpcmi
);
68 HRESULT
DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
);
69 HRESULT
DoRename(LPCMINVOKECOMMANDINFO lpcmi
);
70 HRESULT
DoProperties(LPCMINVOKECOMMANDINFO lpcmi
);
71 HRESULT
DoFormat(LPCMINVOKECOMMANDINFO lpcmi
);
72 HRESULT
DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
73 HRESULT
DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
74 DWORD
BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
);
75 HRESULT
TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
);
76 HRESULT
InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
);
77 PDynamicShellEntry
GetDynamicEntry(UINT idCmd
);
80 CDefaultContextMenu();
81 ~CDefaultContextMenu();
82 HRESULT WINAPI
Initialize(const DEFCONTEXTMENU
*pdcm
);
85 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
86 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
87 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
90 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
93 virtual HRESULT WINAPI
HandleMenuMsg2(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*plResult
);
95 BEGIN_COM_MAP(CDefaultContextMenu
)
96 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
97 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
98 COM_INTERFACE_ENTRY_IID(IID_IContextMenu3
, IContextMenu3
)
102 CDefaultContextMenu::CDefaultContextMenu() :
108 m_bGroupPolicyActive(0),
109 m_pDynamicEntries(NULL
),
112 m_pStaticEntries(NULL
),
118 CDefaultContextMenu::~CDefaultContextMenu()
120 /* Free dynamic shell extension entries */
121 PDynamicShellEntry pDynamicEntry
= m_pDynamicEntries
, pNextDynamic
;
122 while (pDynamicEntry
)
124 pNextDynamic
= pDynamicEntry
->pNext
;
125 pDynamicEntry
->pCM
->Release();
126 HeapFree(GetProcessHeap(), 0, pDynamicEntry
);
127 pDynamicEntry
= pNextDynamic
;
130 /* Free static shell extension entries */
131 PStaticShellEntry pStaticEntry
= m_pStaticEntries
, pNextStatic
;
134 pNextStatic
= pStaticEntry
->pNext
;
135 HeapFree(GetProcessHeap(), 0, pStaticEntry
->szClass
);
136 HeapFree(GetProcessHeap(), 0, pStaticEntry
->szVerb
);
137 HeapFree(GetProcessHeap(), 0, pStaticEntry
);
138 pStaticEntry
= pNextStatic
;
142 CoTaskMemFree(m_pidlFolder
);
143 _ILFreeaPidl(const_cast<PITEMID_CHILD
*>(m_apidl
), m_cidl
);
146 HRESULT WINAPI
CDefaultContextMenu::Initialize(const DEFCONTEXTMENU
*pdcm
)
148 CComPtr
<IDataObject
> pDataObj
;
150 TRACE("cidl %u\n", pdcm
->cidl
);
153 m_apidl
= const_cast<PCUITEMID_CHILD_ARRAY
>(_ILCopyaPidl(pdcm
->apidl
, m_cidl
));
154 if (m_cidl
&& !m_apidl
)
155 return E_OUTOFMEMORY
;
158 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
))))
159 m_pDataObj
= pDataObj
;
161 if (pdcm
->pidlFolder
)
163 m_pidlFolder
= ILClone(pdcm
->pidlFolder
);
167 CComPtr
<IPersistFolder2
> pf
= NULL
;
168 if (SUCCEEDED(m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
170 if (FAILED(pf
->GetCurFolder(reinterpret_cast<LPITEMIDLIST
*>(&m_pidlFolder
))))
171 ERR("GetCurFolder failed\n");
173 TRACE("pidlFolder %p\n", m_pidlFolder
);
180 CDefaultContextMenu::AddStaticEntry(const WCHAR
*szVerb
, const WCHAR
*szClass
)
182 PStaticShellEntry pEntry
= m_pStaticEntries
, pLastEntry
= NULL
;
185 if (!wcsicmp(pEntry
->szVerb
, szVerb
))
187 /* entry already exists */
191 pEntry
= pEntry
->pNext
;
194 TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb
), debugstr_w(szClass
));
196 pEntry
= (StaticShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry
));
199 pEntry
->pNext
= NULL
;
200 pEntry
->szVerb
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb
) + 1) * sizeof(WCHAR
));
202 wcscpy(pEntry
->szVerb
, szVerb
);
203 pEntry
->szClass
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass
) + 1) * sizeof(WCHAR
));
205 wcscpy(pEntry
->szClass
, szClass
);
208 if (!wcsicmp(szVerb
, L
"open"))
210 /* open verb is always inserted in front */
211 pEntry
->pNext
= m_pStaticEntries
;
212 m_pStaticEntries
= pEntry
;
215 pLastEntry
->pNext
= pEntry
;
217 m_pStaticEntries
= pEntry
;
221 CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey
, const WCHAR
*pwszClass
)
224 DWORD cchName
, dwIndex
= 0;
226 TRACE("AddStaticEntryForKey %x %ls\n", hKey
, pwszClass
);
230 cchName
= _countof(wszName
);
231 if (RegEnumKeyExW(hKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
234 AddStaticEntry(wszName
, pwszClass
);
239 CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR
* szExt
)
246 static WCHAR szShell
[] = L
"\\shell";
247 static WCHAR szShellAssoc
[] = L
"SystemFileAssociations\\";
249 TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt
));
251 Length
= wcslen(szExt
);
252 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
254 wcscpy(szBuffer
, szExt
);
255 wcscpy(&szBuffer
[Length
], szShell
);
256 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
257 if (result
== ERROR_SUCCESS
)
259 szBuffer
[Length
] = 0;
260 AddStaticEntryForKey(hKey
, szExt
);
265 dwBuffer
= sizeof(szBuffer
);
266 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, (LPBYTE
)szBuffer
, &dwBuffer
);
267 if (result
== ERROR_SUCCESS
)
269 Length
= wcslen(szBuffer
);
270 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
272 wcscpy(&szBuffer
[Length
], szShell
);
273 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
275 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
276 if (result
== ERROR_SUCCESS
)
278 szBuffer
[Length
] = 0;
279 AddStaticEntryForKey(hKey
, szBuffer
);
285 wcscpy(szBuffer
, szShellAssoc
);
286 dwBuffer
= sizeof(szBuffer
) - sizeof(szShellAssoc
) - sizeof(WCHAR
);
287 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, L
"PerceivedType", RRF_RT_REG_SZ
, NULL
, (LPBYTE
)&szBuffer
[_countof(szShellAssoc
) - 1], &dwBuffer
);
288 if (result
== ERROR_SUCCESS
)
290 Length
= wcslen(&szBuffer
[_countof(szShellAssoc
)]) + _countof(szShellAssoc
);
291 wcscat(szBuffer
, L
"\\shell");
292 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
294 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
295 if (result
== ERROR_SUCCESS
)
297 szBuffer
[Length
] = 0;
298 AddStaticEntryForKey(hKey
, szBuffer
);
309 CComPtr
<IDataObject
> pDataObj
;
311 if(SUCCEEDED(OleGetClipboard(&pDataObj
)))
316 TRACE("pDataObj=%p\n", pDataObj
.p
);
318 /* Set the FORMATETC structure*/
319 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
320 if(SUCCEEDED(pDataObj
->GetData(&formatetc
, &medium
)))
323 ReleaseStgMedium(&medium
);
332 DisablePasteOptions(HMENU hMenu
)
336 mii
.cbSize
= sizeof(mii
);
337 mii
.fMask
= MIIM_STATE
;
338 mii
.fState
= MFS_DISABLED
;
340 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
));
341 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
));
345 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
)
347 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
351 if (!memcmp(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
)))
353 pEntry
= pEntry
->pNext
;
360 CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
)
364 TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey
, wine_dbgstr_guid(pclsid
));
366 if (IsShellExtensionAlreadyLoaded(pclsid
))
369 CComPtr
<IContextMenu
> pcm
;
370 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IContextMenu
, &pcm
));
373 ERR("SHCoCreateInstance failed %x\n", GetLastError());
377 CComPtr
<IShellExtInit
> pExtInit
;
378 hr
= pcm
->QueryInterface(IID_PPV_ARG(IShellExtInit
, &pExtInit
));
381 ERR("Failed to query for interface IID_IShellExtInit hr %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));
385 hr
= pExtInit
->Initialize(m_pidlFolder
, m_pDataObj
, hKey
);
388 TRACE("Failed to initialize shell extension error %x pclsid %s\n", hr
, wine_dbgstr_guid(pclsid
));
392 PDynamicShellEntry pEntry
= (DynamicShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
395 return E_OUTOFMEMORY
;
398 pEntry
->iIdCmdFirst
= 0;
399 pEntry
->pNext
= NULL
;
401 pEntry
->pCM
= pcm
.Detach();
402 memcpy(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
));
404 if (m_pDynamicEntries
)
406 PDynamicShellEntry pLastEntry
= m_pDynamicEntries
;
408 while (pLastEntry
->pNext
)
409 pLastEntry
= pLastEntry
->pNext
;
411 pLastEntry
->pNext
= pEntry
;
414 m_pDynamicEntries
= pEntry
;
420 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey
)
423 WCHAR wszName
[MAX_PATH
], wszBuf
[MAX_PATH
], *pwszClsid
;
428 if (RegOpenKeyExW(hRootKey
, L
"shellex\\ContextMenuHandlers", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
430 TRACE("RegOpenKeyExW failed\n");
437 cchName
= _countof(wszName
);
438 if (RegEnumKeyExW(hKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
441 /* Key name or key value is CLSID */
443 hr
= CLSIDFromString(wszName
, &clsid
);
448 DWORD cchBuf
= _countof(wszBuf
);
449 if (RegGetValueW(hKey
, wszName
, NULL
, RRF_RT_REG_SZ
, NULL
, wszBuf
, &cchBuf
) == ERROR_SUCCESS
)
450 hr
= CLSIDFromString(wszBuf
, &clsid
);
455 if (m_bGroupPolicyActive
)
457 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
458 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
463 NULL
) == ERROR_SUCCESS
)
465 LoadDynamicContextMenuHandler(hKey
, &clsid
);
469 LoadDynamicContextMenuHandler(hKey
, &clsid
);
478 CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
480 if (!m_pDynamicEntries
)
487 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
490 m_iIdSHEFirst
= idCmdFirst
;
493 HRESULT hr
= pEntry
->pCM
->QueryContextMenu(hMenu
, IndexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
496 pEntry
->iIdCmdFirst
= idCmdFirst
;
497 pEntry
->NumIds
= LOWORD(hr
);
498 IndexMenu
+= pEntry
->NumIds
;
499 idCmdFirst
+= pEntry
->NumIds
+ 0x10;
501 TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry
, hr
, pEntry
->pCM
, pEntry
->iIdCmdFirst
, pEntry
->NumIds
);
502 pEntry
= pEntry
->pNext
;
505 m_iIdSHELast
= idCmdFirst
;
506 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst
, m_iIdSHELast
);
511 CDefaultContextMenu::BuildBackgroundContextMenu(
520 TRACE("BuildBackgroundContextMenu entered\n");
522 SFGAOF rfg
= SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
523 HRESULT hr
= m_psf
->GetAttributesOf(0, NULL
, &rfg
);
526 ERR("GetAttributesOf failed: %x\n", hr
);
530 if (!_ILIsDesktop(m_pidlFolder
))
532 WCHAR wszBuf
[MAX_PATH
];
534 /* view option is only available in browsing mode */
535 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_001");
536 if (hSubMenu
&& LoadStringW(shell32_hInstance
, FCIDM_SHVIEW_VIEW
, wszBuf
, _countof(wszBuf
)))
538 TRACE("wszBuf %s\n", debugstr_w(wszBuf
));
541 ZeroMemory(&mii
, sizeof(mii
));
542 mii
.cbSize
= sizeof(mii
);
543 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_ID
;
544 mii
.fType
= MFT_STRING
;
545 mii
.wID
= iIdCmdFirst
++;
546 mii
.dwTypeData
= wszBuf
;
547 mii
.cch
= wcslen(mii
.dwTypeData
);
548 mii
.fState
= MFS_ENABLED
;
549 mii
.hSubMenu
= hSubMenu
;
550 InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, &mii
);
551 DestroyMenu(hSubMenu
);
555 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
558 /* merge general background context menu in */
559 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), IndexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
560 DestroyMenu(hSubMenu
);
563 if (!HasClipboardData())
565 TRACE("disabling paste options\n");
566 DisablePasteOptions(hMenu
);
569 /* Directory is progid of filesystem folders only */
570 if ((rfg
& (SFGAO_FILESYSTEM
|SFGAO_FOLDER
)) == (SFGAO_FILESYSTEM
|SFGAO_FOLDER
))
572 /* Load context menu handlers */
573 TRACE("Add background handlers: %p\n", m_pidlFolder
);
575 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory\\Background", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
577 EnumerateDynamicContextHandlerForKey(hKey
);
581 if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, GetMenuItemCount(hMenu
) - 1, iIdCmdFirst
, iIdCmdLast
))
583 /* seperate dynamic context menu items */
584 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
) - 1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
592 CDefaultContextMenu::AddStaticContextMenusToMenu(
601 mii
.cbSize
= sizeof(mii
);
602 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
603 mii
.fType
= MFT_STRING
;
605 mii
.dwTypeData
= NULL
;
606 m_iIdSCMFirst
= mii
.wID
;
608 PStaticShellEntry pEntry
= m_pStaticEntries
;
612 fState
= MFS_ENABLED
;
613 mii
.dwTypeData
= NULL
;
615 /* set first entry as default */
616 if (pEntry
== m_pStaticEntries
)
617 fState
|= MFS_DEFAULT
;
619 if (!wcsicmp(pEntry
->szVerb
, L
"open"))
621 /* override default when open verb is found */
622 fState
|= MFS_DEFAULT
;
623 idResource
= IDS_OPEN_VERB
;
625 else if (!wcsicmp(pEntry
->szVerb
, L
"explore"))
626 idResource
= IDS_EXPLORE_VERB
;
627 else if (!wcsicmp(pEntry
->szVerb
, L
"runas"))
628 idResource
= IDS_RUNAS_VERB
;
629 else if (!wcsicmp(pEntry
->szVerb
, L
"edit"))
630 idResource
= IDS_EDIT_VERB
;
631 else if (!wcsicmp(pEntry
->szVerb
, L
"find"))
632 idResource
= IDS_FIND_VERB
;
633 else if (!wcsicmp(pEntry
->szVerb
, L
"print"))
634 idResource
= IDS_PRINT_VERB
;
635 else if (!wcsicmp(pEntry
->szVerb
, L
"printto"))
637 pEntry
= pEntry
->pNext
;
643 /* By default use verb for menu item name */
644 mii
.dwTypeData
= pEntry
->szVerb
;
648 if (LoadStringW(shell32_hInstance
, idResource
, wszVerb
, _countof(wszVerb
)))
649 mii
.dwTypeData
= wszVerb
; /* use translated verb */
651 ERR("Failed to load string\n");
656 HRESULT hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"%s\\shell\\%s", pEntry
->szClass
, pEntry
->szVerb
);
661 DWORD cbVerb
= sizeof(wszVerb
);
662 LONG res
= RegOpenKeyW(HKEY_CLASSES_ROOT
, wszKey
, &hkVerb
);
663 if (res
== ERROR_SUCCESS
)
665 res
= RegLoadMUIStringW(hkVerb
,
672 if (res
== ERROR_SUCCESS
)
674 /* use description for the menu entry */
675 mii
.dwTypeData
= wszVerb
;
683 mii
.cch
= wcslen(mii
.dwTypeData
);
685 InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, &mii
);
688 pEntry
= pEntry
->pNext
;
691 m_iIdSCMLast
= mii
.wID
- 1;
695 void WINAPI
_InsertMenuItemW(
707 ZeroMemory(&mii
, sizeof(mii
));
708 mii
.cbSize
= sizeof(mii
);
709 if (fType
== MFT_SEPARATOR
)
710 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
711 else if (fType
== MFT_STRING
)
713 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
714 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
716 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), wszText
, _countof(wszText
)))
717 mii
.dwTypeData
= wszText
;
720 ERR("failed to load string %p\n", dwTypeData
);
725 mii
.dwTypeData
= (LPWSTR
)dwTypeData
;
731 InsertMenuItemW(hMenu
, indexMenu
, fByPosition
, &mii
);
735 CDefaultContextMenu::BuildShellItemContextMenu(
744 TRACE("BuildShellItemContextMenu entered\n");
748 hr
= m_psf
->GetDisplayNameOf(m_apidl
[0], SHGDN_FORPARSING
, &strFile
);
751 WCHAR wszPath
[MAX_PATH
];
752 hr
= StrRetToBufW(&strFile
, m_apidl
[0], wszPath
, _countof(wszPath
));
755 LPCWSTR pwszExt
= PathFindExtensionW(wszPath
);
758 /* enumerate dynamic/static for a given file class */
759 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pwszExt
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
761 /* add static verbs */
762 AddStaticEntryForFileClass(pwszExt
);
764 /* load dynamic extensions from file extension key */
765 EnumerateDynamicContextHandlerForKey(hKey
);
770 DWORD dwSize
= sizeof(wszTemp
);
771 if (RegGetValueW(HKEY_CLASSES_ROOT
, pwszExt
, NULL
, RRF_RT_REG_SZ
, NULL
, wszTemp
, &dwSize
) == ERROR_SUCCESS
)
773 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, wszTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
775 /* add static verbs from progid key */
776 AddStaticEntryForFileClass(wszTemp
);
778 /* load dynamic extensions from progid key */
779 EnumerateDynamicContextHandlerForKey(hKey
);
787 ERR("GetDisplayNameOf failed: %x\n", hr
);
789 GUID
*pGuid
= _ILGetGUIDPointer(m_apidl
[0]);
795 wcscpy(buffer
, L
"CLSID\\");
796 hr
= StringFromCLSID(*pGuid
, &pwszCLSID
);
799 wcscpy(&buffer
[6], pwszCLSID
);
800 TRACE("buffer %s\n", debugstr_w(buffer
));
801 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
803 EnumerateDynamicContextHandlerForKey(hKey
);
804 AddStaticEntryForFileClass(buffer
);
807 CoTaskMemFree(pwszCLSID
);
811 if (_ILIsDrive(m_apidl
[0]))
813 AddStaticEntryForFileClass(L
"Drive");
814 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
816 EnumerateDynamicContextHandlerForKey(hKey
);
822 /* add static actions */
823 SFGAOF rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
824 hr
= m_psf
->GetAttributesOf(m_cidl
, m_apidl
, &rfg
);
827 ERR("GetAttributesOf failed: %x\n", hr
);
831 if (rfg
& SFGAO_FOLDER
)
833 /* add the default verbs open / explore */
834 AddStaticEntryForFileClass(L
"Folder");
835 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
837 EnumerateDynamicContextHandlerForKey(hKey
);
841 /* Directory is only loaded for real filesystem directories */
842 if (rfg
& SFGAO_FILESYSTEM
)
844 AddStaticEntryForFileClass(L
"Directory");
845 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
847 EnumerateDynamicContextHandlerForKey(hKey
);
853 /* AllFilesystemObjects class is loaded only for files and directories */
854 if (rfg
& SFGAO_FILESYSTEM
)
856 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
858 /* sendto service is registered here */
859 EnumerateDynamicContextHandlerForKey(hKey
);
863 if (!(rfg
& SFGAO_FOLDER
))
865 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
867 EnumerateDynamicContextHandlerForKey(hKey
);
873 /* add static context menu handlers */
874 UINT IndexMenu
= AddStaticContextMenusToMenu(hMenu
, 0);
876 /* now process dynamic context menu handlers */
877 BOOL bAddSep
= FALSE
;
878 IndexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, IndexMenu
, iIdCmdFirst
, iIdCmdLast
);
879 TRACE("IndexMenu %d\n", IndexMenu
);
881 if (_ILIsDrive(m_apidl
[0]))
883 char szDrive
[8] = {0};
886 _ILGetDrive(m_apidl
[0], szDrive
, sizeof(szDrive
));
887 if (GetVolumeInformationA(szDrive
, NULL
, 0, NULL
, NULL
, &dwFlags
, NULL
, 0))
889 /* Disable format if read only */
890 if (!(dwFlags
& FILE_READ_ONLY_VOLUME
))
892 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
893 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
899 BOOL bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
900 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
902 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
903 if (rfg
& SFGAO_CANMOVE
)
904 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
905 if (rfg
& SFGAO_CANCOPY
)
906 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
908 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PASTE
), MFS_ENABLED
);
913 if (rfg
& SFGAO_CANLINK
)
916 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
917 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
920 if (rfg
& SFGAO_CANDELETE
)
925 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
927 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
930 if (rfg
& SFGAO_CANRENAME
)
934 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
936 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
940 if (rfg
& SFGAO_HASPROPSHEET
)
942 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
943 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
951 CDefaultContextMenu::QueryContextMenu(
959 idCmdFirst
= BuildShellItemContextMenu(hMenu
, idCmdFirst
, idCmdLast
, uFlags
);
961 idCmdFirst
= BuildBackgroundContextMenu(hMenu
, idCmdFirst
, idCmdLast
, uFlags
);
968 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
970 /* Note: CWM_GETISHELLBROWSER returns not referenced object */
971 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
975 CComPtr
<IShellView
> lpSV
;
976 if (FAILED(lpSB
->QueryActiveShellView(&lpSV
)))
980 if (SUCCEEDED(lpSV
->GetWindow(&hwndSV
)))
981 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
986 CDefaultContextMenu::DoRefresh(
987 LPCMINVOKECOMMANDINFO lpcmi
)
989 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
991 HRESULT hr
= m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &ppf2
));
994 hr
= ppf2
->GetCurFolder(&pidl
);
997 SHChangeNotify(SHCNE_UPDATEDIR
, SHCNF_IDLIST
, pidl
, NULL
);
1005 CDefaultContextMenu::DoPaste(
1006 LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
)
1010 CComPtr
<IDataObject
> pda
;
1011 hr
= OleGetClipboard(&pda
);
1015 CComPtr
<IShellFolder
> psfDesktop
;
1016 CComPtr
<IShellFolder
> psfTarget
= NULL
;
1018 hr
= SHGetDesktopFolder(&psfDesktop
);
1022 /* Find target folder */
1025 hr
= m_psf
->BindToObject(m_apidl
[0], NULL
, IID_PPV_ARG(IShellFolder
, &psfTarget
));
1029 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
1032 /* cidl is zero due to explorer view */
1033 hr
= m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &ppf2
));
1036 hr
= ppf2
->GetCurFolder(&pidl
);
1039 if (_ILIsDesktop(pidl
))
1041 /* use desktop shellfolder */
1042 psfTarget
= psfDesktop
;
1046 /* retrieve target desktop folder */
1047 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfTarget
));
1049 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
.p
, _ILIsDesktop(pidl
));
1057 ERR("no IShellFolder\n");
1061 FORMATETC formatetc2
;
1063 InitFormatEtc(formatetc2
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
1067 if (SUCCEEDED(pda
->GetData(&formatetc2
, &medium2
)))
1069 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium2
.hGlobal
);
1072 if (*pdwFlag
== DROPEFFECT_COPY
)
1078 ERR("No drop effect obtained");
1080 GlobalUnlock(medium2
.hGlobal
);
1085 dwKey
= MK_CONTROL
|MK_SHIFT
;
1088 CComPtr
<IDropTarget
> pdrop
;
1089 hr
= psfTarget
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pdrop
));
1092 ERR("Error getting IDropTarget interface\n");
1096 SHSimulateDrop(pdrop
, pda
, dwKey
, NULL
, NULL
);
1098 TRACE("CP result %x\n", hr
);
1103 CDefaultContextMenu::DoOpenOrExplore(
1104 LPCMINVOKECOMMANDINFO lpcmi
)
1111 CDefaultContextMenu::DoCreateLink(
1112 LPCMINVOKECOMMANDINFO lpcmi
)
1114 CComPtr
<IDataObject
> pDataObj
;
1115 CComPtr
<IDropTarget
> pDT
;
1117 CComPtr
<IPersistFolder2
> ppf2
= NULL
;
1119 CComPtr
<IShellFolder
> psfDesktop
;
1120 CComPtr
<IShellFolder
> psfTarget
= NULL
;
1122 hr
= SHGetDesktopFolder(&psfDesktop
);
1126 if (SUCCEEDED(hr
= SHCreateDataObject(m_pidlFolder
, m_cidl
, m_apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
))))
1128 hr
= m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &ppf2
));
1131 hr
= ppf2
->GetCurFolder(&pidl
);
1134 if (_ILIsDesktop(pidl
))
1136 /* use desktop shellfolder */
1137 psfTarget
= psfDesktop
;
1141 /* retrieve target desktop folder */
1142 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_PPV_ARG(IShellFolder
, &psfTarget
));
1144 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
.p
, _ILIsDesktop(pidl
));
1153 ERR("no IShellFolder\n");
1157 hr
= psfTarget
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pDT
));
1160 ERR("no IDropTarget Interface\n");
1163 SHSimulateDrop(pDT
, pDataObj
, MK_CONTROL
|MK_SHIFT
, NULL
, NULL
);
1168 HRESULT
CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi
) {
1169 TRACE("(%p) Deleting\n", this);
1171 CComPtr
<IDataObject
> pDataObject
;
1173 if (SUCCEEDED(SHCreateDataObject(m_pidlFolder
, m_cidl
, m_apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObject
))))
1176 CoMarshalInterThreadInterfaceInStream(IID_IDataObject
, pDataObject
, &s
);
1177 SHCreateThread(DoDeleteThreadProc
, s
, NULL
, NULL
);
1185 CDefaultContextMenu::DoCopyOrCut(
1186 LPCMINVOKECOMMANDINFO lpcmi
,
1189 CComPtr
<IDataObject
> pDataObj
;
1192 if (SUCCEEDED(SHCreateDataObject(m_pidlFolder
, m_cidl
, m_apidl
, NULL
, IID_PPV_ARG(IDataObject
, &pDataObj
))))
1196 FORMATETC formatetc
;
1198 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
1199 pDataObj
->GetData(&formatetc
, &medium
);
1200 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium
.hGlobal
);
1202 *pdwFlag
= DROPEFFECT_MOVE
;
1203 GlobalUnlock(medium
.hGlobal
);
1204 pDataObj
->SetData(&formatetc
, &medium
, TRUE
);
1207 hr
= OleSetClipboard(pDataObj
);
1211 /* Note: CWM_GETISHELLBROWSER returns not referenced object */
1212 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1215 ERR("failed to get shellbrowser\n");
1219 CComPtr
<IShellView
> lpSV
;
1220 hr
= lpSB
->QueryActiveShellView(&lpSV
);
1223 ERR("failed to query the active shellview\n");
1227 hr
= lpSV
->GetItemObject(SVGIO_SELECTION
, IID_PPV_ARG(IDataObject
, &pDataObj
));
1230 hr
= OleSetClipboard(pDataObj
);
1232 ERR("OleSetClipboard failed");
1233 pDataObj
->Release();
1235 ERR("failed to get item object\n");
1241 CDefaultContextMenu::DoRename(
1242 LPCMINVOKECOMMANDINFO lpcmi
)
1244 /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
1245 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1248 ERR("CWM_GETISHELLBROWSER failed\n");
1252 /* is the treeview focused */
1254 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1256 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1258 (void)TreeView_EditLabel(hwnd
, hItem
);
1261 CComPtr
<IShellView
> lpSV
;
1262 HRESULT hr
= lpSB
->QueryActiveShellView(&lpSV
);
1265 ERR("CWM_GETISHELLBROWSER failed\n");
1269 SVSIF selFlags
= SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
;
1270 lpSV
->SelectItem(m_apidl
[0], selFlags
);
1275 CDefaultContextMenu::DoProperties(
1276 LPCMINVOKECOMMANDINFO lpcmi
)
1279 const ITEMIDLIST
*pidlParent
= m_pidlFolder
, *pidlChild
;
1283 CComPtr
<IPersistFolder2
> pf
;
1285 /* pidlFolder is optional */
1286 if (SUCCEEDED(m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
1288 pf
->GetCurFolder((_ITEMIDLIST
**)&pidlParent
);
1293 pidlChild
= m_apidl
[0];
1296 /* Set pidlChild to last pidl of current folder */
1297 if (pidlParent
== m_pidlFolder
)
1298 pidlParent
= (ITEMIDLIST
*)ILClone(pidlParent
);
1300 pidlChild
= (ITEMIDLIST
*)ILClone(ILFindLastID(pidlParent
));
1301 ILRemoveLastID((ITEMIDLIST
*)pidlParent
);
1304 if (_ILIsMyComputer(pidlChild
))
1306 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1309 else if (_ILIsDesktop(pidlChild
))
1311 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1314 else if (_ILIsDrive(pidlChild
))
1316 WCHAR wszBuf
[MAX_PATH
];
1317 ILGetDisplayName(pidlChild
, wszBuf
);
1318 if (!SH_ShowDriveProperties(wszBuf
, pidlParent
, &pidlChild
))
1321 else if (_ILIsNetHood(pidlChild
))
1324 if (32 >= (UINT
)ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1325 L
"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1326 NULL
, SW_SHOWDEFAULT
))
1329 else if (_ILIsBitBucket(pidlChild
))
1331 /* FIXME: detect the drive path of bitbucket if appropiate */
1332 if(!SH_ShowRecycleBinProperties(L
'C'))
1338 WARN("SHMultiFileProperties is not yet implemented\n");
1341 hr
= m_psf
->GetDisplayNameOf(pidlChild
, SHGDN_FORPARSING
, &strFile
);
1344 WCHAR wszBuf
[MAX_PATH
];
1345 hr
= StrRetToBufW(&strFile
, pidlChild
, wszBuf
, _countof(wszBuf
));
1347 hr
= SH_ShowPropertiesDialog(wszBuf
, pidlParent
, &pidlChild
);
1349 ERR("StrRetToBufW failed\n");
1352 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1355 /* Free allocated PIDLs */
1356 if (pidlParent
!= m_pidlFolder
)
1357 ILFree((ITEMIDLIST
*)pidlParent
);
1358 if (m_cidl
< 1 || pidlChild
!= m_apidl
[0])
1359 ILFree((ITEMIDLIST
*)pidlChild
);
1365 CDefaultContextMenu::DoFormat(
1366 LPCMINVOKECOMMANDINFO lpcmi
)
1368 char szDrive
[8] = {0};
1370 if (!_ILGetDrive(m_apidl
[0], szDrive
, sizeof(szDrive
)))
1372 ERR("pidl is not a drive\n");
1376 SHFormatDrive(lpcmi
->hwnd
, szDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1380 PDynamicShellEntry
CDefaultContextMenu::GetDynamicEntry(UINT idCmd
)
1382 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1384 while(pEntry
&& idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1385 pEntry
= pEntry
->pNext
;
1390 if (idCmd
< pEntry
->iIdCmdFirst
|| idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1397 CDefaultContextMenu::DoDynamicShellExtensions(
1398 LPCMINVOKECOMMANDINFO lpcmi
)
1400 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, m_iIdSHEFirst
, m_iIdSHELast
);
1402 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
1403 PDynamicShellEntry pEntry
= GetDynamicEntry(idCmd
);
1407 /* invoke the dynamic context menu */
1408 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
- pEntry
->iIdCmdFirst
);
1409 return pEntry
->pCM
->InvokeCommand(lpcmi
);
1413 CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
)
1415 LPSHELLBROWSER lpSB
;
1423 /* Get a pointer to the shell browser */
1424 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1428 /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
1429 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwndTree
)) && hwndTree
)
1430 FlagsName
= L
"ExplorerFlags";
1432 FlagsName
= L
"BrowserFlags";
1434 /* Try to get the flag from the verb */
1435 hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"%s\\shell\\%s", pEntry
->szClass
, pEntry
->szVerb
);
1439 cbVerb
= sizeof(wFlags
);
1440 if (RegGetValueW(HKEY_CLASSES_ROOT
, wszKey
, FlagsName
, RRF_RT_REG_DWORD
, NULL
, &wFlags
, &cbVerb
) == ERROR_SUCCESS
)
1449 CDefaultContextMenu::TryToBrowse(
1450 LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
)
1452 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageW(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1458 hr
= lpSB
->BrowseObject(ILCombine(m_pidlFolder
, pidl
), wFlags
);
1464 CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
)
1466 LPITEMIDLIST pidlFull
= ILCombine(m_pidlFolder
, pidl
);
1467 if (pidlFull
== NULL
)
1472 WCHAR wszPath
[MAX_PATH
];
1473 BOOL bHasPath
= SHGetPathFromIDListW(pidlFull
, wszPath
);
1475 WCHAR wszDir
[MAX_PATH
];
1478 wcscpy(wszDir
, wszPath
);
1479 PathRemoveFileSpec(wszDir
);
1483 SHGetPathFromIDListW(m_pidlFolder
, wszDir
);
1487 RegOpenKeyExW(HKEY_CLASSES_ROOT
, pEntry
->szClass
, 0, KEY_READ
, &hkeyClass
);
1489 SHELLEXECUTEINFOW sei
;
1490 ZeroMemory(&sei
, sizeof(sei
));
1491 sei
.cbSize
= sizeof(sei
);
1492 sei
.hwnd
= lpcmi
->hwnd
;
1493 sei
.nShow
= SW_SHOWNORMAL
;
1494 sei
.lpVerb
= pEntry
->szVerb
;
1495 sei
.lpDirectory
= wszDir
;
1496 sei
.lpIDList
= pidlFull
;
1497 sei
.hkeyClass
= hkeyClass
;
1498 sei
.fMask
= SEE_MASK_CLASSKEY
| SEE_MASK_IDLIST
;
1501 sei
.lpFile
= wszPath
;
1504 ShellExecuteExW(&sei
);
1506 RegCloseKey(hkeyClass
);
1514 CDefaultContextMenu::DoStaticShellExtensions(
1515 LPCMINVOKECOMMANDINFO lpcmi
)
1517 PStaticShellEntry pEntry
= m_pStaticEntries
;
1518 INT iCmd
= LOWORD(lpcmi
->lpVerb
) - m_iIdSCMFirst
;
1522 while (pEntry
&& (iCmd
--) > 0)
1523 pEntry
= pEntry
->pNext
;
1528 /* Get the browse flags to see if we need to browse */
1529 DWORD wFlags
= BrowserFlagsFromVerb(lpcmi
, pEntry
);
1530 BOOL bBrowsed
= FALSE
;
1532 for (i
=0; i
< m_cidl
; i
++)
1534 /* Check if we need to browse */
1537 /* In xp if we have browsed, we don't open any more folders .
1538 * In win7 we browse to the first folder we find and
1539 * open new windows fo for each of the rest of the folders */
1543 hr
= TryToBrowse(lpcmi
, m_apidl
[i
], wFlags
);
1551 InvokePidl(lpcmi
, m_apidl
[i
], pEntry
);
1559 CDefaultContextMenu::InvokeCommand(
1560 LPCMINVOKECOMMANDINFO lpcmi
)
1562 switch(LOWORD(lpcmi
->lpVerb
))
1564 case FCIDM_SHVIEW_BIGICON
:
1565 case FCIDM_SHVIEW_SMALLICON
:
1566 case FCIDM_SHVIEW_LISTVIEW
:
1567 case FCIDM_SHVIEW_REPORTVIEW
:
1568 case 0x30: /* FIX IDS in resource files */
1572 case FCIDM_SHVIEW_AUTOARRANGE
:
1573 case FCIDM_SHVIEW_SNAPTOGRID
:
1574 return NotifyShellViewWindow(lpcmi
, FALSE
);
1575 case FCIDM_SHVIEW_REFRESH
:
1576 return DoRefresh(lpcmi
);
1577 case FCIDM_SHVIEW_INSERT
:
1578 return DoPaste(lpcmi
, FALSE
);
1579 case FCIDM_SHVIEW_INSERTLINK
:
1580 return DoPaste(lpcmi
, TRUE
);
1581 case FCIDM_SHVIEW_OPEN
:
1582 case FCIDM_SHVIEW_EXPLORE
:
1583 return DoOpenOrExplore(lpcmi
);
1584 case FCIDM_SHVIEW_COPY
:
1585 case FCIDM_SHVIEW_CUT
:
1586 return DoCopyOrCut(lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1587 case FCIDM_SHVIEW_CREATELINK
:
1588 return DoCreateLink(lpcmi
);
1589 case FCIDM_SHVIEW_DELETE
:
1590 return DoDelete(lpcmi
);
1591 case FCIDM_SHVIEW_RENAME
:
1592 return DoRename(lpcmi
);
1593 case FCIDM_SHVIEW_PROPERTIES
:
1594 return DoProperties(lpcmi
);
1596 return DoFormat(lpcmi
);
1599 if (m_iIdSHEFirst
&& m_iIdSHELast
)
1601 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSHELast
)
1602 return DoDynamicShellExtensions(lpcmi
);
1605 if (m_iIdSCMFirst
&& m_iIdSCMLast
)
1607 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSCMLast
)
1608 return DoStaticShellExtensions(lpcmi
);
1611 FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi
->lpVerb
));
1612 return E_UNEXPECTED
;
1617 CDefaultContextMenu::GetCommandString(
1629 CDefaultContextMenu::HandleMenuMsg(
1634 /* FIXME: Should we implement this as well? */
1640 CDefaultContextMenu::HandleMenuMsg2(
1648 case WM_INITMENUPOPUP
:
1650 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1653 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1654 pEntry
= pEntry
->pNext
;
1660 DRAWITEMSTRUCT
* pDrawStruct
= reinterpret_cast<DRAWITEMSTRUCT
*>(lParam
);
1661 PDynamicShellEntry pEntry
= GetDynamicEntry(pDrawStruct
->itemID
);
1663 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1666 case WM_MEASUREITEM
:
1668 MEASUREITEMSTRUCT
* pMeasureStruct
= reinterpret_cast<MEASUREITEMSTRUCT
*>(lParam
);
1669 PDynamicShellEntry pEntry
= GetDynamicEntry(pMeasureStruct
->itemID
);
1671 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1678 ERR("Got unknown message:%d\n", uMsg
);
1685 IDefaultContextMenu_Constructor(
1686 const DEFCONTEXTMENU
*pdcm
,
1694 CComObject
<CDefaultContextMenu
> *pCM
;
1695 HRESULT hr
= CComObject
<CDefaultContextMenu
>::CreateInstance(&pCM
);
1698 pCM
->AddRef(); // CreateInstance returns object with 0 ref count */
1700 CComPtr
<IUnknown
> pResult
;
1701 hr
= pCM
->QueryInterface(riid
, (void **)&pResult
);
1708 hr
= pCM
->Initialize(pdcm
);
1715 *ppv
= pResult
.Detach();
1717 TRACE("This(%p) cidl %u\n", *ppv
, pdcm
->cidl
);
1721 /*************************************************************************
1722 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1728 SHCreateDefaultContextMenu(
1729 const DEFCONTEXTMENU
*pdcm
,
1734 HRESULT hr
= IDefaultContextMenu_Constructor(pdcm
, riid
, ppv
);
1736 ERR("IDefaultContextMenu_Constructor failed: %x\n", hr
);
1737 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1741 /*************************************************************************
1742 * CDefFolderMenu_Create2 [SHELL32.701]
1748 CDefFolderMenu_Create2(
1749 PCIDLIST_ABSOLUTE pidlFolder
,
1752 PCUITEMID_CHILD_ARRAY apidl
,
1754 LPFNDFMCALLBACK lpfn
,
1756 const HKEY
*ahkeyClsKeys
,
1757 IContextMenu
**ppcm
)
1759 DEFCONTEXTMENU pdcm
;
1762 pdcm
.pidlFolder
= pidlFolder
;
1766 pdcm
.punkAssociationInfo
= NULL
;
1768 pdcm
.aKeys
= ahkeyClsKeys
;
1770 HRESULT hr
= SHCreateDefaultContextMenu(&pdcm
, IID_PPV_ARG(IContextMenu
, ppcm
));