3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: dll/win32/shell32/shv_item_new.c
5 * PURPOSE: provides default context menu implementation
6 * PROGRAMMERS: Johannes Anderwald (johannes.anderwald@reactos.org)
13 //fixme: this isn't in wine's shlwapi header, and the definition doesnt match the
14 // windows headers. When wine's header and lib are fixed this can be removed.
15 DWORD WINAPI
SHAnsiToUnicode(LPCSTR lpSrcStr
, LPWSTR lpDstStr
, int iLen
);
18 WINE_DEFAULT_DEBUG_CHANNEL(dmenu
);
20 typedef struct _DynamicShellEntry_
26 struct _DynamicShellEntry_
*pNext
;
27 } DynamicShellEntry
, *PDynamicShellEntry
;
29 typedef struct _StaticShellEntry_
33 struct _StaticShellEntry_
*pNext
;
34 } StaticShellEntry
, *PStaticShellEntry
;
38 // verbs for InvokeCommandInfo
40 struct _StaticInvokeCommandMap_
44 } g_StaticInvokeCmdMap
[] =
46 { "RunAs", 0 }, // Unimplemented
47 { "Print", 0 }, // Unimplemented
48 { "Preview", 0 }, // Unimplemented
49 { "Open", FCIDM_SHVIEW_OPEN
},
50 { CMDSTR_NEWFOLDERA
, FCIDM_SHVIEW_NEWFOLDER
},
51 { CMDSTR_VIEWLISTA
, FCIDM_SHVIEW_LISTVIEW
},
52 { CMDSTR_VIEWDETAILSA
, FCIDM_SHVIEW_REPORTVIEW
}
56 class CDefaultContextMenu
:
57 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
59 public IObjectWithSite
62 CComPtr
<IUnknown
> m_site
;
63 CComPtr
<IShellFolder
> m_psf
;
65 PCUITEMID_CHILD_ARRAY m_apidl
;
66 CComPtr
<IDataObject
> m_pDataObj
;
69 PIDLIST_ABSOLUTE m_pidlFolder
;
70 DWORD m_bGroupPolicyActive
;
71 PDynamicShellEntry m_pDynamicEntries
; /* first dynamic shell extension entry */
72 UINT m_iIdSHEFirst
; /* first used id */
73 UINT m_iIdSHELast
; /* last used id */
74 PStaticShellEntry m_pStaticEntries
; /* first static shell extension entry */
75 UINT m_iIdSCMFirst
; /* first static used id */
76 UINT m_iIdSCMLast
; /* last static used id */
78 void AddStaticEntry(const HKEY hkeyClass
, const WCHAR
*szVerb
);
79 void AddStaticEntriesForKey(HKEY hKey
);
80 BOOL
IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
);
81 HRESULT
LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
);
82 BOOL
EnumerateDynamicContextHandlerForKey(HKEY hRootKey
);
83 UINT
InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
);
84 UINT
BuildBackgroundContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
85 UINT
AddStaticContextMenusToMenu(HMENU hMenu
, UINT IndexMenu
);
86 UINT
BuildShellItemContextMenu(HMENU hMenu
, UINT iIdCmdFirst
, UINT iIdCmdLast
, UINT uFlags
);
87 HRESULT
NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
);
88 HRESULT
DoPaste(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
);
89 HRESULT
DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
);
90 HRESULT
DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
);
91 HRESULT
DoRefresh(LPCMINVOKECOMMANDINFO lpcmi
);
92 HRESULT
DoDelete(LPCMINVOKECOMMANDINFO lpcmi
);
93 HRESULT
DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
);
94 HRESULT
DoRename(LPCMINVOKECOMMANDINFO lpcmi
);
95 HRESULT
DoProperties(LPCMINVOKECOMMANDINFO lpcmi
);
96 HRESULT
DoFormat(LPCMINVOKECOMMANDINFO lpcmi
);
97 HRESULT
DoCreateNewFolder(LPCMINVOKECOMMANDINFO lpici
);
98 HRESULT
DoDynamicShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
99 HRESULT
DoStaticShellExtensions(LPCMINVOKECOMMANDINFO lpcmi
);
100 DWORD
BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
);
101 HRESULT
TryToBrowse(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
);
102 HRESULT
InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
);
103 PDynamicShellEntry
GetDynamicEntry(UINT idCmd
);
104 BOOL
MapVerbToCmdId(PVOID Verb
, PUINT idCmd
, BOOL IsUnicode
);
107 CDefaultContextMenu();
108 ~CDefaultContextMenu();
109 HRESULT WINAPI
Initialize(const DEFCONTEXTMENU
*pdcm
);
112 virtual HRESULT WINAPI
QueryContextMenu(HMENU hMenu
, UINT indexMenu
, UINT idCmdFirst
, UINT idCmdLast
, UINT uFlags
);
113 virtual HRESULT WINAPI
InvokeCommand(LPCMINVOKECOMMANDINFO lpcmi
);
114 virtual HRESULT WINAPI
GetCommandString(UINT_PTR idCommand
, UINT uFlags
, UINT
*lpReserved
, LPSTR lpszName
, UINT uMaxNameLen
);
117 virtual HRESULT WINAPI
HandleMenuMsg(UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
120 virtual HRESULT WINAPI
HandleMenuMsg2(UINT uMsg
, WPARAM wParam
, LPARAM lParam
, LRESULT
*plResult
);
123 virtual HRESULT STDMETHODCALLTYPE
SetSite(IUnknown
*pUnkSite
);
124 virtual HRESULT STDMETHODCALLTYPE
GetSite(REFIID riid
, void **ppvSite
);
126 BEGIN_COM_MAP(CDefaultContextMenu
)
127 COM_INTERFACE_ENTRY_IID(IID_IContextMenu
, IContextMenu
)
128 COM_INTERFACE_ENTRY_IID(IID_IContextMenu2
, IContextMenu2
)
129 COM_INTERFACE_ENTRY_IID(IID_IContextMenu3
, IContextMenu3
)
130 COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite
, IObjectWithSite
)
134 CDefaultContextMenu::CDefaultContextMenu() :
142 m_bGroupPolicyActive(0),
143 m_pDynamicEntries(NULL
),
146 m_pStaticEntries(NULL
),
152 CDefaultContextMenu::~CDefaultContextMenu()
154 /* Free dynamic shell extension entries */
155 PDynamicShellEntry pDynamicEntry
= m_pDynamicEntries
, pNextDynamic
;
156 while (pDynamicEntry
)
158 pNextDynamic
= pDynamicEntry
->pNext
;
159 pDynamicEntry
->pCM
->Release();
160 HeapFree(GetProcessHeap(), 0, pDynamicEntry
);
161 pDynamicEntry
= pNextDynamic
;
164 /* Free static shell extension entries */
165 PStaticShellEntry pStaticEntry
= m_pStaticEntries
, pNextStatic
;
168 pNextStatic
= pStaticEntry
->pNext
;
169 HeapFree(GetProcessHeap(), 0, pStaticEntry
->szVerb
);
170 HeapFree(GetProcessHeap(), 0, pStaticEntry
);
171 pStaticEntry
= pNextStatic
;
174 for (UINT i
= 0; i
< m_cKeys
; i
++)
175 RegCloseKey(m_aKeys
[i
]);
176 HeapFree(GetProcessHeap(), 0, m_aKeys
);
179 CoTaskMemFree(m_pidlFolder
);
180 _ILFreeaPidl(const_cast<PITEMID_CHILD
*>(m_apidl
), m_cidl
);
183 HRESULT WINAPI
CDefaultContextMenu::Initialize(const DEFCONTEXTMENU
*pdcm
)
185 TRACE("cidl %u\n", pdcm
->cidl
);
188 m_apidl
= const_cast<PCUITEMID_CHILD_ARRAY
>(_ILCopyaPidl(pdcm
->apidl
, m_cidl
));
189 if (m_cidl
&& !m_apidl
)
190 return E_OUTOFMEMORY
;
193 m_cKeys
= pdcm
->cKeys
;
196 m_aKeys
= (HKEY
*)HeapAlloc(GetProcessHeap(), 0, sizeof(HKEY
) * pdcm
->cKeys
);
198 return E_OUTOFMEMORY
;
199 memcpy(m_aKeys
, pdcm
->aKeys
, sizeof(HKEY
) * pdcm
->cKeys
);
202 m_psf
->GetUIObjectOf(pdcm
->hwnd
, m_cidl
, m_apidl
, IID_NULL_PPV_ARG(IDataObject
, &m_pDataObj
));
204 if (pdcm
->pidlFolder
)
206 m_pidlFolder
= ILClone(pdcm
->pidlFolder
);
210 CComPtr
<IPersistFolder2
> pf
= NULL
;
211 if (SUCCEEDED(m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
213 if (FAILED(pf
->GetCurFolder(reinterpret_cast<LPITEMIDLIST
*>(&m_pidlFolder
))))
214 ERR("GetCurFolder failed\n");
216 TRACE("pidlFolder %p\n", m_pidlFolder
);
222 void CDefaultContextMenu::AddStaticEntry(const HKEY hkeyClass
, const WCHAR
*szVerb
)
224 PStaticShellEntry pEntry
= m_pStaticEntries
, pLastEntry
= NULL
;
227 if (!wcsicmp(pEntry
->szVerb
, szVerb
))
229 /* entry already exists */
233 pEntry
= pEntry
->pNext
;
236 TRACE("adding verb %s\n", debugstr_w(szVerb
));
238 pEntry
= (StaticShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(StaticShellEntry
));
241 pEntry
->pNext
= NULL
;
242 pEntry
->szVerb
= (LPWSTR
)HeapAlloc(GetProcessHeap(), 0, (wcslen(szVerb
) + 1) * sizeof(WCHAR
));
244 wcscpy(pEntry
->szVerb
, szVerb
);
245 pEntry
->hkClass
= hkeyClass
;
248 if (!wcsicmp(szVerb
, L
"open"))
250 /* open verb is always inserted in front */
251 pEntry
->pNext
= m_pStaticEntries
;
252 m_pStaticEntries
= pEntry
;
255 pLastEntry
->pNext
= pEntry
;
257 m_pStaticEntries
= pEntry
;
260 void CDefaultContextMenu::AddStaticEntriesForKey(HKEY hKey
)
263 DWORD cchName
, dwIndex
= 0;
266 LRESULT lres
= RegOpenKeyExW(hKey
, L
"shell", 0, KEY_READ
, &hShellKey
);
267 if (lres
!= STATUS_SUCCESS
)
272 cchName
= _countof(wszName
);
273 if (RegEnumKeyExW(hShellKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
276 AddStaticEntry(hKey
, wszName
);
279 RegCloseKey(hShellKey
);
287 CComPtr
<IDataObject
> pDataObj
;
289 if (SUCCEEDED(OleGetClipboard(&pDataObj
)))
294 TRACE("pDataObj=%p\n", pDataObj
.p
);
296 /* Set the FORMATETC structure*/
297 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_SHELLIDLIST
), TYMED_HGLOBAL
);
298 if (SUCCEEDED(pDataObj
->GetData(&formatetc
, &medium
)))
301 ReleaseStgMedium(&medium
);
310 DisablePasteOptions(HMENU hMenu
)
314 mii
.cbSize
= sizeof(mii
);
315 mii
.fMask
= MIIM_STATE
;
316 mii
.fState
= MFS_DISABLED
;
318 SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERT
, FALSE
, &mii
);
319 SetMenuItemInfoW(hMenu
, FCIDM_SHVIEW_INSERTLINK
, FALSE
, &mii
);
323 CDefaultContextMenu::IsShellExtensionAlreadyLoaded(const CLSID
*pclsid
)
325 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
329 if (!memcmp(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
)))
331 pEntry
= pEntry
->pNext
;
338 CDefaultContextMenu::LoadDynamicContextMenuHandler(HKEY hKey
, const CLSID
*pclsid
)
342 TRACE("LoadDynamicContextMenuHandler entered with This %p hKey %p pclsid %s\n", this, hKey
, wine_dbgstr_guid(pclsid
));
344 if (IsShellExtensionAlreadyLoaded(pclsid
))
347 CComPtr
<IContextMenu
> pcm
;
348 hr
= SHCoCreateInstance(NULL
, pclsid
, NULL
, IID_PPV_ARG(IContextMenu
, &pcm
));
349 if (FAILED_UNEXPECTEDLY(hr
))
352 CComPtr
<IShellExtInit
> pExtInit
;
353 hr
= pcm
->QueryInterface(IID_PPV_ARG(IShellExtInit
, &pExtInit
));
354 if (FAILED_UNEXPECTEDLY(hr
))
357 hr
= pExtInit
->Initialize(m_pidlFolder
, m_pDataObj
, hKey
);
358 if (FAILED_UNEXPECTEDLY(hr
))
361 PDynamicShellEntry pEntry
= (DynamicShellEntry
*)HeapAlloc(GetProcessHeap(), 0, sizeof(DynamicShellEntry
));
363 return E_OUTOFMEMORY
;
365 pEntry
->iIdCmdFirst
= 0;
366 pEntry
->pNext
= NULL
;
368 pEntry
->pCM
= pcm
.Detach();
369 memcpy(&pEntry
->ClassID
, pclsid
, sizeof(CLSID
));
371 if (m_pDynamicEntries
)
373 PDynamicShellEntry pLastEntry
= m_pDynamicEntries
;
375 while (pLastEntry
->pNext
)
376 pLastEntry
= pLastEntry
->pNext
;
378 pLastEntry
->pNext
= pEntry
;
381 m_pDynamicEntries
= pEntry
;
387 CDefaultContextMenu::EnumerateDynamicContextHandlerForKey(HKEY hRootKey
)
390 WCHAR wszName
[MAX_PATH
], wszBuf
[MAX_PATH
], *pwszClsid
;
395 if (RegOpenKeyExW(hRootKey
, L
"shellex\\ContextMenuHandlers", 0, KEY_READ
, &hKey
) != ERROR_SUCCESS
)
397 TRACE("RegOpenKeyExW failed\n");
404 cchName
= _countof(wszName
);
405 if (RegEnumKeyExW(hKey
, dwIndex
++, wszName
, &cchName
, NULL
, NULL
, NULL
, NULL
) != ERROR_SUCCESS
)
408 /* Key name or key value is CLSID */
410 hr
= CLSIDFromString(wszName
, &clsid
);
415 DWORD cchBuf
= _countof(wszBuf
);
416 if (RegGetValueW(hKey
, wszName
, NULL
, RRF_RT_REG_SZ
, NULL
, wszBuf
, &cchBuf
) == ERROR_SUCCESS
)
417 hr
= CLSIDFromString(wszBuf
, &clsid
);
422 if (m_bGroupPolicyActive
)
424 if (RegGetValueW(HKEY_LOCAL_MACHINE
,
425 L
"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved",
430 NULL
) == ERROR_SUCCESS
)
432 LoadDynamicContextMenuHandler(hKey
, &clsid
);
436 LoadDynamicContextMenuHandler(hKey
, &clsid
);
445 CDefaultContextMenu::InsertMenuItemsOfDynamicContextMenuExtension(HMENU hMenu
, UINT IndexMenu
, UINT idCmdFirst
, UINT idCmdLast
)
447 if (!m_pDynamicEntries
)
454 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
457 m_iIdSHEFirst
= idCmdFirst
;
460 HRESULT hr
= pEntry
->pCM
->QueryContextMenu(hMenu
, IndexMenu
++, idCmdFirst
, idCmdLast
, CMF_NORMAL
);
463 pEntry
->iIdCmdFirst
= idCmdFirst
;
464 pEntry
->NumIds
= LOWORD(hr
);
465 IndexMenu
+= pEntry
->NumIds
;
466 idCmdFirst
+= pEntry
->NumIds
+ 0x10;
468 TRACE("pEntry %p hr %x contextmenu %p cmdfirst %x num ids %x\n", pEntry
, hr
, pEntry
->pCM
, pEntry
->iIdCmdFirst
, pEntry
->NumIds
);
469 pEntry
= pEntry
->pNext
;
472 m_iIdSHELast
= idCmdFirst
;
473 TRACE("SH_LoadContextMenuHandlers first %x last %x\n", m_iIdSHEFirst
, m_iIdSHELast
);
478 CDefaultContextMenu::BuildBackgroundContextMenu(
487 TRACE("BuildBackgroundContextMenu entered\n");
489 SFGAOF rfg
= SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
490 HRESULT hr
= m_psf
->GetAttributesOf(0, NULL
, &rfg
);
493 ERR("GetAttributesOf failed: %x\n", hr
);
497 hSubMenu
= LoadMenuW(shell32_hInstance
, L
"MENU_002");
500 /* view option is only available in browsing mode */
501 if (_ILIsDesktop(m_pidlFolder
))
502 DeleteMenu(hSubMenu
, FCIDM_SHVIEW_VIEW
, MF_BYCOMMAND
);
504 /* merge general background context menu in */
505 iIdCmdFirst
= Shell_MergeMenus(hMenu
, GetSubMenu(hSubMenu
, 0), IndexMenu
, 0, 0xFFFF, MM_DONTREMOVESEPS
| MM_SUBMENUSHAVEIDS
) + 1;
506 DestroyMenu(hSubMenu
);
509 if (!HasClipboardData())
511 TRACE("disabling paste options\n");
512 DisablePasteOptions(hMenu
);
515 /* Directory is progid of filesystem folders only */
516 if ((rfg
& (SFGAO_FILESYSTEM
|SFGAO_FOLDER
)) == (SFGAO_FILESYSTEM
|SFGAO_FOLDER
))
518 /* Load context menu handlers */
519 TRACE("Add background handlers: %p\n", m_pidlFolder
);
521 if (RegOpenKeyExW(HKEY_CLASSES_ROOT
, L
"Directory\\Background", 0, KEY_READ
, &hKey
) == ERROR_SUCCESS
)
523 EnumerateDynamicContextHandlerForKey(hKey
);
527 if (InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, GetMenuItemCount(hMenu
) - 1, iIdCmdFirst
, iIdCmdLast
))
529 /* seperate dynamic context menu items */
530 _InsertMenuItemW(hMenu
, GetMenuItemCount(hMenu
) - 1, TRUE
, -1, MFT_SEPARATOR
, NULL
, MFS_ENABLED
);
538 CDefaultContextMenu::AddStaticContextMenusToMenu(
547 mii
.cbSize
= sizeof(mii
);
548 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
| MIIM_DATA
;
549 mii
.fType
= MFT_STRING
;
551 mii
.dwTypeData
= NULL
;
552 m_iIdSCMFirst
= mii
.wID
;
554 PStaticShellEntry pEntry
= m_pStaticEntries
;
558 fState
= MFS_ENABLED
;
559 mii
.dwTypeData
= NULL
;
561 /* set first entry as default */
562 if (pEntry
== m_pStaticEntries
)
563 fState
|= MFS_DEFAULT
;
565 if (!wcsicmp(pEntry
->szVerb
, L
"open"))
567 /* override default when open verb is found */
568 fState
|= MFS_DEFAULT
;
569 idResource
= IDS_OPEN_VERB
;
571 else if (!wcsicmp(pEntry
->szVerb
, L
"explore"))
572 idResource
= IDS_EXPLORE_VERB
;
573 else if (!wcsicmp(pEntry
->szVerb
, L
"runas"))
574 idResource
= IDS_RUNAS_VERB
;
575 else if (!wcsicmp(pEntry
->szVerb
, L
"edit"))
576 idResource
= IDS_EDIT_VERB
;
577 else if (!wcsicmp(pEntry
->szVerb
, L
"find"))
578 idResource
= IDS_FIND_VERB
;
579 else if (!wcsicmp(pEntry
->szVerb
, L
"print"))
580 idResource
= IDS_PRINT_VERB
;
581 else if (!wcsicmp(pEntry
->szVerb
, L
"printto"))
583 pEntry
= pEntry
->pNext
;
589 /* By default use verb for menu item name */
590 mii
.dwTypeData
= pEntry
->szVerb
;
594 if (LoadStringW(shell32_hInstance
, idResource
, wszVerb
, _countof(wszVerb
)))
595 mii
.dwTypeData
= wszVerb
; /* use translated verb */
597 ERR("Failed to load string\n");
602 HRESULT hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"shell\\%s", pEntry
->szVerb
);
607 DWORD cbVerb
= sizeof(wszVerb
);
608 LONG res
= RegOpenKeyW(pEntry
->hkClass
, wszKey
, &hkVerb
);
609 if (res
== ERROR_SUCCESS
)
611 res
= RegLoadMUIStringW(hkVerb
,
618 if (res
== ERROR_SUCCESS
)
620 /* use description for the menu entry */
621 mii
.dwTypeData
= wszVerb
;
629 mii
.cch
= wcslen(mii
.dwTypeData
);
631 InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, &mii
);
634 pEntry
= pEntry
->pNext
;
637 m_iIdSCMLast
= mii
.wID
- 1;
641 void WINAPI
_InsertMenuItemW(
653 ZeroMemory(&mii
, sizeof(mii
));
654 mii
.cbSize
= sizeof(mii
);
655 if (fType
== MFT_SEPARATOR
)
656 mii
.fMask
= MIIM_ID
| MIIM_TYPE
;
657 else if (fType
== MFT_STRING
)
659 mii
.fMask
= MIIM_ID
| MIIM_TYPE
| MIIM_STATE
;
660 if ((ULONG_PTR
)HIWORD((ULONG_PTR
)dwTypeData
) == 0)
662 if (LoadStringW(shell32_hInstance
, LOWORD((ULONG_PTR
)dwTypeData
), wszText
, _countof(wszText
)))
663 mii
.dwTypeData
= wszText
;
666 ERR("failed to load string %p\n", dwTypeData
);
671 mii
.dwTypeData
= (LPWSTR
)dwTypeData
;
677 InsertMenuItemW(hMenu
, indexMenu
, fByPosition
, &mii
);
681 CDefaultContextMenu::BuildShellItemContextMenu(
689 TRACE("BuildShellItemContextMenu entered\n");
692 for (UINT i
= 0; i
< m_cKeys
; i
++)
694 AddStaticEntriesForKey(m_aKeys
[i
]);
695 EnumerateDynamicContextHandlerForKey(m_aKeys
[i
]);
698 /* add static actions */
699 SFGAOF rfg
= SFGAO_BROWSABLE
| SFGAO_CANCOPY
| SFGAO_CANLINK
| SFGAO_CANMOVE
| SFGAO_CANDELETE
| SFGAO_CANRENAME
| SFGAO_HASPROPSHEET
| SFGAO_FILESYSTEM
| SFGAO_FOLDER
;
700 hr
= m_psf
->GetAttributesOf(m_cidl
, m_apidl
, &rfg
);
703 ERR("GetAttributesOf failed: %x\n", hr
);
707 /* add static context menu handlers */
708 UINT IndexMenu
= AddStaticContextMenusToMenu(hMenu
, 0);
710 /* now process dynamic context menu handlers */
711 BOOL bAddSep
= FALSE
;
712 IndexMenu
= InsertMenuItemsOfDynamicContextMenuExtension(hMenu
, IndexMenu
, iIdCmdFirst
, iIdCmdLast
);
713 TRACE("IndexMenu %d\n", IndexMenu
);
715 if (_ILIsDrive(m_apidl
[0]))
717 char szDrive
[8] = {0};
720 _ILGetDrive(m_apidl
[0], szDrive
, sizeof(szDrive
));
721 if (GetVolumeInformationA(szDrive
, NULL
, 0, NULL
, NULL
, &dwFlags
, NULL
, 0))
723 /* Disable format if read only */
724 if (!(dwFlags
& FILE_READ_ONLY_VOLUME
))
726 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
727 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0x7ABC, MFT_STRING
, MAKEINTRESOURCEW(IDS_FORMATDRIVE
), MFS_ENABLED
);
733 BOOL bClipboardData
= (HasClipboardData() && (rfg
& SFGAO_FILESYSTEM
));
734 if (rfg
& (SFGAO_CANCOPY
| SFGAO_CANMOVE
) || bClipboardData
)
736 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
737 if (rfg
& SFGAO_CANMOVE
)
738 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_CUT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CUT
), MFS_ENABLED
);
739 if (rfg
& SFGAO_CANCOPY
)
740 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_COPY
, MFT_STRING
, MAKEINTRESOURCEW(IDS_COPY
), MFS_ENABLED
);
742 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_INSERT
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PASTE
), MFS_ENABLED
);
747 if (rfg
& SFGAO_CANLINK
)
750 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
751 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_CREATELINK
, MFT_STRING
, MAKEINTRESOURCEW(IDS_CREATELINK
), MFS_ENABLED
);
754 if (rfg
& SFGAO_CANDELETE
)
759 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
761 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_DELETE
, MFT_STRING
, MAKEINTRESOURCEW(IDS_DELETE
), MFS_ENABLED
);
764 if (rfg
& SFGAO_CANRENAME
)
768 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
770 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_RENAME
, MFT_STRING
, MAKEINTRESOURCEW(IDS_RENAME
), MFS_ENABLED
);
774 if (rfg
& SFGAO_HASPROPSHEET
)
776 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, 0, MFT_SEPARATOR
, NULL
, 0);
777 _InsertMenuItemW(hMenu
, IndexMenu
++, TRUE
, FCIDM_SHVIEW_PROPERTIES
, MFT_STRING
, MAKEINTRESOURCEW(IDS_PROPERTIES
), MFS_ENABLED
);
785 CDefaultContextMenu::QueryContextMenu(
793 idCmdFirst
= BuildShellItemContextMenu(hMenu
, idCmdFirst
, idCmdLast
, uFlags
);
795 idCmdFirst
= BuildBackgroundContextMenu(hMenu
, idCmdFirst
, idCmdLast
, uFlags
);
801 CDefaultContextMenu::NotifyShellViewWindow(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bRefresh
)
806 /* Get a pointer to the shell browser */
807 CComPtr
<IShellView
> psv
;
808 HRESULT hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
809 if (FAILED_UNEXPECTEDLY(hr
))
813 if (SUCCEEDED(psv
->GetWindow(&hwndSV
)))
814 SendMessageW(hwndSV
, WM_COMMAND
, MAKEWPARAM(LOWORD(lpcmi
->lpVerb
), 0), 0);
819 HRESULT
CDefaultContextMenu::DoRefresh(LPCMINVOKECOMMANDINFO lpcmi
)
824 /* Get a pointer to the shell view */
825 CComPtr
<IShellView
> psv
;
826 HRESULT hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
827 if (FAILED_UNEXPECTEDLY(hr
))
831 if (FAILED_UNEXPECTEDLY(hr
))
837 HRESULT
CDefaultContextMenu::DoPaste(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bLink
)
841 CComPtr
<IDataObject
> pda
;
842 hr
= OleGetClipboard(&pda
);
843 if (FAILED_UNEXPECTEDLY(hr
))
846 FORMATETC formatetc2
;
848 InitFormatEtc(formatetc2
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
852 if (SUCCEEDED(pda
->GetData(&formatetc2
, &medium2
)))
854 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium2
.hGlobal
);
857 if (*pdwFlag
== DROPEFFECT_COPY
)
863 ERR("No drop effect obtained");
865 GlobalUnlock(medium2
.hGlobal
);
870 dwKey
= MK_CONTROL
|MK_SHIFT
;
873 CComPtr
<IDropTarget
> pdrop
;
875 hr
= m_psf
->GetUIObjectOf(NULL
, 1, &m_apidl
[0], IID_NULL_PPV_ARG(IDropTarget
, &pdrop
));
877 hr
= m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pdrop
));
879 if (FAILED_UNEXPECTEDLY(hr
))
882 SHSimulateDrop(pdrop
, pda
, dwKey
, NULL
, NULL
);
884 TRACE("CP result %x\n", hr
);
889 CDefaultContextMenu::DoOpenOrExplore(LPCMINVOKECOMMANDINFO lpcmi
)
895 HRESULT
CDefaultContextMenu::DoCreateLink(LPCMINVOKECOMMANDINFO lpcmi
)
897 if (!m_cidl
|| !m_pDataObj
)
900 CComPtr
<IDropTarget
> pDT
;
901 HRESULT hr
= m_psf
->CreateViewObject(NULL
, IID_PPV_ARG(IDropTarget
, &pDT
));
902 if (FAILED_UNEXPECTEDLY(hr
))
905 SHSimulateDrop(pDT
, m_pDataObj
, MK_CONTROL
|MK_SHIFT
, NULL
, NULL
);
910 HRESULT
CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi
)
912 if (!m_cidl
|| !m_pDataObj
)
915 DoDeleteAsync(m_pDataObj
, lpcmi
->fMask
);
919 HRESULT
CDefaultContextMenu::DoCopyOrCut(LPCMINVOKECOMMANDINFO lpcmi
, BOOL bCopy
)
921 if (!m_cidl
|| !m_pDataObj
)
928 InitFormatEtc(formatetc
, RegisterClipboardFormatW(CFSTR_PREFERREDDROPEFFECT
), TYMED_HGLOBAL
);
929 m_pDataObj
->GetData(&formatetc
, &medium
);
930 DWORD
* pdwFlag
= (DWORD
*)GlobalLock(medium
.hGlobal
);
932 *pdwFlag
= DROPEFFECT_MOVE
;
933 GlobalUnlock(medium
.hGlobal
);
934 m_pDataObj
->SetData(&formatetc
, &medium
, TRUE
);
937 HRESULT hr
= OleSetClipboard(m_pDataObj
);
938 if (FAILED_UNEXPECTEDLY(hr
))
944 HRESULT
CDefaultContextMenu::DoRename(LPCMINVOKECOMMANDINFO lpcmi
)
946 CComPtr
<IShellBrowser
> psb
;
949 if (!m_site
|| !m_cidl
)
952 /* Get a pointer to the shell browser */
953 hr
= IUnknown_QueryService(m_site
, SID_IShellBrowser
, IID_PPV_ARG(IShellBrowser
, &psb
));
954 if (FAILED_UNEXPECTEDLY(hr
))
957 CComPtr
<IShellView
> lpSV
;
958 hr
= psb
->QueryActiveShellView(&lpSV
);
959 if (FAILED_UNEXPECTEDLY(hr
))
962 SVSIF selFlags
= SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
| SVSI_FOCUSED
| SVSI_SELECT
;
963 hr
= lpSV
->SelectItem(m_apidl
[0], selFlags
);
964 if (FAILED_UNEXPECTEDLY(hr
))
971 CDefaultContextMenu::DoProperties(
972 LPCMINVOKECOMMANDINFO lpcmi
)
975 const ITEMIDLIST
*pidlParent
= m_pidlFolder
, *pidlChild
;
979 CComPtr
<IPersistFolder2
> pf
;
981 /* pidlFolder is optional */
982 if (SUCCEEDED(m_psf
->QueryInterface(IID_PPV_ARG(IPersistFolder2
, &pf
))))
984 pf
->GetCurFolder((_ITEMIDLIST
**)&pidlParent
);
989 pidlChild
= m_apidl
[0];
992 /* Set pidlChild to last pidl of current folder */
993 if (pidlParent
== m_pidlFolder
)
994 pidlParent
= (ITEMIDLIST
*)ILClone(pidlParent
);
996 pidlChild
= (ITEMIDLIST
*)ILClone(ILFindLastID(pidlParent
));
997 ILRemoveLastID((ITEMIDLIST
*)pidlParent
);
1000 if (_ILIsMyComputer(pidlChild
))
1002 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL sysdm.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1005 else if (_ILIsDesktop(pidlChild
))
1007 if (32 >= (UINT
)ShellExecuteW(lpcmi
->hwnd
, L
"open", L
"rundll32.exe shell32.dll,Control_RunDLL desk.cpl", NULL
, NULL
, SW_SHOWNORMAL
))
1010 else if (_ILIsDrive(pidlChild
))
1012 WCHAR wszBuf
[MAX_PATH
];
1013 ILGetDisplayName(pidlChild
, wszBuf
);
1014 if (!SH_ShowDriveProperties(wszBuf
, pidlParent
, &pidlChild
))
1017 else if (_ILIsNetHood(pidlChild
))
1020 if (32 >= (UINT
)ShellExecuteW(NULL
, L
"open", L
"explorer.exe",
1021 L
"::{7007ACC7-3202-11D1-AAD2-00805FC1270E}",
1022 NULL
, SW_SHOWDEFAULT
))
1025 else if (_ILIsBitBucket(pidlChild
))
1027 /* FIXME: detect the drive path of bitbucket if appropiate */
1028 if (!SH_ShowRecycleBinProperties(L
'C'))
1034 WARN("SHMultiFileProperties is not yet implemented\n");
1037 hr
= m_psf
->GetDisplayNameOf(pidlChild
, SHGDN_FORPARSING
, &strFile
);
1040 WCHAR wszBuf
[MAX_PATH
];
1041 hr
= StrRetToBufW(&strFile
, pidlChild
, wszBuf
, _countof(wszBuf
));
1043 hr
= SH_ShowPropertiesDialog(wszBuf
, pidlParent
, &pidlChild
);
1045 ERR("StrRetToBufW failed\n");
1048 ERR("IShellFolder_GetDisplayNameOf failed for apidl\n");
1051 /* Free allocated PIDLs */
1052 if (pidlParent
!= m_pidlFolder
)
1053 ILFree((ITEMIDLIST
*)pidlParent
);
1054 if (m_cidl
< 1 || pidlChild
!= m_apidl
[0])
1055 ILFree((ITEMIDLIST
*)pidlChild
);
1061 CDefaultContextMenu::DoFormat(
1062 LPCMINVOKECOMMANDINFO lpcmi
)
1064 char szDrive
[8] = {0};
1066 if (!_ILGetDrive(m_apidl
[0], szDrive
, sizeof(szDrive
)))
1068 ERR("pidl is not a drive\n");
1072 SHFormatDrive(lpcmi
->hwnd
, szDrive
[0] - 'A', SHFMT_ID_DEFAULT
, 0);
1076 // This code is taken from CNewMenu and should be shared between the 2 classes
1078 CDefaultContextMenu::DoCreateNewFolder(
1079 LPCMINVOKECOMMANDINFO lpici
)
1081 WCHAR wszPath
[MAX_PATH
];
1082 WCHAR wszName
[MAX_PATH
];
1083 WCHAR wszNewFolder
[25];
1086 /* Get folder path */
1087 hr
= SHGetPathFromIDListW(m_pidlFolder
, wszPath
);
1088 if (FAILED_UNEXPECTEDLY(hr
))
1091 if (!LoadStringW(shell32_hInstance
, IDS_NEWFOLDER
, wszNewFolder
, _countof(wszNewFolder
)))
1094 /* Create the name of the new directory */
1095 if (!PathYetAnotherMakeUniqueName(wszName
, wszPath
, NULL
, wszNewFolder
))
1098 /* Create the new directory and show the appropriate dialog in case of error */
1099 if (SHCreateDirectory(lpici
->hwnd
, wszName
) != ERROR_SUCCESS
)
1102 /* Show and select the new item in the def view */
1104 PITEMID_CHILD pidlNewItem
;
1105 CComPtr
<IShellView
> psv
;
1107 /* Notify the view object about the new item */
1108 SHChangeNotify(SHCNE_MKDIR
, SHCNF_PATHW
, (LPCVOID
)wszName
, NULL
);
1113 /* Get a pointer to the shell view */
1114 hr
= IUnknown_QueryService(m_site
, SID_IFolderView
, IID_PPV_ARG(IShellView
, &psv
));
1115 if (FAILED_UNEXPECTEDLY(hr
))
1118 /* Attempt to get the pidl of the new item */
1119 hr
= SHILCreateFromPathW(wszName
, &pidl
, NULL
);
1120 if (FAILED_UNEXPECTEDLY(hr
))
1123 pidlNewItem
= ILFindLastID(pidl
);
1125 hr
= psv
->SelectItem(pidlNewItem
, SVSI_DESELECTOTHERS
| SVSI_EDIT
| SVSI_ENSUREVISIBLE
|
1126 SVSI_FOCUSED
| SVSI_SELECT
);
1127 if (FAILED_UNEXPECTEDLY(hr
))
1135 PDynamicShellEntry
CDefaultContextMenu::GetDynamicEntry(UINT idCmd
)
1137 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1139 while(pEntry
&& idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1140 pEntry
= pEntry
->pNext
;
1145 if (idCmd
< pEntry
->iIdCmdFirst
|| idCmd
> pEntry
->iIdCmdFirst
+ pEntry
->NumIds
)
1151 //FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
1152 #define MAX_VERB 260
1155 CDefaultContextMenu::MapVerbToCmdId(PVOID Verb
, PUINT idCmd
, BOOL IsUnicode
)
1157 WCHAR UnicodeStr
[MAX_VERB
];
1159 /* Loop through all the static verbs looking for a match */
1160 for (UINT i
= 0; i
< _countof(g_StaticInvokeCmdMap
); i
++)
1162 /* We can match both ANSI and unicode strings */
1165 /* The static verbs are ANSI, get a unicode version before doing the compare */
1166 SHAnsiToUnicode(g_StaticInvokeCmdMap
[i
].szStringVerb
, UnicodeStr
, MAX_VERB
);
1167 if (!wcscmp(UnicodeStr
, (LPWSTR
)Verb
))
1169 /* Return the Corresponding Id */
1170 *idCmd
= g_StaticInvokeCmdMap
[i
].IntVerb
;
1176 if (!strcmp(g_StaticInvokeCmdMap
[i
].szStringVerb
, (LPSTR
)Verb
))
1178 *idCmd
= g_StaticInvokeCmdMap
[i
].IntVerb
;
1188 CDefaultContextMenu::DoDynamicShellExtensions(
1189 LPCMINVOKECOMMANDINFO lpcmi
)
1191 TRACE("verb %p first %x last %x", lpcmi
->lpVerb
, m_iIdSHEFirst
, m_iIdSHELast
);
1193 UINT idCmd
= LOWORD(lpcmi
->lpVerb
);
1194 PDynamicShellEntry pEntry
= GetDynamicEntry(idCmd
);
1198 /* invoke the dynamic context menu */
1199 lpcmi
->lpVerb
= MAKEINTRESOURCEA(idCmd
- pEntry
->iIdCmdFirst
);
1200 return pEntry
->pCM
->InvokeCommand(lpcmi
);
1204 CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFO lpcmi
, PStaticShellEntry pEntry
)
1206 CComPtr
<IShellBrowser
> psb
;
1217 /* Get a pointer to the shell browser */
1218 hr
= IUnknown_QueryService(m_site
, SID_IShellBrowser
, IID_PPV_ARG(IShellBrowser
, &psb
));
1219 if (FAILED_UNEXPECTEDLY(hr
))
1222 /* See if we are in Explore or Browse mode. If the browser's tree is present, we are in Explore mode.*/
1223 if (SUCCEEDED(psb
->GetControlWindow(FCW_TREE
, &hwndTree
)) && hwndTree
)
1224 FlagsName
= L
"ExplorerFlags";
1226 FlagsName
= L
"BrowserFlags";
1228 /* Try to get the flag from the verb */
1229 hr
= StringCbPrintfW(wszKey
, sizeof(wszKey
), L
"shell\\%s", pEntry
->szVerb
);
1230 if (FAILED_UNEXPECTEDLY(hr
))
1233 cbVerb
= sizeof(wFlags
);
1234 if (RegGetValueW(pEntry
->hkClass
, wszKey
, FlagsName
, RRF_RT_REG_DWORD
, NULL
, &wFlags
, &cbVerb
) == ERROR_SUCCESS
)
1243 CDefaultContextMenu::TryToBrowse(
1244 LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, DWORD wFlags
)
1246 CComPtr
<IShellBrowser
> psb
;
1252 /* Get a pointer to the shell browser */
1253 hr
= IUnknown_QueryService(m_site
, SID_IShellBrowser
, IID_PPV_ARG(IShellBrowser
, &psb
));
1254 if (FAILED_UNEXPECTEDLY(hr
))
1257 return psb
->BrowseObject(ILCombine(m_pidlFolder
, pidl
), wFlags
);
1261 CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi
, LPCITEMIDLIST pidl
, PStaticShellEntry pEntry
)
1263 LPITEMIDLIST pidlFull
= ILCombine(m_pidlFolder
, pidl
);
1264 if (pidlFull
== NULL
)
1269 WCHAR wszPath
[MAX_PATH
];
1270 BOOL bHasPath
= SHGetPathFromIDListW(pidlFull
, wszPath
);
1272 WCHAR wszDir
[MAX_PATH
];
1275 wcscpy(wszDir
, wszPath
);
1276 PathRemoveFileSpec(wszDir
);
1280 SHGetPathFromIDListW(m_pidlFolder
, wszDir
);
1283 SHELLEXECUTEINFOW sei
;
1284 ZeroMemory(&sei
, sizeof(sei
));
1285 sei
.cbSize
= sizeof(sei
);
1286 sei
.hwnd
= lpcmi
->hwnd
;
1287 sei
.nShow
= SW_SHOWNORMAL
;
1288 sei
.lpVerb
= pEntry
->szVerb
;
1289 sei
.lpDirectory
= wszDir
;
1290 sei
.lpIDList
= pidlFull
;
1291 sei
.hkeyClass
= pEntry
->hkClass
;
1292 sei
.fMask
= SEE_MASK_CLASSKEY
| SEE_MASK_IDLIST
;
1295 sei
.lpFile
= wszPath
;
1298 ShellExecuteExW(&sei
);
1306 CDefaultContextMenu::DoStaticShellExtensions(
1307 LPCMINVOKECOMMANDINFO lpcmi
)
1309 PStaticShellEntry pEntry
= m_pStaticEntries
;
1310 INT iCmd
= LOWORD(lpcmi
->lpVerb
) - m_iIdSCMFirst
;
1314 while (pEntry
&& (iCmd
--) > 0)
1315 pEntry
= pEntry
->pNext
;
1320 /* Get the browse flags to see if we need to browse */
1321 DWORD wFlags
= BrowserFlagsFromVerb(lpcmi
, pEntry
);
1322 BOOL bBrowsed
= FALSE
;
1324 for (i
=0; i
< m_cidl
; i
++)
1326 /* Check if we need to browse */
1329 /* In xp if we have browsed, we don't open any more folders .
1330 * In win7 we browse to the first folder we find and
1331 * open new windows fo for each of the rest of the folders */
1335 hr
= TryToBrowse(lpcmi
, m_apidl
[i
], wFlags
);
1343 InvokePidl(lpcmi
, m_apidl
[i
], pEntry
);
1351 CDefaultContextMenu::InvokeCommand(
1352 LPCMINVOKECOMMANDINFO lpcmi
)
1354 CMINVOKECOMMANDINFO LocalInvokeInfo
;
1358 /* Take a local copy of the fixed members of the
1359 struct as we might need to modify the verb */
1360 LocalInvokeInfo
= *lpcmi
;
1362 /* Check if this is a string verb */
1363 if (HIWORD(LocalInvokeInfo
.lpVerb
))
1365 /* Get the ID which corresponds to this verb, and update our local copy */
1366 if (MapVerbToCmdId((LPVOID
)LocalInvokeInfo
.lpVerb
, &CmdId
, FALSE
))
1367 LocalInvokeInfo
.lpVerb
= MAKEINTRESOURCEA(CmdId
);
1370 /* Check if this is a Id */
1371 switch (LOWORD(LocalInvokeInfo
.lpVerb
))
1373 case FCIDM_SHVIEW_BIGICON
:
1374 case FCIDM_SHVIEW_SMALLICON
:
1375 case FCIDM_SHVIEW_LISTVIEW
:
1376 case FCIDM_SHVIEW_REPORTVIEW
:
1377 case 0x30: /* FIX IDS in resource files */
1381 case FCIDM_SHVIEW_AUTOARRANGE
:
1382 case FCIDM_SHVIEW_SNAPTOGRID
:
1383 Result
= NotifyShellViewWindow(&LocalInvokeInfo
, FALSE
);
1385 case FCIDM_SHVIEW_REFRESH
:
1386 Result
= DoRefresh(&LocalInvokeInfo
);
1388 case FCIDM_SHVIEW_INSERT
:
1389 Result
= DoPaste(&LocalInvokeInfo
, FALSE
);
1391 case FCIDM_SHVIEW_INSERTLINK
:
1392 Result
= DoPaste(&LocalInvokeInfo
, TRUE
);
1394 case FCIDM_SHVIEW_OPEN
:
1395 case FCIDM_SHVIEW_EXPLORE
:
1396 Result
= DoOpenOrExplore(&LocalInvokeInfo
);
1398 case FCIDM_SHVIEW_COPY
:
1399 case FCIDM_SHVIEW_CUT
:
1400 Result
= DoCopyOrCut(&LocalInvokeInfo
, LOWORD(LocalInvokeInfo
.lpVerb
) == FCIDM_SHVIEW_COPY
);
1402 case FCIDM_SHVIEW_CREATELINK
:
1403 Result
= DoCreateLink(&LocalInvokeInfo
);
1405 case FCIDM_SHVIEW_DELETE
:
1406 Result
= DoDelete(&LocalInvokeInfo
);
1408 case FCIDM_SHVIEW_RENAME
:
1409 Result
= DoRename(&LocalInvokeInfo
);
1411 case FCIDM_SHVIEW_PROPERTIES
:
1412 Result
= DoProperties(&LocalInvokeInfo
);
1415 Result
= DoFormat(&LocalInvokeInfo
);
1417 case FCIDM_SHVIEW_NEWFOLDER
:
1418 Result
= DoCreateNewFolder(&LocalInvokeInfo
);
1421 Result
= E_UNEXPECTED
;
1425 /* Check for ID's we didn't find a handler for */
1426 if (Result
== E_UNEXPECTED
)
1428 if (m_iIdSHEFirst
&& m_iIdSHELast
)
1430 if (LOWORD(LocalInvokeInfo
.lpVerb
) >= m_iIdSHEFirst
&& LOWORD(LocalInvokeInfo
.lpVerb
) <= m_iIdSHELast
)
1431 Result
= DoDynamicShellExtensions(&LocalInvokeInfo
);
1434 if (m_iIdSCMFirst
&& m_iIdSCMLast
)
1436 if (LOWORD(LocalInvokeInfo
.lpVerb
) >= m_iIdSCMFirst
&& LOWORD(LocalInvokeInfo
.lpVerb
) <= m_iIdSCMLast
)
1437 Result
= DoStaticShellExtensions(&LocalInvokeInfo
);
1441 if (Result
== E_UNEXPECTED
)
1442 FIXME("Unhandled Verb %xl\n", LOWORD(LocalInvokeInfo
.lpVerb
));
1449 CDefaultContextMenu::GetCommandString(
1456 /* We don't handle the help text yet */
1457 if (uFlags
== GCS_HELPTEXTA
||
1458 uFlags
== GCS_HELPTEXTW
)
1463 /* Loop looking for a matching Id */
1464 for (UINT i
= 0; i
< _countof(g_StaticInvokeCmdMap
); i
++)
1466 if (g_StaticInvokeCmdMap
[i
].IntVerb
== idCommand
)
1468 /* Validation just returns S_OK on a match */
1469 if (uFlags
== GCS_VALIDATEA
|| uFlags
== GCS_VALIDATEW
)
1472 /* Return a copy of the ANSI verb */
1473 if (uFlags
== GCS_VERBA
)
1474 return StringCchCopyA(lpszName
, uMaxNameLen
, g_StaticInvokeCmdMap
[i
].szStringVerb
);
1476 /* Convert the ANSI verb to unicode and return that */
1477 if (uFlags
== GCS_VERBW
)
1479 if (SHAnsiToUnicode(g_StaticInvokeCmdMap
[i
].szStringVerb
, (LPWSTR
)lpszName
, uMaxNameLen
))
1485 return E_INVALIDARG
;
1490 CDefaultContextMenu::HandleMenuMsg(
1495 /* FIXME: Should we implement this as well? */
1501 CDefaultContextMenu::HandleMenuMsg2(
1509 case WM_INITMENUPOPUP
:
1511 PDynamicShellEntry pEntry
= m_pDynamicEntries
;
1514 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1515 pEntry
= pEntry
->pNext
;
1521 DRAWITEMSTRUCT
* pDrawStruct
= reinterpret_cast<DRAWITEMSTRUCT
*>(lParam
);
1522 PDynamicShellEntry pEntry
= GetDynamicEntry(pDrawStruct
->itemID
);
1524 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1527 case WM_MEASUREITEM
:
1529 MEASUREITEMSTRUCT
* pMeasureStruct
= reinterpret_cast<MEASUREITEMSTRUCT
*>(lParam
);
1530 PDynamicShellEntry pEntry
= GetDynamicEntry(pMeasureStruct
->itemID
);
1532 SHForwardContextMenuMsg(pEntry
->pCM
, uMsg
, wParam
, lParam
, plResult
, TRUE
);
1539 ERR("Got unknown message:%d\n", uMsg
);
1546 CDefaultContextMenu::SetSite(IUnknown
*pUnkSite
)
1554 CDefaultContextMenu::GetSite(REFIID riid
, void **ppvSite
)
1559 return m_site
->QueryInterface(riid
, ppvSite
);
1564 CDefaultContextMenu_CreateInstance(const DEFCONTEXTMENU
*pdcm
, REFIID riid
, void **ppv
)
1566 return ShellObjectCreatorInit
<CDefaultContextMenu
>(pdcm
, riid
, ppv
);
1569 /*************************************************************************
1570 * SHCreateDefaultContextMenu [SHELL32.325] Vista API
1574 static void AddClassKey(const WCHAR
* szClass
, HKEY
* buffer
, UINT
* cKeys
)
1578 result
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, szClass
, 0, KEY_READ
| KEY_QUERY_VALUE
, &hkey
);
1579 if (result
!= ERROR_SUCCESS
)
1582 buffer
[*cKeys
] = hkey
;
1586 void HackFillKeys(DEFCONTEXTMENU
*pdcm
, HKEY
* buffer
)
1588 PCUITEMID_CHILD pidl
= pdcm
->apidl
[0];
1590 pdcm
->aKeys
= buffer
;
1592 if (_ILIsValue(pidl
))
1594 FileStructW
* pFileData
= _ILGetFileStructW(pidl
);
1595 LPWSTR extension
= PathFindExtension(pFileData
->wszName
);
1599 AddClassKey(extension
, buffer
, &pdcm
->cKeys
);
1601 WCHAR wszClass
[40], wszClass2
[40];
1602 DWORD dwSize
= sizeof(wszClass
);
1603 if (RegGetValueW(HKEY_CLASSES_ROOT
, extension
, NULL
, RRF_RT_REG_SZ
, NULL
, wszClass
, &dwSize
) == ERROR_SUCCESS
)
1605 swprintf(wszClass2
, L
"%s//%s", extension
, wszClass
);
1607 AddClassKey(wszClass
, buffer
, &pdcm
->cKeys
);
1608 AddClassKey(wszClass2
, buffer
, &pdcm
->cKeys
);
1611 swprintf(wszClass2
, L
"SystemFileAssociations//%s", extension
);
1612 AddClassKey(wszClass2
, buffer
, &pdcm
->cKeys
);
1614 if (RegGetValueW(HKEY_CLASSES_ROOT
, extension
, L
"PerceivedType ", RRF_RT_REG_SZ
, NULL
, wszClass
, &dwSize
) == ERROR_SUCCESS
)
1616 swprintf(wszClass2
, L
"SystemFileAssociations//%s", wszClass
);
1617 AddClassKey(wszClass2
, buffer
, &pdcm
->cKeys
);
1621 AddClassKey(L
"AllFilesystemObjects", buffer
, &pdcm
->cKeys
);
1622 AddClassKey(L
"*", buffer
, &pdcm
->cKeys
);
1624 else if (_ILIsSpecialFolder(pidl
))
1626 GUID
*pGuid
= _ILGetGUIDPointer(pidl
);
1632 wcscpy(key
, L
"CLSID\\");
1633 HRESULT hr
= StringFromCLSID(*pGuid
, &pwszCLSID
);
1636 wcscpy(&key
[6], pwszCLSID
);
1637 AddClassKey(key
, buffer
, &pdcm
->cKeys
);
1640 AddClassKey(L
"Folder", buffer
, &pdcm
->cKeys
);
1642 else if (_ILIsFolder(pidl
))
1644 AddClassKey(L
"AllFilesystemObjects", buffer
, &pdcm
->cKeys
);
1645 AddClassKey(L
"Directory", buffer
, &pdcm
->cKeys
);
1646 AddClassKey(L
"Folder", buffer
, &pdcm
->cKeys
);
1648 else if (_ILIsDrive(pidl
))
1650 AddClassKey(L
"Drive", buffer
, &pdcm
->cKeys
);
1651 AddClassKey(L
"Folder", buffer
, &pdcm
->cKeys
);
1657 SHCreateDefaultContextMenu(const DEFCONTEXTMENU
*pdcm
, REFIID riid
, void **ppv
)
1659 /* HACK: move to the shell folders implementation */
1661 if (!pdcm
->aKeys
&& pdcm
->cidl
)
1662 HackFillKeys((DEFCONTEXTMENU
*)pdcm
, hkeyHack
);
1664 HRESULT hr
= CDefaultContextMenu_CreateInstance(pdcm
, riid
, ppv
);
1665 if (FAILED_UNEXPECTEDLY(hr
))
1671 /*************************************************************************
1672 * CDefFolderMenu_Create2 [SHELL32.701]
1678 CDefFolderMenu_Create2(
1679 PCIDLIST_ABSOLUTE pidlFolder
,
1682 PCUITEMID_CHILD_ARRAY apidl
,
1684 LPFNDFMCALLBACK lpfn
,
1686 const HKEY
*ahkeyClsKeys
,
1687 IContextMenu
**ppcm
)
1689 DEFCONTEXTMENU pdcm
;
1692 pdcm
.pidlFolder
= pidlFolder
;
1696 pdcm
.punkAssociationInfo
= NULL
;
1698 pdcm
.aKeys
= ahkeyClsKeys
;
1700 HRESULT hr
= SHCreateDefaultContextMenu(&pdcm
, IID_PPV_ARG(IContextMenu
, ppcm
));
1701 if (FAILED_UNEXPECTEDLY(hr
))