4 * Copyright 2016 Sylvain Deverre <deverre dot sylv at gmail dot com>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * Wraps the component categories manager enum
25 #include "shellbars.h"
27 #define REGPATH L"Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\Discardable\\PostSetup\\Component Categories"
28 #define IMPLEMENTING L"Implementing"
29 #define REQUIRING L"Requiring"
31 typedef struct categoryCacheHeader
33 DWORD dwSize
; // size of header only
34 DWORD version
; // currently 1
35 SYSTEMTIME writeTime
; // time we were written to registry
36 DWORD classCount
; // number of classes following
37 } CATCACHEHDR
, *PCATCACHEHDR
;
40 * This class manages a cached explorer component categories items, writing cache if it
42 * It is used by CSHEnumClassesOfCategories internally.
44 class CComCatCachedCategory
47 CComCatCachedCategory();
48 virtual ~CComCatCachedCategory();
49 HRESULT
WriteCacheToDSA(HDSA pDest
);
50 HRESULT STDMETHODCALLTYPE
Initialize(CATID
&catID
, BOOL reloadCache
);
52 BOOL
LoadFromRegistry();
53 HRESULT
LoadFromComCatMgr();
59 CComCatCachedCategory::CComCatCachedCategory()
61 fLocalDsa
= DSA_Create(sizeof(GUID
), 5);
64 HRESULT STDMETHODCALLTYPE
CComCatCachedCategory::Initialize(CATID
&catID
, BOOL reloadCache
)
69 if (reloadCache
|| !LoadFromRegistry())
71 hr
= LoadFromComCatMgr();
72 if (FAILED_UNEXPECTEDLY(hr
))
76 if (FAILED_UNEXPECTEDLY(hr
))
82 CComCatCachedCategory::~CComCatCachedCategory()
84 DSA_Destroy(fLocalDsa
);
87 BOOL
CComCatCachedCategory::LoadFromRegistry()
89 WCHAR bufKey
[MAX_PATH
];
90 WCHAR guidStr
[MAX_PATH
];
92 CComHeapPtr
<CATCACHEHDR
> buffer
;
99 if (!StringFromGUID2(fCategory
, guidStr
, MAX_PATH
))
102 wsprintf(bufKey
, L
"%s\\%s\\%s", REGPATH
, guidStr
, L
"Enum");
104 // Try to read key and get proper value size
105 if (SHGetValue(HKEY_CURRENT_USER
, bufKey
, IMPLEMENTING
, NULL
, NULL
, &dataSize
))
108 buffer
.Attach((PCATCACHEHDR
)CoTaskMemAlloc(dataSize
));
110 SHGetValue(HKEY_CURRENT_USER
, bufKey
, IMPLEMENTING
, NULL
, buffer
, &dataSize
);
111 guidArray
= (GUID
*)(buffer
+ 1);
112 for (i
= 0; i
< buffer
->classCount
; i
++)
114 // Add class to cache
115 DSA_InsertItem(fLocalDsa
, DSA_APPEND
, guidArray
+ i
);
121 HRESULT
CComCatCachedCategory::CacheDSA()
123 WCHAR bufKey
[MAX_PATH
];
124 WCHAR guidStr
[MAX_PATH
];
128 CComHeapPtr
<CATCACHEHDR
> buffer
;
132 elemCount
= DSA_GetItemCount(fLocalDsa
);
133 bufferSize
= sizeof(CATCACHEHDR
) + elemCount
* sizeof(GUID
);
134 if (!StringFromGUID2(fCategory
, guidStr
, MAX_PATH
))
137 buffer
.Attach((PCATCACHEHDR
)CoTaskMemAlloc(bufferSize
));
139 return E_OUTOFMEMORY
;
141 // Correctly fill cache header
142 buffer
->dwSize
= sizeof(CATCACHEHDR
);
144 GetSystemTime(&buffer
->writeTime
);
145 buffer
->classCount
= (DWORD
)elemCount
;
147 guidArray
= (GUID
*)(buffer
+ 1);
148 wsprintf(bufKey
, L
"%s\\%s\\%s", REGPATH
, guidStr
, L
"Enum");
150 // Write DSA contents inside the memory buffer allocated
151 for(i
= 0; i
< elemCount
; i
++)
153 tmp
= (GUID
*)DSA_GetItemPtr(fLocalDsa
, i
);
160 // Save items to registry
161 SHSetValue(HKEY_CURRENT_USER
, bufKey
, IMPLEMENTING
, REG_BINARY
, buffer
, bufferSize
);
167 HRESULT
CComCatCachedCategory::LoadFromComCatMgr()
170 CComPtr
<ICatInformation
> pCatInformation
;
171 CComPtr
<IEnumGUID
> pEnumGUID
;
175 // Get component categories manager instance
176 hr
= CoCreateInstance(CLSID_StdComponentCategoriesMgr
, NULL
, CLSCTX_INPROC_SERVER
,
177 IID_PPV_ARG(ICatInformation
, &pCatInformation
));
178 if (FAILED_UNEXPECTEDLY(hr
))
181 // Get the proper enumerator
182 hr
= pCatInformation
->EnumClassesOfCategories(1, &fCategory
, NULL
, NULL
, &pEnumGUID
);
183 if (FAILED_UNEXPECTEDLY(hr
))
186 // Enumerate elements
190 pEnumGUID
->Next(1, &tmp
, &pFetched
);
193 if (DSA_InsertItem(fLocalDsa
, DSA_APPEND
, &tmp
) == E_OUTOFMEMORY
)
194 return E_OUTOFMEMORY
;
197 while (pFetched
> 0);
201 HRESULT
CComCatCachedCategory::WriteCacheToDSA(HDSA pDest
)
204 for(i
= 0; i
< DSA_GetItemCount(fLocalDsa
); i
++)
206 if (DSA_InsertItem(pDest
, DSA_APPEND
, DSA_GetItemPtr(fLocalDsa
, i
)) == DSA_ERR
)
207 return E_OUTOFMEMORY
;
212 class CSHEnumClassesOfCategories
:
213 public CComCoClass
<CSHEnumClassesOfCategories
>,
214 public CComObjectRootEx
<CComMultiThreadModelNoCS
>,
218 CComPtr
<ICatInformation
> fCatInformation
;
223 CSHEnumClassesOfCategories();
224 virtual ~CSHEnumClassesOfCategories();
225 virtual HRESULT STDMETHODCALLTYPE
Initialize(ULONG cImplemented
, CATID
*pImplemented
, ULONG cRequired
, CATID
*pRequired
);
226 // *** IEnumGUID methods ***
227 virtual HRESULT STDMETHODCALLTYPE
Clone(IEnumCLSID
**ppvOut
);
228 virtual HRESULT STDMETHODCALLTYPE
Next(ULONG cElt
, CLSID
*pElts
, ULONG
*pFetched
);
229 virtual HRESULT STDMETHODCALLTYPE
Reset();
230 virtual HRESULT STDMETHODCALLTYPE
Skip(ULONG nbElts
);
232 BEGIN_COM_MAP(CSHEnumClassesOfCategories
)
233 COM_INTERFACE_ENTRY_IID(IID_IEnumGUID
, IEnumGUID
)
237 CSHEnumClassesOfCategories::CSHEnumClassesOfCategories()
240 fDsa
= DSA_Create(sizeof(GUID
), 5);
243 CSHEnumClassesOfCategories::~CSHEnumClassesOfCategories()
249 HRESULT
CSHEnumClassesOfCategories::Initialize(ULONG cImplemented
, CATID
*pImplemented
, ULONG cRequired
, CATID
*pRequired
)
257 // Parameter validation:
258 // - We must have at least one category to manage.
259 // - The array pointers must not be NULL if there is a non-zero
260 // element count specified for them.
261 if (cImplemented
== 0 && cRequired
== 0)
263 if ((cImplemented
&& !pImplemented
) || (cRequired
&& !pRequired
))
266 // For each implemented category, create a cache and add it to our local DSA.
267 for (i
= 0; i
< cImplemented
; i
++)
269 CComCatCachedCategory cachedCat
;
270 hr
= cachedCat
.Initialize(pImplemented
[i
], FALSE
);
271 if (FAILED_UNEXPECTEDLY(hr
))
273 cachedCat
.WriteCacheToDSA(fDsa
);
276 // TODO: Implement caching of the required categories.
279 FIXME("Implement required categories class enumeration\n");
281 // Only fail in case we didn't look at the implemented categories.
282 if (cImplemented
== 0)
289 // *** IEnumGUID methods ***
291 HRESULT STDMETHODCALLTYPE
CSHEnumClassesOfCategories::Clone(IEnumCLSID
**ppvOut
)
296 HRESULT STDMETHODCALLTYPE
CSHEnumClassesOfCategories::Next(ULONG cElt
, CLSID
*pElts
, ULONG
*pFetched
)
305 for (i
= 0; i
< cElt
&& (fCursor
< (ULONG
)DSA_GetItemCount(fDsa
)); i
++)
307 tmp
= (GUID
*)DSA_GetItemPtr(fDsa
, fCursor
+ i
);
319 HRESULT STDMETHODCALLTYPE
CSHEnumClassesOfCategories::Reset()
325 HRESULT STDMETHODCALLTYPE
CSHEnumClassesOfCategories::Skip(ULONG nbElts
)
327 if (fCursor
+ nbElts
>= (ULONG
)DSA_GetItemCount(fDsa
))
333 /*************************************************************************
334 * SHEnumClassesOfCategories [BROWSEUI.136]
336 extern "C" HRESULT WINAPI
SHEnumClassesOfCategories(ULONG cImplemented
, CATID
*pImplemented
, ULONG cRequired
, CATID
*pRequired
, IEnumGUID
**out
)
340 hr
= ShellObjectCreatorInit
<CSHEnumClassesOfCategories
>(
341 cImplemented
, pImplemented
, cRequired
, pRequired
, IID_PPV_ARG(IEnumGUID
, out
));
342 if (FAILED_UNEXPECTEDLY(hr
))