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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, 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
, const CATID
*impl_catids
, ULONG req_count
, const 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
*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%X\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 (cImplemented
== (ULONG
)-1)
168 if (cRequired
== (ULONG
)-1)
171 if (iface
== NULL
|| ppenumCLSID
== NULL
||
172 (cImplemented
&& rgcatidImpl
== NULL
) ||
173 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
175 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
176 cRequired
, rgcatidReq
);
177 if (categories
== NULL
) return E_OUTOFMEMORY
;
178 *ppenumCLSID
= COMCAT_CLSID_IEnumGUID_Construct(categories
);
179 if (*ppenumCLSID
== NULL
) {
180 HeapFree(GetProcessHeap(), 0, categories
);
181 return E_OUTOFMEMORY
;
183 IEnumGUID_AddRef(*ppenumCLSID
);
187 /**********************************************************************
188 * COMCAT_ICatInformation_IsClassOfCategories
190 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
191 LPCATINFORMATION iface
,
198 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
199 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
201 struct class_categories
*categories
;
204 if (WINE_TRACE_ON(ole
)) {
206 TRACE("\n\tCLSID:\t%s\n\tImplemented %u\n",debugstr_guid(rclsid
),cImplemented
);
207 for (count
= 0; count
< cImplemented
; ++count
)
208 TRACE("\t\t%s\n",debugstr_guid(&rgcatidImpl
[count
]));
209 TRACE("\tRequired %u\n",cRequired
);
210 for (count
= 0; count
< cRequired
; ++count
)
211 TRACE("\t\t%s\n",debugstr_guid(&rgcatidReq
[count
]));
214 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
215 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
217 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
218 if (FAILED(res
)) return res
;
220 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
221 cRequired
, rgcatidReq
);
222 if (categories
== NULL
) return E_OUTOFMEMORY
;
224 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
225 if (res
== ERROR_SUCCESS
) {
226 res
= COMCAT_IsClassOfCategories(key
, categories
);
228 } else res
= S_FALSE
;
230 HeapFree(GetProcessHeap(), 0, categories
);
235 /**********************************************************************
236 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
238 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
239 LPCATINFORMATION iface
,
241 LPENUMCATID
*ppenumCATID
)
243 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
244 static const WCHAR postfix
[24] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
245 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
246 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
248 TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid
));
250 if (iface
== NULL
|| rclsid
== NULL
|| ppenumCATID
== NULL
)
253 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
254 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
258 /**********************************************************************
259 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
261 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
262 LPCATINFORMATION iface
,
264 LPENUMCATID
*ppenumCATID
)
266 /* ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
267 static const WCHAR postfix
[21] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
268 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
269 'r', 'i', 'e', 's', 0 };
271 TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid
));
273 if (iface
== NULL
|| rclsid
== NULL
|| ppenumCATID
== NULL
)
276 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
277 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
281 /**********************************************************************
282 * COMCAT_ICatInformation_Vtbl
284 const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
286 COMCAT_ICatInformation_QueryInterface
,
287 COMCAT_ICatInformation_AddRef
,
288 COMCAT_ICatInformation_Release
,
289 COMCAT_ICatInformation_EnumCategories
,
290 COMCAT_ICatInformation_GetCategoryDesc
,
291 COMCAT_ICatInformation_EnumClassesOfCategories
,
292 COMCAT_ICatInformation_IsClassOfCategories
,
293 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
294 COMCAT_ICatInformation_EnumReqCategoriesOfClass
297 /**********************************************************************
298 * IEnumCATEGORYINFO implementation
300 * This implementation is not thread-safe. The manager itself is, but
301 * I can't imagine a valid use of an enumerator in several threads.
305 const IEnumCATEGORYINFOVtbl
*lpVtbl
;
310 } IEnumCATEGORYINFOImpl
;
312 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(LPENUMCATEGORYINFO iface
)
314 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
318 if (This
== NULL
) return E_POINTER
;
320 return InterlockedIncrement(&This
->ref
);
323 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
324 LPENUMCATEGORYINFO iface
,
328 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
329 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
331 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
333 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
334 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
336 *ppvObj
= (LPVOID
)iface
;
337 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
341 return E_NOINTERFACE
;
344 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(LPENUMCATEGORYINFO iface
)
346 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
351 if (This
== NULL
) return E_POINTER
;
353 ref
= InterlockedDecrement(&This
->ref
);
355 if (This
->key
) RegCloseKey(This
->key
);
356 HeapFree(GetProcessHeap(), 0, This
);
362 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
363 LPENUMCATEGORYINFO iface
,
368 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
373 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
375 if (This
->key
) while (fetched
< celt
) {
381 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
382 NULL
, NULL
, NULL
, NULL
);
383 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
384 ++(This
->next_index
);
386 res
= CLSIDFromString(catid
, &rgelt
->catid
);
387 if (FAILED(res
)) continue;
389 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
390 if (res
!= ERROR_SUCCESS
) continue;
392 res
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
393 rgelt
->szDescription
, 128);
395 if (FAILED(res
)) continue;
397 rgelt
->lcid
= This
->lcid
;
402 if (pceltFetched
) *pceltFetched
= fetched
;
403 return fetched
== celt
? S_OK
: S_FALSE
;
406 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
407 LPENUMCATEGORYINFO iface
,
410 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
414 if (This
== NULL
) return E_POINTER
;
415 This
->next_index
+= celt
;
416 /* This should return S_FALSE when there aren't celt elems to skip. */
420 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface
)
422 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
426 if (This
== NULL
) return E_POINTER
;
427 This
->next_index
= 0;
431 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
432 LPENUMCATEGORYINFO iface
,
433 IEnumCATEGORYINFO
**ppenum
)
435 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
436 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
437 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
438 'r', 'i', 'e', 's', 0 };
439 IEnumCATEGORYINFOImpl
*new_this
;
443 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
445 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
446 if (new_this
== NULL
) return E_OUTOFMEMORY
;
448 new_this
->lpVtbl
= This
->lpVtbl
;
450 new_this
->lcid
= This
->lcid
;
451 /* FIXME: could we more efficiently use DuplicateHandle? */
452 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
453 new_this
->next_index
= This
->next_index
;
455 *ppenum
= (LPENUMCATEGORYINFO
)new_this
;
459 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
461 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
462 COMCAT_IEnumCATEGORYINFO_AddRef
,
463 COMCAT_IEnumCATEGORYINFO_Release
,
464 COMCAT_IEnumCATEGORYINFO_Next
,
465 COMCAT_IEnumCATEGORYINFO_Skip
,
466 COMCAT_IEnumCATEGORYINFO_Reset
,
467 COMCAT_IEnumCATEGORYINFO_Clone
470 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
472 IEnumCATEGORYINFOImpl
*This
;
474 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
476 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
477 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
478 'r', 'i', 'e', 's', 0 };
480 This
->lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
482 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
484 return (LPENUMCATEGORYINFO
)This
;
487 /**********************************************************************
488 * COMCAT_GetCategoryDesc
490 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
493 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
496 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
498 if (pszDesc
== NULL
) return E_INVALIDARG
;
500 /* FIXME: lcid comparisons are more complex than this! */
501 wsprintfW(valname
, fmt
, lcid
);
502 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
503 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
504 FIXME("Simplified lcid comparison\n");
505 return CAT_E_NODESCRIPTION
;
507 pszDesc
[size
/ sizeof(WCHAR
)] = (WCHAR
)0;
512 /**********************************************************************
513 * COMCAT_PrepareClassCategories
515 static struct class_categories
*COMCAT_PrepareClassCategories(
516 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
518 struct class_categories
*categories
;
521 categories
= HeapAlloc(
522 GetProcessHeap(), HEAP_ZERO_MEMORY
,
523 sizeof(struct class_categories
) +
524 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
525 if (categories
== NULL
) return categories
;
527 strings
= (WCHAR
*)(categories
+ 1);
528 categories
->impl_strings
= strings
;
529 while (impl_count
--) {
530 StringFromGUID2(impl_catids
++, strings
, 39);
535 categories
->req_strings
= strings
;
536 while (req_count
--) {
537 StringFromGUID2(req_catids
++, strings
, 39);
545 /**********************************************************************
546 * COMCAT_IsClassOfCategories
548 static HRESULT
COMCAT_IsClassOfCategories(
550 struct class_categories
const* categories
)
552 static const WCHAR impl_keyname
[] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
553 't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
554 'g', 'o', 'r', 'i', 'e', 's', 0 };
555 static const WCHAR req_keyname
[] = { 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'd',
556 ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r',
563 /* Check that every given category is implemented by class. */
564 res
= RegOpenKeyExW(key
, impl_keyname
, 0, KEY_READ
, &subkey
);
565 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
566 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
568 res
= RegOpenKeyExW(subkey
, string
, 0, 0, &catkey
);
569 if (res
!= ERROR_SUCCESS
) {
577 /* Check that all categories required by class are given. */
578 res
= RegOpenKeyExW(key
, req_keyname
, 0, KEY_READ
, &subkey
);
579 if (res
== ERROR_SUCCESS
) {
580 for (index
= 0; ; ++index
) {
584 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
585 NULL
, NULL
, NULL
, NULL
);
586 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
587 if (size
!= 38) continue; /* bogus catid in registry */
588 for (string
= categories
->req_strings
; *string
; string
+= 39)
589 if (!strcmpiW(string
, keyname
)) break;
601 /**********************************************************************
602 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
604 * This implementation is not thread-safe. The manager itself is, but
605 * I can't imagine a valid use of an enumerator in several threads.
609 const IEnumGUIDVtbl
*lpVtbl
;
611 struct class_categories
*categories
;
614 } CLSID_IEnumGUIDImpl
;
616 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
618 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
621 if (This
== NULL
) return E_POINTER
;
623 return InterlockedIncrement(&This
->ref
);
626 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
631 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
632 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
634 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
636 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
637 IsEqualGUID(riid
, &IID_IEnumGUID
))
639 *ppvObj
= (LPVOID
)iface
;
640 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
644 return E_NOINTERFACE
;
647 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
649 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
654 if (This
== NULL
) return E_POINTER
;
656 ref
= InterlockedDecrement(&This
->ref
);
658 if (This
->key
) RegCloseKey(This
->key
);
659 HeapFree(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
660 HeapFree(GetProcessHeap(), 0, This
);
666 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
672 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
677 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
679 if (This
->key
) while (fetched
< celt
) {
685 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
686 NULL
, NULL
, NULL
, NULL
);
687 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
688 ++(This
->next_index
);
690 res
= CLSIDFromString(clsid
, rgelt
);
691 if (FAILED(res
)) continue;
693 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
694 if (res
!= ERROR_SUCCESS
) continue;
696 res
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
698 if (res
!= S_OK
) continue;
704 if (pceltFetched
) *pceltFetched
= fetched
;
705 return fetched
== celt
? S_OK
: S_FALSE
;
708 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
712 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
716 if (This
== NULL
) return E_POINTER
;
717 This
->next_index
+= celt
;
718 FIXME("Never returns S_FALSE\n");
722 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
724 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
728 if (This
== NULL
) return E_POINTER
;
729 This
->next_index
= 0;
733 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
737 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
738 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
739 CLSID_IEnumGUIDImpl
*new_this
;
744 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
746 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
747 if (new_this
== NULL
) return E_OUTOFMEMORY
;
749 new_this
->lpVtbl
= This
->lpVtbl
;
751 size
= HeapSize(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
752 new_this
->categories
=
753 HeapAlloc(GetProcessHeap(), 0, size
);
754 if (new_this
->categories
== NULL
) {
755 HeapFree(GetProcessHeap(), 0, new_this
);
756 return E_OUTOFMEMORY
;
758 memcpy((LPVOID
)new_this
->categories
, This
->categories
, size
);
759 /* FIXME: could we more efficiently use DuplicateHandle? */
760 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
761 new_this
->next_index
= This
->next_index
;
763 *ppenum
= (LPENUMGUID
)new_this
;
767 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
769 COMCAT_CLSID_IEnumGUID_QueryInterface
,
770 COMCAT_CLSID_IEnumGUID_AddRef
,
771 COMCAT_CLSID_IEnumGUID_Release
,
772 COMCAT_CLSID_IEnumGUID_Next
,
773 COMCAT_CLSID_IEnumGUID_Skip
,
774 COMCAT_CLSID_IEnumGUID_Reset
,
775 COMCAT_CLSID_IEnumGUID_Clone
778 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*categories
)
780 CLSID_IEnumGUIDImpl
*This
;
782 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
784 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
786 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
787 This
->categories
= categories
;
788 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
790 return (LPENUMGUID
)This
;
793 /**********************************************************************
794 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
796 * This implementation is not thread-safe. The manager itself is, but
797 * I can't imagine a valid use of an enumerator in several threads.
801 const IEnumGUIDVtbl
*lpVtbl
;
806 } CATID_IEnumGUIDImpl
;
808 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
810 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
813 if (This
== NULL
) return E_POINTER
;
815 return InterlockedIncrement(&This
->ref
);
818 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
823 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
824 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
826 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
828 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
829 IsEqualGUID(riid
, &IID_IEnumGUID
))
831 *ppvObj
= (LPVOID
)iface
;
832 COMCAT_CATID_IEnumGUID_AddRef(iface
);
836 return E_NOINTERFACE
;
839 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
841 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
846 if (This
== NULL
) return E_POINTER
;
848 ref
= InterlockedDecrement(&This
->ref
);
850 if (This
->key
) RegCloseKey(This
->key
);
851 HeapFree(GetProcessHeap(), 0, This
);
857 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
863 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
868 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
870 if (This
->key
) while (fetched
< celt
) {
875 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
876 NULL
, NULL
, NULL
, NULL
);
877 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
878 ++(This
->next_index
);
880 res
= CLSIDFromString(catid
, rgelt
);
881 if (FAILED(res
)) continue;
887 if (pceltFetched
) *pceltFetched
= fetched
;
888 return fetched
== celt
? S_OK
: S_FALSE
;
891 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
895 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
899 if (This
== NULL
) return E_POINTER
;
900 This
->next_index
+= celt
;
901 FIXME("Never returns S_FALSE\n");
905 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
907 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
911 if (This
== NULL
) return E_POINTER
;
912 This
->next_index
= 0;
916 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
920 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
921 CATID_IEnumGUIDImpl
*new_this
;
925 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
927 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
928 if (new_this
== NULL
) return E_OUTOFMEMORY
;
930 new_this
->lpVtbl
= This
->lpVtbl
;
932 lstrcpyW(new_this
->keyname
, This
->keyname
);
933 /* FIXME: could we more efficiently use DuplicateHandle? */
934 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
935 new_this
->next_index
= This
->next_index
;
937 *ppenum
= (LPENUMGUID
)new_this
;
941 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
943 COMCAT_CATID_IEnumGUID_QueryInterface
,
944 COMCAT_CATID_IEnumGUID_AddRef
,
945 COMCAT_CATID_IEnumGUID_Release
,
946 COMCAT_CATID_IEnumGUID_Next
,
947 COMCAT_CATID_IEnumGUID_Skip
,
948 COMCAT_CATID_IEnumGUID_Reset
,
949 COMCAT_CATID_IEnumGUID_Clone
952 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
953 REFCLSID rclsid
, LPCWSTR postfix
)
955 CATID_IEnumGUIDImpl
*This
;
957 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
959 WCHAR prefix
[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
961 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
962 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
963 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
964 lstrcpyW(This
->keyname
+ 44, postfix
);
965 RegOpenKeyExW(HKEY_CLASSES_ROOT
, This
->keyname
, 0, KEY_READ
, &This
->key
);
967 return (LPENUMGUID
)This
;