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
[] = L
"Component Categories";
71 static const WCHAR impl_keyname
[] = L
"Implemented Categories";
72 static const WCHAR req_keyname
[] = L
"Required Categories";
74 /**********************************************************************
75 * COMCAT_RegisterClassCategories
77 static HRESULT
COMCAT_RegisterClassCategories(
83 WCHAR keyname
[CHARS_IN_GUID
];
85 HKEY clsid_key
, class_key
, type_key
;
87 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
89 /* Format the class key name. */
90 res
= StringFromGUID2(rclsid
, keyname
, CHARS_IN_GUID
);
91 if (FAILED(res
)) return res
;
93 /* Create (or open) the CLSID key. */
94 res
= create_classes_key(HKEY_CLASSES_ROOT
, L
"CLSID", KEY_READ
|KEY_WRITE
, &clsid_key
);
95 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
97 /* Create (or open) the class key. */
98 res
= create_classes_key(clsid_key
, keyname
, KEY_READ
|KEY_WRITE
, &class_key
);
99 if (res
== ERROR_SUCCESS
) {
100 /* Create (or open) the category type key. */
101 res
= create_classes_key(class_key
, type
, KEY_READ
|KEY_WRITE
, &type_key
);
102 if (res
== ERROR_SUCCESS
) {
103 for (; cCategories
; --cCategories
, ++rgcatid
) {
106 /* Format the category key name. */
107 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
108 if (FAILED(res
)) continue;
110 /* Do the register. */
111 res
= create_classes_key(type_key
, keyname
, KEY_READ
|KEY_WRITE
, &key
);
112 if (res
== ERROR_SUCCESS
) RegCloseKey(key
);
116 RegCloseKey(class_key
);
118 RegCloseKey(clsid_key
);
123 /**********************************************************************
124 * COMCAT_UnRegisterClassCategories
126 static HRESULT
COMCAT_UnRegisterClassCategories(
130 const CATID
*rgcatid
)
132 WCHAR keyname
[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
136 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
138 /* Format the class category type key name. */
139 res
= StringFromGUID2(rclsid
, keyname
+ 6, CHARS_IN_GUID
);
140 if (FAILED(res
)) return res
;
142 lstrcpyW(keyname
+ 45, type
);
144 /* Open the class category type key. */
145 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
|KEY_WRITE
, &type_key
);
146 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
148 for (; cCategories
; --cCategories
, ++rgcatid
) {
149 /* Format the category key name. */
150 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
151 if (FAILED(res
)) continue;
153 /* Do the unregister. */
154 RegDeleteKeyW(type_key
, keyname
);
156 RegCloseKey(type_key
);
161 /**********************************************************************
162 * COMCAT_GetCategoryDesc
164 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
169 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
171 if (pszDesc
== NULL
) return E_INVALIDARG
;
173 /* FIXME: lcid comparisons are more complex than this! */
174 wsprintfW(valname
, L
"%lX", lcid
);
175 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
176 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
177 FIXME("Simplified lcid comparison\n");
178 return CAT_E_NODESCRIPTION
;
180 pszDesc
[size
/ sizeof(WCHAR
)] = 0;
185 /**********************************************************************
186 * COMCAT_PrepareClassCategories
188 static struct class_categories
*COMCAT_PrepareClassCategories(
189 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
191 struct class_categories
*categories
;
195 size
= sizeof(struct class_categories
) + ((impl_count
+ req_count
)*CHARS_IN_GUID
+ 2)*sizeof(WCHAR
);
196 categories
= HeapAlloc(GetProcessHeap(), 0, size
);
197 if (categories
== NULL
) return categories
;
199 categories
->size
= size
;
200 categories
->impl_offset
= sizeof(struct class_categories
);
201 categories
->req_offset
= categories
->impl_offset
+ (impl_count
*CHARS_IN_GUID
+ 1)*sizeof(WCHAR
);
203 strings
= (WCHAR
*)(categories
+ 1);
204 while (impl_count
--) {
205 StringFromGUID2(impl_catids
++, strings
, CHARS_IN_GUID
);
206 strings
+= CHARS_IN_GUID
;
210 while (req_count
--) {
211 StringFromGUID2(req_catids
++, strings
, CHARS_IN_GUID
);
212 strings
+= CHARS_IN_GUID
;
219 /**********************************************************************
220 * COMCAT_IsClassOfCategories
222 static HRESULT
COMCAT_IsClassOfCategories(
224 struct class_categories
const* categories
)
226 const WCHAR
*impl_strings
, *req_strings
;
232 impl_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->impl_offset
);
233 req_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->req_offset
);
235 /* Check that every given category is implemented by class. */
237 res
= open_classes_key(key
, impl_keyname
, KEY_READ
, &subkey
);
238 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
239 for (string
= impl_strings
; *string
; string
+= CHARS_IN_GUID
) {
241 res
= open_classes_key(subkey
, string
, READ_CONTROL
, &catkey
);
242 if (res
!= ERROR_SUCCESS
) {
251 /* Check that all categories required by class are given. */
252 res
= open_classes_key(key
, req_keyname
, KEY_READ
, &subkey
);
253 if (res
== ERROR_SUCCESS
) {
254 for (index
= 0; ; ++index
) {
255 WCHAR keyname
[CHARS_IN_GUID
];
256 DWORD size
= CHARS_IN_GUID
;
258 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
259 NULL
, NULL
, NULL
, NULL
);
260 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
261 if (size
!= CHARS_IN_GUID
-1) continue; /* bogus catid in registry */
262 for (string
= req_strings
; *string
; string
+= CHARS_IN_GUID
)
263 if (!wcsicmp(string
, keyname
)) break;
275 /**********************************************************************
276 * COMCAT_ICatRegister_QueryInterface
278 static HRESULT WINAPI
COMCAT_ICatRegister_QueryInterface(
283 TRACE("%s\n",debugstr_guid(riid
));
285 if (ppvObj
== NULL
) return E_POINTER
;
287 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
289 ICatRegister_AddRef(iface
);
293 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
294 *ppvObj
= &COMCAT_ComCatMgr
.ICatInformation_iface
;
295 ICatRegister_AddRef(iface
);
299 return E_NOINTERFACE
;
302 /**********************************************************************
303 * COMCAT_ICatRegister_AddRef
305 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
307 return 2; /* non-heap based object */
310 /**********************************************************************
311 * COMCAT_ICatRegister_Release
313 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
315 return 1; /* non-heap based object */
318 /**********************************************************************
319 * COMCAT_ICatRegister_RegisterCategories
321 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
331 if (cCategories
&& rgci
== NULL
)
334 /* Create (or open) the component categories key. */
335 res
= create_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
336 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
338 for (; cCategories
; --cCategories
, ++rgci
)
340 WCHAR keyname
[CHARS_IN_GUID
];
344 /* Create (or open) the key for this category. */
345 if (!StringFromGUID2(&rgci
->catid
, keyname
, CHARS_IN_GUID
)) continue;
346 res
= create_classes_key(comcat_key
, keyname
, KEY_READ
|KEY_WRITE
, &cat_key
);
347 if (res
!= ERROR_SUCCESS
) continue;
349 /* Set the value for this locale's description. */
350 wsprintfW(valname
, L
"%lX", rgci
->lcid
);
351 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
, (const BYTE
*)rgci
->szDescription
,
352 (lstrlenW(rgci
->szDescription
) + 1) * sizeof(WCHAR
));
354 RegCloseKey(cat_key
);
357 RegCloseKey(comcat_key
);
361 /**********************************************************************
362 * COMCAT_ICatRegister_UnRegisterCategories
364 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterCategories(
374 if (cCategories
&& rgcatid
== NULL
)
377 /* Open the component categories key. */
378 res
= open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
379 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
381 for (; cCategories
; --cCategories
, ++rgcatid
) {
382 WCHAR keyname
[CHARS_IN_GUID
];
384 /* Delete the key for this category. */
385 if (!StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
)) continue;
386 RegDeleteKeyW(comcat_key
, keyname
);
389 RegCloseKey(comcat_key
);
393 /**********************************************************************
394 * COMCAT_ICatRegister_RegisterClassImplCategories
396 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassImplCategories(
404 return COMCAT_RegisterClassCategories(
405 rclsid
, impl_keyname
, cCategories
, rgcatid
);
408 /**********************************************************************
409 * COMCAT_ICatRegister_UnRegisterClassImplCategories
411 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassImplCategories(
419 return COMCAT_UnRegisterClassCategories(
420 rclsid
, impl_keyname
, cCategories
, rgcatid
);
423 /**********************************************************************
424 * COMCAT_ICatRegister_RegisterClassReqCategories
426 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassReqCategories(
434 return COMCAT_RegisterClassCategories(
435 rclsid
, req_keyname
, cCategories
, rgcatid
);
438 /**********************************************************************
439 * COMCAT_ICatRegister_UnRegisterClassReqCategories
441 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassReqCategories(
449 return COMCAT_UnRegisterClassCategories(
450 rclsid
, req_keyname
, cCategories
, rgcatid
);
453 /**********************************************************************
454 * COMCAT_ICatInformation_QueryInterface
456 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
457 LPCATINFORMATION iface
,
461 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
464 /**********************************************************************
465 * COMCAT_ICatInformation_AddRef
467 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
469 return ICatRegister_AddRef(&COMCAT_ComCatMgr
.ICatRegister_iface
);
472 /**********************************************************************
473 * COMCAT_ICatInformation_Release
475 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
477 return ICatRegister_Release(&COMCAT_ComCatMgr
.ICatRegister_iface
);
480 /**********************************************************************
481 * COMCAT_ICatInformation_EnumCategories
483 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
484 LPCATINFORMATION iface
,
486 IEnumCATEGORYINFO
**ppenumCatInfo
)
490 if (ppenumCatInfo
== NULL
) return E_POINTER
;
492 return EnumCATEGORYINFO_Construct(lcid
, ppenumCatInfo
);
495 /**********************************************************************
496 * COMCAT_ICatInformation_GetCategoryDesc
498 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
499 LPCATINFORMATION iface
,
504 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
505 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
506 'r', 'i', 'e', 's', '\\', 0 };
510 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid
), lcid
);
512 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
514 /* Open the key for this category. */
515 if (!StringFromGUID2(rcatid
, keyname
+ 21, CHARS_IN_GUID
)) return E_FAIL
;
516 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
517 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
519 /* Allocate a sensible amount of memory for the description. */
520 *ppszDesc
= CoTaskMemAlloc(128 * sizeof(WCHAR
));
521 if (*ppszDesc
== NULL
) {
523 return E_OUTOFMEMORY
;
526 /* Get the description, and make sure it's null terminated. */
527 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
530 CoTaskMemFree(*ppszDesc
);
537 /**********************************************************************
538 * COMCAT_ICatInformation_EnumClassesOfCategories
540 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
541 LPCATINFORMATION iface
,
546 LPENUMCLSID
*ppenumCLSID
)
548 struct class_categories
*categories
;
553 if (cImplemented
== (ULONG
)-1)
555 if (cRequired
== (ULONG
)-1)
558 if (ppenumCLSID
== NULL
||
559 (cImplemented
&& rgcatidImpl
== NULL
) ||
560 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
562 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
563 cRequired
, rgcatidReq
);
564 if (categories
== NULL
) return E_OUTOFMEMORY
;
566 hr
= CLSIDEnumGUID_Construct(categories
, ppenumCLSID
);
569 HeapFree(GetProcessHeap(), 0, categories
);
576 /**********************************************************************
577 * COMCAT_ICatInformation_IsClassOfCategories
579 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
580 LPCATINFORMATION iface
,
587 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
589 struct class_categories
*categories
;
594 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid
),cImplemented
);
595 for (count
= 0; count
< cImplemented
; ++count
)
596 TRACE(" %s\n",debugstr_guid(&rgcatidImpl
[count
]));
597 TRACE("Required %u\n",cRequired
);
598 for (count
= 0; count
< cRequired
; ++count
)
599 TRACE(" %s\n",debugstr_guid(&rgcatidReq
[count
]));
602 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
603 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
605 res
= StringFromGUID2(rclsid
, keyname
+ 6, CHARS_IN_GUID
);
606 if (FAILED(res
)) return res
;
608 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
609 cRequired
, rgcatidReq
);
610 if (categories
== NULL
) return E_OUTOFMEMORY
;
612 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
613 if (res
== ERROR_SUCCESS
) {
614 res
= COMCAT_IsClassOfCategories(key
, categories
);
616 } else res
= S_FALSE
;
618 HeapFree(GetProcessHeap(), 0, categories
);
623 /**********************************************************************
624 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
626 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
627 LPCATINFORMATION iface
,
629 LPENUMCATID
*ppenumCATID
)
631 TRACE("%s\n",debugstr_guid(rclsid
));
633 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
636 return CATIDEnumGUID_Construct(rclsid
, L
"\\Implemented Categories", ppenumCATID
);
639 /**********************************************************************
640 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
642 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
643 LPCATINFORMATION iface
,
645 LPENUMCATID
*ppenumCATID
)
647 TRACE("%s\n",debugstr_guid(rclsid
));
649 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
652 return CATIDEnumGUID_Construct(rclsid
, L
"\\Required Categories", ppenumCATID
);
655 /**********************************************************************
656 * COMCAT_ICatRegister_Vtbl
658 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
660 COMCAT_ICatRegister_QueryInterface
,
661 COMCAT_ICatRegister_AddRef
,
662 COMCAT_ICatRegister_Release
,
663 COMCAT_ICatRegister_RegisterCategories
,
664 COMCAT_ICatRegister_UnRegisterCategories
,
665 COMCAT_ICatRegister_RegisterClassImplCategories
,
666 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
667 COMCAT_ICatRegister_RegisterClassReqCategories
,
668 COMCAT_ICatRegister_UnRegisterClassReqCategories
672 /**********************************************************************
673 * COMCAT_ICatInformation_Vtbl
675 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
677 COMCAT_ICatInformation_QueryInterface
,
678 COMCAT_ICatInformation_AddRef
,
679 COMCAT_ICatInformation_Release
,
680 COMCAT_ICatInformation_EnumCategories
,
681 COMCAT_ICatInformation_GetCategoryDesc
,
682 COMCAT_ICatInformation_EnumClassesOfCategories
,
683 COMCAT_ICatInformation_IsClassOfCategories
,
684 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
685 COMCAT_ICatInformation_EnumReqCategoriesOfClass
688 HRESULT WINAPI
ComCat_CreateInstance(IClassFactory
*iface
, IUnknown
*pUnkOuter
, REFIID riid
, void **ppvObj
)
691 TRACE("%s\n",debugstr_guid(riid
));
693 if (ppvObj
== NULL
) return E_POINTER
;
695 /* Don't support aggregation (Windows doesn't) */
696 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
698 res
= ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
699 if (SUCCEEDED(res
)) {
703 return CLASS_E_CLASSNOTAVAILABLE
;
706 /**********************************************************************
707 * IEnumCATEGORYINFO implementation
709 * This implementation is not thread-safe. The manager itself is, but
710 * I can't imagine a valid use of an enumerator in several threads.
714 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface
;
719 } IEnumCATEGORYINFOImpl
;
721 static inline IEnumCATEGORYINFOImpl
*impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO
*iface
)
723 return CONTAINING_RECORD(iface
, IEnumCATEGORYINFOImpl
, IEnumCATEGORYINFO_iface
);
726 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO
*iface
)
728 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
732 return InterlockedIncrement(&This
->ref
);
735 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
736 IEnumCATEGORYINFO
*iface
,
740 TRACE("%s\n",debugstr_guid(riid
));
742 if (ppvObj
== NULL
) return E_POINTER
;
744 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
745 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
748 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
752 return E_NOINTERFACE
;
755 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO
*iface
)
757 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
762 ref
= InterlockedDecrement(&This
->ref
);
764 if (This
->key
) RegCloseKey(This
->key
);
765 HeapFree(GetProcessHeap(), 0, This
);
771 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
772 IEnumCATEGORYINFO
*iface
,
777 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
782 if (rgelt
== NULL
) return E_POINTER
;
784 if (This
->key
) while (fetched
< celt
) {
787 WCHAR catid
[CHARS_IN_GUID
];
788 DWORD cName
= CHARS_IN_GUID
;
791 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
792 NULL
, NULL
, NULL
, NULL
);
793 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
794 ++(This
->next_index
);
796 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
797 if (FAILED(hr
)) continue;
799 res
= open_classes_key(This
->key
, catid
, KEY_READ
, &subkey
);
800 if (res
!= ERROR_SUCCESS
) continue;
802 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
803 rgelt
->szDescription
, 128);
805 if (FAILED(hr
)) continue;
807 rgelt
->lcid
= This
->lcid
;
812 if (pceltFetched
) *pceltFetched
= fetched
;
813 return fetched
== celt
? S_OK
: S_FALSE
;
816 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
817 IEnumCATEGORYINFO
*iface
,
820 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
824 This
->next_index
+= celt
;
825 /* This should return S_FALSE when there aren't celt elems to skip. */
829 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO
*iface
)
831 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
835 This
->next_index
= 0;
839 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
840 IEnumCATEGORYINFO
*iface
,
841 IEnumCATEGORYINFO
**ppenum
)
843 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
844 IEnumCATEGORYINFOImpl
*new_this
;
848 if (ppenum
== NULL
) return E_POINTER
;
850 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
851 if (new_this
== NULL
) return E_OUTOFMEMORY
;
853 new_this
->IEnumCATEGORYINFO_iface
= This
->IEnumCATEGORYINFO_iface
;
855 new_this
->lcid
= This
->lcid
;
856 /* FIXME: could we more efficiently use DuplicateHandle? */
857 open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
, &new_this
->key
);
858 new_this
->next_index
= This
->next_index
;
860 *ppenum
= &new_this
->IEnumCATEGORYINFO_iface
;
864 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
866 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
867 COMCAT_IEnumCATEGORYINFO_AddRef
,
868 COMCAT_IEnumCATEGORYINFO_Release
,
869 COMCAT_IEnumCATEGORYINFO_Next
,
870 COMCAT_IEnumCATEGORYINFO_Skip
,
871 COMCAT_IEnumCATEGORYINFO_Reset
,
872 COMCAT_IEnumCATEGORYINFO_Clone
875 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
)
877 IEnumCATEGORYINFOImpl
*This
;
881 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
882 if (!This
) return E_OUTOFMEMORY
;
884 This
->IEnumCATEGORYINFO_iface
.lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
887 open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
, &This
->key
);
889 *ret
= &This
->IEnumCATEGORYINFO_iface
;
893 /**********************************************************************
894 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
896 * This implementation is not thread-safe. The manager itself is, but
897 * I can't imagine a valid use of an enumerator in several threads.
901 IEnumGUID IEnumGUID_iface
;
903 struct class_categories
*categories
;
906 } CLSID_IEnumGUIDImpl
;
908 static inline CLSID_IEnumGUIDImpl
*impl_from_IEnumCLSID(IEnumGUID
*iface
)
910 return CONTAINING_RECORD(iface
, CLSID_IEnumGUIDImpl
, IEnumGUID_iface
);
913 static HRESULT WINAPI
CLSIDEnumGUID_QueryInterface(
918 TRACE("%s\n",debugstr_guid(riid
));
920 if (ppvObj
== NULL
) return E_POINTER
;
922 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
923 IsEqualGUID(riid
, &IID_IEnumGUID
))
926 IEnumGUID_AddRef(iface
);
930 return E_NOINTERFACE
;
933 static ULONG WINAPI
CLSIDEnumGUID_AddRef(IEnumGUID
*iface
)
935 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
938 return InterlockedIncrement(&This
->ref
);
941 static ULONG WINAPI
CLSIDEnumGUID_Release(IEnumGUID
*iface
)
943 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
948 ref
= InterlockedDecrement(&This
->ref
);
950 if (This
->key
) RegCloseKey(This
->key
);
951 HeapFree(GetProcessHeap(), 0, This
->categories
);
952 HeapFree(GetProcessHeap(), 0, This
);
958 static HRESULT WINAPI
CLSIDEnumGUID_Next(
964 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
969 if (rgelt
== NULL
) return E_POINTER
;
971 if (This
->key
) while (fetched
< celt
) {
974 WCHAR clsid
[CHARS_IN_GUID
];
975 DWORD cName
= CHARS_IN_GUID
;
978 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
979 NULL
, NULL
, NULL
, NULL
);
980 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
981 ++(This
->next_index
);
983 hr
= CLSIDFromString(clsid
, rgelt
);
984 if (FAILED(hr
)) continue;
986 res
= open_classes_key(This
->key
, clsid
, KEY_READ
, &subkey
);
987 if (res
!= ERROR_SUCCESS
) continue;
989 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
991 if (hr
!= S_OK
) continue;
997 if (pceltFetched
) *pceltFetched
= fetched
;
998 return fetched
== celt
? S_OK
: S_FALSE
;
1001 static HRESULT WINAPI
CLSIDEnumGUID_Skip(
1005 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1009 This
->next_index
+= celt
;
1010 FIXME("Never returns S_FALSE\n");
1014 static HRESULT WINAPI
CLSIDEnumGUID_Reset(IEnumGUID
*iface
)
1016 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1020 This
->next_index
= 0;
1024 static HRESULT WINAPI
CLSIDEnumGUID_Clone(
1028 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1029 CLSID_IEnumGUIDImpl
*cloned
;
1031 TRACE("(%p)->(%p)\n", This
, ppenum
);
1033 if (ppenum
== NULL
) return E_POINTER
;
1037 cloned
= HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID_IEnumGUIDImpl
));
1038 if (cloned
== NULL
) return E_OUTOFMEMORY
;
1040 cloned
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1043 cloned
->categories
= HeapAlloc(GetProcessHeap(), 0, This
->categories
->size
);
1044 if (cloned
->categories
== NULL
) {
1045 HeapFree(GetProcessHeap(), 0, cloned
);
1046 return E_OUTOFMEMORY
;
1048 memcpy(cloned
->categories
, This
->categories
, This
->categories
->size
);
1051 open_classes_key(HKEY_CLASSES_ROOT
, L
"CLSID", KEY_READ
, &cloned
->key
);
1052 cloned
->next_index
= This
->next_index
;
1054 *ppenum
= &cloned
->IEnumGUID_iface
;
1058 static const IEnumGUIDVtbl CLSIDEnumGUIDVtbl
=
1060 CLSIDEnumGUID_QueryInterface
,
1061 CLSIDEnumGUID_AddRef
,
1062 CLSIDEnumGUID_Release
,
1065 CLSIDEnumGUID_Reset
,
1069 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*categories
, IEnumCLSID
**ret
)
1071 CLSID_IEnumGUIDImpl
*This
;
1075 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1076 if (!This
) return E_OUTOFMEMORY
;
1078 This
->IEnumGUID_iface
.lpVtbl
= &CLSIDEnumGUIDVtbl
;
1080 This
->categories
= categories
;
1081 open_classes_key(HKEY_CLASSES_ROOT
, L
"CLSID", KEY_READ
, &This
->key
);
1083 *ret
= &This
->IEnumGUID_iface
;
1088 /**********************************************************************
1089 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1091 * This implementation is not thread-safe. The manager itself is, but
1092 * I can't imagine a valid use of an enumerator in several threads.
1096 IEnumGUID IEnumGUID_iface
;
1101 } CATID_IEnumGUIDImpl
;
1103 static inline CATID_IEnumGUIDImpl
*impl_from_IEnumCATID(IEnumGUID
*iface
)
1105 return CONTAINING_RECORD(iface
, CATID_IEnumGUIDImpl
, IEnumGUID_iface
);
1108 static HRESULT WINAPI
CATIDEnumGUID_QueryInterface(
1113 TRACE("%s\n",debugstr_guid(riid
));
1115 if (ppvObj
== NULL
) return E_POINTER
;
1117 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1118 IsEqualGUID(riid
, &IID_IEnumGUID
))
1121 IEnumGUID_AddRef(iface
);
1125 return E_NOINTERFACE
;
1128 static ULONG WINAPI
CATIDEnumGUID_AddRef(IEnumGUID
*iface
)
1130 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1133 return InterlockedIncrement(&This
->ref
);
1136 static ULONG WINAPI
CATIDEnumGUID_Release(IEnumGUID
*iface
)
1138 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1143 ref
= InterlockedDecrement(&This
->ref
);
1145 if (This
->key
) RegCloseKey(This
->key
);
1146 HeapFree(GetProcessHeap(), 0, This
);
1152 static HRESULT WINAPI
CATIDEnumGUID_Next(
1156 ULONG
*pceltFetched
)
1158 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1163 if (rgelt
== NULL
) return E_POINTER
;
1165 if (This
->key
) while (fetched
< celt
) {
1168 WCHAR catid
[CHARS_IN_GUID
];
1169 DWORD cName
= CHARS_IN_GUID
;
1171 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1172 NULL
, NULL
, NULL
, NULL
);
1173 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1174 ++(This
->next_index
);
1176 hr
= CLSIDFromString(catid
, rgelt
);
1177 if (FAILED(hr
)) continue;
1183 if (pceltFetched
) *pceltFetched
= fetched
;
1184 return fetched
== celt
? S_OK
: S_FALSE
;
1187 static HRESULT WINAPI
CATIDEnumGUID_Skip(
1191 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1195 This
->next_index
+= celt
;
1196 FIXME("Never returns S_FALSE\n");
1200 static HRESULT WINAPI
CATIDEnumGUID_Reset(IEnumGUID
*iface
)
1202 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1206 This
->next_index
= 0;
1210 static HRESULT WINAPI
CATIDEnumGUID_Clone(
1214 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1215 CATID_IEnumGUIDImpl
*new_this
;
1219 if (ppenum
== NULL
) return E_POINTER
;
1221 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1222 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1224 new_this
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1226 lstrcpyW(new_this
->keyname
, This
->keyname
);
1227 /* FIXME: could we more efficiently use DuplicateHandle? */
1228 open_classes_key(HKEY_CLASSES_ROOT
, new_this
->keyname
, KEY_READ
, &new_this
->key
);
1229 new_this
->next_index
= This
->next_index
;
1231 *ppenum
= &new_this
->IEnumGUID_iface
;
1235 static const IEnumGUIDVtbl CATIDEnumGUIDVtbl
=
1237 CATIDEnumGUID_QueryInterface
,
1238 CATIDEnumGUID_AddRef
,
1239 CATIDEnumGUID_Release
,
1242 CATIDEnumGUID_Reset
,
1246 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR postfix
, IEnumGUID
**ret
)
1248 WCHAR keyname
[100], clsidW
[CHARS_IN_GUID
];
1249 CATID_IEnumGUIDImpl
*This
;
1253 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1254 if (!This
) return E_OUTOFMEMORY
;
1256 StringFromGUID2(rclsid
, clsidW
, CHARS_IN_GUID
);
1258 This
->IEnumGUID_iface
.lpVtbl
= &CATIDEnumGUIDVtbl
;
1260 lstrcpyW(keyname
, L
"CLSID\\");
1261 lstrcatW(keyname
, clsidW
);
1262 lstrcatW(keyname
, postfix
);
1264 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1266 *ret
= &This
->IEnumGUID_iface
;