2 * Comcat implementation
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
34 #include "compobj_private.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
40 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
;
41 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
;
45 ICatRegister ICatRegister_iface
;
46 ICatInformation ICatInformation_iface
;
49 /* static ComCatMgr instance */
50 static ComCatMgrImpl COMCAT_ComCatMgr
=
52 { &COMCAT_ICatRegister_Vtbl
},
53 { &COMCAT_ICatInformation_Vtbl
}
56 struct class_categories
58 ULONG size
; /* total length, including structure itself */
63 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
);
64 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*class_categories
, IEnumCLSID
**ret
);
65 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR impl_req
, IEnumCATID
**ret
);
67 /**********************************************************************
68 * File-scope string constants
70 static const WCHAR comcat_keyname
[] = {
71 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
72 static const WCHAR impl_keyname
[] = {
73 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
74 static const WCHAR req_keyname
[] = {
75 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
76 static const WCHAR clsid_keyname
[] = { 'C','L','S','I','D',0 };
79 /**********************************************************************
80 * COMCAT_RegisterClassCategories
82 static HRESULT
COMCAT_RegisterClassCategories(
88 WCHAR keyname
[CHARS_IN_GUID
];
90 HKEY clsid_key
, class_key
, type_key
;
92 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
94 /* Format the class key name. */
95 res
= StringFromGUID2(rclsid
, keyname
, CHARS_IN_GUID
);
96 if (FAILED(res
)) return res
;
98 /* Create (or open) the CLSID key. */
99 res
= create_classes_key(HKEY_CLASSES_ROOT
, clsid_keyname
, KEY_READ
|KEY_WRITE
, &clsid_key
);
100 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
102 /* Create (or open) the class key. */
103 res
= create_classes_key(clsid_key
, keyname
, KEY_READ
|KEY_WRITE
, &class_key
);
104 if (res
== ERROR_SUCCESS
) {
105 /* Create (or open) the category type key. */
106 res
= create_classes_key(class_key
, type
, KEY_READ
|KEY_WRITE
, &type_key
);
107 if (res
== ERROR_SUCCESS
) {
108 for (; cCategories
; --cCategories
, ++rgcatid
) {
111 /* Format the category key name. */
112 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
113 if (FAILED(res
)) continue;
115 /* Do the register. */
116 res
= create_classes_key(type_key
, keyname
, KEY_READ
|KEY_WRITE
, &key
);
117 if (res
== ERROR_SUCCESS
) RegCloseKey(key
);
121 RegCloseKey(class_key
);
123 RegCloseKey(clsid_key
);
128 /**********************************************************************
129 * COMCAT_UnRegisterClassCategories
131 static HRESULT
COMCAT_UnRegisterClassCategories(
135 const CATID
*rgcatid
)
137 WCHAR keyname
[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
141 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
143 /* Format the class category type key name. */
144 res
= StringFromGUID2(rclsid
, keyname
+ 6, CHARS_IN_GUID
);
145 if (FAILED(res
)) return res
;
147 lstrcpyW(keyname
+ 45, type
);
149 /* Open the class category type key. */
150 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
|KEY_WRITE
, &type_key
);
151 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
153 for (; cCategories
; --cCategories
, ++rgcatid
) {
154 /* Format the category key name. */
155 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
156 if (FAILED(res
)) continue;
158 /* Do the unregister. */
159 RegDeleteKeyW(type_key
, keyname
);
161 RegCloseKey(type_key
);
166 /**********************************************************************
167 * COMCAT_GetCategoryDesc
169 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
172 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
175 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
177 if (pszDesc
== NULL
) return E_INVALIDARG
;
179 /* FIXME: lcid comparisons are more complex than this! */
180 wsprintfW(valname
, fmt
, lcid
);
181 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
182 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
183 FIXME("Simplified lcid comparison\n");
184 return CAT_E_NODESCRIPTION
;
186 pszDesc
[size
/ sizeof(WCHAR
)] = 0;
191 /**********************************************************************
192 * COMCAT_PrepareClassCategories
194 static struct class_categories
*COMCAT_PrepareClassCategories(
195 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
197 struct class_categories
*categories
;
201 size
= sizeof(struct class_categories
) + ((impl_count
+ req_count
)*CHARS_IN_GUID
+ 2)*sizeof(WCHAR
);
202 categories
= HeapAlloc(GetProcessHeap(), 0, size
);
203 if (categories
== NULL
) return categories
;
205 categories
->size
= size
;
206 categories
->impl_offset
= sizeof(struct class_categories
);
207 categories
->req_offset
= categories
->impl_offset
+ (impl_count
*CHARS_IN_GUID
+ 1)*sizeof(WCHAR
);
209 strings
= (WCHAR
*)(categories
+ 1);
210 while (impl_count
--) {
211 StringFromGUID2(impl_catids
++, strings
, CHARS_IN_GUID
);
212 strings
+= CHARS_IN_GUID
;
216 while (req_count
--) {
217 StringFromGUID2(req_catids
++, strings
, CHARS_IN_GUID
);
218 strings
+= CHARS_IN_GUID
;
225 /**********************************************************************
226 * COMCAT_IsClassOfCategories
228 static HRESULT
COMCAT_IsClassOfCategories(
230 struct class_categories
const* categories
)
232 const WCHAR
*impl_strings
, *req_strings
;
238 impl_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->impl_offset
);
239 req_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->req_offset
);
241 /* Check that every given category is implemented by class. */
243 res
= open_classes_key(key
, impl_keyname
, KEY_READ
, &subkey
);
244 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
245 for (string
= impl_strings
; *string
; string
+= CHARS_IN_GUID
) {
247 res
= open_classes_key(subkey
, string
, READ_CONTROL
, &catkey
);
248 if (res
!= ERROR_SUCCESS
) {
257 /* Check that all categories required by class are given. */
258 res
= open_classes_key(key
, req_keyname
, KEY_READ
, &subkey
);
259 if (res
== ERROR_SUCCESS
) {
260 for (index
= 0; ; ++index
) {
261 WCHAR keyname
[CHARS_IN_GUID
];
262 DWORD size
= CHARS_IN_GUID
;
264 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
265 NULL
, NULL
, NULL
, NULL
);
266 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
267 if (size
!= CHARS_IN_GUID
-1) continue; /* bogus catid in registry */
268 for (string
= req_strings
; *string
; string
+= CHARS_IN_GUID
)
269 if (!wcsicmp(string
, keyname
)) break;
281 /**********************************************************************
282 * COMCAT_ICatRegister_QueryInterface
284 static HRESULT WINAPI
COMCAT_ICatRegister_QueryInterface(
289 TRACE("%s\n",debugstr_guid(riid
));
291 if (ppvObj
== NULL
) return E_POINTER
;
293 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
295 ICatRegister_AddRef(iface
);
299 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
300 *ppvObj
= &COMCAT_ComCatMgr
.ICatInformation_iface
;
301 ICatRegister_AddRef(iface
);
305 return E_NOINTERFACE
;
308 /**********************************************************************
309 * COMCAT_ICatRegister_AddRef
311 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
313 return 2; /* non-heap based object */
316 /**********************************************************************
317 * COMCAT_ICatRegister_Release
319 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
321 return 1; /* non-heap based object */
324 /**********************************************************************
325 * COMCAT_ICatRegister_RegisterCategories
327 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
337 if (cCategories
&& rgci
== NULL
)
340 /* Create (or open) the component categories key. */
341 res
= create_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
342 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
344 for (; cCategories
; --cCategories
, ++rgci
) {
345 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
346 WCHAR keyname
[CHARS_IN_GUID
];
350 /* Create (or open) the key for this category. */
351 if (!StringFromGUID2(&rgci
->catid
, keyname
, CHARS_IN_GUID
)) continue;
352 res
= create_classes_key(comcat_key
, keyname
, KEY_READ
|KEY_WRITE
, &cat_key
);
353 if (res
!= ERROR_SUCCESS
) continue;
355 /* Set the value for this locale's description. */
356 wsprintfW(valname
, fmt
, rgci
->lcid
);
357 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
, (const BYTE
*)rgci
->szDescription
,
358 (lstrlenW(rgci
->szDescription
) + 1) * sizeof(WCHAR
));
360 RegCloseKey(cat_key
);
363 RegCloseKey(comcat_key
);
367 /**********************************************************************
368 * COMCAT_ICatRegister_UnRegisterCategories
370 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterCategories(
380 if (cCategories
&& rgcatid
== NULL
)
383 /* Open the component categories key. */
384 res
= open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
385 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
387 for (; cCategories
; --cCategories
, ++rgcatid
) {
388 WCHAR keyname
[CHARS_IN_GUID
];
390 /* Delete the key for this category. */
391 if (!StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
)) continue;
392 RegDeleteKeyW(comcat_key
, keyname
);
395 RegCloseKey(comcat_key
);
399 /**********************************************************************
400 * COMCAT_ICatRegister_RegisterClassImplCategories
402 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassImplCategories(
410 return COMCAT_RegisterClassCategories(
411 rclsid
, impl_keyname
, cCategories
, rgcatid
);
414 /**********************************************************************
415 * COMCAT_ICatRegister_UnRegisterClassImplCategories
417 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassImplCategories(
425 return COMCAT_UnRegisterClassCategories(
426 rclsid
, impl_keyname
, cCategories
, rgcatid
);
429 /**********************************************************************
430 * COMCAT_ICatRegister_RegisterClassReqCategories
432 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassReqCategories(
440 return COMCAT_RegisterClassCategories(
441 rclsid
, req_keyname
, cCategories
, rgcatid
);
444 /**********************************************************************
445 * COMCAT_ICatRegister_UnRegisterClassReqCategories
447 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassReqCategories(
455 return COMCAT_UnRegisterClassCategories(
456 rclsid
, req_keyname
, cCategories
, rgcatid
);
459 /**********************************************************************
460 * COMCAT_ICatInformation_QueryInterface
462 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
463 LPCATINFORMATION iface
,
467 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
470 /**********************************************************************
471 * COMCAT_ICatInformation_AddRef
473 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
475 return ICatRegister_AddRef(&COMCAT_ComCatMgr
.ICatRegister_iface
);
478 /**********************************************************************
479 * COMCAT_ICatInformation_Release
481 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
483 return ICatRegister_Release(&COMCAT_ComCatMgr
.ICatRegister_iface
);
486 /**********************************************************************
487 * COMCAT_ICatInformation_EnumCategories
489 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
490 LPCATINFORMATION iface
,
492 IEnumCATEGORYINFO
**ppenumCatInfo
)
496 if (ppenumCatInfo
== NULL
) return E_POINTER
;
498 return EnumCATEGORYINFO_Construct(lcid
, ppenumCatInfo
);
501 /**********************************************************************
502 * COMCAT_ICatInformation_GetCategoryDesc
504 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
505 LPCATINFORMATION iface
,
510 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
511 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
512 'r', 'i', 'e', 's', '\\', 0 };
516 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid
), lcid
);
518 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
520 /* Open the key for this category. */
521 if (!StringFromGUID2(rcatid
, keyname
+ 21, CHARS_IN_GUID
)) return E_FAIL
;
522 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
523 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
525 /* Allocate a sensible amount of memory for the description. */
526 *ppszDesc
= CoTaskMemAlloc(128 * sizeof(WCHAR
));
527 if (*ppszDesc
== NULL
) {
529 return E_OUTOFMEMORY
;
532 /* Get the description, and make sure it's null terminated. */
533 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
536 CoTaskMemFree(*ppszDesc
);
543 /**********************************************************************
544 * COMCAT_ICatInformation_EnumClassesOfCategories
546 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
547 LPCATINFORMATION iface
,
552 LPENUMCLSID
*ppenumCLSID
)
554 struct class_categories
*categories
;
559 if (cImplemented
== (ULONG
)-1)
561 if (cRequired
== (ULONG
)-1)
564 if (ppenumCLSID
== NULL
||
565 (cImplemented
&& rgcatidImpl
== NULL
) ||
566 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
568 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
569 cRequired
, rgcatidReq
);
570 if (categories
== NULL
) return E_OUTOFMEMORY
;
572 hr
= CLSIDEnumGUID_Construct(categories
, ppenumCLSID
);
575 HeapFree(GetProcessHeap(), 0, categories
);
582 /**********************************************************************
583 * COMCAT_ICatInformation_IsClassOfCategories
585 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
586 LPCATINFORMATION iface
,
593 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
595 struct class_categories
*categories
;
600 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid
),cImplemented
);
601 for (count
= 0; count
< cImplemented
; ++count
)
602 TRACE(" %s\n",debugstr_guid(&rgcatidImpl
[count
]));
603 TRACE("Required %u\n",cRequired
);
604 for (count
= 0; count
< cRequired
; ++count
)
605 TRACE(" %s\n",debugstr_guid(&rgcatidReq
[count
]));
608 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
609 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
611 res
= StringFromGUID2(rclsid
, keyname
+ 6, CHARS_IN_GUID
);
612 if (FAILED(res
)) return res
;
614 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
615 cRequired
, rgcatidReq
);
616 if (categories
== NULL
) return E_OUTOFMEMORY
;
618 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
619 if (res
== ERROR_SUCCESS
) {
620 res
= COMCAT_IsClassOfCategories(key
, categories
);
622 } else res
= S_FALSE
;
624 HeapFree(GetProcessHeap(), 0, categories
);
629 /**********************************************************************
630 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
632 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
633 LPCATINFORMATION iface
,
635 LPENUMCATID
*ppenumCATID
)
637 static const WCHAR postfix
[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
638 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
639 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
641 TRACE("%s\n",debugstr_guid(rclsid
));
643 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
646 return CATIDEnumGUID_Construct(rclsid
, postfix
, ppenumCATID
);
649 /**********************************************************************
650 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
652 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
653 LPCATINFORMATION iface
,
655 LPENUMCATID
*ppenumCATID
)
657 static const WCHAR postfix
[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
658 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
659 'r', 'i', 'e', 's', 0 };
661 TRACE("%s\n",debugstr_guid(rclsid
));
663 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
666 return CATIDEnumGUID_Construct(rclsid
, postfix
, ppenumCATID
);
669 /**********************************************************************
670 * COMCAT_ICatRegister_Vtbl
672 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
674 COMCAT_ICatRegister_QueryInterface
,
675 COMCAT_ICatRegister_AddRef
,
676 COMCAT_ICatRegister_Release
,
677 COMCAT_ICatRegister_RegisterCategories
,
678 COMCAT_ICatRegister_UnRegisterCategories
,
679 COMCAT_ICatRegister_RegisterClassImplCategories
,
680 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
681 COMCAT_ICatRegister_RegisterClassReqCategories
,
682 COMCAT_ICatRegister_UnRegisterClassReqCategories
686 /**********************************************************************
687 * COMCAT_ICatInformation_Vtbl
689 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
691 COMCAT_ICatInformation_QueryInterface
,
692 COMCAT_ICatInformation_AddRef
,
693 COMCAT_ICatInformation_Release
,
694 COMCAT_ICatInformation_EnumCategories
,
695 COMCAT_ICatInformation_GetCategoryDesc
,
696 COMCAT_ICatInformation_EnumClassesOfCategories
,
697 COMCAT_ICatInformation_IsClassOfCategories
,
698 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
699 COMCAT_ICatInformation_EnumReqCategoriesOfClass
702 HRESULT WINAPI
ComCat_CreateInstance(IClassFactory
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, void **ppvObj
)
705 TRACE("%s\n",debugstr_guid(riid
));
707 if (ppvObj
== NULL
) return E_POINTER
;
709 /* Don't support aggregation (Windows doesn't) */
710 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
712 res
= ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
713 if (SUCCEEDED(res
)) {
717 return CLASS_E_CLASSNOTAVAILABLE
;
720 /**********************************************************************
721 * IEnumCATEGORYINFO implementation
723 * This implementation is not thread-safe. The manager itself is, but
724 * I can't imagine a valid use of an enumerator in several threads.
728 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface
;
733 } IEnumCATEGORYINFOImpl
;
735 static inline IEnumCATEGORYINFOImpl
*impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO
*iface
)
737 return CONTAINING_RECORD(iface
, IEnumCATEGORYINFOImpl
, IEnumCATEGORYINFO_iface
);
740 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO
*iface
)
742 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
746 return InterlockedIncrement(&This
->ref
);
749 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
750 IEnumCATEGORYINFO
*iface
,
754 TRACE("%s\n",debugstr_guid(riid
));
756 if (ppvObj
== NULL
) return E_POINTER
;
758 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
759 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
762 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
766 return E_NOINTERFACE
;
769 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO
*iface
)
771 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
776 ref
= InterlockedDecrement(&This
->ref
);
778 if (This
->key
) RegCloseKey(This
->key
);
779 HeapFree(GetProcessHeap(), 0, This
);
785 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
786 IEnumCATEGORYINFO
*iface
,
791 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
796 if (rgelt
== NULL
) return E_POINTER
;
798 if (This
->key
) while (fetched
< celt
) {
801 WCHAR catid
[CHARS_IN_GUID
];
802 DWORD cName
= CHARS_IN_GUID
;
805 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
806 NULL
, NULL
, NULL
, NULL
);
807 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
808 ++(This
->next_index
);
810 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
811 if (FAILED(hr
)) continue;
813 res
= open_classes_key(This
->key
, catid
, KEY_READ
, &subkey
);
814 if (res
!= ERROR_SUCCESS
) continue;
816 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
817 rgelt
->szDescription
, 128);
819 if (FAILED(hr
)) continue;
821 rgelt
->lcid
= This
->lcid
;
826 if (pceltFetched
) *pceltFetched
= fetched
;
827 return fetched
== celt
? S_OK
: S_FALSE
;
830 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
831 IEnumCATEGORYINFO
*iface
,
834 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
838 This
->next_index
+= celt
;
839 /* This should return S_FALSE when there aren't celt elems to skip. */
843 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO
*iface
)
845 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
849 This
->next_index
= 0;
853 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
854 IEnumCATEGORYINFO
*iface
,
855 IEnumCATEGORYINFO
**ppenum
)
857 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
858 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
859 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
860 'r', 'i', 'e', 's', 0 };
861 IEnumCATEGORYINFOImpl
*new_this
;
865 if (ppenum
== NULL
) return E_POINTER
;
867 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
868 if (new_this
== NULL
) return E_OUTOFMEMORY
;
870 new_this
->IEnumCATEGORYINFO_iface
= This
->IEnumCATEGORYINFO_iface
;
872 new_this
->lcid
= This
->lcid
;
873 /* FIXME: could we more efficiently use DuplicateHandle? */
874 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &new_this
->key
);
875 new_this
->next_index
= This
->next_index
;
877 *ppenum
= &new_this
->IEnumCATEGORYINFO_iface
;
881 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
883 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
884 COMCAT_IEnumCATEGORYINFO_AddRef
,
885 COMCAT_IEnumCATEGORYINFO_Release
,
886 COMCAT_IEnumCATEGORYINFO_Next
,
887 COMCAT_IEnumCATEGORYINFO_Skip
,
888 COMCAT_IEnumCATEGORYINFO_Reset
,
889 COMCAT_IEnumCATEGORYINFO_Clone
892 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
)
894 static const WCHAR keyname
[] = {'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0};
895 IEnumCATEGORYINFOImpl
*This
;
899 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
900 if (!This
) return E_OUTOFMEMORY
;
902 This
->IEnumCATEGORYINFO_iface
.lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
905 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
907 *ret
= &This
->IEnumCATEGORYINFO_iface
;
911 /**********************************************************************
912 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
914 * This implementation is not thread-safe. The manager itself is, but
915 * I can't imagine a valid use of an enumerator in several threads.
919 IEnumGUID IEnumGUID_iface
;
921 struct class_categories
*categories
;
924 } CLSID_IEnumGUIDImpl
;
926 static inline CLSID_IEnumGUIDImpl
*impl_from_IEnumCLSID(IEnumGUID
*iface
)
928 return CONTAINING_RECORD(iface
, CLSID_IEnumGUIDImpl
, IEnumGUID_iface
);
931 static HRESULT WINAPI
CLSIDEnumGUID_QueryInterface(
936 TRACE("%s\n",debugstr_guid(riid
));
938 if (ppvObj
== NULL
) return E_POINTER
;
940 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
941 IsEqualGUID(riid
, &IID_IEnumGUID
))
944 IEnumGUID_AddRef(iface
);
948 return E_NOINTERFACE
;
951 static ULONG WINAPI
CLSIDEnumGUID_AddRef(IEnumGUID
*iface
)
953 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
956 return InterlockedIncrement(&This
->ref
);
959 static ULONG WINAPI
CLSIDEnumGUID_Release(IEnumGUID
*iface
)
961 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
966 ref
= InterlockedDecrement(&This
->ref
);
968 if (This
->key
) RegCloseKey(This
->key
);
969 HeapFree(GetProcessHeap(), 0, This
->categories
);
970 HeapFree(GetProcessHeap(), 0, This
);
976 static HRESULT WINAPI
CLSIDEnumGUID_Next(
982 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
987 if (rgelt
== NULL
) return E_POINTER
;
989 if (This
->key
) while (fetched
< celt
) {
992 WCHAR clsid
[CHARS_IN_GUID
];
993 DWORD cName
= CHARS_IN_GUID
;
996 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
997 NULL
, NULL
, NULL
, NULL
);
998 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
999 ++(This
->next_index
);
1001 hr
= CLSIDFromString(clsid
, rgelt
);
1002 if (FAILED(hr
)) continue;
1004 res
= open_classes_key(This
->key
, clsid
, KEY_READ
, &subkey
);
1005 if (res
!= ERROR_SUCCESS
) continue;
1007 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
1008 RegCloseKey(subkey
);
1009 if (hr
!= S_OK
) continue;
1015 if (pceltFetched
) *pceltFetched
= fetched
;
1016 return fetched
== celt
? S_OK
: S_FALSE
;
1019 static HRESULT WINAPI
CLSIDEnumGUID_Skip(
1023 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1027 This
->next_index
+= celt
;
1028 FIXME("Never returns S_FALSE\n");
1032 static HRESULT WINAPI
CLSIDEnumGUID_Reset(IEnumGUID
*iface
)
1034 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1038 This
->next_index
= 0;
1042 static HRESULT WINAPI
CLSIDEnumGUID_Clone(
1046 static const WCHAR keynameW
[] = {'C','L','S','I','D',0};
1047 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1048 CLSID_IEnumGUIDImpl
*cloned
;
1050 TRACE("(%p)->(%p)\n", This
, ppenum
);
1052 if (ppenum
== NULL
) return E_POINTER
;
1056 cloned
= HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID_IEnumGUIDImpl
));
1057 if (cloned
== NULL
) return E_OUTOFMEMORY
;
1059 cloned
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1062 cloned
->categories
= HeapAlloc(GetProcessHeap(), 0, This
->categories
->size
);
1063 if (cloned
->categories
== NULL
) {
1064 HeapFree(GetProcessHeap(), 0, cloned
);
1065 return E_OUTOFMEMORY
;
1067 memcpy(cloned
->categories
, This
->categories
, This
->categories
->size
);
1070 open_classes_key(HKEY_CLASSES_ROOT
, keynameW
, KEY_READ
, &cloned
->key
);
1071 cloned
->next_index
= This
->next_index
;
1073 *ppenum
= &cloned
->IEnumGUID_iface
;
1077 static const IEnumGUIDVtbl CLSIDEnumGUIDVtbl
=
1079 CLSIDEnumGUID_QueryInterface
,
1080 CLSIDEnumGUID_AddRef
,
1081 CLSIDEnumGUID_Release
,
1084 CLSIDEnumGUID_Reset
,
1088 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*categories
, IEnumCLSID
**ret
)
1090 static const WCHAR keyname
[] = {'C','L','S','I','D',0};
1091 CLSID_IEnumGUIDImpl
*This
;
1095 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1096 if (!This
) return E_OUTOFMEMORY
;
1098 This
->IEnumGUID_iface
.lpVtbl
= &CLSIDEnumGUIDVtbl
;
1100 This
->categories
= categories
;
1101 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1103 *ret
= &This
->IEnumGUID_iface
;
1108 /**********************************************************************
1109 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1111 * This implementation is not thread-safe. The manager itself is, but
1112 * I can't imagine a valid use of an enumerator in several threads.
1116 IEnumGUID IEnumGUID_iface
;
1121 } CATID_IEnumGUIDImpl
;
1123 static inline CATID_IEnumGUIDImpl
*impl_from_IEnumCATID(IEnumGUID
*iface
)
1125 return CONTAINING_RECORD(iface
, CATID_IEnumGUIDImpl
, IEnumGUID_iface
);
1128 static HRESULT WINAPI
CATIDEnumGUID_QueryInterface(
1133 TRACE("%s\n",debugstr_guid(riid
));
1135 if (ppvObj
== NULL
) return E_POINTER
;
1137 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1138 IsEqualGUID(riid
, &IID_IEnumGUID
))
1141 IEnumGUID_AddRef(iface
);
1145 return E_NOINTERFACE
;
1148 static ULONG WINAPI
CATIDEnumGUID_AddRef(IEnumGUID
*iface
)
1150 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1153 return InterlockedIncrement(&This
->ref
);
1156 static ULONG WINAPI
CATIDEnumGUID_Release(IEnumGUID
*iface
)
1158 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1163 ref
= InterlockedDecrement(&This
->ref
);
1165 if (This
->key
) RegCloseKey(This
->key
);
1166 HeapFree(GetProcessHeap(), 0, This
);
1172 static HRESULT WINAPI
CATIDEnumGUID_Next(
1176 ULONG
*pceltFetched
)
1178 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1183 if (rgelt
== NULL
) return E_POINTER
;
1185 if (This
->key
) while (fetched
< celt
) {
1188 WCHAR catid
[CHARS_IN_GUID
];
1189 DWORD cName
= CHARS_IN_GUID
;
1191 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1192 NULL
, NULL
, NULL
, NULL
);
1193 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1194 ++(This
->next_index
);
1196 hr
= CLSIDFromString(catid
, rgelt
);
1197 if (FAILED(hr
)) continue;
1203 if (pceltFetched
) *pceltFetched
= fetched
;
1204 return fetched
== celt
? S_OK
: S_FALSE
;
1207 static HRESULT WINAPI
CATIDEnumGUID_Skip(
1211 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1215 This
->next_index
+= celt
;
1216 FIXME("Never returns S_FALSE\n");
1220 static HRESULT WINAPI
CATIDEnumGUID_Reset(IEnumGUID
*iface
)
1222 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1226 This
->next_index
= 0;
1230 static HRESULT WINAPI
CATIDEnumGUID_Clone(
1234 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1235 CATID_IEnumGUIDImpl
*new_this
;
1239 if (ppenum
== NULL
) return E_POINTER
;
1241 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1242 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1244 new_this
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1246 lstrcpyW(new_this
->keyname
, This
->keyname
);
1247 /* FIXME: could we more efficiently use DuplicateHandle? */
1248 open_classes_key(HKEY_CLASSES_ROOT
, new_this
->keyname
, KEY_READ
, &new_this
->key
);
1249 new_this
->next_index
= This
->next_index
;
1251 *ppenum
= &new_this
->IEnumGUID_iface
;
1255 static const IEnumGUIDVtbl CATIDEnumGUIDVtbl
=
1257 CATIDEnumGUID_QueryInterface
,
1258 CATIDEnumGUID_AddRef
,
1259 CATIDEnumGUID_Release
,
1262 CATIDEnumGUID_Reset
,
1266 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR postfix
, IEnumGUID
**ret
)
1268 static const WCHAR prefixW
[] = {'C','L','S','I','D','\\',0};
1269 WCHAR keyname
[100], clsidW
[CHARS_IN_GUID
];
1270 CATID_IEnumGUIDImpl
*This
;
1274 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1275 if (!This
) return E_OUTOFMEMORY
;
1277 StringFromGUID2(rclsid
, clsidW
, CHARS_IN_GUID
);
1279 This
->IEnumGUID_iface
.lpVtbl
= &CATIDEnumGUIDVtbl
;
1281 lstrcpyW(keyname
, prefixW
);
1282 lstrcatW(keyname
, clsidW
);
1283 lstrcatW(keyname
, postfix
);
1285 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1287 *ret
= &This
->IEnumGUID_iface
;