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_
* Next
;
29 } DynamicShellEntry
, *PDynamicShellEntry
;
31 typedef struct _StaticShellEntry_
35 struct _StaticShellEntry_
* Next
;
36 } StaticShellEntry
, *PStaticShellEntry
;
38 WCHAR
*build_paths_list(LPCWSTR wszBasePath
, int cidl
, LPCITEMIDLIST
*pidls
);
40 class IDefaultContextMenuImpl
:
41 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
46 IDataObject
* pDataObj
;
47 DWORD bGroupPolicyActive
;
48 PDynamicShellEntry dhead
; /* first dynamic shell extension entry */
49 UINT iIdSHEFirst
; /* first used id */
50 UINT iIdSHELast
; /* last used id */
51 PStaticShellEntry shead
; /* first static shell extension entry */
52 UINT iIdSCMFirst
; /* first static used id */
53 UINT iIdSCMLast
; /* last static used id */
55 IDefaultContextMenuImpl();
56 ~IDefaultContextMenuImpl();
57 HRESULT WINAPI
Initialize(const DEFCONTEXTMENU
*pdcm
);
58 void SH_AddStaticEntry(const WCHAR
*szVerb
, const WCHAR
*szClass
);
59 void SH_AddStaticEntryForKey(HKEY hKey
, const WCHAR
*szClass
);
60 void SH_AddStaticEntryForFileClass(const WCHAR
*szExt
);
61 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*szClass
);
62 HRESULT
SH_LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*szClass
, BOOL bExternalInit
);
63 UINT
EnumerateDynamicContextHandlerForKey(HKEY hRootKey
);
64 UINT
InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
);
65 UINT
BuildBackgroundContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
66 UINT
AddStaticContextMenusToMenu(HMENU hMenu
, UINT indexMenu
);
67 UINT
BuildShellItemContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
68 HRESULT
DoPaste(LPCMINVOKECOMMANDINFO lpcmi
);
69 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
70 HRESULT
DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
);
71 HRESULT
DoDelete(LPCMINVOKECOMMANDINFO lpcmi
);
72 HRESULT
DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
);
73 HRESULT
DoRename(LPCMINVOKECOMMANDINFO lpcmi
);
74 HRESULT
DoProperties(LPCMINVOKECOMMANDINFO lpcmi
);
75 HRESULT
DoFormat(LPCMINVOKECOMMANDINFO lpcmi
);
76 HRESULT
DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
77 HRESULT
DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
80 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
81 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
82 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
85 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
87 BEGIN_COM_MAP(IDefaultContextMenuImpl
)
88 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
89 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
93 IDefaultContextMenuImpl::IDefaultContextMenuImpl()
95 memset (&dcm
, 0, sizeof(dcm
));
97 bGroupPolicyActive
= 0;
106 IDefaultContextMenuImpl::~IDefaultContextMenuImpl()
108 PDynamicShellEntry dEntry
, dNext
;
109 PStaticShellEntry sEntry
, sNext
;
111 /* free dynamic shell extension entries */
115 dNext
= dEntry
->Next
;
116 dEntry
->CMenu
->Release();
117 HeapFree(GetProcessHeap(), 0, dEntry
);
120 /* free static shell extension entries */
124 sNext
= sEntry
->Next
;
125 HeapFree(GetProcessHeap(), 0, sEntry
->szClass
);
126 HeapFree(GetProcessHeap(), 0, sEntry
->szVerb
);
127 HeapFree(GetProcessHeap(), 0, sEntry
);
132 HRESULT WINAPI
IDefaultContextMenuImpl::Initialize(const DEFCONTEXTMENU
*pdcm
)
134 IDataObject
*newDataObj
;
136 TRACE("cidl %u\n", dcm
.cidl
);
137 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, IID_IDataObject
, (void**)&newDataObj
)))
138 pDataObj
= newDataObj
;
139 CopyMemory(&dcm
, pdcm
, sizeof(DEFCONTEXTMENU
));
144 IDefaultContextMenuImpl::SH_AddStaticEntry(const WCHAR
*szVerb
, const WCHAR
* szClass
)
146 PStaticShellEntry curEntry
;
147 PStaticShellEntry lastEntry
= NULL
;
152 if (!wcsicmp(curEntry
->szVerb
, szVerb
))
154 /* entry already exists */
157 lastEntry
= curEntry
;
158 curEntry
= curEntry
->Next
;
161 TRACE("adding verb %s szClass %s\n", debugstr_w(szVerb
), debugstr_w(szClass
));
163 curEntry
= (StaticShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry
));
166 curEntry
->Next
= NULL
;
167 curEntry
->szVerb
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb
) + 1) * sizeof(WCHAR
));
168 if (curEntry
->szVerb
)
169 wcscpy(curEntry
->szVerb
, szVerb
);
170 curEntry
->szClass
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szClass
) + 1) * sizeof(WCHAR
));
171 if (curEntry
->szClass
)
172 wcscpy(curEntry
->szClass
, szClass
);
175 if (!wcsicmp(szVerb
, L
"open"))
177 /* open verb is always inserted in front */
178 curEntry
->Next
= shead
;
187 lastEntry
->Next
= curEntry
;
196 IDefaultContextMenuImpl::SH_AddStaticEntryForKey(HKEY hKey
, const WCHAR
* szClass
)
207 dwName
= sizeof(szName
) / sizeof(WCHAR
);
208 result
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
209 szName
[(sizeof(szName
)/sizeof(WCHAR
))-1] = 0;
210 if (result
== ERROR_SUCCESS
)
212 SH_AddStaticEntry(szName
, szClass
);
215 } while(result
== ERROR_SUCCESS
);
219 IDefaultContextMenuImpl::SH_AddStaticEntryForFileClass(const WCHAR
* szExt
)
226 static WCHAR szShell
[] = L
"\\shell";
227 static WCHAR szShellAssoc
[] = L
"SystemFileAssociations\\";
229 TRACE("SH_AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt
));
231 Length
= wcslen(szExt
);
232 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
234 wcscpy(szBuffer
, szExt
);
235 wcscpy(&szBuffer
[Length
], szShell
);
236 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
237 if (result
== ERROR_SUCCESS
)
239 szBuffer
[Length
] = 0;
240 SH_AddStaticEntryForKey(hKey
, szExt
);
245 dwBuffer
= sizeof(szBuffer
);
246 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, (LPBYTE
)szBuffer
, &dwBuffer
);
247 if (result
== ERROR_SUCCESS
)
249 Length
= wcslen(szBuffer
);
250 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
252 wcscpy(&szBuffer
[Length
], szShell
);
253 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
255 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
256 if (result
== ERROR_SUCCESS
)
258 szBuffer
[Length
] = 0;
259 SH_AddStaticEntryForKey(hKey
, szBuffer
);
265 wcscpy(szBuffer
, szShellAssoc
);
266 dwBuffer
= sizeof(szBuffer
) - sizeof(szShellAssoc
) - sizeof(WCHAR
);
267 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, L
"PerceivedType", RRF_RT_REG_SZ
, NULL
, (LPBYTE
)&szBuffer
[_countof(szShellAssoc
) - 1], &dwBuffer
);
268 if (result
== ERROR_SUCCESS
)
270 Length
= wcslen(&szBuffer
[_countof(szShellAssoc
)]) + _countof(szShellAssoc
);
271 wcscat(szBuffer
, L
"\\shell");
272 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
274 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
275 if (result
== ERROR_SUCCESS
)
277 szBuffer
[Length
] = 0;
278 SH_AddStaticEntryForKey(hKey
, szBuffer
);
291 if(SUCCEEDED(OleGetClipboard(&pda
)))
296 TRACE("pda=%p\n", pda
);
298 /* Set the FORMATETC structure*/
299 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
300 if(SUCCEEDED(pda
->GetData(&formatetc
, &medium
)))
303 ReleaseStgMedium(&medium
);
314 DisablePasteOptions(HMENU hMenu
)
318 mii
.cbSize
= sizeof(mii
);
319 mii
.fMask
= MIIM_STATE
;
320 mii
.fState
= MFS_DISABLED
;
322 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
));
323 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
));
327 IDefaultContextMenuImpl::IsShellExtensionAlreadyLoaded(const CLSID
* szClass
)
329 PDynamicShellEntry curEntry
= dhead
;
333 if (!memcmp(&curEntry
->ClassID
, szClass
, sizeof(CLSID
)))
335 curEntry
= curEntry
->Next
;
342 IDefaultContextMenuImpl::SH_LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
* pClass
, BOOL bExternalInit
)
345 IContextMenu
* cmobj
;
346 IShellExtInit
*shext
;
347 PDynamicShellEntry curEntry
;
350 StringFromCLSID(*pClass
, &pstr
);
352 TRACE("SH_LoadDynamicContextMenuHandler entered with This %p hKey %p pClass %s bExternalInit %u\n", this, hKey
, wine_dbgstr_guid(pClass
), bExternalInit
);
354 if (IsShellExtensionAlreadyLoaded(pClass
))
357 hr
= SHCoCreateInstance(NULL
, pClass
, NULL
, IID_IContextMenu
, (void**)&cmobj
);
360 ERR("SHCoCreateInstance failed %x\n", GetLastError());
366 hr
= cmobj
->QueryInterface(IID_IShellExtInit
, (void**)&shext
);
369 ERR("Failed to query for interface IID_IShellExtInit hr %x pClass %s\n", hr
, wine_dbgstr_guid(pClass
));
373 hr
= shext
->Initialize(NULL
, pDataObj
, hKey
);
377 TRACE("Failed to initialize shell extension error %x pClass %s\n", hr
, wine_dbgstr_guid(pClass
));
383 curEntry
= (DynamicShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
387 return E_OUTOFMEMORY
;
390 curEntry
->iIdCmdFirst
= 0;
391 curEntry
->Next
= NULL
;
392 curEntry
->NumIds
= 0;
393 curEntry
->CMenu
= cmobj
;
394 memcpy(&curEntry
->ClassID
, pClass
, sizeof(CLSID
));
398 PDynamicShellEntry pEntry
= dhead
;
402 pEntry
= pEntry
->Next
;
405 pEntry
->Next
= curEntry
;
416 IDefaultContextMenuImpl::EnumerateDynamicContextHandlerForKey(HKEY hRootKey
)
418 WCHAR szKey
[MAX_PATH
] = {0};
419 WCHAR szName
[MAX_PATH
] = {0};
420 DWORD dwIndex
, dwName
;
427 static const WCHAR szShellEx
[] = { 's', 'h', 'e', 'l', 'l', 'e', 'x', '\\', 'C', 'o', 'n', 't', 'e', 'x', 't', 'M', 'e', 'n', 'u', 'H', 'a', 'n', 'd', 'l', 'e', 'r', 's', 0 };
429 if (RegOpenKeyExW(hRootKey
, szShellEx
, 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
431 TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey
));
440 res
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
441 if (res
== ERROR_SUCCESS
)
443 hResult
= CLSIDFromString(szName
, &clsid
);
447 if (RegGetValueW(hKey
, szName
, NULL
, RRF_RT_REG_SZ
, NULL
, szKey
, &dwName
) == ERROR_SUCCESS
)
449 hResult
= CLSIDFromString(szKey
, &clsid
);
452 if (SUCCEEDED(hResult
))
454 if (bGroupPolicyActive
)
456 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
457 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
462 &dwName
) == ERROR_SUCCESS
)
464 SH_LoadDynamicContextMenuHandler(hKey
, &clsid
, TRUE
);
469 SH_LoadDynamicContextMenuHandler(hKey
, &clsid
, TRUE
);
474 } while(res
== ERROR_SUCCESS
);
481 IDefaultContextMenuImpl::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
483 PDynamicShellEntry curEntry
;
496 iIdSHEFirst
= idCmdFirst
;
499 hResult
= curEntry
->CMenu
->QueryContextMenu(hMenu
, indexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
500 if (SUCCEEDED(hResult
))
502 curEntry
->iIdCmdFirst
= idCmdFirst
;
503 curEntry
->NumIds
= LOWORD(hResult
);
504 indexMenu
+= curEntry
->NumIds
;
505 idCmdFirst
+= curEntry
->NumIds
+ 0x10;
507 TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry
, hResult
, curEntry
->CMenu
, curEntry
->iIdCmdFirst
, curEntry
->NumIds
);
508 curEntry
= curEntry
->Next
;
511 iIdSHELast
= idCmdFirst
;
512 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", iIdSHEFirst
, iIdSHELast
);
517 IDefaultContextMenuImpl::BuildBackgroundContextMenu(
524 WCHAR szBuffer
[MAX_PATH
];
529 ZeroMemory(&mii
, sizeof(mii
));
531 TRACE("BuildBackgroundContextMenu entered\n");
533 if (!_ILIsDesktop(dcm
.pidlFolder
))
535 /* view option is only available in browsing mode */
536 hSubMenu
= LoadMenuA(shell32_hInstance
, "MENU_001");
540 LoadStringW(shell32_hInstance
, FCIDM_SHVIEW_VIEW
, szBuffer
, MAX_PATH
);
541 szBuffer
[MAX_PATH
-1] = 0;
543 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
545 mii
.cbSize
= sizeof(mii
);
546 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_ID
;
547 mii
.fType
= MFT_STRING
;
548 mii
.wID
= iIdCmdFirst
++;
549 mii
.dwTypeData
= szBuffer
;
550 mii
.cch
= wcslen( mii
.dwTypeData
);
551 mii
.fState
= MFS_ENABLED
;
552 mii
.hSubMenu
= hSubMenu
;
553 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
554 DestroyMenu(hSubMenu
);
557 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
560 /* merge general background context menu in */
561 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), indexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
562 DestroyMenu(hSubMenu
);
565 if (!HasClipboardData())
567 TRACE("disabling paste options\n");
568 DisablePasteOptions(hMenu
);
570 /* load extensions from HKCR\* key */
571 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
575 &hKey
) == ERROR_SUCCESS
)
577 EnumerateDynamicContextHandlerForKey(hKey
);
581 /* load create new shell extension */
582 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
583 L
"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}",
586 &hKey
) == ERROR_SUCCESS
)
588 SH_LoadDynamicContextMenuHandler(hKey
, &CLSID_NewMenu
, TRUE
);
592 if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, GetMenuItemCount(hMenu
) - 1, iIdCmdFirst
, iIdCmdLast
))
594 /* seperate dynamic context menu items */
595 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
) - 1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
602 IDefaultContextMenuImpl::AddStaticContextMenusToMenu(
608 PStaticShellEntry curEntry
;
615 mii
.cbSize
= sizeof(mii
);
616 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
617 mii
.fType
= MFT_STRING
;
618 mii
.fState
= MFS_ENABLED
;
620 mii
.dwTypeData
= NULL
;
621 iIdSCMFirst
= mii
.wID
;
627 fState
= MFS_ENABLED
;
628 if (!wcsicmp(curEntry
->szVerb
, L
"open"))
630 fState
|= MFS_DEFAULT
;
631 idResource
= IDS_OPEN_VERB
;
633 else if (!wcsicmp(curEntry
->szVerb
, L
"explore"))
634 idResource
= IDS_EXPLORE_VERB
;
635 else if (!wcsicmp(curEntry
->szVerb
, L
"runas"))
636 idResource
= IDS_RUNAS_VERB
;
637 else if (!wcsicmp(curEntry
->szVerb
, L
"edit"))
638 idResource
= IDS_EDIT_VERB
;
639 else if (!wcsicmp(curEntry
->szVerb
, L
"find"))
640 idResource
= IDS_FIND_VERB
;
641 else if (!wcsicmp(curEntry
->szVerb
, L
"print"))
642 idResource
= IDS_PRINT_VERB
;
643 else if (!wcsicmp(curEntry
->szVerb
, L
"printto"))
645 curEntry
= curEntry
->Next
;
653 if (LoadStringW(shell32_hInstance
, idResource
, szVerb
, sizeof(szVerb
) / sizeof(WCHAR
)))
655 /* use translated verb */
656 szVerb
[(sizeof(szVerb
)/sizeof(WCHAR
))-1] = L
'\0';
657 mii
.dwTypeData
= szVerb
;
661 ERR("Failed to load string, defaulting to NULL value for mii.dwTypeData\n");
666 Length
= wcslen(curEntry
->szClass
) + wcslen(curEntry
->szVerb
) + 8;
667 if (Length
< sizeof(szTemp
) / sizeof(WCHAR
))
669 wcscpy(szTemp
, curEntry
->szClass
);
670 wcscat(szTemp
, L
"\\shell\\");
671 wcscat(szTemp
, curEntry
->szVerb
);
672 dwSize
= sizeof(szVerb
);
674 if (RegGetValueW(HKEY_CLASSES_ROOT
, szTemp
, NULL
, RRF_RT_REG_SZ
, NULL
, szVerb
, &dwSize
) == ERROR_SUCCESS
)
676 /* use description for the menu entry */
677 mii
.dwTypeData
= szVerb
;
681 /* use verb for the menu entry */
682 mii
.dwTypeData
= curEntry
->szVerb
;
688 mii
.cch
= wcslen(mii
.dwTypeData
);
690 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
693 curEntry
= curEntry
->Next
;
695 iIdSCMLast
= mii
.wID
- 1;
699 void WINAPI
_InsertMenuItemW (
711 ZeroMemory(&mii
, sizeof(mii
));
712 mii
.cbSize
= sizeof(mii
);
713 if (fType
== MFT_SEPARATOR
)
715 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
717 else if (fType
== MFT_STRING
)
719 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
720 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
722 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), szText
, sizeof(szText
) / sizeof(WCHAR
)))
724 szText
[(sizeof(szText
)/sizeof(WCHAR
))-1] = 0;
725 mii
.dwTypeData
= szText
;
729 ERR("failed to load string %p\n", dwTypeData
);
735 mii
.dwTypeData
= (LPWSTR
) dwTypeData
;
742 InsertMenuItemW( hmenu
, indexMenu
, fByPosition
, &mii
);
746 IDefaultContextMenuImpl::BuildShellItemContextMenu(
752 WCHAR szPath
[MAX_PATH
];
758 BOOL bAddSep
= FALSE
;
765 TRACE("BuildShellItemContextMenu entered\n");
767 hr
= dcm
.psf
->GetDisplayNameOf(dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
);
770 hr
= StrRetToBufW(&strFile
, dcm
.apidl
[0], szPath
, MAX_PATH
);
773 pOffset
= wcsrchr(szPath
, L
'.');
776 /* enumerate dynamic/static for a given file class */
777 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pOffset
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
779 /* add static verbs */
780 SH_AddStaticEntryForFileClass(pOffset
);
781 /* load dynamic extensions from file extension key */
782 EnumerateDynamicContextHandlerForKey(hKey
);
785 dwSize
= sizeof(szTemp
);
786 if (RegGetValueW(HKEY_CLASSES_ROOT
, pOffset
, NULL
, RRF_RT_REG_SZ
, NULL
, szTemp
, &dwSize
) == ERROR_SUCCESS
)
788 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
790 /* add static verbs from progid key */
791 SH_AddStaticEntryForFileClass(szTemp
);
792 /* load dynamic extensions from progid key */
793 EnumerateDynamicContextHandlerForKey(hKey
);
798 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
800 /* load default extensions */
801 EnumerateDynamicContextHandlerForKey(hKey
);
807 ERR("GetDisplayNameOf failed: %x\n", hr
);
809 guid
= _ILGetGUIDPointer(dcm
.apidl
[0]);
815 wcscpy(buffer
, L
"CLSID\\");
816 hr
= StringFromCLSID(*guid
, &pwszCLSID
);
819 wcscpy(&buffer
[6], pwszCLSID
);
820 TRACE("buffer %s\n", debugstr_w(buffer
));
821 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
823 EnumerateDynamicContextHandlerForKey(hKey
);
824 SH_AddStaticEntryForFileClass(buffer
);
827 CoTaskMemFree(pwszCLSID
);
832 if (_ILIsDrive(dcm
.apidl
[0]))
834 SH_AddStaticEntryForFileClass(L
"Drive");
835 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
837 EnumerateDynamicContextHandlerForKey(hKey
);
843 /* add static actions */
844 rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
845 hr
= dcm
.psf
->GetAttributesOf(dcm
.cidl
, dcm
.apidl
, &rfg
);
848 WARN("GetAttributesOf failed: %x\n", hr
);
852 if ((rfg
& SFGAO_FOLDER
) || _ILIsControlPanel(dcm
.apidl
[dcm
.cidl
]))
854 /* add the default verbs open / explore */
855 SH_AddStaticEntryForFileClass(L
"Folder");
856 SH_AddStaticEntryForFileClass(L
"Directory");
857 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
859 EnumerateDynamicContextHandlerForKey(hKey
);
862 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
864 EnumerateDynamicContextHandlerForKey(hKey
);
870 if (rfg
& SFGAO_FILESYSTEM
)
872 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
874 /* sendto service is registered here */
875 EnumerateDynamicContextHandlerForKey(hKey
);
880 /* add static context menu handlers */
881 indexMenu
= AddStaticContextMenusToMenu(hMenu
, 0);
882 /* now process dynamic context menu handlers */
883 indexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, indexMenu
, iIdCmdFirst
, iIdCmdLast
);
884 TRACE("indexMenu %d\n", indexMenu
);
886 if (_ILIsDrive(dcm
.apidl
[0]))
888 /* The 'Format' option must be always available,
889 * thus it is not registered as a static shell extension
891 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
892 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
896 bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
897 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
899 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
900 if (rfg
& SFGAO_CANMOVE
)
901 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
902 if (rfg
& SFGAO_CANCOPY
)
903 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
905 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_INSERT
), MFS_ENABLED
);
911 if (rfg
& SFGAO_CANLINK
)
914 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
915 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
919 if (rfg
& SFGAO_CANDELETE
)
924 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
926 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
929 if (rfg
& SFGAO_CANRENAME
)
933 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
935 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
939 if (rfg
& SFGAO_HASPROPSHEET
)
941 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
942 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
950 IDefaultContextMenuImpl::QueryContextMenu(
959 idCmdFirst
= BuildShellItemContextMenu(hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
963 idCmdFirst
= BuildBackgroundContextMenu(hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
971 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
974 LPSHELLVIEW lpSV
= NULL
;
977 if((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0)))
979 if(SUCCEEDED(lpSB
->QueryActiveShellView(&lpSV
)))
981 lpSV
->GetWindow(&hwndSV
);
985 if (LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_REFRESH
|| bRefresh
)
993 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
999 IDefaultContextMenuImpl::DoPaste(
1000 LPCMINVOKECOMMANDINFO lpcmi
)
1004 FORMATETC formatetc
;
1005 LPITEMIDLIST
* apidl
;
1007 IShellFolder
*psfFrom
= NULL
, *psfDesktop
, *psfTarget
= NULL
;
1009 ISFHelper
*psfhlpdst
, *psfhlpsrc
;
1012 if (OleGetClipboard(&pda
) != S_OK
)
1015 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
1016 hr
= pda
->GetData(&formatetc
, &medium
);
1024 /* lock the handle */
1025 lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
1028 ReleaseStgMedium(&medium
);
1033 /* convert the data into pidl */
1034 apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1039 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
1042 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1043 ReleaseStgMedium(&medium
);
1048 if (_ILIsDesktop(pidl
))
1050 /* use desktop shellfolder */
1051 psfFrom
= psfDesktop
;
1053 else if (FAILED(psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfFrom
)))
1055 ERR("no IShellFolder\n");
1057 psfDesktop
->Release();
1059 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1060 ReleaseStgMedium(&medium
);
1068 psfDesktop
->Release();
1069 hr
= dcm
.psf
->BindToObject(dcm
.apidl
[0], NULL
, IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1073 IPersistFolder2
*ppf2
= NULL
;
1076 /* cidl is zero due to explorer view */
1077 hr
= dcm
.psf
->QueryInterface (IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1080 hr
= ppf2
->GetCurFolder (&pidl
);
1084 if (_ILIsDesktop(pidl
))
1086 /* use desktop shellfolder */
1087 psfTarget
= psfDesktop
;
1091 /* retrieve target desktop folder */
1092 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1094 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
, _ILIsDesktop(pidl
));
1102 ERR("no IShellFolder\n");
1106 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1107 ReleaseStgMedium(&medium
);
1114 /* get source and destination shellfolder */
1115 if (FAILED(psfTarget
->QueryInterface(IID_ISFHelper
, (LPVOID
*)&psfhlpdst
)))
1117 ERR("no IID_ISFHelper for destination\n");
1120 psfTarget
->Release();
1122 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1123 ReleaseStgMedium(&medium
);
1129 if (FAILED(psfFrom
->QueryInterface(IID_ISFHelper
, (LPVOID
*)&psfhlpsrc
)))
1131 ERR("no IID_ISFHelper for source\n");
1133 psfhlpdst
->Release();
1135 psfTarget
->Release();
1137 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1138 ReleaseStgMedium(&medium
);
1144 * do we want to perform a copy or move ???
1146 hr
= psfhlpdst
->CopyItems(psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
);
1148 psfhlpdst
->Release();
1149 psfhlpsrc
->Release();
1151 psfTarget
->Release();
1153 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1154 ReleaseStgMedium(&medium
);
1156 TRACE("CP result %x\n", hr
);
1161 IDefaultContextMenuImpl::DoOpenOrExplore(
1162 LPCMINVOKECOMMANDINFO lpcmi
)
1169 GetUniqueFileName(LPWSTR szBasePath
, LPWSTR szExt
, LPWSTR szTarget
, BOOL bShortcut
)
1171 UINT RetryCount
= 0, Length
;
1177 Length
= LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, szLnk
, sizeof(szLnk
) / sizeof(WCHAR
));
1185 swprintf(szTarget
, L
"%s%s(%u).%s", szLnk
, szBasePath
, RetryCount
, szExt
);
1187 swprintf(szTarget
, L
"%s%s.%s", szLnk
, szBasePath
, szExt
);
1192 swprintf(szTarget
, L
"%s(%u).%s", szBasePath
, RetryCount
, szExt
);
1194 swprintf(szTarget
, L
"%s.%s", szBasePath
, szExt
);
1197 hFile
= CreateFileW(szTarget
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1198 if (hFile
!= INVALID_HANDLE_VALUE
)
1204 } while(RetryCount
++ < 100);
1211 IDefaultContextMenuImpl::DoCreateLink(
1212 LPCMINVOKECOMMANDINFO lpcmi
)
1214 WCHAR szPath
[MAX_PATH
];
1215 WCHAR szTarget
[MAX_PATH
] = {0};
1216 WCHAR szDirPath
[MAX_PATH
];
1221 IShellLinkW
* nLink
;
1223 static WCHAR szLnk
[] = L
"lnk";
1225 if (dcm
.psf
->GetDisplayNameOf(dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1227 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1231 if (StrRetToBufW(&strFile
, dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1234 pszExt
= wcsrchr(szPath
, L
'.');
1236 if (pszExt
&& !wcsicmp(pszExt
+ 1, szLnk
))
1238 if (!GetUniqueFileName(szPath
, pszExt
+ 1, szTarget
, TRUE
))
1241 hr
= IShellLink_ConstructFromFile(NULL
, IID_IPersistFile
, dcm
.apidl
[0], (LPVOID
*)&ipf
);
1246 hr
= ipf
->Save(szTarget
, FALSE
);
1248 NotifyShellViewWindow(lpcmi
, TRUE
);
1253 if (!GetUniqueFileName(szPath
, szLnk
, szTarget
, TRUE
))
1256 hr
= ShellLink::_CreatorClass::CreateInstance(NULL
, IID_IShellLinkW
, (void**)&nLink
);
1262 GetFullPathName(szPath
, MAX_PATH
, szDirPath
, &pszFile
);
1263 if (pszFile
) pszFile
[0] = 0;
1265 if (SUCCEEDED(nLink
->SetPath(szPath
)) &&
1266 SUCCEEDED(nLink
->SetWorkingDirectory(szDirPath
)))
1268 if (SUCCEEDED(nLink
->QueryInterface(IID_IPersistFile
, (LPVOID
*)&ipf
)))
1270 hr
= ipf
->Save(szTarget
, TRUE
);
1275 NotifyShellViewWindow(lpcmi
, TRUE
);
1281 IDefaultContextMenuImpl::DoDelete(
1282 LPCMINVOKECOMMANDINFO lpcmi
)
1286 WCHAR szPath
[MAX_PATH
];
1287 LPWSTR wszPath
, wszPos
;
1290 LPSHELLBROWSER lpSB
;
1294 hr
= dcm
.psf
->GetDisplayNameOf(dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1297 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1300 ZeroMemory(szPath
, sizeof(szPath
));
1301 hr
= StrRetToBufW(&strTemp
, dcm
.apidl
[0], szPath
, MAX_PATH
);
1304 ERR("StrRetToBufW failed with %x\n", hr
);
1308 /* Only keep the base path */
1309 wszPos
= strrchrW(szPath
, '\\');
1312 *(wszPos
+ 1) = '\0';
1315 wszPath
= build_paths_list(szPath
, dcm
.cidl
, dcm
.apidl
);
1317 ZeroMemory(&op
, sizeof(op
));
1318 op
.hwnd
= GetActiveWindow();
1319 op
.wFunc
= FO_DELETE
;
1321 op
.fFlags
= FOF_ALLOWUNDO
;
1322 ret
= SHFileOperationW(&op
);
1326 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(wszPath
));
1330 /* get the active IShellView */
1331 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0)))
1333 /* is the treeview focused */
1334 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1336 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1339 (void)TreeView_DeleteItem(hwnd
, hItem
);
1343 NotifyShellViewWindow(lpcmi
, TRUE
);
1345 HeapFree(GetProcessHeap(), 0, wszPath
);
1351 IDefaultContextMenuImpl::DoCopyOrCut(
1352 LPCMINVOKECOMMANDINFO lpcmi
,
1355 LPSHELLBROWSER lpSB
;
1357 LPDATAOBJECT pDataObj
;
1360 if (SUCCEEDED(SHCreateDataObject(dcm
.pidlFolder
, dcm
.cidl
, dcm
.apidl
, NULL
, IID_IDataObject
, (void**)&pDataObj
)))
1362 hr
= OleSetClipboard(pDataObj
);
1363 pDataObj
->Release();
1367 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1370 TRACE("failed to get shellbrowser\n");
1374 hr
= lpSB
->QueryActiveShellView(&lpSV
);
1377 TRACE("failed to query the active shellview\n");
1381 hr
= lpSV
->GetItemObject(SVGIO_SELECTION
, IID_IDataObject
, (LPVOID
*)&pDataObj
);
1384 TRACE("failed to get item object\n");
1388 hr
= OleSetClipboard(pDataObj
);
1391 WARN("OleSetClipboard failed");
1393 pDataObj
->Release();
1399 IDefaultContextMenuImpl::DoRename(
1400 LPCMINVOKECOMMANDINFO lpcmi
)
1402 LPSHELLBROWSER lpSB
;
1406 /* get the active IShellView */
1407 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0)))
1409 /* is the treeview focused */
1410 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1412 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1415 (void)TreeView_EditLabel(hwnd
, hItem
);
1419 if(SUCCEEDED(lpSB
->QueryActiveShellView(&lpSV
)))
1421 lpSV
->SelectItem(dcm
.apidl
[0],
1422 SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
);
1431 IDefaultContextMenuImpl::DoProperties(
1432 LPCMINVOKECOMMANDINFO lpcmi
)
1434 WCHAR szDrive
[MAX_PATH
];
1437 if (dcm
.cidl
&& _ILIsMyComputer(dcm
.apidl
[0]))
1439 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1442 else if (dcm
.cidl
== 0 && dcm
.pidlFolder
!= NULL
&& _ILIsDesktop(dcm
.pidlFolder
))
1444 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1447 else if (_ILIsDrive(dcm
.apidl
[0]))
1449 ILGetDisplayName(dcm
.apidl
[0], szDrive
);
1450 SH_ShowDriveProperties(szDrive
, dcm
.pidlFolder
, dcm
.apidl
);
1453 else if (_ILIsNetHood(dcm
.apidl
[0]))
1456 ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1457 L
"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1458 NULL
, SW_SHOWDEFAULT
);
1461 else if (_ILIsBitBucket(dcm
.apidl
[0]))
1464 * detect the drive path of bitbucket if appropiate
1467 SH_ShowRecycleBinProperties(L
'C');
1472 WARN("SHMultiFileProperties is not yet implemented\n");
1474 if (dcm
.psf
->GetDisplayNameOf(dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1476 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1480 if (StrRetToBufW(&strFile
, dcm
.apidl
[0], szDrive
, MAX_PATH
) != S_OK
)
1483 return SH_ShowPropertiesDialog(szDrive
, dcm
.pidlFolder
, dcm
.apidl
);
1487 IDefaultContextMenuImpl::DoFormat(
1488 LPCMINVOKECOMMANDINFO lpcmi
)
1490 char sDrive
[5] = {0};
1492 if (!_ILGetDrive(dcm
.apidl
[0], sDrive
, sizeof(sDrive
)))
1494 ERR("pidl is not a drive\n");
1498 SHFormatDrive(lpcmi
->hwnd
, sDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1503 IDefaultContextMenuImpl::DoDynamicShellExtensions(
1504 LPCMINVOKECOMMANDINFO lpcmi
)
1506 UINT verb
= LOWORD(lpcmi
->lpVerb
);
1507 PDynamicShellEntry pCurrent
= dhead
;
1509 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, iIdSHEFirst
, iIdSHELast
);
1511 while(pCurrent
&& verb
> pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1512 pCurrent
= pCurrent
->Next
;
1517 if (verb
>= pCurrent
->iIdCmdFirst
&& verb
<= pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1519 /* invoke the dynamic context menu */
1520 lpcmi
->lpVerb
= MAKEINTRESOURCEA(verb
- pCurrent
->iIdCmdFirst
);
1521 return pCurrent
->CMenu
->InvokeCommand(lpcmi
);
1529 IDefaultContextMenuImpl::DoStaticShellExtensions(
1530 LPCMINVOKECOMMANDINFO lpcmi
)
1533 WCHAR szPath
[MAX_PATH
];
1534 WCHAR szDir
[MAX_PATH
];
1535 SHELLEXECUTEINFOW sei
;
1536 PStaticShellEntry pCurrent
= shead
;
1537 int verb
= LOWORD(lpcmi
->lpVerb
) - iIdSCMFirst
;
1540 while(pCurrent
&& verb
-- > 0)
1541 pCurrent
= pCurrent
->Next
;
1547 if (dcm
.psf
->GetDisplayNameOf(dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1549 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1553 if (StrRetToBufW(&strFile
, dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1556 wcscpy(szDir
, szPath
);
1557 PathRemoveFileSpec(szDir
);
1559 ZeroMemory(&sei
, sizeof(sei
));
1560 sei
.cbSize
= sizeof(sei
);
1561 sei
.fMask
= SEE_MASK_CLASSNAME
;
1562 sei
.lpClass
= pCurrent
->szClass
;
1563 sei
.hwnd
= lpcmi
->hwnd
;
1564 sei
.nShow
= SW_SHOWNORMAL
;
1565 sei
.lpVerb
= pCurrent
->szVerb
;
1566 sei
.lpFile
= szPath
;
1567 sei
.lpDirectory
= szDir
;
1568 ShellExecuteExW(&sei
);
1575 IDefaultContextMenuImpl::InvokeCommand(
1576 LPCMINVOKECOMMANDINFO lpcmi
)
1578 switch(LOWORD(lpcmi
->lpVerb
))
1580 case FCIDM_SHVIEW_BIGICON
:
1581 case FCIDM_SHVIEW_SMALLICON
:
1582 case FCIDM_SHVIEW_LISTVIEW
:
1583 case FCIDM_SHVIEW_REPORTVIEW
:
1584 case 0x30: /* FIX IDS in resource files */
1588 case FCIDM_SHVIEW_AUTOARRANGE
:
1589 case FCIDM_SHVIEW_SNAPTOGRID
:
1590 case FCIDM_SHVIEW_REFRESH
:
1591 return NotifyShellViewWindow(lpcmi
, FALSE
);
1592 case FCIDM_SHVIEW_INSERT
:
1593 case FCIDM_SHVIEW_INSERTLINK
:
1594 return DoPaste(lpcmi
);
1595 case FCIDM_SHVIEW_OPEN
:
1596 case FCIDM_SHVIEW_EXPLORE
:
1597 return DoOpenOrExplore(lpcmi
);
1598 case FCIDM_SHVIEW_COPY
:
1599 case FCIDM_SHVIEW_CUT
:
1600 return DoCopyOrCut(lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1601 case FCIDM_SHVIEW_CREATELINK
:
1602 return DoCreateLink(lpcmi
);
1603 case FCIDM_SHVIEW_DELETE
:
1604 return DoDelete(lpcmi
);
1605 case FCIDM_SHVIEW_RENAME
:
1606 return DoRename(lpcmi
);
1607 case FCIDM_SHVIEW_PROPERTIES
:
1608 return DoProperties(lpcmi
);
1610 return DoFormat(lpcmi
);
1613 if (iIdSHEFirst
&& iIdSHELast
)
1615 if (LOWORD(lpcmi
->lpVerb
) >= iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= iIdSHELast
)
1617 return DoDynamicShellExtensions(lpcmi
);
1621 if (iIdSCMFirst
&& iIdSCMLast
)
1623 if (LOWORD(lpcmi
->lpVerb
) >= iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= iIdSCMLast
)
1625 return DoStaticShellExtensions(lpcmi
);
1629 FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi
->lpVerb
));
1630 return E_UNEXPECTED
;
1635 IDefaultContextMenuImpl::GetCommandString(
1648 IDefaultContextMenuImpl::HandleMenuMsg(
1659 IDefaultContextMenu_Constructor(
1660 const DEFCONTEXTMENU
*pdcm
,
1664 CComObject
<IDefaultContextMenuImpl
> *theContextMenu
;
1665 CComPtr
<IUnknown
> result
;
1671 ATLTRY (theContextMenu
= new CComObject
<IDefaultContextMenuImpl
>);
1672 if (theContextMenu
== NULL
)
1673 return E_OUTOFMEMORY
;
1674 hResult
= theContextMenu
->QueryInterface (riid
, (void **)&result
);
1675 if (FAILED (hResult
))
1677 delete theContextMenu
;
1680 hResult
= theContextMenu
->Initialize (pdcm
);
1681 if (FAILED (hResult
))
1683 *ppv
= result
.Detach ();
1684 TRACE("This(%p)(%x) cidl %u\n", *ppv
, hResult
, pdcm
->cidl
);
1688 /*************************************************************************
1689 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1695 SHCreateDefaultContextMenu(
1696 const DEFCONTEXTMENU
*pdcm
,
1700 HRESULT hr
= E_FAIL
;
1703 hr
= IDefaultContextMenu_Constructor( pdcm
, riid
, ppv
);
1704 if (FAILED(hr
)) WARN("IDefaultContextMenu_Constructor failed: %x\n", hr
);
1705 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1709 /*************************************************************************
1710 * CDefFolderMenu_Create2 [SHELL32.701]
1716 CDefFolderMenu_Create2(
1717 LPCITEMIDLIST pidlFolder
,
1720 LPCITEMIDLIST
*apidl
,
1722 LPFNDFMCALLBACK lpfn
,
1724 const HKEY
*ahkeyClsKeys
,
1725 IContextMenu
**ppcm
)
1727 DEFCONTEXTMENU pdcm
;
1732 pdcm
.pidlFolder
= pidlFolder
;
1736 pdcm
.punkAssociationInfo
= NULL
;
1738 pdcm
.aKeys
= ahkeyClsKeys
;
1740 hr
= SHCreateDefaultContextMenu(&pdcm
, IID_IContextMenu
, (void**)ppcm
);