From 8edf4f092690d0f19460fa339563d153c3772747 Mon Sep 17 00:00:00 2001 From: Whindmar Saksit Date: Sat, 12 Jul 2025 15:18:39 +0200 Subject: [PATCH] [SHELL32][NTOBJSHEX] CDefaultContextMenu cannot close keys it does not own (#8233) --- dll/shellext/ntobjshex/foldercommon.h | 13 +++--- dll/win32/shell32/CDefaultContextMenu.cpp | 22 +++++----- dll/win32/shell32/folders/CDesktopFolder.cpp | 41 +++++------------ dll/win32/shell32/folders/CDrivesFolder.cpp | 10 ++--- dll/win32/shell32/folders/CFSFolder.cpp | 46 +++++--------------- dll/win32/shell32/folders/CNetFolder.cpp | 7 ++- dll/win32/shell32/folders/CRegFolder.cpp | 15 ++----- 7 files changed, 50 insertions(+), 104 deletions(-) diff --git a/dll/shellext/ntobjshex/foldercommon.h b/dll/shellext/ntobjshex/foldercommon.h index fddae8bd1b5..922af5ec6c8 100644 --- a/dll/shellext/ntobjshex/foldercommon.h +++ b/dll/shellext/ntobjshex/foldercommon.h @@ -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; diff --git a/dll/win32/shell32/CDefaultContextMenu.cpp b/dll/win32/shell32/CDefaultContextMenu.cpp index ddbe835528a..af879c59e5f 100644 --- a/dll/win32/shell32/CDefaultContextMenu.cpp +++ b/dll/win32/shell32/CDefaultContextMenu.cpp @@ -299,7 +299,7 @@ class CDefaultContextMenu : UINT m_cidl; PCUITEMID_CHILD_ARRAY m_apidl; CComPtr 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) diff --git a/dll/win32/shell32/folders/CDesktopFolder.cpp b/dll/win32/shell32/folders/CDesktopFolder.cpp index abc6f7a1f04..941e9027dda 100644 --- a/dll/win32/shell32/folders/CDesktopFolder.cpp +++ b/dll/win32/shell32/folders/CDesktopFolder.cpp @@ -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)) diff --git a/dll/win32/shell32/folders/CDrivesFolder.cpp b/dll/win32/shell32/folders/CDrivesFolder.cpp index 1111b502967..e97b4346021 100644 --- a/dll/win32/shell32/folders/CDrivesFolder.cpp +++ b/dll/win32/shell32/folders/CDrivesFolder.cpp @@ -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 diff --git a/dll/win32/shell32/folders/CFSFolder.cpp b/dll/win32/shell32/folders/CFSFolder.cpp index e8cdceb3e9c..deb79400e04 100644 --- a/dll/win32/shell32/folders/CFSFolder.cpp +++ b/dll/win32/shell32/folders/CFSFolder.cpp @@ -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)) { diff --git a/dll/win32/shell32/folders/CNetFolder.cpp b/dll/win32/shell32/folders/CNetFolder.cpp index e557e791dc9..63a3f28738a 100644 --- a/dll/win32/shell32/folders/CNetFolder.cpp +++ b/dll/win32/shell32/folders/CNetFolder.cpp @@ -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)) diff --git a/dll/win32/shell32/folders/CRegFolder.cpp b/dll/win32/shell32/folders/CRegFolder.cpp index 48f47e9df6e..0d08b042f95 100644 --- a/dll/win32/shell32/folders/CRegFolder.cpp +++ b/dll/win32/shell32/folders/CRegFolder.cpp @@ -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! */