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 (janderwald@reactos.org)
11 1. In DoStaticShellExtensions, check for "Explore" and "Open" verbs, and for BrowserFlags or
12 ExplorerFlags under those entries. These flags indicate if we should browse to the new item
13 instead of attempting to open it.
14 2. The code in NotifyShellViewWindow to deliver commands to the view is broken. It is an excellent
15 example of the wrong way to do it.
20 WINE_DEFAULT_DEBUG_CHANNEL(dmenu
);
22 typedef struct _DynamicShellEntry_
28 struct _DynamicShellEntry_
*pNext
;
29 } DynamicShellEntry
, *PDynamicShellEntry
;
31 typedef struct _StaticShellEntry_
35 struct _StaticShellEntry_
*pNext
;
36 } StaticShellEntry
, *PStaticShellEntry
;
38 class CDefaultContextMenu
:
39 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
44 IDataObject
*m_pDataObj
;
45 LPCITEMIDLIST m_pidlFolder
;
46 DWORD m_bGroupPolicyActive
;
47 PDynamicShellEntry m_pDynamicEntries
; /* first dynamic shell extension entry */
48 UINT m_iIdSHEFirst
; /* first used id */
49 UINT m_iIdSHELast
; /* last used id */
50 PStaticShellEntry m_pStaticEntries
; /* first static shell extension entry */
51 UINT m_iIdSCMFirst
; /* first static used id */
52 UINT m_iIdSCMLast
; /* last static used id */
54 void AddStaticEntry(LPCWSTR pwszVerb
, LPCWSTR pwszClass
);
55 void AddStaticEntryForKey(HKEY hKey
, LPCWSTR pwszClass
);
56 void AddStaticEntryForFileClass(LPCWSTR pwszExt
);
57 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
);
58 HRESULT
LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
);
59 BOOL
EnumerateDynamicContextHandlerForKey(HKEY hRootKey
);
60 UINT
InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
);
61 UINT
BuildBackgroundContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
62 UINT
AddStaticContextMenusToMenu(HMENU hMenu
, UINT IndexMenu
);
63 UINT
BuildShellItemContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
64 HRESULT
DoPaste(LPCMINVOKECOMMANDINFO lpcmi
);
65 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
66 HRESULT
DoCreateLink(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
);
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_IDataObject
, (void**)&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_IPersistFolder2
, (PVOID
*)&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_IContextMenu
, (void**)&pcm
);
363 ERR("SHCoCreateInstance failed %x\n", GetLastError());
367 IShellExtInit
*pExtInit
;
368 hr
= pcm
->QueryInterface(IID_IShellExtInit
, (void**)&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
)
954 if (OleGetClipboard(&pda
) != S_OK
)
959 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
960 hr
= pda
->GetData(&formatetc
, &medium
);
968 /* lock the handle */
969 LPIDA lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
972 ReleaseStgMedium(&medium
);
977 /* convert the data into pidl */
979 LPITEMIDLIST
*apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
984 IShellFolder
*psfDesktop
;
985 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
988 _ILFreeaPidl(apidl
, lpcida
->cidl
);
989 ReleaseStgMedium(&medium
);
994 /* Find source folder */
995 IShellFolder
*psfFrom
= NULL
;
996 if (_ILIsDesktop(pidl
))
998 /* use desktop shellfolder */
999 psfFrom
= psfDesktop
;
1001 else if (FAILED(psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfFrom
)))
1003 ERR("no IShellFolder\n");
1005 psfDesktop
->Release();
1007 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1008 ReleaseStgMedium(&medium
);
1014 /* Find target folder */
1015 IShellFolder
*psfTarget
= NULL
;
1018 psfDesktop
->Release();
1019 hr
= m_Dcm
.psf
->BindToObject(m_Dcm
.apidl
[0], NULL
, IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1023 IPersistFolder2
*ppf2
= NULL
;
1026 /* cidl is zero due to explorer view */
1027 hr
= m_Dcm
.psf
->QueryInterface(IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1030 hr
= ppf2
->GetCurFolder(&pidl
);
1034 if (_ILIsDesktop(pidl
))
1036 /* use desktop shellfolder */
1037 psfTarget
= psfDesktop
;
1041 /* retrieve target desktop folder */
1042 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1044 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
, _ILIsDesktop(pidl
));
1052 ERR("no IShellFolder\n");
1056 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1057 ReleaseStgMedium(&medium
);
1063 /* get source and destination shellfolder */
1064 ISFHelper
*psfhlpdst
;
1065 if (FAILED(psfTarget
->QueryInterface(IID_ISFHelper
, (LPVOID
*)&psfhlpdst
)))
1067 ERR("no IID_ISFHelper for destination\n");
1070 psfTarget
->Release();
1072 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1073 ReleaseStgMedium(&medium
);
1079 ISFHelper
*psfhlpsrc
;
1080 if (FAILED(psfFrom
->QueryInterface(IID_ISFHelper
, (LPVOID
*)&psfhlpsrc
)))
1082 ERR("no IID_ISFHelper for source\n");
1084 psfhlpdst
->Release();
1086 psfTarget
->Release();
1088 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1089 ReleaseStgMedium(&medium
);
1095 * do we want to perform a copy or move ???
1097 hr
= psfhlpdst
->CopyItems(psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
);
1099 psfhlpdst
->Release();
1100 psfhlpsrc
->Release();
1102 psfTarget
->Release();
1104 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1105 ReleaseStgMedium(&medium
);
1107 TRACE("CP result %x\n", hr
);
1112 CDefaultContextMenu::DoOpenOrExplore(
1113 LPCMINVOKECOMMANDINFO lpcmi
)
1120 GetUniqueFileName(LPWSTR pwszBasePath
, LPCWSTR pwszExt
, LPWSTR pwszTarget
, BOOL bShortcut
)
1126 if (!LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, wszLink
, _countof(wszLink
)))
1131 swprintf(pwszTarget
, L
"%s%s%s", wszLink
, pwszBasePath
, pwszExt
);
1133 swprintf(pwszTarget
, L
"%s%s", pwszBasePath
, pwszExt
);
1135 for (UINT i
= 2; PathFileExistsW(pwszTarget
); ++i
)
1138 swprintf(pwszTarget
, L
"%s%s (%u)%s", wszLink
, pwszBasePath
, i
, pwszExt
);
1140 swprintf(pwszTarget
, L
"%s (%u)%s", pwszBasePath
, i
, pwszExt
);
1148 CDefaultContextMenu::DoCreateLink(
1149 LPCMINVOKECOMMANDINFO lpcmi
)
1151 WCHAR wszTarget
[MAX_PATH
];
1156 if (m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1158 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1162 WCHAR wszPath
[MAX_PATH
];
1163 if (StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], wszPath
, _countof(wszPath
)) != S_OK
)
1166 LPWSTR pwszExt
= PathFindExtensionW(wszPath
);
1168 if (!wcsicmp(pwszExt
, L
".lnk"))
1170 if (!GetUniqueFileName(wszPath
, pwszExt
, wszTarget
, TRUE
))
1173 hr
= IShellLink_ConstructFromFile(NULL
, IID_IPersistFile
, m_Dcm
.apidl
[0], (LPVOID
*)&ppf
);
1177 hr
= ppf
->Save(wszTarget
, FALSE
);
1179 NotifyShellViewWindow(lpcmi
, TRUE
);
1184 if (!GetUniqueFileName(wszPath
, L
".lnk", wszTarget
, TRUE
))
1188 hr
= CShellLink::_CreatorClass::CreateInstance(NULL
, IID_IShellLinkW
, (void**)&pLink
);
1192 WCHAR szDirPath
[MAX_PATH
], *pwszFile
;
1193 GetFullPathName(wszPath
, MAX_PATH
, szDirPath
, &pwszFile
);
1194 if (pwszFile
) pwszFile
[0] = 0;
1196 if (SUCCEEDED(pLink
->SetPath(wszPath
)) &&
1197 SUCCEEDED(pLink
->SetWorkingDirectory(szDirPath
)))
1199 if (SUCCEEDED(pLink
->QueryInterface(IID_IPersistFile
, (LPVOID
*)&ppf
)))
1201 hr
= ppf
->Save(wszTarget
, TRUE
);
1206 NotifyShellViewWindow(lpcmi
, TRUE
);
1212 CDefaultContextMenu::DoDelete(
1213 LPCMINVOKECOMMANDINFO lpcmi
)
1216 HRESULT hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1219 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1223 WCHAR wszPath
[MAX_PATH
];
1224 hr
= StrRetToBufW(&strTemp
, m_Dcm
.apidl
[0], wszPath
, _countof(wszPath
));
1227 ERR("StrRetToBufW failed with %x\n", hr
);
1231 /* Only keep the base path */
1232 LPWSTR pwszFilename
= PathFindFileNameW(wszPath
);
1233 *pwszFilename
= L
'\0';
1235 /* Build paths list */
1236 LPWSTR pwszPaths
= BuildPathsList(wszPath
, m_Dcm
.cidl
, m_Dcm
.apidl
);
1241 SHFILEOPSTRUCTW FileOp
;
1242 ZeroMemory(&FileOp
, sizeof(FileOp
));
1243 FileOp
.hwnd
= GetActiveWindow();
1244 FileOp
.wFunc
= FO_DELETE
;
1245 FileOp
.pFrom
= pwszPaths
;
1246 FileOp
.fFlags
= FOF_ALLOWUNDO
;
1248 if (SHFileOperationW(&FileOp
) != 0)
1250 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(pwszPaths
));
1254 /* Get the active IShellView */
1255 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageW(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1258 /* Is the treeview focused */
1260 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1262 /* Remove selected items from treeview */
1263 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1265 (void)TreeView_DeleteItem(hwnd
, hItem
);
1268 NotifyShellViewWindow(lpcmi
, TRUE
);
1270 HeapFree(GetProcessHeap(), 0, pwszPaths
);
1276 CDefaultContextMenu::DoCopyOrCut(
1277 LPCMINVOKECOMMANDINFO lpcmi
,
1280 LPDATAOBJECT pDataObj
;
1283 if (SUCCEEDED(SHCreateDataObject(m_Dcm
.pidlFolder
, m_Dcm
.cidl
, m_Dcm
.apidl
, NULL
, IID_IDataObject
, (void**)&pDataObj
)))
1285 hr
= OleSetClipboard(pDataObj
);
1286 pDataObj
->Release();
1290 /* Note: CWM_GETISHELLBROWSER returns not referenced object */
1291 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1294 ERR("failed to get shellbrowser\n");
1299 hr
= lpSB
->QueryActiveShellView(&lpSV
);
1302 ERR("failed to query the active shellview\n");
1306 hr
= lpSV
->GetItemObject(SVGIO_SELECTION
, IID_IDataObject
, (LPVOID
*)&pDataObj
);
1309 hr
= OleSetClipboard(pDataObj
);
1311 ERR("OleSetClipboard failed");
1312 pDataObj
->Release();
1314 ERR("failed to get item object\n");
1321 CDefaultContextMenu::DoRename(
1322 LPCMINVOKECOMMANDINFO lpcmi
)
1324 /* get the active IShellView. Note: CWM_GETISHELLBROWSER returns not referenced object */
1325 LPSHELLBROWSER lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1328 ERR("CWM_GETISHELLBROWSER failed\n");
1332 /* is the treeview focused */
1334 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1336 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1338 (void)TreeView_EditLabel(hwnd
, hItem
);
1342 HRESULT hr
= lpSB
->QueryActiveShellView(&lpSV
);
1345 ERR("CWM_GETISHELLBROWSER failed\n");
1349 lpSV
->SelectItem(m_Dcm
.apidl
[0],
1350 SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
);
1356 CDefaultContextMenu::DoProperties(
1357 LPCMINVOKECOMMANDINFO lpcmi
)
1360 const ITEMIDLIST
*pidlParent
= m_Dcm
.pidlFolder
, *pidlChild
;
1364 IPersistFolder2
*pf
;
1366 /* pidlFolder is optional */
1367 if (SUCCEEDED(m_Dcm
.psf
->QueryInterface(IID_IPersistFolder2
, (PVOID
*)&pf
)))
1369 pf
->GetCurFolder((_ITEMIDLIST
**)&pidlParent
);
1375 pidlChild
= m_Dcm
.apidl
[0];
1378 /* Set pidlChild to last pidl of current folder */
1379 if (pidlParent
== m_Dcm
.pidlFolder
)
1380 pidlParent
= (ITEMIDLIST
*)ILClone(pidlParent
);
1382 pidlChild
= (ITEMIDLIST
*)ILClone(ILFindLastID(pidlParent
));
1383 ILRemoveLastID((ITEMIDLIST
*)pidlParent
);
1386 if (_ILIsMyComputer(pidlChild
))
1388 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1391 else if (_ILIsDesktop(pidlChild
))
1393 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1396 else if (_ILIsDrive(pidlChild
))
1398 WCHAR wszBuf
[MAX_PATH
];
1399 ILGetDisplayName(pidlChild
, wszBuf
);
1400 if (!SH_ShowDriveProperties(wszBuf
, pidlParent
, &pidlChild
))
1403 else if (_ILIsNetHood(pidlChild
))
1406 if (32 >= (UINT
)ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1407 L
"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1408 NULL
, SW_SHOWDEFAULT
))
1411 else if (_ILIsBitBucket(pidlChild
))
1413 /* FIXME: detect the drive path of bitbucket if appropiate */
1414 if(!SH_ShowRecycleBinProperties(L
'C'))
1420 WARN("SHMultiFileProperties is not yet implemented\n");
1423 hr
= m_Dcm
.psf
->GetDisplayNameOf(pidlChild
, SHGDN_FORPARSING
, &strFile
);
1426 WCHAR wszBuf
[MAX_PATH
];
1427 hr
= StrRetToBufW(&strFile
, pidlChild
, wszBuf
, _countof(wszBuf
));
1429 hr
= SH_ShowPropertiesDialog(wszBuf
, pidlParent
, &pidlChild
);
1431 ERR("StrRetToBufW failed\n");
1434 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1437 /* Free allocated PIDLs */
1438 if (pidlParent
!= m_Dcm
.pidlFolder
)
1439 ILFree((ITEMIDLIST
*)pidlParent
);
1440 if (m_Dcm
.cidl
< 1 || pidlChild
!= m_Dcm
.apidl
[0])
1441 ILFree((ITEMIDLIST
*)pidlChild
);
1447 CDefaultContextMenu::DoFormat(
1448 LPCMINVOKECOMMANDINFO lpcmi
)
1450 char szDrive
[8] = {0};
1452 if (!_ILGetDrive(m_Dcm
.apidl
[0], szDrive
, sizeof(szDrive
)))
1454 ERR("pidl is not a drive\n");
1458 SHFormatDrive(lpcmi
->hwnd
, szDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1463 CDefaultContextMenu::DoDynamicShellExtensions(
1464 LPCMINVOKECOMMANDINFO lpcmi
)
1466 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
1467 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1469 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, m_iIdSHEFirst
, m_iIdSHELast
);
1471 while(pEntry
&& idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1472 pEntry
= pEntry
->pNext
;
1477 if (idCmd
>= pEntry
->iIdCmdFirst
&& idCmd
<= pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1479 /* invoke the dynamic context menu */
1480 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
- pEntry
->iIdCmdFirst
);
1481 return pEntry
->pCM
->InvokeCommand(lpcmi
);
1489 CDefaultContextMenu::DoStaticShellExtensions(
1490 LPCMINVOKECOMMANDINFO lpcmi
)
1492 PStaticShellEntry pEntry
= m_pStaticEntries
;
1493 INT iCmd
= LOWORD(lpcmi
->lpVerb
) - m_iIdSCMFirst
;
1496 while (pEntry
&& (iCmd
--) > 0)
1497 pEntry
= pEntry
->pNext
;
1503 hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
);
1506 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1510 WCHAR wszPath
[MAX_PATH
];
1511 hr
= StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], wszPath
, MAX_PATH
);
1515 WCHAR wszDir
[MAX_PATH
];
1516 wcscpy(wszDir
, wszPath
);
1517 PathRemoveFileSpec(wszDir
);
1519 SHELLEXECUTEINFOW sei
;
1520 ZeroMemory(&sei
, sizeof(sei
));
1521 sei
.cbSize
= sizeof(sei
);
1522 sei
.fMask
= SEE_MASK_CLASSNAME
;
1523 sei
.lpClass
= pEntry
->szClass
;
1524 sei
.hwnd
= lpcmi
->hwnd
;
1525 sei
.nShow
= SW_SHOWNORMAL
;
1526 sei
.lpVerb
= pEntry
->szVerb
;
1527 sei
.lpFile
= wszPath
;
1528 sei
.lpDirectory
= wszDir
;
1529 ShellExecuteExW(&sei
);
1535 CDefaultContextMenu::InvokeCommand(
1536 LPCMINVOKECOMMANDINFO lpcmi
)
1538 switch(LOWORD(lpcmi
->lpVerb
))
1540 case FCIDM_SHVIEW_BIGICON
:
1541 case FCIDM_SHVIEW_SMALLICON
:
1542 case FCIDM_SHVIEW_LISTVIEW
:
1543 case FCIDM_SHVIEW_REPORTVIEW
:
1544 case 0x30: /* FIX IDS in resource files */
1548 case FCIDM_SHVIEW_AUTOARRANGE
:
1549 case FCIDM_SHVIEW_SNAPTOGRID
:
1550 case FCIDM_SHVIEW_REFRESH
:
1551 return NotifyShellViewWindow(lpcmi
, FALSE
);
1552 case FCIDM_SHVIEW_INSERT
:
1553 case FCIDM_SHVIEW_INSERTLINK
:
1554 return DoPaste(lpcmi
);
1555 case FCIDM_SHVIEW_OPEN
:
1556 case FCIDM_SHVIEW_EXPLORE
:
1557 return DoOpenOrExplore(lpcmi
);
1558 case FCIDM_SHVIEW_COPY
:
1559 case FCIDM_SHVIEW_CUT
:
1560 return DoCopyOrCut(lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1561 case FCIDM_SHVIEW_CREATELINK
:
1562 return DoCreateLink(lpcmi
);
1563 case FCIDM_SHVIEW_DELETE
:
1564 return DoDelete(lpcmi
);
1565 case FCIDM_SHVIEW_RENAME
:
1566 return DoRename(lpcmi
);
1567 case FCIDM_SHVIEW_PROPERTIES
:
1568 return DoProperties(lpcmi
);
1570 return DoFormat(lpcmi
);
1573 if (m_iIdSHEFirst
&& m_iIdSHELast
)
1575 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSHELast
)
1576 return DoDynamicShellExtensions(lpcmi
);
1579 if (m_iIdSCMFirst
&& m_iIdSCMLast
)
1581 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSCMLast
)
1582 return DoStaticShellExtensions(lpcmi
);
1585 FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi
->lpVerb
));
1586 return E_UNEXPECTED
;
1591 CDefaultContextMenu::GetCommandString(
1603 CDefaultContextMenu::HandleMenuMsg(
1613 IDefaultContextMenu_Constructor(
1614 const DEFCONTEXTMENU
*pdcm
,
1622 CComObject
<CDefaultContextMenu
> *pCM
;
1623 HRESULT hr
= CComObject
<CDefaultContextMenu
>::CreateInstance(&pCM
);
1626 pCM
->AddRef(); // CreateInstance returns object with 0 ref count */
1628 CComPtr
<IUnknown
> pResult
;
1629 hr
= pCM
->QueryInterface(riid
, (void **)&pResult
);
1636 hr
= pCM
->Initialize(pdcm
);
1643 *ppv
= pResult
.Detach();
1645 TRACE("This(%p) cidl %u\n", *ppv
, pdcm
->cidl
);
1649 /*************************************************************************
1650 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1656 SHCreateDefaultContextMenu(
1657 const DEFCONTEXTMENU
*pdcm
,
1662 HRESULT hr
= IDefaultContextMenu_Constructor(pdcm
, riid
, ppv
);
1664 ERR("IDefaultContextMenu_Constructor failed: %x\n", hr
);
1665 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1669 /*************************************************************************
1670 * CDefFolderMenu_Create2 [SHELL32.701]
1676 CDefFolderMenu_Create2(
1677 LPCITEMIDLIST pidlFolder
,
1680 LPCITEMIDLIST
*apidl
,
1682 LPFNDFMCALLBACK lpfn
,
1684 const HKEY
*ahkeyClsKeys
,
1685 IContextMenu
**ppcm
)
1687 DEFCONTEXTMENU pdcm
;
1690 pdcm
.pidlFolder
= pidlFolder
;
1694 pdcm
.punkAssociationInfo
= NULL
;
1696 pdcm
.aKeys
= ahkeyClsKeys
;
1698 HRESULT hr
= SHCreateDefaultContextMenu(&pdcm
, IID_IContextMenu
, (void**)ppcm
);