2 * ComCatMgr ICatInformation implementation for comcat.dll
4 * Copyright (C) 2002 John K. Hohm
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 #include "comcat_private.h"
24 #include "wine/debug.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
28 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
);
29 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
32 struct class_categories
{
37 static struct class_categories
*COMCAT_PrepareClassCategories(
38 ULONG impl_count
, CATID
*impl_catids
, ULONG req_count
, CATID
*req_catids
);
39 static HRESULT
COMCAT_IsClassOfCategories(
40 HKEY key
, struct class_categories
const* class_categories
);
41 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(
42 struct class_categories
const* class_categories
);
43 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
44 REFCLSID rclsid
, LPCWSTR impl_req
);
46 /**********************************************************************
47 * COMCAT_ICatInformation_QueryInterface
49 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
50 LPCATINFORMATION iface
,
54 ICOM_THIS_MULTI(ComCatMgrImpl
, infVtbl
, iface
);
55 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
57 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
59 return IUnknown_QueryInterface((LPUNKNOWN
)&This
->unkVtbl
, riid
, ppvObj
);
62 /**********************************************************************
63 * COMCAT_ICatInformation_AddRef
65 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
67 ICOM_THIS_MULTI(ComCatMgrImpl
, infVtbl
, iface
);
70 if (This
== NULL
) return E_POINTER
;
72 return IUnknown_AddRef((LPUNKNOWN
)&This
->unkVtbl
);
75 /**********************************************************************
76 * COMCAT_ICatInformation_Release
78 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
80 ICOM_THIS_MULTI(ComCatMgrImpl
, infVtbl
, iface
);
83 if (This
== NULL
) return E_POINTER
;
85 return IUnknown_Release((LPUNKNOWN
)&This
->unkVtbl
);
88 /**********************************************************************
89 * COMCAT_ICatInformation_EnumCategories
91 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
92 LPCATINFORMATION iface
,
94 LPENUMCATEGORYINFO
*ppenumCatInfo
)
96 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
99 if (iface
== NULL
|| ppenumCatInfo
== NULL
) return E_POINTER
;
101 *ppenumCatInfo
= COMCAT_IEnumCATEGORYINFO_Construct(lcid
);
102 if (*ppenumCatInfo
== NULL
) return E_OUTOFMEMORY
;
103 IEnumCATEGORYINFO_AddRef(*ppenumCatInfo
);
107 /**********************************************************************
108 * COMCAT_ICatInformation_GetCategoryDesc
110 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
111 LPCATINFORMATION iface
,
116 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
117 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
118 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
119 'r', 'i', 'e', 's', '\\', 0 };
123 TRACE("\n\tCATID:\t%s\n\tLCID:\t%lX\n",debugstr_guid(rcatid
), lcid
);
125 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
127 /* Open the key for this category. */
128 if (!StringFromGUID2(rcatid
, keyname
+ 21, 39)) return E_FAIL
;
129 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
130 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
132 /* Allocate a sensible amount of memory for the description. */
133 *ppszDesc
= (PWCHAR
) CoTaskMemAlloc(128 * sizeof(WCHAR
));
134 if (*ppszDesc
== NULL
) {
136 return E_OUTOFMEMORY
;
139 /* Get the description, and make sure it's null terminated. */
140 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
143 CoTaskMemFree(*ppszDesc
);
150 /**********************************************************************
151 * COMCAT_ICatInformation_EnumClassesOfCategories
153 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
154 LPCATINFORMATION iface
,
159 LPENUMCLSID
*ppenumCLSID
)
161 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
162 struct class_categories
*categories
;
166 if (iface
== NULL
|| ppenumCLSID
== NULL
||
167 (cImplemented
&& rgcatidImpl
== NULL
) ||
168 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
170 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
171 cRequired
, rgcatidReq
);
172 if (categories
== NULL
) return E_OUTOFMEMORY
;
173 *ppenumCLSID
= COMCAT_CLSID_IEnumGUID_Construct(categories
);
174 if (*ppenumCLSID
== NULL
) {
175 HeapFree(GetProcessHeap(), 0, categories
);
176 return E_OUTOFMEMORY
;
178 IEnumGUID_AddRef(*ppenumCLSID
);
182 /**********************************************************************
183 * COMCAT_ICatInformation_IsClassOfCategories
185 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
186 LPCATINFORMATION iface
,
193 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
194 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
196 struct class_categories
*categories
;
199 if (WINE_TRACE_ON(ole
)) {
201 TRACE("\n\tCLSID:\t%s\n\tImplemented %lu\n",debugstr_guid(rclsid
),cImplemented
);
202 for (count
= 0; count
< cImplemented
; ++count
)
203 TRACE("\t\t%s\n",debugstr_guid(&rgcatidImpl
[count
]));
204 TRACE("\tRequired %lu\n",cRequired
);
205 for (count
= 0; count
< cRequired
; ++count
)
206 TRACE("\t\t%s\n",debugstr_guid(&rgcatidReq
[count
]));
209 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
210 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
212 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
213 if (FAILED(res
)) return res
;
215 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
216 cRequired
, rgcatidReq
);
217 if (categories
== NULL
) return E_OUTOFMEMORY
;
219 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
220 if (res
== ERROR_SUCCESS
) {
221 res
= COMCAT_IsClassOfCategories(key
, categories
);
223 } else res
= S_FALSE
;
225 HeapFree(GetProcessHeap(), 0, categories
);
230 /**********************************************************************
231 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
233 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
234 LPCATINFORMATION iface
,
236 LPENUMCATID
*ppenumCATID
)
238 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
239 static const WCHAR postfix
[24] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
240 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
241 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
243 TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid
));
245 if (iface
== NULL
|| rclsid
== NULL
|| ppenumCATID
== NULL
)
248 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
249 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
253 /**********************************************************************
254 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
256 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
257 LPCATINFORMATION iface
,
259 LPENUMCATID
*ppenumCATID
)
261 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
262 static const WCHAR postfix
[21] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
263 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
264 'r', 'i', 'e', 's', 0 };
266 TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid
));
268 if (iface
== NULL
|| rclsid
== NULL
|| ppenumCATID
== NULL
)
271 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
272 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
276 /**********************************************************************
277 * COMCAT_ICatInformation_Vtbl
279 const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
281 COMCAT_ICatInformation_QueryInterface
,
282 COMCAT_ICatInformation_AddRef
,
283 COMCAT_ICatInformation_Release
,
284 COMCAT_ICatInformation_EnumCategories
,
285 COMCAT_ICatInformation_GetCategoryDesc
,
286 COMCAT_ICatInformation_EnumClassesOfCategories
,
287 COMCAT_ICatInformation_IsClassOfCategories
,
288 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
289 COMCAT_ICatInformation_EnumReqCategoriesOfClass
292 /**********************************************************************
293 * IEnumCATEGORYINFO implementation
295 * This implementation is not thread-safe. The manager itself is, but
296 * I can't imagine a valid use of an enumerator in several threads.
300 const IEnumCATEGORYINFOVtbl
*lpVtbl
;
305 } IEnumCATEGORYINFOImpl
;
307 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(LPENUMCATEGORYINFO iface
)
309 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
313 if (This
== NULL
) return E_POINTER
;
315 return InterlockedIncrement(&This
->ref
);
318 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
319 LPENUMCATEGORYINFO iface
,
323 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
324 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
326 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
328 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
329 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
331 *ppvObj
= (LPVOID
)iface
;
332 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
336 return E_NOINTERFACE
;
339 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(LPENUMCATEGORYINFO iface
)
341 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
346 if (This
== NULL
) return E_POINTER
;
348 ref
= InterlockedDecrement(&This
->ref
);
350 if (This
->key
) RegCloseKey(This
->key
);
351 HeapFree(GetProcessHeap(), 0, This
);
357 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
358 LPENUMCATEGORYINFO iface
,
363 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
368 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
370 if (This
->key
) while (fetched
< celt
) {
376 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
377 NULL
, NULL
, NULL
, NULL
);
378 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
379 ++(This
->next_index
);
381 res
= CLSIDFromString(catid
, &rgelt
->catid
);
382 if (FAILED(res
)) continue;
384 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
385 if (res
!= ERROR_SUCCESS
) continue;
387 res
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
388 rgelt
->szDescription
, 128);
390 if (FAILED(res
)) continue;
392 rgelt
->lcid
= This
->lcid
;
397 if (pceltFetched
) *pceltFetched
= fetched
;
398 return fetched
== celt
? S_OK
: S_FALSE
;
401 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
402 LPENUMCATEGORYINFO iface
,
405 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
409 if (This
== NULL
) return E_POINTER
;
410 This
->next_index
+= celt
;
411 /* This should return S_FALSE when there aren't celt elems to skip. */
415 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface
)
417 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
421 if (This
== NULL
) return E_POINTER
;
422 This
->next_index
= 0;
426 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
427 LPENUMCATEGORYINFO iface
,
428 IEnumCATEGORYINFO
**ppenum
)
430 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
431 WCHAR keyname
[21] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
432 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
433 'r', 'i', 'e', 's', 0 };
434 IEnumCATEGORYINFOImpl
*new_this
;
438 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
440 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
441 if (new_this
== NULL
) return E_OUTOFMEMORY
;
443 new_this
->lpVtbl
= This
->lpVtbl
;
445 new_this
->lcid
= This
->lcid
;
446 /* FIXME: could we more efficiently use DuplicateHandle? */
447 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
448 new_this
->next_index
= This
->next_index
;
450 *ppenum
= (LPENUMCATEGORYINFO
)new_this
;
454 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
456 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
457 COMCAT_IEnumCATEGORYINFO_AddRef
,
458 COMCAT_IEnumCATEGORYINFO_Release
,
459 COMCAT_IEnumCATEGORYINFO_Next
,
460 COMCAT_IEnumCATEGORYINFO_Skip
,
461 COMCAT_IEnumCATEGORYINFO_Reset
,
462 COMCAT_IEnumCATEGORYINFO_Clone
465 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
467 IEnumCATEGORYINFOImpl
*This
;
469 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
471 WCHAR keyname
[21] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
472 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
473 'r', 'i', 'e', 's', 0 };
475 This
->lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
477 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
479 return (LPENUMCATEGORYINFO
)This
;
482 /**********************************************************************
483 * COMCAT_GetCategoryDesc
485 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
488 WCHAR fmt
[4] = { '%', 'l', 'X', 0 };
491 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
493 if (pszDesc
== NULL
) return E_INVALIDARG
;
495 /* FIXME: lcid comparisons are more complex than this! */
496 wsprintfW(valname
, fmt
, lcid
);
497 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
498 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
499 FIXME("Simplified lcid comparison\n");
500 return CAT_E_NODESCRIPTION
;
502 pszDesc
[size
/ sizeof(WCHAR
)] = (WCHAR
)0;
507 /**********************************************************************
508 * COMCAT_PrepareClassCategories
510 static struct class_categories
*COMCAT_PrepareClassCategories(
511 ULONG impl_count
, CATID
*impl_catids
, ULONG req_count
, CATID
*req_catids
)
513 struct class_categories
*categories
;
516 categories
= HeapAlloc(
517 GetProcessHeap(), HEAP_ZERO_MEMORY
,
518 sizeof(struct class_categories
) +
519 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
520 if (categories
== NULL
) return categories
;
522 strings
= (WCHAR
*)(categories
+ 1);
523 categories
->impl_strings
= strings
;
524 while (impl_count
--) {
525 StringFromGUID2(impl_catids
++, strings
, 39);
530 categories
->req_strings
= strings
;
531 while (req_count
--) {
532 StringFromGUID2(req_catids
++, strings
, 39);
540 /**********************************************************************
541 * COMCAT_IsClassOfCategories
543 static HRESULT
COMCAT_IsClassOfCategories(
545 struct class_categories
const* categories
)
547 WCHAR impl_keyname
[23] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
548 't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
549 'g', 'o', 'r', 'i', 'e', 's', 0 };
550 WCHAR req_keyname
[20] = { 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'd',
551 ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r',
558 /* Check that every given category is implemented by class. */
559 res
= RegOpenKeyExW(key
, impl_keyname
, 0, KEY_READ
, &subkey
);
560 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
561 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
563 res
= RegOpenKeyExW(subkey
, string
, 0, 0, &catkey
);
564 if (res
!= ERROR_SUCCESS
) {
572 /* Check that all categories required by class are given. */
573 res
= RegOpenKeyExW(key
, req_keyname
, 0, KEY_READ
, &subkey
);
574 if (res
== ERROR_SUCCESS
) {
575 for (index
= 0; ; ++index
) {
579 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
580 NULL
, NULL
, NULL
, NULL
);
581 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
582 if (size
!= 38) continue; /* bogus catid in registry */
583 for (string
= categories
->req_strings
; *string
; string
+= 39)
584 if (!strcmpiW(string
, keyname
)) break;
596 /**********************************************************************
597 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
599 * This implementation is not thread-safe. The manager itself is, but
600 * I can't imagine a valid use of an enumerator in several threads.
604 const IEnumGUIDVtbl
*lpVtbl
;
606 const struct class_categories
*categories
;
609 } CLSID_IEnumGUIDImpl
;
611 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
613 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
616 if (This
== NULL
) return E_POINTER
;
618 return InterlockedIncrement(&This
->ref
);
621 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
626 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
627 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
629 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
631 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
632 IsEqualGUID(riid
, &IID_IEnumGUID
))
634 *ppvObj
= (LPVOID
)iface
;
635 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
639 return E_NOINTERFACE
;
642 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
644 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
649 if (This
== NULL
) return E_POINTER
;
651 ref
= InterlockedDecrement(&This
->ref
);
653 if (This
->key
) RegCloseKey(This
->key
);
654 HeapFree(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
655 HeapFree(GetProcessHeap(), 0, This
);
661 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
667 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
672 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
674 if (This
->key
) while (fetched
< celt
) {
680 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
681 NULL
, NULL
, NULL
, NULL
);
682 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
683 ++(This
->next_index
);
685 res
= CLSIDFromString(clsid
, rgelt
);
686 if (FAILED(res
)) continue;
688 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
689 if (res
!= ERROR_SUCCESS
) continue;
691 res
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
693 if (res
!= S_OK
) continue;
699 if (pceltFetched
) *pceltFetched
= fetched
;
700 return fetched
== celt
? S_OK
: S_FALSE
;
703 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
707 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
711 if (This
== NULL
) return E_POINTER
;
712 This
->next_index
+= celt
;
713 FIXME("Never returns S_FALSE\n");
717 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
719 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
723 if (This
== NULL
) return E_POINTER
;
724 This
->next_index
= 0;
728 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
732 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
733 WCHAR keyname
[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
734 CLSID_IEnumGUIDImpl
*new_this
;
739 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
741 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
742 if (new_this
== NULL
) return E_OUTOFMEMORY
;
744 new_this
->lpVtbl
= This
->lpVtbl
;
746 size
= HeapSize(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
747 new_this
->categories
=
748 HeapAlloc(GetProcessHeap(), 0, size
);
749 if (new_this
->categories
== NULL
) {
750 HeapFree(GetProcessHeap(), 0, new_this
);
751 return E_OUTOFMEMORY
;
753 memcpy((LPVOID
)new_this
->categories
, This
->categories
, size
);
754 /* FIXME: could we more efficiently use DuplicateHandle? */
755 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
756 new_this
->next_index
= This
->next_index
;
758 *ppenum
= (LPENUMGUID
)new_this
;
762 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
764 COMCAT_CLSID_IEnumGUID_QueryInterface
,
765 COMCAT_CLSID_IEnumGUID_AddRef
,
766 COMCAT_CLSID_IEnumGUID_Release
,
767 COMCAT_CLSID_IEnumGUID_Next
,
768 COMCAT_CLSID_IEnumGUID_Skip
,
769 COMCAT_CLSID_IEnumGUID_Reset
,
770 COMCAT_CLSID_IEnumGUID_Clone
773 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(
774 struct class_categories
const* categories
)
776 CLSID_IEnumGUIDImpl
*This
;
778 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
780 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
782 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
783 This
->categories
= categories
;
784 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
786 return (LPENUMGUID
)This
;
789 /**********************************************************************
790 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
792 * This implementation is not thread-safe. The manager itself is, but
793 * I can't imagine a valid use of an enumerator in several threads.
797 const IEnumGUIDVtbl
*lpVtbl
;
802 } CATID_IEnumGUIDImpl
;
804 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
806 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
809 if (This
== NULL
) return E_POINTER
;
811 return InterlockedIncrement(&This
->ref
);
814 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
819 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
820 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
822 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
824 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
825 IsEqualGUID(riid
, &IID_IEnumGUID
))
827 *ppvObj
= (LPVOID
)iface
;
828 COMCAT_CATID_IEnumGUID_AddRef(iface
);
832 return E_NOINTERFACE
;
835 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
837 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
842 if (This
== NULL
) return E_POINTER
;
844 ref
= InterlockedDecrement(&This
->ref
);
846 if (This
->key
) RegCloseKey(This
->key
);
847 HeapFree(GetProcessHeap(), 0, This
);
853 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
859 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
864 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
866 if (This
->key
) while (fetched
< celt
) {
871 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
872 NULL
, NULL
, NULL
, NULL
);
873 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
874 ++(This
->next_index
);
876 res
= CLSIDFromString(catid
, rgelt
);
877 if (FAILED(res
)) continue;
883 if (pceltFetched
) *pceltFetched
= fetched
;
884 return fetched
== celt
? S_OK
: S_FALSE
;
887 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
891 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
895 if (This
== NULL
) return E_POINTER
;
896 This
->next_index
+= celt
;
897 FIXME("Never returns S_FALSE\n");
901 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
903 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
907 if (This
== NULL
) return E_POINTER
;
908 This
->next_index
= 0;
912 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
916 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
917 CATID_IEnumGUIDImpl
*new_this
;
921 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
923 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
924 if (new_this
== NULL
) return E_OUTOFMEMORY
;
926 new_this
->lpVtbl
= This
->lpVtbl
;
928 lstrcpyW(new_this
->keyname
, This
->keyname
);
929 /* FIXME: could we more efficiently use DuplicateHandle? */
930 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
931 new_this
->next_index
= This
->next_index
;
933 *ppenum
= (LPENUMGUID
)new_this
;
937 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
939 COMCAT_CATID_IEnumGUID_QueryInterface
,
940 COMCAT_CATID_IEnumGUID_AddRef
,
941 COMCAT_CATID_IEnumGUID_Release
,
942 COMCAT_CATID_IEnumGUID_Next
,
943 COMCAT_CATID_IEnumGUID_Skip
,
944 COMCAT_CATID_IEnumGUID_Reset
,
945 COMCAT_CATID_IEnumGUID_Clone
948 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
949 REFCLSID rclsid
, LPCWSTR postfix
)
951 CATID_IEnumGUIDImpl
*This
;
953 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
955 WCHAR prefix
[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
957 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
958 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
959 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
960 lstrcpyW(This
->keyname
+ 44, postfix
);
961 RegOpenKeyExW(HKEY_CLASSES_ROOT
, This
->keyname
, 0, KEY_READ
, &This
->key
);
963 return (LPENUMGUID
)This
;