mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +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 https://learn.microsoft.com/en-us/previous-versions/windows/desktop/legacy/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);
|
||||
|
||||
|
||||
// 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)
|
||||
{
|
||||
return RegQueryValueExW(hKey, Name, NULL, NULL, NULL, NULL) == ERROR_SUCCESS;
|
||||
|
@ -70,7 +83,8 @@ static const struct _StaticInvokeCommandMap_
|
|||
class CDefaultContextMenu :
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public IContextMenu3,
|
||||
public IObjectWithSite
|
||||
public IObjectWithSite,
|
||||
public IServiceProvider
|
||||
{
|
||||
private:
|
||||
CComPtr<IUnknown> m_site;
|
||||
|
@ -142,11 +156,18 @@ class CDefaultContextMenu :
|
|||
STDMETHOD(SetSite)(IUnknown *pUnkSite) 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)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu, IContextMenu)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu2, IContextMenu2)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IContextMenu3, IContextMenu3)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IObjectWithSite, IObjectWithSite)
|
||||
COM_INTERFACE_ENTRY_IID(IID_IServiceProvider, IServiceProvider)
|
||||
END_COM_MAP()
|
||||
};
|
||||
|
||||
|
@ -531,7 +552,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
|
|||
/* By default use verb for menu item name */
|
||||
mii.dwTypeData = (LPWSTR)info.Verb.GetString();
|
||||
|
||||
WCHAR wszKey[256];
|
||||
WCHAR wszKey[sizeof("shell\\") + MAX_VERB];
|
||||
HRESULT hr;
|
||||
hr = StringCbPrintfW(wszKey, sizeof(wszKey), L"shell\\%s", info.Verb.GetString());
|
||||
if (FAILED_UNEXPECTEDLY(hr))
|
||||
|
@ -1083,9 +1104,6 @@ PDynamicShellEntry CDefaultContextMenu::GetDynamicEntry(UINT idCmd)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
// FIXME: 260 is correct, but should this be part of the SDK or just MAX_PATH?
|
||||
#define MAX_VERB 260
|
||||
|
||||
BOOL
|
||||
CDefaultContextMenu::MapVerbToCmdId(PVOID Verb, PUINT idCmd, BOOL IsUnicode)
|
||||
{
|
||||
|
@ -1141,7 +1159,7 @@ CDefaultContextMenu::BrowserFlagsFromVerb(LPCMINVOKECOMMANDINFOEX lpcmi, PStatic
|
|||
CComPtr<IShellBrowser> psb;
|
||||
HWND hwndTree;
|
||||
LPCWSTR FlagsName;
|
||||
WCHAR wszKey[256];
|
||||
WCHAR wszKey[sizeof("shell\\") + MAX_VERB];
|
||||
HRESULT hr;
|
||||
DWORD wFlags;
|
||||
DWORD cbVerb;
|
||||
|
@ -1260,6 +1278,40 @@ CDefaultContextMenu::InvokeRegVerb(
|
|||
|
||||
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 */
|
||||
DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
|
||||
|
||||
|
@ -1324,6 +1376,7 @@ CDefaultContextMenu::InvokeCommand(
|
|||
{
|
||||
LocalInvokeInfo.lpVerb -= m_iIdSCMFirst;
|
||||
Result = InvokeRegVerb(&LocalInvokeInfo);
|
||||
// TODO: if (FAILED(Result) && !(lpcmi->fMask & CMIC_MASK_FLAG_NO_UI)) SHELL_ErrorBox(m_pSite, Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue