From 19ee935a701b7db55fc27d3605fbe09bc0af9140 Mon Sep 17 00:00:00 2001 From: Giannis Adamopoulos Date: Tue, 31 May 2016 13:39:42 +0000 Subject: [PATCH] [BROWSEUI] - Implement SHEnumClassesOfCategories - Part of the work submitted by Sylvain Deverre. CORE-10838 svn path=/trunk/; revision=71471 --- reactos/dll/win32/browseui/CMakeLists.txt | 1 + reactos/dll/win32/browseui/browseuiord.cpp | 7 - reactos/dll/win32/browseui/comcat.cpp | 336 +++++++++++++++++++++ 3 files changed, 337 insertions(+), 7 deletions(-) create mode 100644 reactos/dll/win32/browseui/comcat.cpp diff --git a/reactos/dll/win32/browseui/CMakeLists.txt b/reactos/dll/win32/browseui/CMakeLists.txt index 02448ca0d76..b0cc60b6488 100644 --- a/reactos/dll/win32/browseui/CMakeLists.txt +++ b/reactos/dll/win32/browseui/CMakeLists.txt @@ -31,6 +31,7 @@ list(APPEND SOURCE travellog.cpp utility.cpp CProgressDialog.cpp + comcat.cpp precomp.h) add_library(browseui SHARED diff --git a/reactos/dll/win32/browseui/browseuiord.cpp b/reactos/dll/win32/browseui/browseuiord.cpp index 7af50998b60..4c08c097f23 100644 --- a/reactos/dll/win32/browseui/browseuiord.cpp +++ b/reactos/dll/win32/browseui/browseuiord.cpp @@ -136,13 +136,6 @@ extern "C" HRESULT WINAPI GetInfoTip(IUnknown *param8, long paramC, LPTSTR *para return E_NOTIMPL; } -/************************************************************************* - * SHEnumClassesOfCategories [BROWSEUI.136] - */ -extern "C" HRESULT WINAPI SHEnumClassesOfCategories(ULONG cImplemented, CATID *pImplemented, ULONG cRequired, CATID *pRequired, IEnumGUID **out) -{ - return E_NOTIMPL; -} /************************************************************************* * SHWriteClassesOfCategories [BROWSEUI.137] diff --git a/reactos/dll/win32/browseui/comcat.cpp b/reactos/dll/win32/browseui/comcat.cpp new file mode 100644 index 00000000000..972b11c055a --- /dev/null +++ b/reactos/dll/win32/browseui/comcat.cpp @@ -0,0 +1,336 @@ +/* + * ReactOS Explorer + * + * Copyright 2016 Sylvain Deverre + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +/* + * Wraps the component categories manager enum + */ + +#include "precomp.h" + +#define REGPATH L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Discardable\\PostSetup\\Component Categories" +#define IMPLEMENTING L"Implementing" +#define REQUIRING L"Requiring" + +typedef struct categoryCacheHeader +{ + DWORD dwSize; // size of header only + DWORD version; // currently 1 + SYSTEMTIME writeTime; // time we were written to registry + DWORD classCount; // number of classes following +} CATCACHEHDR, *PCATCACHEHDR; + +/* + * This class manages a cached explorer component categories items, writing cache if it + * doesn't exist yet. + * It is used by CSHEnumClassesOfCategories internally. + */ +class CComCatCachedCategory +{ + public: + CComCatCachedCategory(); + virtual ~CComCatCachedCategory(); + HRESULT WriteCacheToDSA(HDSA pDest); + HRESULT STDMETHODCALLTYPE Initialize(CATID &catID, BOOL reloadCache); + private: + BOOL LoadFromRegistry(); + HRESULT LoadFromComCatMgr(); + HRESULT CacheDSA(); + CATID fCategory; + HDSA fLocalDsa; +}; + +CComCatCachedCategory::CComCatCachedCategory() +{ + fLocalDsa = DSA_Create(sizeof(GUID), 5); +} + +HRESULT STDMETHODCALLTYPE CComCatCachedCategory::Initialize(CATID &catID, BOOL reloadCache) +{ + HRESULT hr; + + fCategory = catID; + if (reloadCache || !LoadFromRegistry()) + { + hr = LoadFromComCatMgr(); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + hr = CacheDSA(); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + } + return S_OK; +} + +CComCatCachedCategory::~CComCatCachedCategory() +{ + DSA_Destroy(fLocalDsa); +} + +BOOL CComCatCachedCategory::LoadFromRegistry() +{ + WCHAR bufKey[MAX_PATH]; + WCHAR guidStr[MAX_PATH]; + DWORD dataSize, i; + CComHeapPtr buffer; + GUID *guidArray; + + if (!fLocalDsa) + return FALSE; + + dataSize = 0; + if (!StringFromGUID2(fCategory, guidStr, MAX_PATH)) + return FALSE; + + wsprintf(bufKey, L"%s\\%s\\%s", REGPATH , guidStr, L"Enum"); + + // Try to read key and get proper value size + if (SHGetValue(HKEY_CURRENT_USER, bufKey, IMPLEMENTING, NULL, NULL, &dataSize)) + return FALSE; + + buffer.Attach((PCATCACHEHDR)CoTaskMemAlloc(dataSize)); + + SHGetValue(HKEY_CURRENT_USER, bufKey, IMPLEMENTING, NULL, buffer, &dataSize); + guidArray = (GUID*)(buffer + 1); + for (i = 0; i < buffer->classCount; i++) + { + // Add class to cache + DSA_InsertItem(fLocalDsa, DSA_APPEND, guidArray + i); + } + + return TRUE; +} + +HRESULT CComCatCachedCategory::CacheDSA() +{ + WCHAR bufKey[MAX_PATH]; + WCHAR guidStr[MAX_PATH]; + UINT elemCount; + UINT i; + UINT bufferSize; + CComHeapPtr buffer; + GUID *guidArray; + GUID *tmp; + + elemCount = DSA_GetItemCount(fLocalDsa); + bufferSize = sizeof(CATCACHEHDR) + elemCount * sizeof(GUID); + if (!StringFromGUID2(fCategory, guidStr, MAX_PATH)) + return E_FAIL; + + buffer.Attach((PCATCACHEHDR)CoTaskMemAlloc(bufferSize)); + if (!buffer) + return E_OUTOFMEMORY; + + // Correctly fill cache header + buffer->dwSize = sizeof(CATCACHEHDR); + buffer->version = 1; + GetSystemTime(&buffer->writeTime); + buffer->classCount = (DWORD)elemCount; + + guidArray = (GUID*)(buffer + 1); + wsprintf(bufKey, L"%s\\%s\\%s", REGPATH , guidStr, L"Enum"); + + // Write DSA contents inside the memory buffer allocated + for(i = 0; i < elemCount; i++) + { + tmp = (GUID*)DSA_GetItemPtr(fLocalDsa, i); + if (tmp) + { + guidArray[i] = *tmp; + } + } + + // Save items to registry + SHSetValue(HKEY_CURRENT_USER, bufKey, IMPLEMENTING, REG_BINARY, buffer, bufferSize); + + guidArray = NULL; + CoTaskMemFree(buffer); + return S_OK; +} + +HRESULT CComCatCachedCategory::LoadFromComCatMgr() +{ + HRESULT hr; + CComPtr pCatInformation; + CComPtr pEnumGUID; + ULONG pFetched; + CLSID tmp; + + // Get component categories manager instance + hr = CoCreateInstance(CLSID_StdComponentCategoriesMgr, NULL, CLSCTX_INPROC_SERVER, + IID_PPV_ARG(ICatInformation, &pCatInformation)); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + // Get the proper enumerator + hr = pCatInformation->EnumClassesOfCategories(1, &fCategory, NULL, NULL, &pEnumGUID); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + + // Enumerate elements + do + { + pFetched = 0; + pEnumGUID->Next(1, &tmp, &pFetched); + if (pFetched) + { + if (DSA_InsertItem(fLocalDsa, DSA_APPEND, &tmp) == E_OUTOFMEMORY) + return E_OUTOFMEMORY; + } + } + while (pFetched > 0); + return S_OK; +} + +HRESULT CComCatCachedCategory::WriteCacheToDSA(HDSA pDest) +{ + INT i; + for(i = 0; i < DSA_GetItemCount(fLocalDsa); i++) + { + if (DSA_InsertItem(pDest, DSA_APPEND, DSA_GetItemPtr(fLocalDsa, i)) == DSA_ERR) + return E_OUTOFMEMORY; + } + return S_OK; +} + +class CSHEnumClassesOfCategories : + public CComCoClass, + public CComObjectRootEx, + public IEnumGUID +{ + private: + CComPtr fCatInformation; + HDSA fDsa; + ULONG fCursor; + + public: + CSHEnumClassesOfCategories(); + virtual ~CSHEnumClassesOfCategories(); + virtual HRESULT STDMETHODCALLTYPE Initialize(ULONG cImplemented, CATID *pImplemented, ULONG cRequired, CATID *pRequired); + // *** IEnumGUID methods *** + virtual HRESULT STDMETHODCALLTYPE Clone(IEnumCLSID **ppvOut); + virtual HRESULT STDMETHODCALLTYPE Next(ULONG cElt, CLSID *pElts, ULONG *pFetched); + virtual HRESULT STDMETHODCALLTYPE Reset(); + virtual HRESULT STDMETHODCALLTYPE Skip(ULONG nbElts); + + BEGIN_COM_MAP(CSHEnumClassesOfCategories) + COM_INTERFACE_ENTRY_IID(IID_IEnumGUID, IEnumGUID) + END_COM_MAP() +}; + +CSHEnumClassesOfCategories::CSHEnumClassesOfCategories() +{ + fCursor = 0; + fDsa = DSA_Create(sizeof(GUID), 5); +} + +CSHEnumClassesOfCategories::~CSHEnumClassesOfCategories() +{ + if (fDsa) + DSA_Destroy(fDsa); +} + +HRESULT CSHEnumClassesOfCategories::Initialize(ULONG cImplemented, CATID *pImplemented, ULONG cRequired, CATID *pRequired) +{ + UINT i; + HRESULT hr; + + if (!fDsa) + return E_FAIL; + + if (cRequired > 0 || cImplemented == (ULONG)-1) + { + FIXME("Implement required categories class enumeration\n"); + return E_NOTIMPL; + } + + // Don't do anything if we have nothing + if (cRequired == 0 && cImplemented == (ULONG)-1) + return E_FAIL; + + // For each implemented category, create a cache and add it to our local DSA + for (i = 0; i < cImplemented; i++) + { + CComCatCachedCategory cachedCat; + hr = cachedCat.Initialize(pImplemented[i], FALSE); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + cachedCat.WriteCacheToDSA(fDsa); + } + return S_OK; +} + +// *** IEnumGUID methods *** + +HRESULT STDMETHODCALLTYPE CSHEnumClassesOfCategories::Clone(IEnumCLSID **ppvOut) +{ + return E_NOTIMPL; +} + +HRESULT STDMETHODCALLTYPE CSHEnumClassesOfCategories::Next(ULONG cElt, CLSID *pElts, ULONG *pFetched) +{ + ULONG i; + ULONG read; + GUID *tmp; + + if (!pElts) + return E_INVALIDARG; + read = 0; + for (i = 0; i < cElt && (fCursor < (ULONG)DSA_GetItemCount(fDsa)); i++) + { + tmp = (GUID*)DSA_GetItemPtr(fDsa, fCursor + i); + if (!tmp) + break; + pElts[i] = *tmp; + read++; + } + fCursor += read; + if (pFetched) + *pFetched = read; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CSHEnumClassesOfCategories::Reset() +{ + fCursor = 0; + return S_OK; +} + +HRESULT STDMETHODCALLTYPE CSHEnumClassesOfCategories::Skip(ULONG nbElts) +{ + if (fCursor + nbElts >= (ULONG)DSA_GetItemCount(fDsa)) + return E_INVALIDARG; + fCursor += nbElts; + return S_OK; +} + +/************************************************************************* + * SHEnumClassesOfCategories [BROWSEUI.136] + */ +extern "C" HRESULT WINAPI SHEnumClassesOfCategories(ULONG cImplemented, CATID *pImplemented, ULONG cRequired, CATID *pRequired, IEnumGUID **out) +{ + HRESULT hr; + + hr = ShellObjectCreatorInit( + cImplemented, pImplemented, cRequired, pRequired, IID_IEnumGUID, out); + if (FAILED_UNEXPECTEDLY(hr)) + return hr; + return S_OK; +}