mirror of
https://github.com/reactos/reactos.git
synced 2025-08-03 12:26:09 +00:00
[SHELL32] Support IDropTarget handler in IContextMenu static verbs (#5860)
This adds support for the `DropHandler` subkey in static verbs. `IDropTarget` is called when the verb is invoked. The advantage of this is that no library needs to be loaded until the verb is actually invoked unlike `IContextMenu` shell extensions that have to be loaded during menu creation.
This method is preferred for verb implementations that must work on Windows XP, see
dd940354
%28v%3Dvs.85%29?redirectedfrom=MSDN#description
This commit is contained in:
parent
54df31ccac
commit
373816c729
1 changed files with 59 additions and 6 deletions
|
@ -11,6 +11,19 @@
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
WINE_DEFAULT_DEBUG_CHANNEL(dmenu);
|
||||||
|
|
||||||
|
|
||||||
|
// FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
|
||||||
|
#define MAX_VERB 260
|
||||||
|
|
||||||
|
static HRESULT
|
||||||
|
SHELL_GetRegCLSID(HKEY hKey, LPCWSTR SubKey, LPCWSTR Value, CLSID &clsid)
|
||||||
|
{
|
||||||
|
WCHAR buf[42];
|
||||||
|
DWORD cb = sizeof(buf);
|
||||||
|
DWORD err = RegGetValueW(hKey, SubKey, Value, RRF_RT_REG_SZ, NULL, buf, &cb);
|
||||||
|
return !err ? CLSIDFromString(buf, &clsid) : HRESULT_FROM_WIN32(err);
|
||||||
|
}
|
||||||
|
|
||||||
static inline bool RegValueExists(HKEY hKey, LPCWSTR Name)
|
static inline bool RegValueExists(HKEY hKey, LPCWSTR Name)
|
||||||
{
|
{
|
||||||
return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
|
return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
|
||||||
|
@ -70,7 +83,8 @@ static const struct _StaticInvokeCommandMap_
|
||||||
class CDefaultContextMenu :
|
class CDefaultContextMenu :
|
||||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||||
public IContextMenu3,
|
public IContextMenu3,
|
||||||
public IObjectWithSite
|
public IObjectWithSite,
|
||||||
|
public IServiceProvider
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
CComPtr<IUnknown> m_site;
|
CComPtr<IUnknown> m_site;
|
||||||
|
@ -142,11 +156,18 @@ class CDefaultContextMenu :
|
||||||
STDMETHOD(SetSite)(IUnknown *pUnkSite) override;
|
STDMETHOD(SetSite)(IUnknown *pUnkSite) override;
|
||||||
STDMETHOD(GetSite)(REFIID riid, void **ppvSite) override;
|
STDMETHOD(GetSite)(REFIID riid, void **ppvSite) override;
|
||||||
|
|
||||||
|
// IServiceProvider
|
||||||
|
virtual HRESULT STDMETHODCALLTYPE QueryService(REFGUID svc, REFIID riid, void**ppv)
|
||||||
|
{
|
||||||
|
return IUnknown_QueryService(m_site, svc, riid, ppv);
|
||||||
|
}
|
||||||
|
|
||||||
BEGIN_COM_MAP(CDefaultContextMenu)
|
BEGIN_COM_MAP(CDefaultContextMenu)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu3, IContextMenu3)
|
COM_INTERFACE_ENTRY_IID(IID_IContextMenu3, IContextMenu3)
|
||||||
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
|
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
|
||||||
|
COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
|
||||||
END_COM_MAP()
|
END_COM_MAP()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -531,7 +552,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
||||||
/* By default use verb for menu item name */
|
/* By default use verb for menu item name */
|
||||||
mii.dwTypeData = (LPWSTR)info.Verb.GetString();
|
mii.dwTypeData = (LPWSTR)info.Verb.GetString();
|
||||||
|
|
||||||
WCHAR wszKey[256];
|
WCHAR wszKey[sizeof("shell\\") + MAX_VERB];
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", info.Verb.GetString());
|
hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", info.Verb.GetString());
|
||||||
if (FAILED_UNEXPECTEDLY(hr))
|
if (FAILED_UNEXPECTEDLY(hr))
|
||||||
|
@ -1083,9 +1104,6 @@ PDynamicShellEntry CDefaultContextMenu::GetDynamicEntry(UINT idCmd)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
|
|
||||||
#define MAX_VERB 260
|
|
||||||
|
|
||||||
BOOL
|
BOOL
|
||||||
CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
||||||
{
|
{
|
||||||
|
@ -1141,7 +1159,7 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStatic
|
||||||
CComPtr<IShellBrowser> psb;
|
CComPtr<IShellBrowser> psb;
|
||||||
HWND hwndTree;
|
HWND hwndTree;
|
||||||
LPCWSTR FlagsName;
|
LPCWSTR FlagsName;
|
||||||
WCHAR wszKey[256];
|
WCHAR wszKey[sizeof("shell\\") + MAX_VERB];
|
||||||
HRESULT hr;
|
HRESULT hr;
|
||||||
DWORD wFlags;
|
DWORD wFlags;
|
||||||
DWORD cbVerb;
|
DWORD cbVerb;
|
||||||
|
@ -1260,6 +1278,40 @@ CDefaultContextMenu::InvokeRegVerb(
|
||||||
|
|
||||||
PStaticShellEntry pEntry = &m_StaticEntries.GetAt(it);
|
PStaticShellEntry pEntry = &m_StaticEntries.GetAt(it);
|
||||||
|
|
||||||
|
CRegKey VerbKey;
|
||||||
|
WCHAR VerbKeyPath[sizeof("shell\\") + MAX_VERB];
|
||||||
|
hr = StringCbPrintfW(VerbKeyPath, sizeof(VerbKeyPath), L"shell\\%s", pEntry->Verb.GetString());
|
||||||
|
if (SUCCEEDED(hr) && m_pDataObj &&
|
||||||
|
VerbKey.Open(pEntry->hkClass, VerbKeyPath, KEY_READ) == ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
CLSID clsid;
|
||||||
|
|
||||||
|
DWORD KeyState = 0;
|
||||||
|
if (lpcmi->fMask & CMIC_MASK_SHIFT_DOWN)
|
||||||
|
KeyState |= MK_SHIFT;
|
||||||
|
if (lpcmi->fMask & CMIC_MASK_CONTROL_DOWN)
|
||||||
|
KeyState |= MK_CONTROL;
|
||||||
|
|
||||||
|
POINTL *pPtl = NULL;
|
||||||
|
C_ASSERT(sizeof(POINT) == sizeof(POINTL));
|
||||||
|
if (lpcmi->fMask & CMIC_MASK_PTINVOKE)
|
||||||
|
pPtl = (POINTL*)&lpcmi->ptInvoke;
|
||||||
|
|
||||||
|
// TODO: IExecuteCommand
|
||||||
|
|
||||||
|
CComPtr<IDropTarget> pDT;
|
||||||
|
hr = SHELL_GetRegCLSID(VerbKey, L"DropTarget", L"CLSID", clsid);
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
hr = CoCreateInstance(clsid, NULL, CLSCTX_ALL, IID_PPV_ARG(IDropTarget, &pDT));
|
||||||
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
IUnknown_SetSite(pDT, static_cast<IContextMenu*>(this));
|
||||||
|
hr = SHSimulateDrop(pDT, m_pDataObj, KeyState, pPtl, NULL);
|
||||||
|
IUnknown_SetSite(pDT, NULL);
|
||||||
|
return hr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Get the browse flags to see if we need to browse */
|
/* Get the browse flags to see if we need to browse */
|
||||||
DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
|
DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
|
||||||
|
|
||||||
|
@ -1324,6 +1376,7 @@ CDefaultContextMenu::InvokeCommand(
|
||||||
{
|
{
|
||||||
LocalInvokeInfo.lpVerb -= m_iIdSCMFirst;
|
LocalInvokeInfo.lpVerb -= m_iIdSCMFirst;
|
||||||
Result = InvokeRegVerb(&LocalInvokeInfo);
|
Result = InvokeRegVerb(&LocalInvokeInfo);
|
||||||
|
// TODO: if (FAILED(Result) && !(lpcmi->fMask & CMIC_MASK_FLAG_NO_UI)) SHELL_ErrorBox(m_pSite, Result);
|
||||||
return Result;
|
return Result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue