[SHELL32]

- Correctly manage object lifetime in CDefaultContextMenu. Members of DEFCONTEXTMENU need to be referenced or cloned in order to keep them.
CORE-8430 #resolve

svn path=/trunk/; revision=63884
This commit is contained in:
Thomas Faber
2014-08-14 19:47:45 +00:00
parent ccacbf8050
commit 6acec73b44
+77 -65
View File
@@ -37,9 +37,11 @@ class CDefaultContextMenu :
public IContextMenu2
{
private:
DEFCONTEXTMENU m_Dcm;
IShellFolder *m_psf;
UINT m_cidl;
PCUITEMID_CHILD_ARRAY m_apidl;
IDataObject *m_pDataObj;
LPCITEMIDLIST m_pidlFolder;
PIDLIST_ABSOLUTE m_pidlFolder;
DWORD m_bGroupPolicyActive;
PDynamicShellEntry m_pDynamicEntries; /* first dynamic shell extension entry */
UINT m_iIdSHEFirst; /* first used id */
@@ -92,18 +94,20 @@ class CDefaultContextMenu :
END_COM_MAP()
};
CDefaultContextMenu::CDefaultContextMenu()
CDefaultContextMenu::CDefaultContextMenu() :
m_psf(NULL),
m_cidl(0),
m_apidl(NULL),
m_pDataObj(NULL),
m_pidlFolder(NULL),
m_bGroupPolicyActive(0),
m_pDynamicEntries(NULL),
m_iIdSHEFirst(0),
m_iIdSHELast(0),
m_pStaticEntries(NULL),
m_iIdSCMFirst(0),
m_iIdSCMLast(0)
{
memset(&m_Dcm, 0, sizeof(m_Dcm));
m_pDataObj = NULL;
m_pidlFolder = NULL;
m_bGroupPolicyActive = 0;
m_pDynamicEntries = NULL;
m_iIdSHEFirst = 0;
m_iIdSHELast = 0;
m_pStaticEntries = NULL;
m_iIdSCMFirst = 0;
m_iIdSCMLast = 0;
}
CDefaultContextMenu::~CDefaultContextMenu()
@@ -130,9 +134,12 @@ CDefaultContextMenu::~CDefaultContextMenu()
}
if (m_pidlFolder)
ILFree((_ITEMIDLIST*)m_pidlFolder);
CoTaskMemFree(m_pidlFolder);
if (m_pDataObj)
m_pDataObj->Release();
_ILFreeaPidl(const_cast<PITEMID_CHILD *>(m_apidl), m_cidl);
if (m_psf)
m_psf->Release();
}
HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
@@ -140,28 +147,33 @@ HRESULT WINAPI CDefaultContextMenu::Initialize(const DEFCONTEXTMENU *pdcm)
IDataObject *pDataObj;
TRACE("cidl %u\n", pdcm->cidl);
m_cidl = pdcm->cidl;
m_apidl = const_cast<PCUITEMID_CHILD_ARRAY>(_ILCopyaPidl(pdcm->apidl, m_cidl));
if (!m_apidl)
return E_OUTOFMEMORY;
m_psf = pdcm->psf;
m_psf->AddRef();
if (SUCCEEDED(SHCreateDataObject(pdcm->pidlFolder, pdcm->cidl, pdcm->apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
m_pDataObj = pDataObj;
if (!pdcm->cidl)
if (pdcm->pidlFolder)
{
/* Init pidlFolder only if it is background context menu. See IShellExtInit::Initialize */
if (pdcm->pidlFolder)
m_pidlFolder = ILClone(pdcm->pidlFolder);
else
m_pidlFolder = ILClone(pdcm->pidlFolder);
}
else
{
IPersistFolder2 *pf = NULL;
if (SUCCEEDED(m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
{
IPersistFolder2 *pf = NULL;
if (SUCCEEDED(pdcm->psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
{
if (FAILED(pf->GetCurFolder((_ITEMIDLIST**)&m_pidlFolder)))
ERR("GetCurFolder failed\n");
pf->Release();
}
if (FAILED(pf->GetCurFolder(reinterpret_cast<LPITEMIDLIST*>(&m_pidlFolder))))
ERR("GetCurFolder failed\n");
pf->Release();
}
TRACE("pidlFolder %p\n", m_pidlFolder);
}
CopyMemory(&m_Dcm, pdcm, sizeof(DEFCONTEXTMENU));
return S_OK;
}
@@ -603,7 +615,7 @@ CDefaultContextMenu::AddStaticContextMenusToMenu(
/* set first entry as default */
if (pEntry == m_pStaticEntries)
fState |= MFS_DEFAULT;
if (!wcsicmp(pEntry->szVerb, L"open"))
{
/* override default when open verb is found */
@@ -714,14 +726,14 @@ CDefaultContextMenu::BuildShellItemContextMenu(
HRESULT hr;
TRACE("BuildShellItemContextMenu entered\n");
ASSERT(m_Dcm.cidl >= 1);
ASSERT(m_cidl >= 1);
STRRET strFile;
hr = m_Dcm.psf->GetDisplayNameOf(m_Dcm.apidl[0], SHGDN_FORPARSING, &strFile);
hr = m_psf->GetDisplayNameOf(m_apidl[0], SHGDN_FORPARSING, &strFile);
if (hr == S_OK)
{
WCHAR wszPath[MAX_PATH];
hr = StrRetToBufW(&strFile, m_Dcm.apidl[0], wszPath, _countof(wszPath));
hr = StrRetToBufW(&strFile, m_apidl[0], wszPath, _countof(wszPath));
if (hr == S_OK)
{
LPCWSTR pwszExt = PathFindExtensionW(wszPath);
@@ -765,7 +777,7 @@ CDefaultContextMenu::BuildShellItemContextMenu(
else
ERR("GetDisplayNameOf failed: %x\n", hr);
GUID *pGuid = _ILGetGUIDPointer(m_Dcm.apidl[0]);
GUID *pGuid = _ILGetGUIDPointer(m_apidl[0]);
if (pGuid)
{
LPOLESTR pwszCLSID;
@@ -787,7 +799,7 @@ CDefaultContextMenu::BuildShellItemContextMenu(
}
}
if (_ILIsDrive(m_Dcm.apidl[0]))
if (_ILIsDrive(m_apidl[0]))
{
AddStaticEntryForFileClass(L"Drive");
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Drive", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
@@ -800,7 +812,7 @@ CDefaultContextMenu::BuildShellItemContextMenu(
/* add static actions */
SFGAOF rfg = SFGAO_BROWSABLE | SFGAO_CANCOPY | SFGAO_CANLINK | SFGAO_CANMOVE | SFGAO_CANDELETE | SFGAO_CANRENAME | SFGAO_HASPROPSHEET | SFGAO_FILESYSTEM | SFGAO_FOLDER;
hr = m_Dcm.psf->GetAttributesOf(m_Dcm.cidl, m_Dcm.apidl, &rfg);
hr = m_psf->GetAttributesOf(m_cidl, m_apidl, &rfg);
if (FAILED(hr))
{
ERR("GetAttributesOf failed: %x\n", hr);
@@ -818,7 +830,7 @@ CDefaultContextMenu::BuildShellItemContextMenu(
}
/* Directory is only loaded for real filesystem directories */
if (_ILIsFolder(m_Dcm.apidl[0]))
if (_ILIsFolder(m_apidl[0]))
{
AddStaticEntryForFileClass(L"Directory");
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"Directory", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
@@ -830,7 +842,7 @@ CDefaultContextMenu::BuildShellItemContextMenu(
}
/* AllFilesystemObjects class is loaded only for files and directories */
if (_ILIsFolder(m_Dcm.apidl[0]) || _ILIsValue(m_Dcm.apidl[0]))
if (_ILIsFolder(m_apidl[0]) || _ILIsValue(m_apidl[0]))
{
if (RegOpenKeyExW(HKEY_CLASSES_ROOT, L"AllFilesystemObjects", 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
@@ -848,7 +860,7 @@ CDefaultContextMenu::BuildShellItemContextMenu(
IndexMenu = InsertMenuItemsOfDynamicContextMenuExtension(hMenu, IndexMenu, iIdCmdFirst, iIdCmdLast);
TRACE("IndexMenu %d\n", IndexMenu);
if (_ILIsDrive(m_Dcm.apidl[0]))
if (_ILIsDrive(m_apidl[0]))
{
/* The 'Format' option must be always available,
* thus it is not registered as a static shell extension */
@@ -916,7 +928,7 @@ CDefaultContextMenu::QueryContextMenu(
UINT idCmdLast,
UINT uFlags)
{
if (m_Dcm.cidl)
if (m_cidl)
idCmdFirst = BuildShellItemContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
else
idCmdFirst = BuildBackgroundContextMenu(hMenu, idCmdFirst, idCmdLast, uFlags);
@@ -951,7 +963,7 @@ CDefaultContextMenu::DoRefresh(
{
CComPtr<IPersistFolder2> ppf2 = NULL;
LPITEMIDLIST pidl;
HRESULT hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
HRESULT hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
if (SUCCEEDED(hr))
{
hr = ppf2->GetCurFolder(&pidl);
@@ -984,9 +996,9 @@ CDefaultContextMenu::DoPaste(
return hr;
/* Find target folder */
if (m_Dcm.cidl)
if (m_cidl)
{
hr = m_Dcm.psf->BindToObject(m_Dcm.apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
hr = m_psf->BindToObject(m_apidl[0], NULL, IID_PPV_ARG(IShellFolder, &psfTarget));
}
else
{
@@ -994,7 +1006,7 @@ CDefaultContextMenu::DoPaste(
LPITEMIDLIST pidl;
/* cidl is zero due to explorer view */
hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
if (SUCCEEDED(hr))
{
hr = ppf2->GetCurFolder(&pidl);
@@ -1087,9 +1099,9 @@ CDefaultContextMenu::DoCreateLink(
if (FAILED(hr))
return hr;
if (SUCCEEDED(hr = SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
if (SUCCEEDED(hr = SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
{
hr = m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
hr = m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &ppf2));
if (SUCCEEDED(hr))
{
hr = ppf2->GetCurFolder(&pidl);
@@ -1134,13 +1146,13 @@ HRESULT CDefaultContextMenu::DoDelete(LPCMINVOKECOMMANDINFO lpcmi) {
LPDATAOBJECT pDataObj;
if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
{
pDataObj->AddRef();
SHCreateThread(DoDeleteThreadProc, pDataObj, NULL, NULL);
pDataObj->Release();
}
else
}
else
return E_FAIL;
return S_OK;
@@ -1154,7 +1166,7 @@ CDefaultContextMenu::DoCopyOrCut(
LPDATAOBJECT pDataObj;
HRESULT hr;
if (SUCCEEDED(SHCreateDataObject(m_Dcm.pidlFolder, m_Dcm.cidl, m_Dcm.apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
if (SUCCEEDED(SHCreateDataObject(m_pidlFolder, m_cidl, m_apidl, NULL, IID_PPV_ARG(IDataObject, &pDataObj))))
{
if (!bCopy)
{
@@ -1233,7 +1245,7 @@ CDefaultContextMenu::DoRename(
return hr;
}
lpSV->SelectItem(m_Dcm.apidl[0],
lpSV->SelectItem(m_apidl[0],
SVSI_DESELECTOTHERS | SVSI_EDIT | SVSI_ENSUREVISIBLE | SVSI_FOCUSED | SVSI_SELECT);
lpSV->Release();
return S_OK;
@@ -1244,26 +1256,26 @@ CDefaultContextMenu::DoProperties(
LPCMINVOKECOMMANDINFO lpcmi)
{
HRESULT hr = S_OK;
const ITEMIDLIST *pidlParent = m_Dcm.pidlFolder, *pidlChild;
const ITEMIDLIST *pidlParent = m_pidlFolder, *pidlChild;
if (!pidlParent)
{
IPersistFolder2 *pf;
/* pidlFolder is optional */
if (SUCCEEDED(m_Dcm.psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
if (SUCCEEDED(m_psf->QueryInterface(IID_PPV_ARG(IPersistFolder2, &pf))))
{
pf->GetCurFolder((_ITEMIDLIST**)&pidlParent);
pf->Release();
}
}
if (m_Dcm.cidl > 0)
pidlChild = m_Dcm.apidl[0];
if (m_cidl > 0)
pidlChild = m_apidl[0];
else
{
/* Set pidlChild to last pidl of current folder */
if (pidlParent == m_Dcm.pidlFolder)
if (pidlParent == m_pidlFolder)
pidlParent = (ITEMIDLIST*)ILClone(pidlParent);
pidlChild = (ITEMIDLIST*)ILClone(ILFindLastID(pidlParent));
@@ -1303,11 +1315,11 @@ CDefaultContextMenu::DoProperties(
}
else
{
if (m_Dcm.cidl > 1)
if (m_cidl > 1)
WARN("SHMultiFileProperties is not yet implemented\n");
STRRET strFile;
hr = m_Dcm.psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
hr = m_psf->GetDisplayNameOf(pidlChild, SHGDN_FORPARSING, &strFile);
if (SUCCEEDED(hr))
{
WCHAR wszBuf[MAX_PATH];
@@ -1322,9 +1334,9 @@ CDefaultContextMenu::DoProperties(
}
/* Free allocated PIDLs */
if (pidlParent != m_Dcm.pidlFolder)
if (pidlParent != m_pidlFolder)
ILFree((ITEMIDLIST*)pidlParent);
if (m_Dcm.cidl < 1 || pidlChild != m_Dcm.apidl[0])
if (m_cidl < 1 || pidlChild != m_apidl[0])
ILFree((ITEMIDLIST*)pidlChild);
return hr;
@@ -1336,7 +1348,7 @@ CDefaultContextMenu::DoFormat(
{
char szDrive[8] = {0};
if (!_ILGetDrive(m_Dcm.apidl[0], szDrive, sizeof(szDrive)))
if (!_ILGetDrive(m_apidl[0], szDrive, sizeof(szDrive)))
{
ERR("pidl is not a drive\n");
return E_FAIL;
@@ -1417,7 +1429,7 @@ CDefaultContextMenu::TryToBrowse(
if (lpSB == NULL)
return E_FAIL;
hr = lpSB->BrowseObject(ILCombine(m_Dcm.pidlFolder, pidl), wFlags);
hr = lpSB->BrowseObject(ILCombine(m_pidlFolder, pidl), wFlags);
return hr;
}
@@ -1425,7 +1437,7 @@ CDefaultContextMenu::TryToBrowse(
HRESULT
CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl, PStaticShellEntry pEntry)
{
LPITEMIDLIST pidlFull = ILCombine(m_Dcm.pidlFolder, pidl);
LPITEMIDLIST pidlFull = ILCombine(m_pidlFolder, pidl);
if (pidlFull == NULL)
{
return E_FAIL;
@@ -1442,7 +1454,7 @@ CDefaultContextMenu::InvokePidl(LPCMINVOKECOMMANDINFO lpcmi, LPCITEMIDLIST pidl,
}
else
{
SHGetPathFromIDListW(m_Dcm.pidlFolder, wszDir);
SHGetPathFromIDListW(m_pidlFolder, wszDir);
}
HKEY hkeyClass;
@@ -1491,7 +1503,7 @@ CDefaultContextMenu::DoStaticShellExtensions(
DWORD wFlags = BrowserFlagsFromVerb(lpcmi, pEntry);
BOOL bBrowsed = FALSE;
for (i=0; i < m_Dcm.cidl; i++)
for (i=0; i < m_cidl; i++)
{
/* Check if we need to browse */
if (wFlags > 0)
@@ -1502,7 +1514,7 @@ CDefaultContextMenu::DoStaticShellExtensions(
if (bBrowsed)
continue;
hr = TryToBrowse(lpcmi, m_Dcm.apidl[i], wFlags);
hr = TryToBrowse(lpcmi, m_apidl[i], wFlags);
if (SUCCEEDED(hr))
{
bBrowsed = TRUE;
@@ -1510,7 +1522,7 @@ CDefaultContextMenu::DoStaticShellExtensions(
}
}
InvokePidl(lpcmi, m_Dcm.apidl[i], pEntry);
InvokePidl(lpcmi, m_apidl[i], pEntry);
}
return S_OK;