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
) {
382 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
383 NULL
, NULL
, NULL
, NULL
);
384 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
385 ++(This
->next_index
);
387 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
388 if (FAILED(hr
)) continue;
390 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
391 if (res
!= ERROR_SUCCESS
) continue;
393 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
394 rgelt
->szDescription
, 128);
396 if (FAILED(hr
)) continue;
398 rgelt
->lcid
= This
->lcid
;
403 if (pceltFetched
) *pceltFetched
= fetched
;
404 return fetched
== celt
? S_OK
: S_FALSE
;
407 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
408 LPENUMCATEGORYINFO iface
,
411 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
415 if (This
== NULL
) return E_POINTER
;
416 This
->next_index
+= celt
;
417 /* This should return S_FALSE when there aren't celt elems to skip. */
421 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface
)
423 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
427 if (This
== NULL
) return E_POINTER
;
428 This
->next_index
= 0;
432 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
433 LPENUMCATEGORYINFO iface
,
434 IEnumCATEGORYINFO
**ppenum
)
436 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
437 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
438 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
439 'r', 'i', 'e', 's', 0 };
440 IEnumCATEGORYINFOImpl
*new_this
;
444 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
446 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
447 if (new_this
== NULL
) return E_OUTOFMEMORY
;
449 new_this
->lpVtbl
= This
->lpVtbl
;
451 new_this
->lcid
= This
->lcid
;
452 /* FIXME: could we more efficiently use DuplicateHandle? */
453 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
454 new_this
->next_index
= This
->next_index
;
456 *ppenum
= (LPENUMCATEGORYINFO
)new_this
;
460 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
462 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
463 COMCAT_IEnumCATEGORYINFO_AddRef
,
464 COMCAT_IEnumCATEGORYINFO_Release
,
465 COMCAT_IEnumCATEGORYINFO_Next
,
466 COMCAT_IEnumCATEGORYINFO_Skip
,
467 COMCAT_IEnumCATEGORYINFO_Reset
,
468 COMCAT_IEnumCATEGORYINFO_Clone
471 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
473 IEnumCATEGORYINFOImpl
*This
;
475 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
477 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
478 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
479 'r', 'i', 'e', 's', 0 };
481 This
->lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
483 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
485 return (LPENUMCATEGORYINFO
)This
;
488 /**********************************************************************
489 * COMCAT_GetCategoryDesc
491 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
494 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
497 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
499 if (pszDesc
== NULL
) return E_INVALIDARG
;
501 /* FIXME: lcid comparisons are more complex than this! */
502 wsprintfW(valname
, fmt
, lcid
);
503 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
504 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
505 FIXME("Simplified lcid comparison\n");
506 return CAT_E_NODESCRIPTION
;
508 pszDesc
[size
/ sizeof(WCHAR
)] = (WCHAR
)0;
513 /**********************************************************************
514 * COMCAT_PrepareClassCategories
516 static struct class_categories
*COMCAT_PrepareClassCategories(
517 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
519 struct class_categories
*categories
;
522 categories
= HeapAlloc(
523 GetProcessHeap(), HEAP_ZERO_MEMORY
,
524 sizeof(struct class_categories
) +
525 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
526 if (categories
== NULL
) return categories
;
528 strings
= (WCHAR
*)(categories
+ 1);
529 categories
->impl_strings
= strings
;
530 while (impl_count
--) {
531 StringFromGUID2(impl_catids
++, strings
, 39);
536 categories
->req_strings
= strings
;
537 while (req_count
--) {
538 StringFromGUID2(req_catids
++, strings
, 39);
546 /**********************************************************************
547 * COMCAT_IsClassOfCategories
549 static HRESULT
COMCAT_IsClassOfCategories(
551 struct class_categories
const* categories
)
553 static const WCHAR impl_keyname
[] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
554 't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
555 'g', 'o', 'r', 'i', 'e', 's', 0 };
556 static const WCHAR req_keyname
[] = { 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'd',
557 ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r',
564 /* Check that every given category is implemented by class. */
565 res
= RegOpenKeyExW(key
, impl_keyname
, 0, KEY_READ
, &subkey
);
566 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
567 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
569 res
= RegOpenKeyExW(subkey
, string
, 0, 0, &catkey
);
570 if (res
!= ERROR_SUCCESS
) {
578 /* Check that all categories required by class are given. */
579 res
= RegOpenKeyExW(key
, req_keyname
, 0, KEY_READ
, &subkey
);
580 if (res
== ERROR_SUCCESS
) {
581 for (index
= 0; ; ++index
) {
585 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
586 NULL
, NULL
, NULL
, NULL
);
587 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
588 if (size
!= 38) continue; /* bogus catid in registry */
589 for (string
= categories
->req_strings
; *string
; string
+= 39)
590 if (!strcmpiW(string
, keyname
)) break;
602 /**********************************************************************
603 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
605 * This implementation is not thread-safe. The manager itself is, but
606 * I can't imagine a valid use of an enumerator in several threads.
610 const IEnumGUIDVtbl
*lpVtbl
;
612 struct class_categories
*categories
;
615 } CLSID_IEnumGUIDImpl
;
617 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
619 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
622 if (This
== NULL
) return E_POINTER
;
624 return InterlockedIncrement(&This
->ref
);
627 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
632 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
633 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
635 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
637 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
638 IsEqualGUID(riid
, &IID_IEnumGUID
))
640 *ppvObj
= (LPVOID
)iface
;
641 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
645 return E_NOINTERFACE
;
648 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
650 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
655 if (This
== NULL
) return E_POINTER
;
657 ref
= InterlockedDecrement(&This
->ref
);
659 if (This
->key
) RegCloseKey(This
->key
);
660 HeapFree(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
661 HeapFree(GetProcessHeap(), 0, This
);
667 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
673 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
678 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
680 if (This
->key
) while (fetched
< celt
) {
687 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
688 NULL
, NULL
, NULL
, NULL
);
689 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
690 ++(This
->next_index
);
692 hr
= CLSIDFromString(clsid
, rgelt
);
693 if (FAILED(hr
)) continue;
695 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
696 if (res
!= ERROR_SUCCESS
) continue;
698 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
700 if (hr
!= S_OK
) continue;
706 if (pceltFetched
) *pceltFetched
= fetched
;
707 return fetched
== celt
? S_OK
: S_FALSE
;
710 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
714 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
718 if (This
== NULL
) return E_POINTER
;
719 This
->next_index
+= celt
;
720 FIXME("Never returns S_FALSE\n");
724 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
726 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
730 if (This
== NULL
) return E_POINTER
;
731 This
->next_index
= 0;
735 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
739 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
740 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
741 CLSID_IEnumGUIDImpl
*new_this
;
746 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
748 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
749 if (new_this
== NULL
) return E_OUTOFMEMORY
;
751 new_this
->lpVtbl
= This
->lpVtbl
;
753 size
= HeapSize(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
754 new_this
->categories
=
755 HeapAlloc(GetProcessHeap(), 0, size
);
756 if (new_this
->categories
== NULL
) {
757 HeapFree(GetProcessHeap(), 0, new_this
);
758 return E_OUTOFMEMORY
;
760 memcpy((LPVOID
)new_this
->categories
, This
->categories
, size
);
761 /* FIXME: could we more efficiently use DuplicateHandle? */
762 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
763 new_this
->next_index
= This
->next_index
;
765 *ppenum
= (LPENUMGUID
)new_this
;
769 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
771 COMCAT_CLSID_IEnumGUID_QueryInterface
,
772 COMCAT_CLSID_IEnumGUID_AddRef
,
773 COMCAT_CLSID_IEnumGUID_Release
,
774 COMCAT_CLSID_IEnumGUID_Next
,
775 COMCAT_CLSID_IEnumGUID_Skip
,
776 COMCAT_CLSID_IEnumGUID_Reset
,
777 COMCAT_CLSID_IEnumGUID_Clone
780 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*categories
)
782 CLSID_IEnumGUIDImpl
*This
;
784 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
786 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
788 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
789 This
->categories
= categories
;
790 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
792 return (LPENUMGUID
)This
;
795 /**********************************************************************
796 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
798 * This implementation is not thread-safe. The manager itself is, but
799 * I can't imagine a valid use of an enumerator in several threads.
803 const IEnumGUIDVtbl
*lpVtbl
;
808 } CATID_IEnumGUIDImpl
;
810 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
812 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
815 if (This
== NULL
) return E_POINTER
;
817 return InterlockedIncrement(&This
->ref
);
820 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
825 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
826 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
828 if (This
== NULL
|| ppvObj
== NULL
) return E_POINTER
;
830 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
831 IsEqualGUID(riid
, &IID_IEnumGUID
))
833 *ppvObj
= (LPVOID
)iface
;
834 COMCAT_CATID_IEnumGUID_AddRef(iface
);
838 return E_NOINTERFACE
;
841 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
843 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
848 if (This
== NULL
) return E_POINTER
;
850 ref
= InterlockedDecrement(&This
->ref
);
852 if (This
->key
) RegCloseKey(This
->key
);
853 HeapFree(GetProcessHeap(), 0, This
);
859 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
865 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
870 if (This
== NULL
|| rgelt
== NULL
) return E_POINTER
;
872 if (This
->key
) while (fetched
< celt
) {
878 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
879 NULL
, NULL
, NULL
, NULL
);
880 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
881 ++(This
->next_index
);
883 hr
= CLSIDFromString(catid
, rgelt
);
884 if (FAILED(hr
)) continue;
890 if (pceltFetched
) *pceltFetched
= fetched
;
891 return fetched
== celt
? S_OK
: S_FALSE
;
894 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
898 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
902 if (This
== NULL
) return E_POINTER
;
903 This
->next_index
+= celt
;
904 FIXME("Never returns S_FALSE\n");
908 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
910 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
914 if (This
== NULL
) return E_POINTER
;
915 This
->next_index
= 0;
919 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
923 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
924 CATID_IEnumGUIDImpl
*new_this
;
928 if (This
== NULL
|| ppenum
== NULL
) return E_POINTER
;
930 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
931 if (new_this
== NULL
) return E_OUTOFMEMORY
;
933 new_this
->lpVtbl
= This
->lpVtbl
;
935 lstrcpyW(new_this
->keyname
, This
->keyname
);
936 /* FIXME: could we more efficiently use DuplicateHandle? */
937 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
938 new_this
->next_index
= This
->next_index
;
940 *ppenum
= (LPENUMGUID
)new_this
;
944 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
946 COMCAT_CATID_IEnumGUID_QueryInterface
,
947 COMCAT_CATID_IEnumGUID_AddRef
,
948 COMCAT_CATID_IEnumGUID_Release
,
949 COMCAT_CATID_IEnumGUID_Next
,
950 COMCAT_CATID_IEnumGUID_Skip
,
951 COMCAT_CATID_IEnumGUID_Reset
,
952 COMCAT_CATID_IEnumGUID_Clone
955 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
956 REFCLSID rclsid
, LPCWSTR postfix
)
958 CATID_IEnumGUIDImpl
*This
;
960 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
962 WCHAR prefix
[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
964 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
965 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
966 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
967 lstrcpyW(This
->keyname
+ 44, postfix
);
968 RegOpenKeyExW(HKEY_CLASSES_ROOT
, This
->keyname
, 0, KEY_READ
, &This
->key
);
970 return (LPENUMGUID
)This
;