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 class CDefaultContextMenu
:
39 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
44 IDataObject
*m_pDataObj
;
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(const WCHAR
*szVerb
, const WCHAR
*szClass
);
54 void AddStaticEntryForKey(HKEY hKey
, const WCHAR
*szClass
);
55 void AddStaticEntryForFileClass(const WCHAR
*szExt
);
56 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*szClass
);
57 HRESULT
LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*szClass
, BOOL bExternalInit
);
58 UINT
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
);
64 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
65 HRESULT
DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
);
66 HRESULT
DoDelete(LPCMINVOKECOMMANDINFO lpcmi
);
67 HRESULT
DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
);
68 HRESULT
DoRename(LPCMINVOKECOMMANDINFO lpcmi
);
69 HRESULT
DoProperties(LPCMINVOKECOMMANDINFO lpcmi
);
70 HRESULT
DoFormat(LPCMINVOKECOMMANDINFO lpcmi
);
71 HRESULT
DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
72 HRESULT
DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
75 CDefaultContextMenu();
76 ~CDefaultContextMenu();
77 HRESULT WINAPI
Initialize(const DEFCONTEXTMENU
*pdcm
);
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(CDefaultContextMenu
)
88 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
89 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
93 CDefaultContextMenu::CDefaultContextMenu()
95 memset (&m_Dcm
, 0, sizeof(m_Dcm
));
97 m_bGroupPolicyActive
= 0;
98 m_pDynamicEntries
= NULL
;
101 m_pStaticEntries
= NULL
;
106 CDefaultContextMenu::~CDefaultContextMenu()
108 PDynamicShellEntry dEntry
, dNext
;
109 PStaticShellEntry sEntry
, sNext
;
111 /* free dynamic shell extension entries */
112 dEntry
= m_pDynamicEntries
;
115 dNext
= dEntry
->Next
;
116 dEntry
->CMenu
->Release();
117 HeapFree(GetProcessHeap(), 0, dEntry
);
120 /* free static shell extension entries */
121 sEntry
= m_pStaticEntries
;
124 sNext
= sEntry
->Next
;
125 HeapFree(GetProcessHeap(), 0, sEntry
->szClass
);
126 HeapFree(GetProcessHeap(), 0, sEntry
->szVerb
);
127 HeapFree(GetProcessHeap(), 0, sEntry
);
132 HRESULT WINAPI
CDefaultContextMenu::Initialize(const DEFCONTEXTMENU
*pdcm
)
134 IDataObject
*pDataObj
;
136 TRACE("cidl %u\n", pdcm
->cidl
);
137 if (SUCCEEDED(SHCreateDataObject(pdcm
->pidlFolder
, pdcm
->cidl
, pdcm
->apidl
, NULL
, IID_IDataObject
, (void**)&pDataObj
)))
138 m_pDataObj
= pDataObj
;
139 CopyMemory(&m_Dcm
, pdcm
, sizeof(DEFCONTEXTMENU
));
144 CDefaultContextMenu::AddStaticEntry(const WCHAR
*szVerb
, const WCHAR
*szClass
)
146 PStaticShellEntry curEntry
;
147 PStaticShellEntry lastEntry
= NULL
;
149 curEntry
= m_pStaticEntries
;
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
= m_pStaticEntries
;
179 m_pStaticEntries
= curEntry
;
182 lastEntry
->Next
= curEntry
;
184 m_pStaticEntries
= curEntry
;
188 CDefaultContextMenu::AddStaticEntryForKey(HKEY hKey
, const WCHAR
*pwszClass
)
195 TRACE("AddStaticEntryForKey %x %ls\n", hKey
, pwszClass
);
200 dwSize
= sizeof(wszName
) / sizeof(WCHAR
);
201 result
= RegEnumKeyExW(hKey
, dwIndex
, wszName
, &dwSize
, NULL
, NULL
, NULL
, NULL
);
202 if (result
== ERROR_SUCCESS
)
203 AddStaticEntry(wszName
, pwszClass
);
206 } while(result
== ERROR_SUCCESS
);
210 CDefaultContextMenu::AddStaticEntryForFileClass(const WCHAR
* szExt
)
217 static WCHAR szShell
[] = L
"\\shell";
218 static WCHAR szShellAssoc
[] = L
"SystemFileAssociations\\";
220 TRACE("AddStaticEntryForFileClass entered with %s\n", debugstr_w(szExt
));
222 Length
= wcslen(szExt
);
223 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
225 wcscpy(szBuffer
, szExt
);
226 wcscpy(&szBuffer
[Length
], szShell
);
227 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
228 if (result
== ERROR_SUCCESS
)
230 szBuffer
[Length
] = 0;
231 AddStaticEntryForKey(hKey
, szExt
);
236 dwBuffer
= sizeof(szBuffer
);
237 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, NULL
, RRF_RT_REG_SZ
, NULL
, (LPBYTE
)szBuffer
, &dwBuffer
);
238 if (result
== ERROR_SUCCESS
)
240 Length
= wcslen(szBuffer
);
241 if (Length
+ (sizeof(szShell
) / sizeof(WCHAR
)) + 1 < sizeof(szBuffer
) / sizeof(WCHAR
))
243 wcscpy(&szBuffer
[Length
], szShell
);
244 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
246 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
247 if (result
== ERROR_SUCCESS
)
249 szBuffer
[Length
] = 0;
250 AddStaticEntryForKey(hKey
, szBuffer
);
256 wcscpy(szBuffer
, szShellAssoc
);
257 dwBuffer
= sizeof(szBuffer
) - sizeof(szShellAssoc
) - sizeof(WCHAR
);
258 result
= RegGetValueW(HKEY_CLASSES_ROOT
, szExt
, L
"PerceivedType", RRF_RT_REG_SZ
, NULL
, (LPBYTE
)&szBuffer
[_countof(szShellAssoc
) - 1], &dwBuffer
);
259 if (result
== ERROR_SUCCESS
)
261 Length
= wcslen(&szBuffer
[_countof(szShellAssoc
)]) + _countof(szShellAssoc
);
262 wcscat(szBuffer
, L
"\\shell");
263 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
265 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szBuffer
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hKey
);
266 if (result
== ERROR_SUCCESS
)
268 szBuffer
[Length
] = 0;
269 AddStaticEntryForKey(hKey
, szBuffer
);
282 if(SUCCEEDED(OleGetClipboard(&pda
)))
287 TRACE("pda=%p\n", pda
);
289 /* Set the FORMATETC structure*/
290 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
291 if(SUCCEEDED(pda
->GetData(&formatetc
, &medium
)))
294 ReleaseStgMedium(&medium
);
305 DisablePasteOptions(HMENU hMenu
)
309 mii
.cbSize
= sizeof(mii
);
310 mii
.fMask
= MIIM_STATE
;
311 mii
.fState
= MFS_DISABLED
;
313 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
));
314 TRACE("result %d\n", SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
));
318 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID
* szClass
)
320 PDynamicShellEntry curEntry
= m_pDynamicEntries
;
324 if (!memcmp(&curEntry
->ClassID
, szClass
, sizeof(CLSID
)))
326 curEntry
= curEntry
->Next
;
333 CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pClass
, BOOL bExternalInit
)
337 IShellExtInit
*shext
;
338 PDynamicShellEntry curEntry
;
341 StringFromCLSID(*pClass
, &pstr
);
343 TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pClass %s bExternalInit %u\n", this, hKey
, wine_dbgstr_guid(pClass
), bExternalInit
);
345 if (IsShellExtensionAlreadyLoaded(pClass
))
348 hr
= SHCoCreateInstance(NULL
, pClass
, NULL
, IID_IContextMenu
, (void**)&cmobj
);
351 ERR("SHCoCreateInstance failed %x\n", GetLastError());
357 hr
= cmobj
->QueryInterface(IID_IShellExtInit
, (void**)&shext
);
360 ERR("Failed to query for interface IID_IShellExtInit hr %x pClass %s\n", hr
, wine_dbgstr_guid(pClass
));
365 hr
= shext
->Initialize(NULL
, m_pDataObj
, hKey
);
369 TRACE("Failed to initialize shell extension error %x pClass %s\n", hr
, wine_dbgstr_guid(pClass
));
375 curEntry
= (DynamicShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
379 return E_OUTOFMEMORY
;
382 curEntry
->iIdCmdFirst
= 0;
383 curEntry
->Next
= NULL
;
384 curEntry
->NumIds
= 0;
385 curEntry
->CMenu
= cmobj
;
386 memcpy(&curEntry
->ClassID
, pClass
, sizeof(CLSID
));
388 if (m_pDynamicEntries
)
390 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
393 pEntry
= pEntry
->Next
;
395 pEntry
->Next
= curEntry
;
398 m_pDynamicEntries
= curEntry
;
404 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey
)
406 WCHAR szKey
[MAX_PATH
] = {0};
407 WCHAR szName
[MAX_PATH
] = {0};
408 DWORD dwIndex
, dwName
;
415 if (RegOpenKeyExW(hRootKey
, L
"shellex\\ContextMenuHandlers", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
417 TRACE("RegOpenKeyExW failed for key %s\n", debugstr_w(szKey
));
426 res
= RegEnumKeyExW(hKey
, dwIndex
, szName
, &dwName
, NULL
, NULL
, NULL
, NULL
);
427 if (res
== ERROR_SUCCESS
)
429 hResult
= CLSIDFromString(szName
, &clsid
);
433 if (RegGetValueW(hKey
, szName
, NULL
, RRF_RT_REG_SZ
, NULL
, szKey
, &dwName
) == ERROR_SUCCESS
)
435 hResult
= CLSIDFromString(szKey
, &clsid
);
438 if (SUCCEEDED(hResult
))
440 if (m_bGroupPolicyActive
)
442 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
443 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
448 &dwName
) == ERROR_SUCCESS
)
450 LoadDynamicContextMenuHandler(hKey
, &clsid
, TRUE
);
455 LoadDynamicContextMenuHandler(hKey
, &clsid
, TRUE
);
460 } while(res
== ERROR_SUCCESS
);
467 CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
469 PDynamicShellEntry curEntry
;
472 if (!m_pDynamicEntries
)
479 curEntry
= m_pDynamicEntries
;
482 m_iIdSHEFirst
= idCmdFirst
;
485 hResult
= curEntry
->CMenu
->QueryContextMenu(hMenu
, indexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
486 if (SUCCEEDED(hResult
))
488 curEntry
->iIdCmdFirst
= idCmdFirst
;
489 curEntry
->NumIds
= LOWORD(hResult
);
490 indexMenu
+= curEntry
->NumIds
;
491 idCmdFirst
+= curEntry
->NumIds
+ 0x10;
493 TRACE("curEntry %p hresult %x contextmenu %p cmdfirst %x num ids %x\n", curEntry
, hResult
, curEntry
->CMenu
, curEntry
->iIdCmdFirst
, curEntry
->NumIds
);
494 curEntry
= curEntry
->Next
;
497 m_iIdSHELast
= idCmdFirst
;
498 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst
, m_iIdSHELast
);
503 CDefaultContextMenu::BuildBackgroundContextMenu(
510 WCHAR szBuffer
[MAX_PATH
];
515 ZeroMemory(&mii
, sizeof(mii
));
517 TRACE("BuildBackgroundContextMenu entered\n");
519 if (!_ILIsDesktop(m_Dcm
.pidlFolder
))
521 /* view option is only available in browsing mode */
522 hSubMenu
= LoadMenuA(shell32_hInstance
, "MENU_001");
526 LoadStringW(shell32_hInstance
, FCIDM_SHVIEW_VIEW
, szBuffer
, MAX_PATH
);
527 szBuffer
[MAX_PATH
-1] = 0;
529 TRACE("szBuffer %s\n", debugstr_w(szBuffer
));
531 mii
.cbSize
= sizeof(mii
);
532 mii
.fMask
= MIIM_TYPE
| MIIM_STATE
| MIIM_SUBMENU
| MIIM_ID
;
533 mii
.fType
= MFT_STRING
;
534 mii
.wID
= iIdCmdFirst
++;
535 mii
.dwTypeData
= szBuffer
;
536 mii
.cch
= wcslen( mii
.dwTypeData
);
537 mii
.fState
= MFS_ENABLED
;
538 mii
.hSubMenu
= hSubMenu
;
539 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
540 DestroyMenu(hSubMenu
);
543 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
546 /* merge general background context menu in */
547 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), indexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
548 DestroyMenu(hSubMenu
);
551 if (!HasClipboardData())
553 TRACE("disabling paste options\n");
554 DisablePasteOptions(hMenu
);
556 /* load extensions from HKCR\* key */
557 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
561 &hKey
) == ERROR_SUCCESS
)
563 EnumerateDynamicContextHandlerForKey(hKey
);
567 /* load create new shell extension */
568 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
,
569 L
"CLSID\\{D969A300-E7FF-11d0-A93B-00A0C90F2719}",
572 &hKey
) == ERROR_SUCCESS
)
574 LoadDynamicContextMenuHandler(hKey
, &CLSID_NewMenu
, TRUE
);
578 if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, GetMenuItemCount(hMenu
) - 1, iIdCmdFirst
, iIdCmdLast
))
580 /* seperate dynamic context menu items */
581 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
) - 1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
588 CDefaultContextMenu::AddStaticContextMenusToMenu(
594 PStaticShellEntry curEntry
;
600 mii
.cbSize
= sizeof(mii
);
601 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
602 mii
.fType
= MFT_STRING
;
603 mii
.fState
= MFS_ENABLED
;
605 mii
.dwTypeData
= NULL
;
606 m_iIdSCMFirst
= mii
.wID
;
608 curEntry
= m_pStaticEntries
;
612 fState
= MFS_ENABLED
;
613 mii
.dwTypeData
= NULL
;
615 if (!wcsicmp(curEntry
->szVerb
, L
"open"))
617 fState
|= MFS_DEFAULT
;
618 idResource
= IDS_OPEN_VERB
;
620 else if (!wcsicmp(curEntry
->szVerb
, L
"explore"))
621 idResource
= IDS_EXPLORE_VERB
;
622 else if (!wcsicmp(curEntry
->szVerb
, L
"runas"))
623 idResource
= IDS_RUNAS_VERB
;
624 else if (!wcsicmp(curEntry
->szVerb
, L
"edit"))
625 idResource
= IDS_EDIT_VERB
;
626 else if (!wcsicmp(curEntry
->szVerb
, L
"find"))
627 idResource
= IDS_FIND_VERB
;
628 else if (!wcsicmp(curEntry
->szVerb
, L
"print"))
629 idResource
= IDS_PRINT_VERB
;
630 else if (!wcsicmp(curEntry
->szVerb
, L
"printto"))
632 curEntry
= curEntry
->Next
;
640 if (LoadStringW(shell32_hInstance
, idResource
, szVerb
, sizeof(szVerb
) / sizeof(WCHAR
)))
641 mii
.dwTypeData
= szVerb
; /* use translated verb */
643 ERR("Failed to load string, defaulting to NULL value for mii.dwTypeData\n");
648 Length
= wcslen(curEntry
->szClass
) + wcslen(curEntry
->szVerb
) + 8;
649 if (Length
< sizeof(wszKey
) / sizeof(WCHAR
))
651 wcscpy(wszKey
, curEntry
->szClass
);
652 wcscat(wszKey
, L
"\\shell\\");
653 wcscat(wszKey
, curEntry
->szVerb
);
654 dwSize
= sizeof(szVerb
);
656 if (RegGetValueW(HKEY_CLASSES_ROOT
, wszKey
, NULL
, RRF_RT_REG_SZ
, NULL
, szVerb
, &dwSize
) == ERROR_SUCCESS
)
657 mii
.dwTypeData
= szVerb
; /* use description for the menu entry */
659 mii
.dwTypeData
= curEntry
->szVerb
; /* use verb for the menu entry */
663 mii
.cch
= wcslen(mii
.dwTypeData
);
665 InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, &mii
);
668 curEntry
= curEntry
->Next
;
670 m_iIdSCMLast
= mii
.wID
- 1;
674 void WINAPI
_InsertMenuItemW(
686 ZeroMemory(&mii
, sizeof(mii
));
687 mii
.cbSize
= sizeof(mii
);
688 if (fType
== MFT_SEPARATOR
)
690 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
692 else if (fType
== MFT_STRING
)
694 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
695 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
697 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), szText
, sizeof(szText
) / sizeof(WCHAR
)))
699 szText
[(sizeof(szText
)/sizeof(WCHAR
))-1] = 0;
700 mii
.dwTypeData
= szText
;
704 ERR("failed to load string %p\n", dwTypeData
);
710 mii
.dwTypeData
= (LPWSTR
) dwTypeData
;
717 InsertMenuItemW( hmenu
, indexMenu
, fByPosition
, &mii
);
721 CDefaultContextMenu::BuildShellItemContextMenu(
727 WCHAR szPath
[MAX_PATH
];
733 BOOL bAddSep
= FALSE
;
740 TRACE("BuildShellItemContextMenu entered\n");
742 hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
);
745 hr
= StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], szPath
, MAX_PATH
);
748 pOffset
= wcsrchr(szPath
, L
'.');
751 /* enumerate dynamic/static for a given file class */
752 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, pOffset
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
754 /* add static verbs */
755 AddStaticEntryForFileClass(pOffset
);
756 /* load dynamic extensions from file extension key */
757 EnumerateDynamicContextHandlerForKey(hKey
);
760 dwSize
= sizeof(szTemp
);
761 if (RegGetValueW(HKEY_CLASSES_ROOT
, pOffset
, NULL
, RRF_RT_REG_SZ
, NULL
, szTemp
, &dwSize
) == ERROR_SUCCESS
)
763 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, szTemp
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
765 /* add static verbs from progid key */
766 AddStaticEntryForFileClass(szTemp
);
767 /* load dynamic extensions from progid key */
768 EnumerateDynamicContextHandlerForKey(hKey
);
773 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"*", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
775 /* load default extensions */
776 EnumerateDynamicContextHandlerForKey(hKey
);
782 ERR("GetDisplayNameOf failed: %x\n", hr
);
784 guid
= _ILGetGUIDPointer(m_Dcm
.apidl
[0]);
790 wcscpy(buffer
, L
"CLSID\\");
791 hr
= StringFromCLSID(*guid
, &pwszCLSID
);
794 wcscpy(&buffer
[6], pwszCLSID
);
795 TRACE("buffer %s\n", debugstr_w(buffer
));
796 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, buffer
, 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
798 EnumerateDynamicContextHandlerForKey(hKey
);
799 AddStaticEntryForFileClass(buffer
);
802 CoTaskMemFree(pwszCLSID
);
806 if (_ILIsDrive(m_Dcm
.apidl
[0]))
808 AddStaticEntryForFileClass(L
"Drive");
809 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Drive", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
811 EnumerateDynamicContextHandlerForKey(hKey
);
817 /* add static actions */
818 rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
819 hr
= m_Dcm
.psf
->GetAttributesOf(m_Dcm
.cidl
, m_Dcm
.apidl
, &rfg
);
822 ERR("GetAttributesOf failed: %x\n", hr
);
826 if ((rfg
& SFGAO_FOLDER
) || _ILIsControlPanel(m_Dcm
.apidl
[m_Dcm
.cidl
]))
828 /* add the default verbs open / explore */
829 AddStaticEntryForFileClass(L
"Folder");
830 AddStaticEntryForFileClass(L
"Directory");
831 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Folder", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
833 EnumerateDynamicContextHandlerForKey(hKey
);
836 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
838 EnumerateDynamicContextHandlerForKey(hKey
);
843 if (rfg
& SFGAO_FILESYSTEM
)
845 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"AllFilesystemObjects", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
847 /* sendto service is registered here */
848 EnumerateDynamicContextHandlerForKey(hKey
);
853 /* add static context menu handlers */
854 indexMenu
= AddStaticContextMenusToMenu(hMenu
, 0);
855 /* now process dynamic context menu handlers */
856 indexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, indexMenu
, iIdCmdFirst
, iIdCmdLast
);
857 TRACE("indexMenu %d\n", indexMenu
);
859 if (_ILIsDrive(m_Dcm
.apidl
[0]))
861 /* The 'Format' option must be always available,
862 * thus it is not registered as a static shell extension
864 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
865 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
869 bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
870 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
872 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
873 if (rfg
& SFGAO_CANMOVE
)
874 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
875 if (rfg
& SFGAO_CANCOPY
)
876 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
878 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_INSERT
), MFS_ENABLED
);
883 if (rfg
& SFGAO_CANLINK
)
886 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
887 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
890 if (rfg
& SFGAO_CANDELETE
)
895 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
897 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
900 if (rfg
& SFGAO_CANRENAME
)
904 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
906 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
910 if (rfg
& SFGAO_HASPROPSHEET
)
912 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
913 _InsertMenuItemW(hMenu
, indexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
921 CDefaultContextMenu::QueryContextMenu(
930 idCmdFirst
= BuildShellItemContextMenu(hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
934 idCmdFirst
= BuildBackgroundContextMenu(hmenu
, idCmdFirst
, idCmdLast
, uFlags
);
942 NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
945 LPSHELLVIEW lpSV
= NULL
;
948 if((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0)))
950 if(SUCCEEDED(lpSB
->QueryActiveShellView(&lpSV
)))
952 lpSV
->GetWindow(&hwndSV
);
956 if (LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_REFRESH
|| bRefresh
)
964 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
970 CDefaultContextMenu::DoPaste(
971 LPCMINVOKECOMMANDINFO lpcmi
)
976 LPITEMIDLIST
* apidl
;
978 IShellFolder
*psfFrom
= NULL
, *psfDesktop
, *psfTarget
= NULL
;
980 ISFHelper
*psfhlpdst
, *psfhlpsrc
;
983 if (OleGetClipboard(&pda
) != S_OK
)
986 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
987 hr
= pda
->GetData(&formatetc
, &medium
);
995 /* lock the handle */
996 lpcida
= (LPIDA
)GlobalLock(medium
.hGlobal
);
999 ReleaseStgMedium(&medium
);
1004 /* convert the data into pidl */
1005 apidl
= _ILCopyCidaToaPidl(&pidl
, lpcida
);
1010 if (FAILED(SHGetDesktopFolder(&psfDesktop
)))
1013 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1014 ReleaseStgMedium(&medium
);
1019 if (_ILIsDesktop(pidl
))
1021 /* use desktop shellfolder */
1022 psfFrom
= psfDesktop
;
1024 else if (FAILED(psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfFrom
)))
1026 ERR("no IShellFolder\n");
1028 psfDesktop
->Release();
1030 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1031 ReleaseStgMedium(&medium
);
1039 psfDesktop
->Release();
1040 hr
= m_Dcm
.psf
->BindToObject(m_Dcm
.apidl
[0], NULL
, IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1044 IPersistFolder2
*ppf2
= NULL
;
1047 /* cidl is zero due to explorer view */
1048 hr
= m_Dcm
.psf
->QueryInterface(IID_IPersistFolder2
, (LPVOID
*) &ppf2
);
1051 hr
= ppf2
->GetCurFolder(&pidl
);
1055 if (_ILIsDesktop(pidl
))
1057 /* use desktop shellfolder */
1058 psfTarget
= psfDesktop
;
1062 /* retrieve target desktop folder */
1063 hr
= psfDesktop
->BindToObject(pidl
, NULL
, IID_IShellFolder
, (LPVOID
*)&psfTarget
);
1065 TRACE("psfTarget %x %p, Desktop %u\n", hr
, psfTarget
, _ILIsDesktop(pidl
));
1073 ERR("no IShellFolder\n");
1077 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1078 ReleaseStgMedium(&medium
);
1084 /* get source and destination shellfolder */
1085 if (FAILED(psfTarget
->QueryInterface(IID_ISFHelper
, (LPVOID
*)&psfhlpdst
)))
1087 ERR("no IID_ISFHelper for destination\n");
1090 psfTarget
->Release();
1092 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1093 ReleaseStgMedium(&medium
);
1099 if (FAILED(psfFrom
->QueryInterface(IID_ISFHelper
, (LPVOID
*)&psfhlpsrc
)))
1101 ERR("no IID_ISFHelper for source\n");
1103 psfhlpdst
->Release();
1105 psfTarget
->Release();
1107 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1108 ReleaseStgMedium(&medium
);
1114 * do we want to perform a copy or move ???
1116 hr
= psfhlpdst
->CopyItems(psfFrom
, lpcida
->cidl
, (LPCITEMIDLIST
*)apidl
);
1118 psfhlpdst
->Release();
1119 psfhlpsrc
->Release();
1121 psfTarget
->Release();
1123 _ILFreeaPidl(apidl
, lpcida
->cidl
);
1124 ReleaseStgMedium(&medium
);
1126 TRACE("CP result %x\n", hr
);
1131 CDefaultContextMenu::DoOpenOrExplore(
1132 LPCMINVOKECOMMANDINFO lpcmi
)
1139 GetUniqueFileName(LPWSTR szBasePath
, LPWSTR szExt
, LPWSTR szTarget
, BOOL bShortcut
)
1141 UINT RetryCount
= 0, Length
;
1146 Length
= LoadStringW(shell32_hInstance
, IDS_LNK_FILE
, szLnk
, sizeof(szLnk
) / sizeof(WCHAR
));
1153 swprintf(szTarget
, L
"%s%s(%u).%s", szLnk
, szBasePath
, RetryCount
, szExt
);
1155 swprintf(szTarget
, L
"%s%s.%s", szLnk
, szBasePath
, szExt
);
1160 swprintf(szTarget
, L
"%s(%u).%s", szBasePath
, RetryCount
, szExt
);
1162 swprintf(szTarget
, L
"%s.%s", szBasePath
, szExt
);
1165 hFile
= CreateFileW(szTarget
, GENERIC_WRITE
, 0, NULL
, CREATE_NEW
, FILE_ATTRIBUTE_NORMAL
, NULL
);
1166 if (hFile
!= INVALID_HANDLE_VALUE
)
1172 } while(RetryCount
++ < 100);
1179 CDefaultContextMenu::DoCreateLink(
1180 LPCMINVOKECOMMANDINFO lpcmi
)
1182 WCHAR szPath
[MAX_PATH
];
1183 WCHAR szTarget
[MAX_PATH
] = {0};
1184 WCHAR szDirPath
[MAX_PATH
];
1189 IShellLinkW
* nLink
;
1191 static WCHAR szLnk
[] = L
"lnk";
1193 if (m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1195 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1199 if (StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], szPath
, MAX_PATH
) != S_OK
)
1202 pszExt
= wcsrchr(szPath
, L
'.');
1204 if (pszExt
&& !wcsicmp(pszExt
+ 1, szLnk
))
1206 if (!GetUniqueFileName(szPath
, pszExt
+ 1, szTarget
, TRUE
))
1209 hr
= IShellLink_ConstructFromFile(NULL
, IID_IPersistFile
, m_Dcm
.apidl
[0], (LPVOID
*)&ipf
);
1213 hr
= ipf
->Save(szTarget
, FALSE
);
1215 NotifyShellViewWindow(lpcmi
, TRUE
);
1220 if (!GetUniqueFileName(szPath
, szLnk
, szTarget
, TRUE
))
1223 hr
= CShellLink::_CreatorClass::CreateInstance(NULL
, IID_IShellLinkW
, (void**)&nLink
);
1227 GetFullPathName(szPath
, MAX_PATH
, szDirPath
, &pszFile
);
1228 if (pszFile
) pszFile
[0] = 0;
1230 if (SUCCEEDED(nLink
->SetPath(szPath
)) &&
1231 SUCCEEDED(nLink
->SetWorkingDirectory(szDirPath
)))
1233 if (SUCCEEDED(nLink
->QueryInterface(IID_IPersistFile
, (LPVOID
*)&ipf
)))
1235 hr
= ipf
->Save(szTarget
, TRUE
);
1240 NotifyShellViewWindow(lpcmi
, TRUE
);
1246 CDefaultContextMenu::DoDelete(
1247 LPCMINVOKECOMMANDINFO lpcmi
)
1251 WCHAR szPath
[MAX_PATH
];
1252 LPWSTR wszPath
, wszPos
;
1255 LPSHELLBROWSER lpSB
;
1259 hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strTemp
);
1262 ERR("IShellFolder_GetDisplayNameOf failed with %x\n", hr
);
1265 ZeroMemory(szPath
, sizeof(szPath
));
1266 hr
= StrRetToBufW(&strTemp
, m_Dcm
.apidl
[0], szPath
, MAX_PATH
);
1269 ERR("StrRetToBufW failed with %x\n", hr
);
1273 /* Only keep the base path */
1274 wszPos
= strrchrW(szPath
, '\\');
1277 *(wszPos
+ 1) = '\0';
1280 wszPath
= BuildPathsList(szPath
, m_Dcm
.cidl
, m_Dcm
.apidl
);
1282 ZeroMemory(&op
, sizeof(op
));
1283 op
.hwnd
= GetActiveWindow();
1284 op
.wFunc
= FO_DELETE
;
1286 op
.fFlags
= FOF_ALLOWUNDO
;
1287 ret
= SHFileOperationW(&op
);
1291 ERR("SHFileOperation failed with 0x%x for %s\n", GetLastError(), debugstr_w(wszPath
));
1295 /* get the active IShellView */
1296 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0)))
1298 /* is the treeview focused */
1299 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1301 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1304 (void)TreeView_DeleteItem(hwnd
, hItem
);
1308 NotifyShellViewWindow(lpcmi
, TRUE
);
1310 HeapFree(GetProcessHeap(), 0, wszPath
);
1316 CDefaultContextMenu::DoCopyOrCut(
1317 LPCMINVOKECOMMANDINFO lpcmi
,
1320 LPSHELLBROWSER lpSB
;
1322 LPDATAOBJECT pDataObj
;
1325 if (SUCCEEDED(SHCreateDataObject(m_Dcm
.pidlFolder
, m_Dcm
.cidl
, m_Dcm
.apidl
, NULL
, IID_IDataObject
, (void**)&pDataObj
)))
1327 hr
= OleSetClipboard(pDataObj
);
1328 pDataObj
->Release();
1332 lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0);
1335 TRACE("failed to get shellbrowser\n");
1339 hr
= lpSB
->QueryActiveShellView(&lpSV
);
1342 TRACE("failed to query the active shellview\n");
1346 hr
= lpSV
->GetItemObject(SVGIO_SELECTION
, IID_IDataObject
, (LPVOID
*)&pDataObj
);
1349 TRACE("failed to get item object\n");
1353 hr
= OleSetClipboard(pDataObj
);
1356 WARN("OleSetClipboard failed");
1358 pDataObj
->Release();
1364 CDefaultContextMenu::DoRename(
1365 LPCMINVOKECOMMANDINFO lpcmi
)
1367 LPSHELLBROWSER lpSB
;
1371 /* get the active IShellView */
1372 if ((lpSB
= (LPSHELLBROWSER
)SendMessageA(lpcmi
->hwnd
, CWM_GETISHELLBROWSER
, 0, 0)))
1374 /* is the treeview focused */
1375 if (SUCCEEDED(lpSB
->GetControlWindow(FCW_TREE
, &hwnd
)))
1377 HTREEITEM hItem
= TreeView_GetSelection(hwnd
);
1380 (void)TreeView_EditLabel(hwnd
, hItem
);
1384 if(SUCCEEDED(lpSB
->QueryActiveShellView(&lpSV
)))
1386 lpSV
->SelectItem(m_Dcm
.apidl
[0],
1387 SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
);
1396 CDefaultContextMenu::DoProperties(
1397 LPCMINVOKECOMMANDINFO lpcmi
)
1399 WCHAR szDrive
[MAX_PATH
];
1402 if (m_Dcm
.cidl
&& _ILIsMyComputer(m_Dcm
.apidl
[0]))
1404 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1407 else if (m_Dcm
.cidl
== 0 && m_Dcm
.pidlFolder
!= NULL
&& _ILIsDesktop(m_Dcm
.pidlFolder
))
1409 ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
);
1412 else if (_ILIsDrive(m_Dcm
.apidl
[0]))
1414 ILGetDisplayName(m_Dcm
.apidl
[0], szDrive
);
1415 SH_ShowDriveProperties(szDrive
, m_Dcm
.pidlFolder
, m_Dcm
.apidl
);
1418 else if (_ILIsNetHood(m_Dcm
.apidl
[0]))
1421 ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1422 L
"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1423 NULL
, SW_SHOWDEFAULT
);
1426 else if (_ILIsBitBucket(m_Dcm
.apidl
[0]))
1429 * detect the drive path of bitbucket if appropiate
1432 SH_ShowRecycleBinProperties(L
'C');
1437 WARN("SHMultiFileProperties is not yet implemented\n");
1439 if (m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
) != S_OK
)
1441 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1445 if (StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], szDrive
, MAX_PATH
) != S_OK
)
1448 return SH_ShowPropertiesDialog(szDrive
, m_Dcm
.pidlFolder
, m_Dcm
.apidl
);
1452 CDefaultContextMenu::DoFormat(
1453 LPCMINVOKECOMMANDINFO lpcmi
)
1455 char sDrive
[5] = {0};
1457 if (!_ILGetDrive(m_Dcm
.apidl
[0], sDrive
, sizeof(sDrive
)))
1459 ERR("pidl is not a drive\n");
1463 SHFormatDrive(lpcmi
->hwnd
, sDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1468 CDefaultContextMenu::DoDynamicShellExtensions(
1469 LPCMINVOKECOMMANDINFO lpcmi
)
1471 UINT verb
= LOWORD(lpcmi
->lpVerb
);
1472 PDynamicShellEntry pCurrent
= m_pDynamicEntries
;
1474 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, m_iIdSHEFirst
, m_iIdSHELast
);
1476 while(pCurrent
&& verb
> pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1477 pCurrent
= pCurrent
->Next
;
1482 if (verb
>= pCurrent
->iIdCmdFirst
&& verb
<= pCurrent
->iIdCmdFirst
+ pCurrent
->NumIds
)
1484 /* invoke the dynamic context menu */
1485 lpcmi
->lpVerb
= MAKEINTRESOURCEA(verb
- pCurrent
->iIdCmdFirst
);
1486 return pCurrent
->CMenu
->InvokeCommand(lpcmi
);
1494 CDefaultContextMenu::DoStaticShellExtensions(
1495 LPCMINVOKECOMMANDINFO lpcmi
)
1498 WCHAR szPath
[MAX_PATH
];
1499 WCHAR szDir
[MAX_PATH
];
1500 SHELLEXECUTEINFOW sei
;
1501 PStaticShellEntry pCurrent
= m_pStaticEntries
;
1502 int verb
= LOWORD(lpcmi
->lpVerb
) - m_iIdSCMFirst
;
1505 while(pCurrent
&& verb
-- > 0)
1506 pCurrent
= pCurrent
->Next
;
1511 hr
= m_Dcm
.psf
->GetDisplayNameOf(m_Dcm
.apidl
[0], SHGDN_FORPARSING
, &strFile
);
1514 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1518 hr
= StrRetToBufW(&strFile
, m_Dcm
.apidl
[0], szPath
, MAX_PATH
);
1522 wcscpy(szDir
, szPath
);
1523 PathRemoveFileSpec(szDir
);
1525 ZeroMemory(&sei
, sizeof(sei
));
1526 sei
.cbSize
= sizeof(sei
);
1527 sei
.fMask
= SEE_MASK_CLASSNAME
;
1528 sei
.lpClass
= pCurrent
->szClass
;
1529 sei
.hwnd
= lpcmi
->hwnd
;
1530 sei
.nShow
= SW_SHOWNORMAL
;
1531 sei
.lpVerb
= pCurrent
->szVerb
;
1532 sei
.lpFile
= szPath
;
1533 sei
.lpDirectory
= szDir
;
1534 ShellExecuteExW(&sei
);
1540 CDefaultContextMenu::InvokeCommand(
1541 LPCMINVOKECOMMANDINFO lpcmi
)
1543 switch(LOWORD(lpcmi
->lpVerb
))
1545 case FCIDM_SHVIEW_BIGICON
:
1546 case FCIDM_SHVIEW_SMALLICON
:
1547 case FCIDM_SHVIEW_LISTVIEW
:
1548 case FCIDM_SHVIEW_REPORTVIEW
:
1549 case 0x30: /* FIX IDS in resource files */
1553 case FCIDM_SHVIEW_AUTOARRANGE
:
1554 case FCIDM_SHVIEW_SNAPTOGRID
:
1555 case FCIDM_SHVIEW_REFRESH
:
1556 return NotifyShellViewWindow(lpcmi
, FALSE
);
1557 case FCIDM_SHVIEW_INSERT
:
1558 case FCIDM_SHVIEW_INSERTLINK
:
1559 return DoPaste(lpcmi
);
1560 case FCIDM_SHVIEW_OPEN
:
1561 case FCIDM_SHVIEW_EXPLORE
:
1562 return DoOpenOrExplore(lpcmi
);
1563 case FCIDM_SHVIEW_COPY
:
1564 case FCIDM_SHVIEW_CUT
:
1565 return DoCopyOrCut(lpcmi
, LOWORD(lpcmi
->lpVerb
) == FCIDM_SHVIEW_COPY
);
1566 case FCIDM_SHVIEW_CREATELINK
:
1567 return DoCreateLink(lpcmi
);
1568 case FCIDM_SHVIEW_DELETE
:
1569 return DoDelete(lpcmi
);
1570 case FCIDM_SHVIEW_RENAME
:
1571 return DoRename(lpcmi
);
1572 case FCIDM_SHVIEW_PROPERTIES
:
1573 return DoProperties(lpcmi
);
1575 return DoFormat(lpcmi
);
1578 if (m_iIdSHEFirst
&& m_iIdSHELast
)
1580 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSHEFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSHELast
)
1582 return DoDynamicShellExtensions(lpcmi
);
1586 if (m_iIdSCMFirst
&& m_iIdSCMLast
)
1588 if (LOWORD(lpcmi
->lpVerb
) >= m_iIdSCMFirst
&& LOWORD(lpcmi
->lpVerb
) <= m_iIdSCMLast
)
1590 return DoStaticShellExtensions(lpcmi
);
1594 FIXME("Unhandled Verb %xl\n", LOWORD(lpcmi
->lpVerb
));
1595 return E_UNEXPECTED
;
1600 CDefaultContextMenu::GetCommandString(
1612 CDefaultContextMenu::HandleMenuMsg(
1622 IDefaultContextMenu_Constructor(
1623 const DEFCONTEXTMENU
*pdcm
,
1627 CComObject
<CDefaultContextMenu
> *theContextMenu
;
1628 CComPtr
<IUnknown
> result
;
1634 ATLTRY (theContextMenu
= new CComObject
<CDefaultContextMenu
>);
1635 if (theContextMenu
== NULL
)
1636 return E_OUTOFMEMORY
;
1637 hResult
= theContextMenu
->QueryInterface(riid
, (void **)&result
);
1638 if (FAILED(hResult
))
1640 delete theContextMenu
;
1643 hResult
= theContextMenu
->Initialize(pdcm
);
1644 if (FAILED(hResult
))
1646 *ppv
= result
.Detach();
1647 TRACE("This(%p)(%x) cidl %u\n", *ppv
, hResult
, pdcm
->cidl
);
1651 /*************************************************************************
1652 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1658 SHCreateDefaultContextMenu(
1659 const DEFCONTEXTMENU
*pdcm
,
1663 HRESULT hr
= E_FAIL
;
1666 hr
= IDefaultContextMenu_Constructor(pdcm
, riid
, ppv
);
1668 ERR("IDefaultContextMenu_Constructor failed: %x\n", hr
);
1669 TRACE("pcm %p hr %x\n", pdcm
, hr
);
1673 /*************************************************************************
1674 * CDefFolderMenu_Create2 [SHELL32.701]
1680 CDefFolderMenu_Create2(
1681 LPCITEMIDLIST pidlFolder
,
1684 LPCITEMIDLIST
*apidl
,
1686 LPFNDFMCALLBACK lpfn
,
1688 const HKEY
*ahkeyClsKeys
,
1689 IContextMenu
**ppcm
)
1691 DEFCONTEXTMENU pdcm
;
1696 pdcm
.pidlFolder
= pidlFolder
;
1700 pdcm
.punkAssociationInfo
= NULL
;
1702 pdcm
.aKeys
= ahkeyClsKeys
;
1704 hr
= SHCreateDefaultContextMenu(&pdcm
, IID_IContextMenu
, (void**)ppcm
);