[SHELL32][NTOBJSHEX] CDefaultContextMenu cannot close keys it does not own (#8233)

This commit is contained in:
Whindmar Saksit 2025-07-12 15:18:39 +02:00 committed by GitHub
parent 3fb2905c37
commit 8edf4f0926
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 50 additions and 104 deletions

View file

@ -422,7 +422,7 @@ public:
LPCITEMIDLIST child;
int nkeys = _countof(keys);
UINT nkeys = 0;
if (cidl == 1 && IsSymLink(apidl[0]))
{
const TItemId * info;
@ -452,16 +452,15 @@ public:
if (cidl == 1 && IsFolder(apidl[0]))
{
res = RegOpenKey(HKEY_CLASSES_ROOT, L"Folder", keys + 0);
res = RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Folder", 0, KEY_READ, &keys[0]);
if (!NT_SUCCESS(res))
return HRESULT_FROM_NT(res);
}
else
{
nkeys = 0;
return HRESULT_FROM_WIN32(res);
nkeys++;
}
HRESULT hr = CDefFolderMenu_Create2(parent, hwndOwner, cidl, apidl, psfParent, DefCtxMenuCallback, nkeys, keys, &pcm);
for (UINT i = 0; i < nkeys; ++i)
RegCloseKey(keys[i]);
if (FAILED_UNEXPECTEDLY(hr))
return hr;

View file

@ -299,7 +299,7 @@ class CDefaultContextMenu :
UINT m_cidl;
PCUITEMID_CHILD_ARRAY m_apidl;
CComPtr<IDataObject> m_pDataObj;
HKEY* m_aKeys;
HKEY m_aKeys[16]; // This limit is documented for both the old API and for DEFCONTEXTMENU
UINT m_cKeys;
PIDLIST_ABSOLUTE m_pidlFolder;
DWORD m_bGroupPolicyActive;
@ -387,8 +387,7 @@ CDefaultContextMenu::CDefaultContextMenu() :
m_cidl(0),
m_apidl(NULL),
m_pDataObj(NULL),
m_aKeys(NULL),
m_cKeys(NULL),
m_cKeys(0),
m_pidlFolder(NULL),
m_bGroupPolicyActive(0),
m_iIdQCMFirst(0),
@ -417,7 +416,6 @@ CDefaultContextMenu::~CDefaultContextMenu()
for (UINT i = 0; i < m_cKeys; i++)
RegCloseKey(m_aKeys[i]);
HeapFree(GetProcessHeap(), 0, m_aKeys);
if (m_pidlFolder)
CoTaskMemFree(m_pidlFolder);
@ -428,6 +426,7 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm, LPFND
{
TRACE("cidl %u\n", pdcm->cidl);
HRESULT hr = S_OK;
if (!pdcm->pcmcb && !lpfn)
{
ERR("CDefaultContextMenu needs a callback!\n");
@ -443,13 +442,14 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm, LPFND
m_pfnmcb = lpfn;
m_hwnd = pdcm->hwnd;
m_cKeys = pdcm->cKeys;
if (pdcm->cKeys)
for (UINT i = 0; i < pdcm->cKeys; ++i)
{
m_aKeys = (HKEY*)HeapAlloc(GetProcessHeap(), 0, sizeof(HKEY) * pdcm->cKeys);
if (!m_aKeys)
return E_OUTOFMEMORY;
memcpy(m_aKeys, pdcm->aKeys, sizeof(HKEY) * pdcm->cKeys);
if (i >= _countof(m_aKeys))
hr = E_INVALIDARG;
else if ((m_aKeys[i] = SHRegDuplicateHKey(pdcm->aKeys[i])) != NULL)
m_cKeys++;
else
hr = E_OUTOFMEMORY;
}
m_psf->GetUIObjectOf(pdcm->hwnd, m_cidl, m_apidl, IID_NULL_PPV_ARG(IDataObject, &m_pDataObj));
@ -469,7 +469,7 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm, LPFND
TRACE("pidlFolder %p\n", m_pidlFolder);
}
return S_OK;
return hr;
}
HRESULT CDefaultContextMenu::_DoCallback(UINT uMsg, WPARAM wParam, LPVOID lParam)

View file

@ -657,21 +657,10 @@ HRESULT WINAPI CDesktopFolder::CreateViewObject(
}
else if (IsEqualIID (riid, IID_IContextMenu))
{
HKEY hKeys[16];
UINT cKeys = 0;
AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
DEFCONTEXTMENU dcm;
dcm.hwnd = hwndOwner;
dcm.pcmcb = this;
dcm.pidlFolder = pidlRoot;
dcm.psf = this;
dcm.cidl = 0;
dcm.apidl = NULL;
dcm.cKeys = cKeys;
dcm.aKeys = hKeys;
dcm.punkAssociationInfo = NULL;
hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
CRegKeyHandleArray keys;
AddClassKeyToArray(L"Directory\\Background", keys, keys);
DEFCONTEXTMENU dcm = { hwndOwner, this, pidlRoot, this, 0, NULL, NULL, keys, keys };
hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
}
else if (IsEqualIID (riid, IID_IShellView))
{
@ -795,29 +784,19 @@ HRESULT WINAPI CDesktopFolder::GetUIObjectOf(
/* Do not use the context menu of the CFSFolder here. */
/* We need to pass a pointer of the CDesktopFolder so as the data object that the context menu gets is rooted to the desktop */
/* Otherwise operations like that involve items from both user and shared desktop will not work */
HKEY hKeys[16];
UINT cKeys = 0;
CRegKeyHandleArray keys;
if (self)
{
AddClsidKeyToArray(CLSID_ShellDesktop, hKeys, &cKeys);
AddClassKeyToArray(L"Folder", hKeys, &cKeys);
AddClsidKeyToArray(CLSID_ShellDesktop, keys, keys);
AddClassKeyToArray(L"Folder", keys, keys);
}
else if (cidl > 0)
{
AddFSClassKeysToArray(cidl, apidl, hKeys, &cKeys);
AddFSClassKeysToArray(cidl, apidl, keys, keys);
}
DEFCONTEXTMENU dcm;
dcm.hwnd = hwndOwner;
dcm.pcmcb = this;
dcm.pidlFolder = pidlRoot;
dcm.psf = this;
dcm.cidl = cidl;
dcm.apidl = apidl;
dcm.cKeys = cKeys;
dcm.aKeys = hKeys;
dcm.punkAssociationInfo = NULL;
hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
DEFCONTEXTMENU dcm = { hwndOwner, this, pidlRoot, this, cidl, apidl, NULL, keys, keys };
hr = SHCreateDefaultContextMenu(&dcm, riid, &pObj);
}
}
else if (IsEqualIID (riid, IID_IDataObject) && (cidl >= 1))

View file

@ -459,12 +459,10 @@ HRESULT CDrivesContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
IShellFolder *psf,
IContextMenu **ppcm)
{
HKEY hKeys[2];
UINT cKeys = 0;
AddClassKeyToArray(L"Drive", hKeys, &cKeys);
AddClassKeyToArray(L"Folder", hKeys, &cKeys);
return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, cKeys, hKeys, ppcm);
CRegKeyHandleArray keys;
AddClassKeyToArray(L"Drive", keys, keys);
AddClassKeyToArray(L"Folder", keys, keys);
return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, DrivesContextMenuCallback, keys, keys, ppcm);
}
static HRESULT

View file

@ -1237,29 +1237,18 @@ HRESULT WINAPI CFSFolder::CreateViewObject(HWND hwndOwner,
{
hr = CFSDropTarget_CreateInstance(m_sPathTarget, riid, ppvOut);
}
else if (IsEqualIID (riid, IID_IContextMenu))
{
HKEY hKeys[16];
UINT cKeys = 0;
AddClassKeyToArray(L"Directory\\Background", hKeys, &cKeys);
DEFCONTEXTMENU dcm;
dcm.hwnd = hwndOwner;
dcm.pcmcb = this;
dcm.pidlFolder = m_pidlRoot;
dcm.psf = this;
dcm.cidl = 0;
dcm.apidl = NULL;
dcm.cKeys = cKeys;
dcm.aKeys = hKeys;
dcm.punkAssociationInfo = NULL;
hr = SHCreateDefaultContextMenu (&dcm, riid, ppvOut);
}
else if (bIsShellView)
{
SFV_CREATE sfvparams = {sizeof(SFV_CREATE), this, NULL, this};
SFV_CREATE sfvparams = { sizeof(SFV_CREATE), this, NULL, this };
hr = SHCreateShellFolderView(&sfvparams, (IShellView**)ppvOut);
}
else if (IsEqualIID(riid, IID_IContextMenu))
{
CRegKeyHandleArray keys;
AddClassKeyToArray(L"Directory\\Background", keys, keys);
DEFCONTEXTMENU dcm = { hwndOwner, this, m_pidlRoot, this, 0, NULL, NULL, keys, keys };
hr = SHCreateDefaultContextMenu(&dcm, riid, ppvOut);
}
else
{
hr = E_INVALIDARG;
@ -1383,21 +1372,10 @@ HRESULT WINAPI CFSFolder::GetUIObjectOf(HWND hwndOwner,
if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
{
HKEY hKeys[16];
UINT cKeys = 0;
AddFSClassKeysToArray(cidl, apidl, hKeys, &cKeys);
DEFCONTEXTMENU dcm;
dcm.hwnd = hwndOwner;
dcm.pcmcb = this;
dcm.pidlFolder = m_pidlRoot;
dcm.psf = this;
dcm.cidl = cidl;
dcm.apidl = apidl;
dcm.cKeys = cKeys;
dcm.aKeys = hKeys;
dcm.punkAssociationInfo = NULL;
hr = SHCreateDefaultContextMenu (&dcm, riid, &pObj);
CRegKeyHandleArray keys;
AddFSClassKeysToArray(cidl, apidl, keys, keys);
DEFCONTEXTMENU dcm = { hwndOwner, this, m_pidlRoot, this, cidl, apidl, NULL, keys, keys };
hr = SHCreateDefaultContextMenu(&dcm, riid, &pObj);
}
else if (IsEqualIID (riid, IID_IDataObject))
{

View file

@ -435,11 +435,10 @@ HRESULT WINAPI CNetFolder::GetUIObjectOf(HWND hwndOwner, UINT cidl, PCUITEMID_CH
if (IsEqualIID(riid, IID_IContextMenu) && (cidl >= 1))
{
CRegKeyHandleArray keys;
IContextMenu * pCm = NULL;
HKEY hkey;
UINT cKeys = 0;
AddClassKeyToArray(L"Folder", &hkey, &cKeys);
hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, this, NetFolderMenuCallback, cKeys, &hkey, &pCm);
AddClassKeyToArray(L"Folder", keys, keys);
hr = CDefFolderMenu_Create2(pidlRoot, hwndOwner, cidl, apidl, this, NetFolderMenuCallback, keys, keys, &pCm);
pObj = pCm;
}
else if (IsEqualIID(riid, IID_IDataObject) && (cidl >= 1))

View file

@ -972,17 +972,10 @@ static HRESULT CALLBACK RegFolderContextMenuCallback(IShellFolder *psf, HWND hwn
static HRESULT CRegItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder, HWND hwnd, UINT cidl,
PCUITEMID_CHILD_ARRAY apidl, IShellFolder *psf, IContextMenu **ppcm)
{
HKEY hKeys[3];
UINT cKeys = 0;
CRegKeyHandleArray keys;
const GUID *pGuid = _ILGetGUIDPointer(apidl[0]);
if (pGuid)
{
WCHAR key[sizeof("CLSID\\") + 38];
wcscpy(key, L"CLSID\\");
StringFromGUID2(*pGuid, &key[6], 39);
AddClassKeyToArray(key, hKeys, &cKeys);
}
AddClsidKeyToArray(*pGuid, keys, keys);
// FIXME: CRegFolder should be aggregated by its outer folder and should
// provide the attributes for all required non-registry folders.
@ -993,9 +986,9 @@ static HRESULT CRegItemContextMenu_CreateInstance(PCIDLIST_ABSOLUTE pidlFolder,
SFGAOF att = (psf && cidl) ? SHGetAttributes(pOuterSF ? pOuterSF.p : psf, apidl[0], SFGAO_FOLDER) : 0;
if ((att & SFGAO_FOLDER) && (!pGuid || !HasCLSIDShellFolderValue(*pGuid, L"HideFolderVerbs")))
AddClassKeyToArray(L"Folder", hKeys, &cKeys);
AddClassKeyToArray(L"Folder", keys, keys);
return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, cKeys, hKeys, ppcm);
return CDefFolderMenu_Create2(pidlFolder, hwnd, cidl, apidl, psf, RegFolderContextMenuCallback, keys, keys, ppcm);
}
/* In latest windows version this is exported but it takes different arguments! */