mirror of
https://github.com/reactos/reactos.git
synced 2025-08-04 16:35:49 +00:00
[SHELL32] Implement DragDropHandlers shell extension context menus (#8143)
CORE-11240 CORE-11238
This commit is contained in:
parent
06414ac85a
commit
59e556f3f3
11 changed files with 234 additions and 13 deletions
|
@ -32,6 +32,112 @@ static BOOL InsertMenuItemAt(HMENU hMenu, UINT Pos, UINT Flags)
|
|||
return InsertMenuItemW(hMenu, Pos, TRUE, &mii);
|
||||
}
|
||||
|
||||
static void DCMA_DestroyEntry(DCMENTRY &dcme)
|
||||
{
|
||||
if (!dcme.pCM)
|
||||
return;
|
||||
IUnknown_SetSite(dcme.pCM, NULL);
|
||||
dcme.pCM->Release();
|
||||
dcme.pCM = NULL;
|
||||
}
|
||||
|
||||
void DCMA_Destroy(HDCMA hDCMA)
|
||||
{
|
||||
UINT i = 0;
|
||||
for (DCMENTRY *p; (p = DCMA_GetEntry(hDCMA, i)) != NULL; ++i)
|
||||
DCMA_DestroyEntry(*p);
|
||||
DSA_Destroy(hDCMA);
|
||||
}
|
||||
|
||||
UINT DCMA_InsertMenuItems(
|
||||
_In_ HDCMA hDCMA,
|
||||
_In_ HDCIA hDCIA,
|
||||
_In_opt_ LPCITEMIDLIST pidlFolder,
|
||||
_In_opt_ IDataObject *pDO,
|
||||
_In_opt_ HKEY *pKeys,
|
||||
_In_opt_ UINT nKeys,
|
||||
_In_ QCMINFO *pQCMI,
|
||||
_In_opt_ UINT fCmf,
|
||||
_In_opt_ IUnknown *pUnkSite)
|
||||
{
|
||||
UINT idCmdBase = pQCMI->idCmdFirst, idCmdFirst = idCmdBase;
|
||||
UINT nOffset = 0;
|
||||
|
||||
// Insert in reverse order
|
||||
for (int iCls = DCIA_GetCount(hDCIA) - 1; iCls >= 0; --iCls)
|
||||
{
|
||||
REFCLSID clsid = *DCIA_GetEntry(hDCIA, iCls);
|
||||
if (fCmf & CMF_DEFAULTONLY)
|
||||
{
|
||||
WCHAR szKey[MAX_PATH];
|
||||
wcscpy(szKey, L"CLSID\\");
|
||||
StringFromGUID2(clsid, szKey + _countof(L"CLSID\\") - 1, CHARS_IN_GUID);
|
||||
wcscpy(szKey + _countof(L"CLSID\\") - 1 + CHARS_IN_GUID - 1, L"\\shellex\\MayChangeDefaultMenu");
|
||||
if (!RegKeyExists(HKEY_CLASSES_ROOT, szKey))
|
||||
continue;
|
||||
}
|
||||
|
||||
for (UINT iKey = 0; iKey < nKeys; ++iKey)
|
||||
{
|
||||
CComPtr<IShellExtInit> pInit;
|
||||
HRESULT hr = SHExtCoCreateInstance(NULL, &clsid, NULL, IID_PPV_ARG(IShellExtInit, &pInit));
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
if (FAILED(hr = pInit->Initialize(pidlFolder, pDO, pKeys[iKey])))
|
||||
continue;
|
||||
|
||||
IContextMenu *pCM;
|
||||
if (FAILED(hr = pInit->QueryInterface(IID_PPV_ARG(IContextMenu, &pCM))))
|
||||
break;
|
||||
IUnknown_SetSite(pCM, pUnkSite);
|
||||
|
||||
hr = pCM->QueryContextMenu(pQCMI->hmenu, pQCMI->indexMenu + nOffset, idCmdFirst, pQCMI->idCmdLast, fCmf);
|
||||
const UINT nCount = HRESULT_CODE(hr);
|
||||
const UINT idThisFirst = idCmdFirst - idCmdBase;
|
||||
DCMENTRY dcme = { pCM, idThisFirst, idThisFirst + nCount - 1 };
|
||||
if (hr > 0)
|
||||
{
|
||||
idCmdFirst += nCount;
|
||||
if (DSA_AppendItem(hDCMA, &dcme) >= 0)
|
||||
{
|
||||
if (nOffset == 0 && GetMenuDefaultItem(pQCMI->hmenu, TRUE, 0) == 0)
|
||||
nOffset++; // Insert new items below the default
|
||||
break;
|
||||
}
|
||||
}
|
||||
DCMA_DestroyEntry(dcme);
|
||||
}
|
||||
}
|
||||
return idCmdFirst;
|
||||
}
|
||||
|
||||
HRESULT DCMA_InvokeCommand(HDCMA hDCMA, CMINVOKECOMMANDINFO *pICI)
|
||||
{
|
||||
HRESULT hr = S_FALSE;
|
||||
for (UINT i = 0;; ++i)
|
||||
{
|
||||
DCMENTRY *p = DCMA_GetEntry(hDCMA, i);
|
||||
if (!p)
|
||||
return hr;
|
||||
|
||||
UINT id = LOWORD(pICI->lpVerb);
|
||||
if (!IS_INTRESOURCE(pICI->lpVerb))
|
||||
{
|
||||
if (SUCCEEDED(hr = p->pCM->InvokeCommand(pICI)))
|
||||
return hr;
|
||||
}
|
||||
else if (id >= p->idCmdFirst && id <= p->idCmdLast)
|
||||
{
|
||||
CMINVOKECOMMANDINFOEX ici;
|
||||
CopyMemory(&ici, pICI, min(sizeof(ici), pICI->cbSize));
|
||||
ici.cbSize = min(sizeof(ici), pICI->cbSize);
|
||||
ici.lpVerb = MAKEINTRESOURCEA(id - p->idCmdFirst);
|
||||
ici.lpVerbW = (PWSTR)ici.lpVerb;
|
||||
return p->pCM->InvokeCommand((CMINVOKECOMMANDINFO*)&ici);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
typedef struct _DynamicShellEntry_
|
||||
{
|
||||
UINT iIdCmdFirst;
|
||||
|
|
|
@ -237,7 +237,6 @@ HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, D
|
|||
HMENU hmenu = LoadMenuW(shell32_hInstance, MAKEINTRESOURCEW(IDM_DRAGFILE));
|
||||
if (!hmenu)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
HMENU hpopupmenu = GetSubMenu(hmenu, 0);
|
||||
|
||||
SHELL_LimitDropEffectToItemAttributes(pDataObject, &dwAvailableEffects);
|
||||
|
@ -256,7 +255,19 @@ HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, D
|
|||
else if (dwAvailableEffects & DROPEFFECT_LINK)
|
||||
SetMenuDefaultItem(hpopupmenu, IDM_LINKHERE, FALSE);
|
||||
|
||||
/* FIXME: We need to support shell extensions here */
|
||||
CRegKeyHandleArray keys;
|
||||
HDCIA hDCIA = DCIA_Create();
|
||||
HDCMA hDCMA = DCMA_Create();
|
||||
CComHeapPtr<ITEMIDLIST_ABSOLUTE> pidlFolder(SHELL32_CreateSimpleIDListFromPath(m_sPathTarget, FILE_ATTRIBUTE_DIRECTORY));
|
||||
if (hDCMA && hDCIA && pidlFolder)
|
||||
{
|
||||
AddPidlClassKeysToArray(pidlFolder, keys, keys);
|
||||
for (UINT i = 0; i < keys; ++i)
|
||||
DCIA_AddShellExSubkey(hDCIA, keys[i], L"DragDropHandlers");
|
||||
|
||||
QCMINFO qcmi = { hpopupmenu, 0, DROPIDM_EXTFIRST, DROPIDM_EXTLAST };
|
||||
DCMA_InsertMenuItems(hDCMA, hDCIA, pidlFolder, pDataObject, keys, keys, &qcmi, 0, m_site);
|
||||
}
|
||||
|
||||
/* We shouldn't use the site window here because the menu should work even when we don't have a site */
|
||||
HWND hwndDummy = CreateWindowEx(0,
|
||||
|
@ -279,16 +290,39 @@ HRESULT CFSDropTarget::_GetEffectFromMenu(IDataObject *pDataObject, POINTL pt, D
|
|||
|
||||
DestroyWindow(hwndDummy);
|
||||
|
||||
if (uCommand == 0)
|
||||
return S_FALSE;
|
||||
HRESULT hr = S_FALSE; // S_FALSE means we did not handle the command
|
||||
C_ASSERT(IDM_COPYHERE < DROPIDM_EXTFIRST && IDM_MOVEHERE < DROPIDM_EXTFIRST &&
|
||||
IDM_LINKHERE < DROPIDM_EXTFIRST && DROPIDM_EXTFIRST > 0);
|
||||
if (uCommand >= DROPIDM_EXTFIRST && uCommand <= DROPIDM_EXTLAST)
|
||||
{
|
||||
CMINVOKECOMMANDINFO ici = { sizeof(ici), 0, m_hwndSite, MAKEINTRESOURCEA(uCommand - DROPIDM_EXTFIRST) };
|
||||
ici.nShow = SW_SHOW;
|
||||
if (m_grfKeyState & MK_SHIFT)
|
||||
ici.fMask |= CMIC_MASK_SHIFT_DOWN;
|
||||
if (m_grfKeyState & MK_CONTROL)
|
||||
ici.fMask |= CMIC_MASK_CONTROL_DOWN;
|
||||
DCMA_InvokeCommand(hDCMA, &ici);
|
||||
hr = S_OK;
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
else if (uCommand == 0)
|
||||
{
|
||||
hr = S_OK;
|
||||
*pdwEffect = DROPEFFECT_NONE;
|
||||
}
|
||||
else if (uCommand == IDM_COPYHERE)
|
||||
*pdwEffect = DROPEFFECT_COPY;
|
||||
else if (uCommand == IDM_MOVEHERE)
|
||||
*pdwEffect = DROPEFFECT_MOVE;
|
||||
else if (uCommand == IDM_LINKHERE)
|
||||
*pdwEffect = DROPEFFECT_LINK;
|
||||
else
|
||||
hr = E_UNEXPECTED;
|
||||
|
||||
return S_OK;
|
||||
DCMA_Destroy(hDCMA);
|
||||
DCIA_Destroy(hDCIA);
|
||||
DestroyMenu(hmenu);
|
||||
return hr;
|
||||
}
|
||||
|
||||
HRESULT CFSDropTarget::_RepositionItems(IShellFolderView *psfv, IDataObject *pdtobj, POINTL pt)
|
||||
|
@ -461,7 +495,7 @@ HRESULT WINAPI CFSDropTarget::Drop(IDataObject *pDataObject,
|
|||
if (m_grfKeyState & MK_RBUTTON)
|
||||
{
|
||||
HRESULT hr = _GetEffectFromMenu(pDataObject, pt, pdwEffect, dwAvailableEffects);
|
||||
if (FAILED_UNEXPECTEDLY(hr) || hr == S_FALSE)
|
||||
if (FAILED_UNEXPECTEDLY(hr) || hr == S_OK)
|
||||
return hr;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,6 +23,9 @@
|
|||
#ifndef _CFSDROPTARGET_H_
|
||||
#define _CFSDROPTARGET_H_
|
||||
|
||||
#define DROPIDM_EXTFIRST 100
|
||||
#define DROPIDM_EXTLAST 0x7fff
|
||||
|
||||
class CFSDropTarget :
|
||||
public CComObjectRootEx<CComMultiThreadModelNoCS>,
|
||||
public IDropTarget,
|
||||
|
|
|
@ -179,6 +179,30 @@ SHELL32_ShowShellExtensionProperties(const CLSID *pClsid, IDataObject *pDO);
|
|||
HRESULT
|
||||
SHELL_ShowItemIDListProperties(LPCITEMIDLIST pidl);
|
||||
|
||||
typedef HDSA HDCMA; // DynamicContextMenuArray
|
||||
typedef struct _DCMENTRY
|
||||
{
|
||||
IContextMenu *pCM;
|
||||
UINT idCmdFirst;
|
||||
UINT idCmdLast;
|
||||
} DCMENTRY;
|
||||
#define DCMA_Create() ( (HDCMA)DSA_Create(sizeof(DCMENTRY), 4) )
|
||||
void DCMA_Destroy(HDCMA hDCMA);
|
||||
#define DCMA_GetEntry(hDCMA, iItem) ( (DCMENTRY*)DSA_GetItemPtr((HDSA)(hDCMA), (iItem)) )
|
||||
HRESULT DCMA_InvokeCommand(HDCMA hDCMA, CMINVOKECOMMANDINFO *pICI);
|
||||
|
||||
UINT
|
||||
DCMA_InsertMenuItems(
|
||||
_In_ HDCMA hDCMA,
|
||||
_In_ HDCIA hDCIA,
|
||||
_In_opt_ LPCITEMIDLIST pidlFolder,
|
||||
_In_opt_ IDataObject *pDO,
|
||||
_In_opt_ HKEY *pKeys,
|
||||
_In_opt_ UINT nKeys,
|
||||
_In_ QCMINFO *pQCMI,
|
||||
_In_opt_ UINT fCmf,
|
||||
_In_opt_ IUnknown *pUnkSite);
|
||||
|
||||
HRESULT
|
||||
SHELL32_DefaultContextMenuCallBack(IShellFolder *psf, IDataObject *pdo, UINT msg);
|
||||
UINT
|
||||
|
|
|
@ -9,17 +9,17 @@
|
|||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
||||
|
||||
static HRESULT
|
||||
SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID &clsid)
|
||||
HRESULT
|
||||
SHELL_GetShellExtensionRegCLSID(HKEY hKey, LPCWSTR KeyName, CLSID *pClsId)
|
||||
{
|
||||
// First try the key name
|
||||
if (SUCCEEDED(SHCLSIDFromStringW(KeyName, &clsid)))
|
||||
if (SUCCEEDED(SHCLSIDFromStringW(KeyName, pClsId)))
|
||||
return S_OK;
|
||||
WCHAR buf[42];
|
||||
DWORD cb = sizeof(buf);
|
||||
// and then the default value
|
||||
DWORD err = RegGetValueW(hKey, KeyName, NULL, RRF_RT_REG_SZ, NULL, buf, &cb);
|
||||
return !err ? SHCLSIDFromStringW(buf, &clsid) : HRESULT_FROM_WIN32(err);
|
||||
return !err ? SHCLSIDFromStringW(buf, pClsId) : HRESULT_FROM_WIN32(err);
|
||||
}
|
||||
|
||||
static HRESULT
|
||||
|
@ -148,7 +148,7 @@ SHELL32_OpenPropSheet(LPCWSTR pszCaption, HKEY *ahKeys, UINT cKeys,
|
|||
if (err)
|
||||
break;
|
||||
CLSID clsid;
|
||||
if (SUCCEEDED(SHELL_GetShellExtensionRegCLSID(hKey, KeyName, clsid)))
|
||||
if (SUCCEEDED(SHELL_GetShellExtensionRegCLSID(hKey, KeyName, &clsid)))
|
||||
AddPropSheetHandlerPages(clsid, pDO, hKeyProgID, psh);
|
||||
}
|
||||
RegCloseKey(hKey);
|
||||
|
|
|
@ -466,5 +466,5 @@
|
|||
754 stub -noname SHLimitInputEditWithFlags
|
||||
755 stdcall -noname PathIsEqualOrSubFolder(wstr wstr)
|
||||
756 stub -noname DeleteFileThumbnail
|
||||
757 stdcall -version=0x600+ DisplayNameOfW(ptr ptr long ptr long)
|
||||
866 stdcall -version=0x600+ SHExtCoCreateInstance(wstr ptr ptr ptr ptr)
|
||||
757 stdcall -noname -version=0x600+ DisplayNameOfW(ptr ptr long ptr long)
|
||||
866 stdcall -noname -version=0x600+ SHExtCoCreateInstance(wstr ptr ptr ptr ptr)
|
||||
|
|
|
@ -184,6 +184,7 @@ void CloseRegKeyArray(HKEY* array, UINT cKeys);
|
|||
LSTATUS AddClassKeyToArray(const WCHAR* szClass, HKEY* array, UINT* cKeys);
|
||||
LSTATUS AddClsidKeyToArray(REFCLSID clsid, HKEY* array, UINT* cKeys);
|
||||
void AddFSClassKeysToArray(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, HKEY* array, UINT* cKeys);
|
||||
void AddPidlClassKeysToArray(LPCITEMIDLIST pidl, HKEY* array, UINT* cKeys);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
|
|
|
@ -490,12 +490,23 @@ void AddFSClassKeysToArray(UINT cidl, PCUITEMID_CHILD_ARRAY apidl, HKEY* array,
|
|||
AddClassKeyToArray(L"AllFilesystemObjects", array, cKeys);
|
||||
AddClassKeyToArray(L"Directory", array, cKeys);
|
||||
}
|
||||
else if (_ILIsDrive(pidl))
|
||||
{
|
||||
AddClassKeyToArray(L"Drive", array, cKeys);
|
||||
AddClassKeyToArray(L"Folder", array, cKeys);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERR("Got non FS pidl\n");
|
||||
}
|
||||
}
|
||||
|
||||
void AddPidlClassKeysToArray(LPCITEMIDLIST pidl, HKEY* array, UINT* cKeys)
|
||||
{
|
||||
if ((pidl = ILFindLastID(pidl)) != NULL)
|
||||
AddFSClassKeysToArray(1, &pidl, array, cKeys);
|
||||
}
|
||||
|
||||
HRESULT SH_GetApidlFromDataObject(IDataObject *pDataObject, PIDLIST_ABSOLUTE* ppidlfolder, PUITEMID_CHILD **apidlItems, UINT *pcidl)
|
||||
{
|
||||
CDataObjectHIDA cida(pDataObject);
|
||||
|
|
|
@ -1836,6 +1836,35 @@ SHELL_CreateShell32DefaultExtractIcon(int IconIndex, REFIID riid, LPVOID *ppvOut
|
|||
return initIcon->QueryInterface(riid, ppvOut);
|
||||
}
|
||||
|
||||
int DCIA_AddEntry(HDCIA hDCIA, REFCLSID rClsId)
|
||||
{
|
||||
for (UINT i = 0;; ++i)
|
||||
{
|
||||
const CLSID *pClsId = DCIA_GetEntry(hDCIA, i);
|
||||
if (!pClsId)
|
||||
break;
|
||||
if (IsEqualGUID(*pClsId, rClsId))
|
||||
return i; // Don't allow duplicates
|
||||
}
|
||||
return DSA_AppendItem((HDSA)hDCIA, const_cast<CLSID*>(&rClsId));
|
||||
}
|
||||
|
||||
void DCIA_AddShellExSubkey(HDCIA hDCIA, HKEY hProgId, PCWSTR pszSubkey)
|
||||
{
|
||||
WCHAR szKey[200];
|
||||
PathCombineW(szKey, L"shellex", pszSubkey);
|
||||
HKEY hEnum;
|
||||
if (RegOpenKeyExW(hProgId, szKey, 0, KEY_READ, &hEnum) != ERROR_SUCCESS)
|
||||
return;
|
||||
for (UINT i = 0; RegEnumKeyW(hEnum, i++, szKey, _countof(szKey)) == ERROR_SUCCESS;)
|
||||
{
|
||||
CLSID clsid;
|
||||
if (SUCCEEDED(SHELL_GetShellExtensionRegCLSID(hEnum, szKey, &clsid)))
|
||||
DCIA_AddEntry(hDCIA, clsid);
|
||||
}
|
||||
RegCloseKey(hEnum);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* SHIsBadInterfacePtr [SHELL32.84]
|
||||
*
|
||||
|
|
|
@ -120,6 +120,14 @@ SHELL_CreateFallbackExtractIconForNoAssocFile(REFIID riid, LPVOID *ppvOut)
|
|||
return SHELL_CreateShell32DefaultExtractIcon(id > 1 ? -id : 0, riid, ppvOut);
|
||||
}
|
||||
|
||||
typedef HDSA HDCIA; // DynamicClassIdArray
|
||||
#define DCIA_Create() ( (HDCIA)DSA_Create(sizeof(CLSID), 4) )
|
||||
#define DCIA_Destroy(hDCIA) DSA_Destroy((HDSA)(hDCIA))
|
||||
#define DCIA_GetCount(hDCIA) DSA_GetItemCount((HDSA)(hDCIA))
|
||||
#define DCIA_GetEntry(hDCIA, iItem) ( (const CLSID*)DSA_GetItemPtr((HDSA)(hDCIA), (iItem)) )
|
||||
int DCIA_AddEntry(HDCIA hDCIA, REFCLSID rClsId);
|
||||
void DCIA_AddShellExSubkey(HDCIA hDCIA, HKEY hProgId, PCWSTR pszSubkey);
|
||||
|
||||
#ifdef __cplusplus
|
||||
struct ClipboardViewerChain
|
||||
{
|
||||
|
|
|
@ -133,6 +133,11 @@ HGLOBAL RenderSHELLIDLIST (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cid
|
|||
HGLOBAL RenderFILENAMEA (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
|
||||
HGLOBAL RenderFILENAMEW (LPITEMIDLIST pidlRoot, LPITEMIDLIST * apidl, UINT cidl) DECLSPEC_HIDDEN;
|
||||
|
||||
HRESULT SHELL_GetShellExtensionRegCLSID(
|
||||
HKEY hKey,
|
||||
LPCWSTR KeyName,
|
||||
CLSID *pClsId);
|
||||
|
||||
/* Change Notification */
|
||||
void InitChangeNotifications(void) DECLSPEC_HIDDEN;
|
||||
void FreeChangeNotifications(void) DECLSPEC_HIDDEN;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue