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 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 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 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 IEnumCATEGORYINFOVtbl
*lpVtbl
;
305 } IEnumCATEGORYINFOImpl
;
307 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(LPENUMCATEGORYINFO iface
)
309 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
312 if (This
== NULL
) return E_POINTER
;
314 return ++(This
->ref
);
317 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
318 LPENUMCATEGORYINFO iface
,
322 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
323 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
325 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
327 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
328 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
330 *ppvObj
= (LPVOID
)iface
;
331 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
335 return E_NOINTERFACE
;
338 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(LPENUMCATEGORYINFO iface
)
340 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
343 if (This
== NULL
) return E_POINTER
;
345 if (--(This
->ref
) == 0) {
346 if (This
->key
) RegCloseKey(This
->key
);
347 HeapFree(GetProcessHeap(), 0, This
);
353 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
354 LPENUMCATEGORYINFO iface
,
359 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
364 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
366 if (This
->key
) while (fetched
< celt
) {
372 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
373 NULL
, NULL
, NULL
, NULL
);
374 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
375 ++(This
->next_index
);
377 res
= CLSIDFromString(catid
, &rgelt
->catid
);
378 if (FAILED(res
)) continue;
380 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
381 if (res
!= ERROR_SUCCESS
) continue;
383 res
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
384 rgelt
->szDescription
, 128);
386 if (FAILED(res
)) continue;
388 rgelt
->lcid
= This
->lcid
;
393 if (pceltFetched
) *pceltFetched
= fetched
;
394 return fetched
== celt
? S_OK
: S_FALSE
;
397 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
398 LPENUMCATEGORYINFO iface
,
401 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
405 if (This
== NULL
) return E_POINTER
;
406 This
->next_index
+= celt
;
407 /* This should return S_FALSE when there aren't celt elems to skip. */
411 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface
)
413 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
417 if (This
== NULL
) return E_POINTER
;
418 This
->next_index
= 0;
422 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
423 LPENUMCATEGORYINFO iface
,
424 IEnumCATEGORYINFO
**ppenum
)
426 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
427 WCHAR keyname
[21] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
428 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
429 'r', 'i', 'e', 's', 0 };
430 IEnumCATEGORYINFOImpl
*new_this
;
434 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
436 new_this
= (IEnumCATEGORYINFOImpl
*) HeapAlloc(
437 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
438 if (new_this
== NULL
) return E_OUTOFMEMORY
;
440 new_this
->lpVtbl
= This
->lpVtbl
;
442 new_this
->lcid
= This
->lcid
;
443 /* FIXME: could we more efficiently use DuplicateHandle? */
444 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
445 new_this
->next_index
= This
->next_index
;
447 *ppenum
= (LPENUMCATEGORYINFO
)new_this
;
451 IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
453 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
454 COMCAT_IEnumCATEGORYINFO_AddRef
,
455 COMCAT_IEnumCATEGORYINFO_Release
,
456 COMCAT_IEnumCATEGORYINFO_Next
,
457 COMCAT_IEnumCATEGORYINFO_Skip
,
458 COMCAT_IEnumCATEGORYINFO_Reset
,
459 COMCAT_IEnumCATEGORYINFO_Clone
462 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
464 IEnumCATEGORYINFOImpl
*This
;
466 This
= (IEnumCATEGORYINFOImpl
*) HeapAlloc(
467 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
469 WCHAR keyname
[21] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
470 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
471 'r', 'i', 'e', 's', 0 };
473 This
->lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
475 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
477 return (LPENUMCATEGORYINFO
)This
;
480 /**********************************************************************
481 * COMCAT_GetCategoryDesc
483 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
486 WCHAR fmt
[4] = { '%', 'l', 'X', 0 };
489 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
491 if (pszDesc
== NULL
) return E_INVALIDARG
;
493 /* FIXME: lcid comparisons are more complex than this! */
494 wsprintfW(valname
, fmt
, lcid
);
495 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
496 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
497 FIXME("Simplified lcid comparison\n");
498 return CAT_E_NODESCRIPTION
;
500 pszDesc
[size
/ sizeof(WCHAR
)] = (WCHAR
)0;
505 /**********************************************************************
506 * COMCAT_PrepareClassCategories
508 static struct class_categories
*COMCAT_PrepareClassCategories(
509 ULONG impl_count
, CATID
*impl_catids
, ULONG req_count
, CATID
*req_catids
)
511 struct class_categories
*categories
;
514 categories
= (struct class_categories
*)HeapAlloc(
515 GetProcessHeap(), HEAP_ZERO_MEMORY
,
516 sizeof(struct class_categories
) +
517 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
518 if (categories
== NULL
) return categories
;
520 strings
= (WCHAR
*)(categories
+ 1);
521 categories
->impl_strings
= strings
;
522 while (impl_count
--) {
523 StringFromGUID2(impl_catids
++, strings
, 39);
528 categories
->req_strings
= strings
;
529 while (req_count
--) {
530 StringFromGUID2(req_catids
++, strings
, 39);
538 /**********************************************************************
539 * COMCAT_IsClassOfCategories
541 static HRESULT
COMCAT_IsClassOfCategories(
543 struct class_categories
const* categories
)
545 WCHAR impl_keyname
[23] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
546 't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
547 'g', 'o', 'r', 'i', 'e', 's', 0 };
548 WCHAR req_keyname
[20] = { 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'd',
549 ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r',
556 /* Check that every given category is implemented by class. */
557 res
= RegOpenKeyExW(key
, impl_keyname
, 0, KEY_READ
, &subkey
);
558 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
559 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
561 res
= RegOpenKeyExW(subkey
, string
, 0, 0, &catkey
);
562 if (res
!= ERROR_SUCCESS
) {
570 /* Check that all categories required by class are given. */
571 res
= RegOpenKeyExW(key
, req_keyname
, 0, KEY_READ
, &subkey
);
572 if (res
== ERROR_SUCCESS
) {
573 for (index
= 0; ; ++index
) {
577 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
578 NULL
, NULL
, NULL
, NULL
);
579 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
580 if (size
!= 38) continue; /* bogus catid in registry */
581 for (string
= categories
->req_strings
; *string
; string
+= 39)
582 if (!strcmpiW(string
, keyname
)) break;
594 /**********************************************************************
595 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
597 * This implementation is not thread-safe. The manager itself is, but
598 * I can't imagine a valid use of an enumerator in several threads.
602 IEnumGUIDVtbl
*lpVtbl
;
604 struct class_categories
const *categories
;
607 } CLSID_IEnumGUIDImpl
;
609 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
611 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
614 if (This
== NULL
) return E_POINTER
;
616 return ++(This
->ref
);
619 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
624 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
625 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
627 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
629 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
630 IsEqualGUID(riid
, &IID_IEnumGUID
))
632 *ppvObj
= (LPVOID
)iface
;
633 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
637 return E_NOINTERFACE
;
640 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
642 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
645 if (This
== NULL
) return E_POINTER
;
647 if (--(This
->ref
) == 0) {
648 if (This
->key
) RegCloseKey(This
->key
);
649 HeapFree(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
650 HeapFree(GetProcessHeap(), 0, This
);
656 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
662 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
667 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
669 if (This
->key
) while (fetched
< celt
) {
675 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
676 NULL
, NULL
, NULL
, NULL
);
677 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
678 ++(This
->next_index
);
680 res
= CLSIDFromString(clsid
, rgelt
);
681 if (FAILED(res
)) continue;
683 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
684 if (res
!= ERROR_SUCCESS
) continue;
686 res
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
688 if (res
!= S_OK
) continue;
694 if (pceltFetched
) *pceltFetched
= fetched
;
695 return fetched
== celt
? S_OK
: S_FALSE
;
698 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
702 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
706 if (This
== NULL
) return E_POINTER
;
707 This
->next_index
+= celt
;
708 FIXME("Never returns S_FALSE\n");
712 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
714 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
718 if (This
== NULL
) return E_POINTER
;
719 This
->next_index
= 0;
723 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
727 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
728 WCHAR keyname
[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
729 CLSID_IEnumGUIDImpl
*new_this
;
734 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
736 new_this
= (CLSID_IEnumGUIDImpl
*) HeapAlloc(
737 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
738 if (new_this
== NULL
) return E_OUTOFMEMORY
;
740 new_this
->lpVtbl
= This
->lpVtbl
;
742 size
= HeapSize(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
743 new_this
->categories
= (struct class_categories
*)
744 HeapAlloc(GetProcessHeap(), 0, size
);
745 if (new_this
->categories
== NULL
) {
746 HeapFree(GetProcessHeap(), 0, new_this
);
747 return E_OUTOFMEMORY
;
749 memcpy((LPVOID
)new_this
->categories
, This
->categories
, size
);
750 /* FIXME: could we more efficiently use DuplicateHandle? */
751 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
752 new_this
->next_index
= This
->next_index
;
754 *ppenum
= (LPENUMGUID
)new_this
;
758 IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
760 COMCAT_CLSID_IEnumGUID_QueryInterface
,
761 COMCAT_CLSID_IEnumGUID_AddRef
,
762 COMCAT_CLSID_IEnumGUID_Release
,
763 COMCAT_CLSID_IEnumGUID_Next
,
764 COMCAT_CLSID_IEnumGUID_Skip
,
765 COMCAT_CLSID_IEnumGUID_Reset
,
766 COMCAT_CLSID_IEnumGUID_Clone
769 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(
770 struct class_categories
const* categories
)
772 CLSID_IEnumGUIDImpl
*This
;
774 This
= (CLSID_IEnumGUIDImpl
*) HeapAlloc(
775 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
777 WCHAR keyname
[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
779 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
780 This
->categories
= categories
;
781 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
783 return (LPENUMGUID
)This
;
786 /**********************************************************************
787 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
789 * This implementation is not thread-safe. The manager itself is, but
790 * I can't imagine a valid use of an enumerator in several threads.
794 IEnumGUIDVtbl
*lpVtbl
;
799 } CATID_IEnumGUIDImpl
;
801 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
803 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
806 if (This
== NULL
) return E_POINTER
;
808 return ++(This
->ref
);
811 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
816 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
817 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
819 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
821 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
822 IsEqualGUID(riid
, &IID_IEnumGUID
))
824 *ppvObj
= (LPVOID
)iface
;
825 COMCAT_CATID_IEnumGUID_AddRef(iface
);
829 return E_NOINTERFACE
;
832 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
834 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
837 if (This
== NULL
) return E_POINTER
;
839 if (--(This
->ref
) == 0) {
840 if (This
->key
) RegCloseKey(This
->key
);
841 HeapFree(GetProcessHeap(), 0, This
);
847 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
853 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
858 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
860 if (This
->key
) while (fetched
< celt
) {
865 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
866 NULL
, NULL
, NULL
, NULL
);
867 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
868 ++(This
->next_index
);
870 res
= CLSIDFromString(catid
, rgelt
);
871 if (FAILED(res
)) continue;
877 if (pceltFetched
) *pceltFetched
= fetched
;
878 return fetched
== celt
? S_OK
: S_FALSE
;
881 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
885 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
889 if (This
== NULL
) return E_POINTER
;
890 This
->next_index
+= celt
;
891 FIXME("Never returns S_FALSE\n");
895 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
897 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
901 if (This
== NULL
) return E_POINTER
;
902 This
->next_index
= 0;
906 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
910 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
911 CATID_IEnumGUIDImpl
*new_this
;
915 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
917 new_this
= (CATID_IEnumGUIDImpl
*) HeapAlloc(
918 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
919 if (new_this
== NULL
) return E_OUTOFMEMORY
;
921 new_this
->lpVtbl
= This
->lpVtbl
;
923 lstrcpyW(new_this
->keyname
, This
->keyname
);
924 /* FIXME: could we more efficiently use DuplicateHandle? */
925 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
926 new_this
->next_index
= This
->next_index
;
928 *ppenum
= (LPENUMGUID
)new_this
;
932 IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
934 COMCAT_CATID_IEnumGUID_QueryInterface
,
935 COMCAT_CATID_IEnumGUID_AddRef
,
936 COMCAT_CATID_IEnumGUID_Release
,
937 COMCAT_CATID_IEnumGUID_Next
,
938 COMCAT_CATID_IEnumGUID_Skip
,
939 COMCAT_CATID_IEnumGUID_Reset
,
940 COMCAT_CATID_IEnumGUID_Clone
943 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
944 REFCLSID rclsid
, LPCWSTR postfix
)
946 CATID_IEnumGUIDImpl
*This
;
948 This
= (CATID_IEnumGUIDImpl
*) HeapAlloc(
949 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
951 WCHAR prefix
[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
953 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
954 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
955 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
956 lstrcpyW(This
->keyname
+ 44, postfix
);
957 RegOpenKeyExW(HKEY_CLASSES_ROOT
, This
->keyname
, 0, KEY_READ
, &This
->key
);
959 return (LPENUMGUID
)This
;