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 ICOM_VTABLE(ICatInformation
) COMCAT_ICatInformation_Vtbl
=
281 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
282 COMCAT_ICatInformation_QueryInterface
,
283 COMCAT_ICatInformation_AddRef
,
284 COMCAT_ICatInformation_Release
,
285 COMCAT_ICatInformation_EnumCategories
,
286 COMCAT_ICatInformation_GetCategoryDesc
,
287 COMCAT_ICatInformation_EnumClassesOfCategories
,
288 COMCAT_ICatInformation_IsClassOfCategories
,
289 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
290 COMCAT_ICatInformation_EnumReqCategoriesOfClass
293 /**********************************************************************
294 * IEnumCATEGORYINFO implementation
296 * This implementation is not thread-safe. The manager itself is, but
297 * I can't imagine a valid use of an enumerator in several threads.
301 ICOM_VFIELD(IEnumCATEGORYINFO
);
306 } IEnumCATEGORYINFOImpl
;
308 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(LPENUMCATEGORYINFO iface
)
310 ICOM_THIS(IEnumCATEGORYINFOImpl
, iface
);
313 if (This
== NULL
) return E_POINTER
;
315 return ++(This
->ref
);
318 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
319 LPENUMCATEGORYINFO iface
,
323 ICOM_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 ICOM_THIS(IEnumCATEGORYINFOImpl
, iface
);
344 if (This
== NULL
) return E_POINTER
;
346 if (--(This
->ref
) == 0) {
347 if (This
->key
) RegCloseKey(This
->key
);
348 HeapFree(GetProcessHeap(), 0, This
);
354 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
355 LPENUMCATEGORYINFO iface
,
360 ICOM_THIS(IEnumCATEGORYINFOImpl
, iface
);
365 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
367 if (This
->key
) while (fetched
< celt
) {
373 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
374 NULL
, NULL
, NULL
, NULL
);
375 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
376 ++(This
->next_index
);
378 res
= CLSIDFromString(catid
, &rgelt
->catid
);
379 if (FAILED(res
)) continue;
381 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
382 if (res
!= ERROR_SUCCESS
) continue;
384 res
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
385 rgelt
->szDescription
, 128);
387 if (FAILED(res
)) continue;
389 rgelt
->lcid
= This
->lcid
;
394 if (pceltFetched
) *pceltFetched
= fetched
;
395 return fetched
== celt
? S_OK
: S_FALSE
;
398 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
399 LPENUMCATEGORYINFO iface
,
402 ICOM_THIS(IEnumCATEGORYINFOImpl
, iface
);
406 if (This
== NULL
) return E_POINTER
;
407 This
->next_index
+= celt
;
408 /* This should return S_FALSE when there aren't celt elems to skip. */
412 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface
)
414 ICOM_THIS(IEnumCATEGORYINFOImpl
, iface
);
418 if (This
== NULL
) return E_POINTER
;
419 This
->next_index
= 0;
423 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
424 LPENUMCATEGORYINFO iface
,
425 IEnumCATEGORYINFO
**ppenum
)
427 ICOM_THIS(IEnumCATEGORYINFOImpl
, iface
);
428 WCHAR keyname
[21] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
429 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
430 'r', 'i', 'e', 's', 0 };
431 IEnumCATEGORYINFOImpl
*new_this
;
435 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
437 new_this
= (IEnumCATEGORYINFOImpl
*) HeapAlloc(
438 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
439 if (new_this
== NULL
) return E_OUTOFMEMORY
;
441 new_this
->lpVtbl
= This
->lpVtbl
;
443 new_this
->lcid
= This
->lcid
;
444 /* FIXME: could we more efficiently use DuplicateHandle? */
445 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
446 new_this
->next_index
= This
->next_index
;
448 *ppenum
= (LPENUMCATEGORYINFO
)new_this
;
452 ICOM_VTABLE(IEnumCATEGORYINFO
) COMCAT_IEnumCATEGORYINFO_Vtbl
=
454 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
455 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
456 COMCAT_IEnumCATEGORYINFO_AddRef
,
457 COMCAT_IEnumCATEGORYINFO_Release
,
458 COMCAT_IEnumCATEGORYINFO_Next
,
459 COMCAT_IEnumCATEGORYINFO_Skip
,
460 COMCAT_IEnumCATEGORYINFO_Reset
,
461 COMCAT_IEnumCATEGORYINFO_Clone
464 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
466 IEnumCATEGORYINFOImpl
*This
;
468 This
= (IEnumCATEGORYINFOImpl
*) HeapAlloc(
469 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
= (struct class_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 ICOM_VFIELD(IEnumGUID
);
606 struct class_categories
const *categories
;
609 } CLSID_IEnumGUIDImpl
;
611 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
613 ICOM_THIS(CLSID_IEnumGUIDImpl
, iface
);
616 if (This
== NULL
) return E_POINTER
;
618 return ++(This
->ref
);
621 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
626 ICOM_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 ICOM_THIS(CLSID_IEnumGUIDImpl
, iface
);
647 if (This
== NULL
) return E_POINTER
;
649 if (--(This
->ref
) == 0) {
650 if (This
->key
) RegCloseKey(This
->key
);
651 HeapFree(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
652 HeapFree(GetProcessHeap(), 0, This
);
658 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
664 ICOM_THIS(CLSID_IEnumGUIDImpl
, iface
);
669 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
671 if (This
->key
) while (fetched
< celt
) {
677 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
678 NULL
, NULL
, NULL
, NULL
);
679 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
680 ++(This
->next_index
);
682 res
= CLSIDFromString(clsid
, rgelt
);
683 if (FAILED(res
)) continue;
685 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
686 if (res
!= ERROR_SUCCESS
) continue;
688 res
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
690 if (res
!= S_OK
) continue;
696 if (pceltFetched
) *pceltFetched
= fetched
;
697 return fetched
== celt
? S_OK
: S_FALSE
;
700 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
704 ICOM_THIS(CLSID_IEnumGUIDImpl
, iface
);
708 if (This
== NULL
) return E_POINTER
;
709 This
->next_index
+= celt
;
710 FIXME("Never returns S_FALSE\n");
714 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
716 ICOM_THIS(CLSID_IEnumGUIDImpl
, iface
);
720 if (This
== NULL
) return E_POINTER
;
721 This
->next_index
= 0;
725 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
729 ICOM_THIS(CLSID_IEnumGUIDImpl
, iface
);
730 WCHAR keyname
[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
731 CLSID_IEnumGUIDImpl
*new_this
;
736 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
738 new_this
= (CLSID_IEnumGUIDImpl
*) HeapAlloc(
739 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
740 if (new_this
== NULL
) return E_OUTOFMEMORY
;
742 new_this
->lpVtbl
= This
->lpVtbl
;
744 size
= HeapSize(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
745 new_this
->categories
= (struct class_categories
*)
746 HeapAlloc(GetProcessHeap(), 0, size
);
747 if (new_this
->categories
== NULL
) {
748 HeapFree(GetProcessHeap(), 0, new_this
);
749 return E_OUTOFMEMORY
;
751 memcpy((LPVOID
)new_this
->categories
, This
->categories
, size
);
752 /* FIXME: could we more efficiently use DuplicateHandle? */
753 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
754 new_this
->next_index
= This
->next_index
;
756 *ppenum
= (LPENUMGUID
)new_this
;
760 ICOM_VTABLE(IEnumGUID
) COMCAT_CLSID_IEnumGUID_Vtbl
=
762 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
763 COMCAT_CLSID_IEnumGUID_QueryInterface
,
764 COMCAT_CLSID_IEnumGUID_AddRef
,
765 COMCAT_CLSID_IEnumGUID_Release
,
766 COMCAT_CLSID_IEnumGUID_Next
,
767 COMCAT_CLSID_IEnumGUID_Skip
,
768 COMCAT_CLSID_IEnumGUID_Reset
,
769 COMCAT_CLSID_IEnumGUID_Clone
772 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(
773 struct class_categories
const* categories
)
775 CLSID_IEnumGUIDImpl
*This
;
777 This
= (CLSID_IEnumGUIDImpl
*) HeapAlloc(
778 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
780 WCHAR keyname
[6] = { '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 ICOM_VFIELD(IEnumGUID
);
802 } CATID_IEnumGUIDImpl
;
804 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
806 ICOM_THIS(CATID_IEnumGUIDImpl
, iface
);
809 if (This
== NULL
) return E_POINTER
;
811 return ++(This
->ref
);
814 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
819 ICOM_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 ICOM_THIS(CATID_IEnumGUIDImpl
, iface
);
840 if (This
== NULL
) return E_POINTER
;
842 if (--(This
->ref
) == 0) {
843 if (This
->key
) RegCloseKey(This
->key
);
844 HeapFree(GetProcessHeap(), 0, This
);
850 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
856 ICOM_THIS(CATID_IEnumGUIDImpl
, iface
);
861 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
863 if (This
->key
) while (fetched
< celt
) {
868 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
869 NULL
, NULL
, NULL
, NULL
);
870 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
871 ++(This
->next_index
);
873 res
= CLSIDFromString(catid
, rgelt
);
874 if (FAILED(res
)) continue;
880 if (pceltFetched
) *pceltFetched
= fetched
;
881 return fetched
== celt
? S_OK
: S_FALSE
;
884 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
888 ICOM_THIS(CATID_IEnumGUIDImpl
, iface
);
892 if (This
== NULL
) return E_POINTER
;
893 This
->next_index
+= celt
;
894 FIXME("Never returns S_FALSE\n");
898 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
900 ICOM_THIS(CATID_IEnumGUIDImpl
, iface
);
904 if (This
== NULL
) return E_POINTER
;
905 This
->next_index
= 0;
909 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
913 ICOM_THIS(CATID_IEnumGUIDImpl
, iface
);
914 CATID_IEnumGUIDImpl
*new_this
;
918 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
920 new_this
= (CATID_IEnumGUIDImpl
*) HeapAlloc(
921 GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
922 if (new_this
== NULL
) return E_OUTOFMEMORY
;
924 new_this
->lpVtbl
= This
->lpVtbl
;
926 lstrcpyW(new_this
->keyname
, This
->keyname
);
927 /* FIXME: could we more efficiently use DuplicateHandle? */
928 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
929 new_this
->next_index
= This
->next_index
;
931 *ppenum
= (LPENUMGUID
)new_this
;
935 ICOM_VTABLE(IEnumGUID
) COMCAT_CATID_IEnumGUID_Vtbl
=
937 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
938 COMCAT_CATID_IEnumGUID_QueryInterface
,
939 COMCAT_CATID_IEnumGUID_AddRef
,
940 COMCAT_CATID_IEnumGUID_Release
,
941 COMCAT_CATID_IEnumGUID_Next
,
942 COMCAT_CATID_IEnumGUID_Skip
,
943 COMCAT_CATID_IEnumGUID_Reset
,
944 COMCAT_CATID_IEnumGUID_Clone
947 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
948 REFCLSID rclsid
, LPCWSTR postfix
)
950 CATID_IEnumGUIDImpl
*This
;
952 This
= (CATID_IEnumGUIDImpl
*) HeapAlloc(
953 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
;