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
23 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
25 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
;
26 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
;
30 ICatRegister ICatRegister_iface
;
31 ICatInformation ICatInformation_iface
;
34 /* static ComCatMgr instance */
35 static ComCatMgrImpl COMCAT_ComCatMgr
=
37 { &COMCAT_ICatRegister_Vtbl
},
38 { &COMCAT_ICatInformation_Vtbl
}
41 struct class_categories
{
46 static IEnumCATEGORYINFO
*COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
);
47 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*class_categories
);
48 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR impl_req
);
50 /**********************************************************************
51 * File-scope string constants
53 static const WCHAR comcat_keyname
[] = {
54 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
55 static const WCHAR impl_keyname
[] = {
56 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
57 static const WCHAR req_keyname
[] = {
58 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
59 static const WCHAR clsid_keyname
[] = { 'C','L','S','I','D',0 };
62 /**********************************************************************
63 * COMCAT_RegisterClassCategories
65 static HRESULT
COMCAT_RegisterClassCategories(
73 HKEY clsid_key
, class_key
, type_key
;
75 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
77 /* Format the class key name. */
78 res
= StringFromGUID2(rclsid
, keyname
, 39);
79 if (FAILED(res
)) return res
;
81 /* Create (or open) the CLSID key. */
82 res
= create_classes_key(HKEY_CLASSES_ROOT
, clsid_keyname
, KEY_READ
|KEY_WRITE
, &clsid_key
);
83 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
85 /* Create (or open) the class key. */
86 res
= create_classes_key(clsid_key
, keyname
, KEY_READ
|KEY_WRITE
, &class_key
);
87 if (res
== ERROR_SUCCESS
) {
88 /* Create (or open) the category type key. */
89 res
= create_classes_key(class_key
, type
, KEY_READ
|KEY_WRITE
, &type_key
);
90 if (res
== ERROR_SUCCESS
) {
91 for (; cCategories
; --cCategories
, ++rgcatid
) {
94 /* Format the category key name. */
95 res
= StringFromGUID2(rgcatid
, keyname
, 39);
96 if (FAILED(res
)) continue;
98 /* Do the register. */
99 res
= create_classes_key(type_key
, keyname
, KEY_READ
|KEY_WRITE
, &key
);
100 if (res
== ERROR_SUCCESS
) RegCloseKey(key
);
104 RegCloseKey(class_key
);
106 RegCloseKey(clsid_key
);
111 /**********************************************************************
112 * COMCAT_UnRegisterClassCategories
114 static HRESULT
COMCAT_UnRegisterClassCategories(
118 const CATID
*rgcatid
)
120 WCHAR keyname
[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
124 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
126 /* Format the class category type key name. */
127 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
128 if (FAILED(res
)) return res
;
130 lstrcpyW(keyname
+ 45, type
);
132 /* Open the class category type key. */
133 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
|KEY_WRITE
, &type_key
);
134 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
136 for (; cCategories
; --cCategories
, ++rgcatid
) {
137 /* Format the category key name. */
138 res
= StringFromGUID2(rgcatid
, keyname
, 39);
139 if (FAILED(res
)) continue;
141 /* Do the unregister. */
142 RegDeleteKeyW(type_key
, keyname
);
144 RegCloseKey(type_key
);
149 /**********************************************************************
150 * COMCAT_GetCategoryDesc
152 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
155 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
158 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
160 if (pszDesc
== NULL
) return E_INVALIDARG
;
162 /* FIXME: lcid comparisons are more complex than this! */
163 wsprintfW(valname
, fmt
, lcid
);
164 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
165 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
166 FIXME("Simplified lcid comparison\n");
167 return CAT_E_NODESCRIPTION
;
169 pszDesc
[size
/ sizeof(WCHAR
)] = 0;
174 /**********************************************************************
175 * COMCAT_PrepareClassCategories
177 static struct class_categories
*COMCAT_PrepareClassCategories(
178 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
180 struct class_categories
*categories
;
183 categories
= HeapAlloc(
184 GetProcessHeap(), HEAP_ZERO_MEMORY
,
185 sizeof(struct class_categories
) +
186 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
187 if (categories
== NULL
) return categories
;
189 strings
= (WCHAR
*)(categories
+ 1);
190 categories
->impl_strings
= strings
;
191 while (impl_count
--) {
192 StringFromGUID2(impl_catids
++, strings
, 39);
197 categories
->req_strings
= strings
;
198 while (req_count
--) {
199 StringFromGUID2(req_catids
++, strings
, 39);
207 /**********************************************************************
208 * COMCAT_IsClassOfCategories
210 static HRESULT
COMCAT_IsClassOfCategories(
212 struct class_categories
const* categories
)
219 /* Check that every given category is implemented by class. */
220 if (*categories
->impl_strings
) {
221 res
= open_classes_key(key
, impl_keyname
, KEY_READ
, &subkey
);
222 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
223 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
225 res
= open_classes_key(subkey
, string
, 0, &catkey
);
226 if (res
!= ERROR_SUCCESS
) {
235 /* Check that all categories required by class are given. */
236 res
= open_classes_key(key
, req_keyname
, KEY_READ
, &subkey
);
237 if (res
== ERROR_SUCCESS
) {
238 for (index
= 0; ; ++index
) {
242 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
243 NULL
, NULL
, NULL
, NULL
);
244 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
245 if (size
!= 38) continue; /* bogus catid in registry */
246 for (string
= categories
->req_strings
; *string
; string
+= 39)
247 if (!strcmpiW(string
, keyname
)) break;
259 /**********************************************************************
260 * COMCAT_ICatRegister_QueryInterface
262 static HRESULT WINAPI
COMCAT_ICatRegister_QueryInterface(
267 TRACE("%s\n",debugstr_guid(riid
));
269 if (ppvObj
== NULL
) return E_POINTER
;
271 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
273 ICatRegister_AddRef(iface
);
277 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
278 *ppvObj
= &COMCAT_ComCatMgr
.ICatInformation_iface
;
279 ICatRegister_AddRef(iface
);
283 return E_NOINTERFACE
;
286 /**********************************************************************
287 * COMCAT_ICatRegister_AddRef
289 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
291 return 2; /* non-heap based object */
294 /**********************************************************************
295 * COMCAT_ICatRegister_Release
297 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
299 return 1; /* non-heap based object */
302 /**********************************************************************
303 * COMCAT_ICatRegister_RegisterCategories
305 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
315 if (cCategories
&& rgci
== NULL
)
318 /* Create (or open) the component categories key. */
319 res
= create_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
320 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
322 for (; cCategories
; --cCategories
, ++rgci
) {
323 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
328 /* Create (or open) the key for this category. */
329 if (!StringFromGUID2(&rgci
->catid
, keyname
, 39)) continue;
330 res
= create_classes_key(comcat_key
, keyname
, KEY_READ
|KEY_WRITE
, &cat_key
);
331 if (res
!= ERROR_SUCCESS
) continue;
333 /* Set the value for this locale's description. */
334 wsprintfW(valname
, fmt
, rgci
->lcid
);
335 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
,
336 (CONST BYTE
*)(rgci
->szDescription
),
337 (lstrlenW(rgci
->szDescription
) + 1) * sizeof(WCHAR
));
339 RegCloseKey(cat_key
);
342 RegCloseKey(comcat_key
);
346 /**********************************************************************
347 * COMCAT_ICatRegister_UnRegisterCategories
349 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterCategories(
359 if (cCategories
&& rgcatid
== NULL
)
362 /* Open the component categories key. */
363 res
= open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
364 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
366 for (; cCategories
; --cCategories
, ++rgcatid
) {
369 /* Delete the key for this category. */
370 if (!StringFromGUID2(rgcatid
, keyname
, 39)) continue;
371 RegDeleteKeyW(comcat_key
, keyname
);
374 RegCloseKey(comcat_key
);
378 /**********************************************************************
379 * COMCAT_ICatRegister_RegisterClassImplCategories
381 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassImplCategories(
389 return COMCAT_RegisterClassCategories(
390 rclsid
, impl_keyname
, cCategories
, rgcatid
);
393 /**********************************************************************
394 * COMCAT_ICatRegister_UnRegisterClassImplCategories
396 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassImplCategories(
404 return COMCAT_UnRegisterClassCategories(
405 rclsid
, impl_keyname
, cCategories
, rgcatid
);
408 /**********************************************************************
409 * COMCAT_ICatRegister_RegisterClassReqCategories
411 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassReqCategories(
419 return COMCAT_RegisterClassCategories(
420 rclsid
, req_keyname
, cCategories
, rgcatid
);
423 /**********************************************************************
424 * COMCAT_ICatRegister_UnRegisterClassReqCategories
426 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassReqCategories(
434 return COMCAT_UnRegisterClassCategories(
435 rclsid
, req_keyname
, cCategories
, rgcatid
);
438 /**********************************************************************
439 * COMCAT_ICatInformation_QueryInterface
441 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
442 LPCATINFORMATION iface
,
446 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
449 /**********************************************************************
450 * COMCAT_ICatInformation_AddRef
452 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
454 return ICatRegister_AddRef(&COMCAT_ComCatMgr
.ICatRegister_iface
);
457 /**********************************************************************
458 * COMCAT_ICatInformation_Release
460 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
462 return ICatRegister_Release(&COMCAT_ComCatMgr
.ICatRegister_iface
);
465 /**********************************************************************
466 * COMCAT_ICatInformation_EnumCategories
468 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
469 LPCATINFORMATION iface
,
471 IEnumCATEGORYINFO
**ppenumCatInfo
)
475 if (ppenumCatInfo
== NULL
) return E_POINTER
;
477 *ppenumCatInfo
= COMCAT_IEnumCATEGORYINFO_Construct(lcid
);
478 if (*ppenumCatInfo
== NULL
) return E_OUTOFMEMORY
;
479 IEnumCATEGORYINFO_AddRef(*ppenumCatInfo
);
483 /**********************************************************************
484 * COMCAT_ICatInformation_GetCategoryDesc
486 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
487 LPCATINFORMATION iface
,
492 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
493 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
494 'r', 'i', 'e', 's', '\\', 0 };
498 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid
), lcid
);
500 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
502 /* Open the key for this category. */
503 if (!StringFromGUID2(rcatid
, keyname
+ 21, 39)) return E_FAIL
;
504 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
505 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
507 /* Allocate a sensible amount of memory for the description. */
508 *ppszDesc
= CoTaskMemAlloc(128 * sizeof(WCHAR
));
509 if (*ppszDesc
== NULL
) {
511 return E_OUTOFMEMORY
;
514 /* Get the description, and make sure it's null terminated. */
515 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
518 CoTaskMemFree(*ppszDesc
);
525 /**********************************************************************
526 * COMCAT_ICatInformation_EnumClassesOfCategories
528 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
529 LPCATINFORMATION iface
,
534 LPENUMCLSID
*ppenumCLSID
)
536 struct class_categories
*categories
;
540 if (cImplemented
== (ULONG
)-1)
542 if (cRequired
== (ULONG
)-1)
545 if (ppenumCLSID
== NULL
||
546 (cImplemented
&& rgcatidImpl
== NULL
) ||
547 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
549 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
550 cRequired
, rgcatidReq
);
551 if (categories
== NULL
) return E_OUTOFMEMORY
;
552 *ppenumCLSID
= COMCAT_CLSID_IEnumGUID_Construct(categories
);
553 if (*ppenumCLSID
== NULL
) {
554 HeapFree(GetProcessHeap(), 0, categories
);
555 return E_OUTOFMEMORY
;
557 IEnumGUID_AddRef(*ppenumCLSID
);
561 /**********************************************************************
562 * COMCAT_ICatInformation_IsClassOfCategories
564 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
565 LPCATINFORMATION iface
,
572 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
574 struct class_categories
*categories
;
579 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid
),cImplemented
);
580 for (count
= 0; count
< cImplemented
; ++count
)
581 TRACE(" %s\n",debugstr_guid(&rgcatidImpl
[count
]));
582 TRACE("Required %u\n",cRequired
);
583 for (count
= 0; count
< cRequired
; ++count
)
584 TRACE(" %s\n",debugstr_guid(&rgcatidReq
[count
]));
587 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
588 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
590 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
591 if (FAILED(res
)) return res
;
593 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
594 cRequired
, rgcatidReq
);
595 if (categories
== NULL
) return E_OUTOFMEMORY
;
597 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
598 if (res
== ERROR_SUCCESS
) {
599 res
= COMCAT_IsClassOfCategories(key
, categories
);
601 } else res
= S_FALSE
;
603 HeapFree(GetProcessHeap(), 0, categories
);
608 /**********************************************************************
609 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
611 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
612 LPCATINFORMATION iface
,
614 LPENUMCATID
*ppenumCATID
)
616 static const WCHAR postfix
[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
617 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
618 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
620 TRACE("%s\n",debugstr_guid(rclsid
));
622 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
625 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
626 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
630 /**********************************************************************
631 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
633 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
634 LPCATINFORMATION iface
,
636 LPENUMCATID
*ppenumCATID
)
638 static const WCHAR postfix
[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
639 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
640 'r', 'i', 'e', 's', 0 };
642 TRACE("%s\n",debugstr_guid(rclsid
));
644 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
647 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
648 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
652 /**********************************************************************
653 * COMCAT_ICatRegister_Vtbl
655 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
657 COMCAT_ICatRegister_QueryInterface
,
658 COMCAT_ICatRegister_AddRef
,
659 COMCAT_ICatRegister_Release
,
660 COMCAT_ICatRegister_RegisterCategories
,
661 COMCAT_ICatRegister_UnRegisterCategories
,
662 COMCAT_ICatRegister_RegisterClassImplCategories
,
663 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
664 COMCAT_ICatRegister_RegisterClassReqCategories
,
665 COMCAT_ICatRegister_UnRegisterClassReqCategories
669 /**********************************************************************
670 * COMCAT_ICatInformation_Vtbl
672 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
674 COMCAT_ICatInformation_QueryInterface
,
675 COMCAT_ICatInformation_AddRef
,
676 COMCAT_ICatInformation_Release
,
677 COMCAT_ICatInformation_EnumCategories
,
678 COMCAT_ICatInformation_GetCategoryDesc
,
679 COMCAT_ICatInformation_EnumClassesOfCategories
,
680 COMCAT_ICatInformation_IsClassOfCategories
,
681 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
682 COMCAT_ICatInformation_EnumReqCategoriesOfClass
685 /**********************************************************************
686 * COMCAT_IClassFactory_QueryInterface (also IUnknown)
688 static HRESULT WINAPI
COMCAT_IClassFactory_QueryInterface(
689 LPCLASSFACTORY iface
,
693 TRACE("%s\n",debugstr_guid(riid
));
695 if (ppvObj
== NULL
) return E_POINTER
;
697 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
698 IsEqualGUID(riid
, &IID_IClassFactory
))
701 IClassFactory_AddRef(iface
);
705 return E_NOINTERFACE
;
708 /**********************************************************************
709 * COMCAT_IClassFactory_AddRef (also IUnknown)
711 static ULONG WINAPI
COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface
)
713 return 2; /* non-heap based object */
716 /**********************************************************************
717 * COMCAT_IClassFactory_Release (also IUnknown)
719 static ULONG WINAPI
COMCAT_IClassFactory_Release(LPCLASSFACTORY iface
)
721 return 1; /* non-heap based object */
724 /**********************************************************************
725 * COMCAT_IClassFactory_CreateInstance
727 static HRESULT WINAPI
COMCAT_IClassFactory_CreateInstance(
728 LPCLASSFACTORY iface
,
734 TRACE("%s\n",debugstr_guid(riid
));
736 if (ppvObj
== NULL
) return E_POINTER
;
738 /* Don't support aggregation (Windows doesn't) */
739 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
741 res
= ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
742 if (SUCCEEDED(res
)) {
746 return CLASS_E_CLASSNOTAVAILABLE
;
749 /**********************************************************************
750 * COMCAT_IClassFactory_LockServer
752 static HRESULT WINAPI
COMCAT_IClassFactory_LockServer(
753 LPCLASSFACTORY iface
,
756 FIXME("(%d), stub!\n",fLock
);
760 /**********************************************************************
761 * static ClassFactory instance
763 static const IClassFactoryVtbl ComCatCFVtbl
=
765 COMCAT_IClassFactory_QueryInterface
,
766 COMCAT_IClassFactory_AddRef
,
767 COMCAT_IClassFactory_Release
,
768 COMCAT_IClassFactory_CreateInstance
,
769 COMCAT_IClassFactory_LockServer
772 static const IClassFactoryVtbl
*ComCatCF
= &ComCatCFVtbl
;
774 HRESULT
ComCatCF_Create(REFIID riid
, LPVOID
*ppv
)
776 return IClassFactory_QueryInterface((IClassFactory
*)&ComCatCF
, riid
, ppv
);
779 /**********************************************************************
780 * IEnumCATEGORYINFO implementation
782 * This implementation is not thread-safe. The manager itself is, but
783 * I can't imagine a valid use of an enumerator in several threads.
787 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface
;
792 } IEnumCATEGORYINFOImpl
;
794 static inline IEnumCATEGORYINFOImpl
*impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO
*iface
)
796 return CONTAINING_RECORD(iface
, IEnumCATEGORYINFOImpl
, IEnumCATEGORYINFO_iface
);
799 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO
*iface
)
801 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
805 return InterlockedIncrement(&This
->ref
);
808 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
809 IEnumCATEGORYINFO
*iface
,
813 TRACE("%s\n",debugstr_guid(riid
));
815 if (ppvObj
== NULL
) return E_POINTER
;
817 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
818 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
821 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
825 return E_NOINTERFACE
;
828 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO
*iface
)
830 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
835 ref
= InterlockedDecrement(&This
->ref
);
837 if (This
->key
) RegCloseKey(This
->key
);
838 HeapFree(GetProcessHeap(), 0, This
);
844 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
845 IEnumCATEGORYINFO
*iface
,
850 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
855 if (rgelt
== NULL
) return E_POINTER
;
857 if (This
->key
) while (fetched
< celt
) {
864 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
865 NULL
, NULL
, NULL
, NULL
);
866 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
867 ++(This
->next_index
);
869 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
870 if (FAILED(hr
)) continue;
872 res
= open_classes_key(This
->key
, catid
, KEY_READ
, &subkey
);
873 if (res
!= ERROR_SUCCESS
) continue;
875 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
876 rgelt
->szDescription
, 128);
878 if (FAILED(hr
)) continue;
880 rgelt
->lcid
= This
->lcid
;
885 if (pceltFetched
) *pceltFetched
= fetched
;
886 return fetched
== celt
? S_OK
: S_FALSE
;
889 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
890 IEnumCATEGORYINFO
*iface
,
893 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
897 This
->next_index
+= celt
;
898 /* This should return S_FALSE when there aren't celt elems to skip. */
902 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO
*iface
)
904 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
908 This
->next_index
= 0;
912 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
913 IEnumCATEGORYINFO
*iface
,
914 IEnumCATEGORYINFO
**ppenum
)
916 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
917 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
918 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
919 'r', 'i', 'e', 's', 0 };
920 IEnumCATEGORYINFOImpl
*new_this
;
924 if (ppenum
== NULL
) return E_POINTER
;
926 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
927 if (new_this
== NULL
) return E_OUTOFMEMORY
;
929 new_this
->IEnumCATEGORYINFO_iface
= This
->IEnumCATEGORYINFO_iface
;
931 new_this
->lcid
= This
->lcid
;
932 /* FIXME: could we more efficiently use DuplicateHandle? */
933 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &new_this
->key
);
934 new_this
->next_index
= This
->next_index
;
936 *ppenum
= &new_this
->IEnumCATEGORYINFO_iface
;
940 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
942 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
943 COMCAT_IEnumCATEGORYINFO_AddRef
,
944 COMCAT_IEnumCATEGORYINFO_Release
,
945 COMCAT_IEnumCATEGORYINFO_Next
,
946 COMCAT_IEnumCATEGORYINFO_Skip
,
947 COMCAT_IEnumCATEGORYINFO_Reset
,
948 COMCAT_IEnumCATEGORYINFO_Clone
951 static IEnumCATEGORYINFO
*COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
953 IEnumCATEGORYINFOImpl
*This
;
955 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
957 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
958 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
959 'r', 'i', 'e', 's', 0 };
961 This
->IEnumCATEGORYINFO_iface
.lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
963 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
965 return &This
->IEnumCATEGORYINFO_iface
;
968 /**********************************************************************
969 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
971 * This implementation is not thread-safe. The manager itself is, but
972 * I can't imagine a valid use of an enumerator in several threads.
976 const IEnumGUIDVtbl
*lpVtbl
;
978 struct class_categories
*categories
;
981 } CLSID_IEnumGUIDImpl
;
983 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
985 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
988 return InterlockedIncrement(&This
->ref
);
991 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
996 TRACE("%s\n",debugstr_guid(riid
));
998 if (ppvObj
== NULL
) return E_POINTER
;
1000 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1001 IsEqualGUID(riid
, &IID_IEnumGUID
))
1004 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
1008 return E_NOINTERFACE
;
1011 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
1013 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1018 ref
= InterlockedDecrement(&This
->ref
);
1020 if (This
->key
) RegCloseKey(This
->key
);
1021 HeapFree(GetProcessHeap(), 0, This
->categories
);
1022 HeapFree(GetProcessHeap(), 0, This
);
1028 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
1032 ULONG
*pceltFetched
)
1034 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1039 if (rgelt
== NULL
) return E_POINTER
;
1041 if (This
->key
) while (fetched
< celt
) {
1048 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
1049 NULL
, NULL
, NULL
, NULL
);
1050 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1051 ++(This
->next_index
);
1053 hr
= CLSIDFromString(clsid
, rgelt
);
1054 if (FAILED(hr
)) continue;
1056 res
= open_classes_key(This
->key
, clsid
, KEY_READ
, &subkey
);
1057 if (res
!= ERROR_SUCCESS
) continue;
1059 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
1060 RegCloseKey(subkey
);
1061 if (hr
!= S_OK
) continue;
1067 if (pceltFetched
) *pceltFetched
= fetched
;
1068 return fetched
== celt
? S_OK
: S_FALSE
;
1071 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
1075 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1079 This
->next_index
+= celt
;
1080 FIXME("Never returns S_FALSE\n");
1084 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
1086 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1090 This
->next_index
= 0;
1094 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
1098 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1099 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1100 CLSID_IEnumGUIDImpl
*new_this
;
1105 if (ppenum
== NULL
) return E_POINTER
;
1107 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1108 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1110 new_this
->lpVtbl
= This
->lpVtbl
;
1112 size
= HeapSize(GetProcessHeap(), 0, This
->categories
);
1113 new_this
->categories
=
1114 HeapAlloc(GetProcessHeap(), 0, size
);
1115 if (new_this
->categories
== NULL
) {
1116 HeapFree(GetProcessHeap(), 0, new_this
);
1117 return E_OUTOFMEMORY
;
1119 memcpy(new_this
->categories
, This
->categories
, size
);
1120 /* FIXME: could we more efficiently use DuplicateHandle? */
1121 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &new_this
->key
);
1122 new_this
->next_index
= This
->next_index
;
1124 *ppenum
= (LPENUMGUID
)new_this
;
1128 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
1130 COMCAT_CLSID_IEnumGUID_QueryInterface
,
1131 COMCAT_CLSID_IEnumGUID_AddRef
,
1132 COMCAT_CLSID_IEnumGUID_Release
,
1133 COMCAT_CLSID_IEnumGUID_Next
,
1134 COMCAT_CLSID_IEnumGUID_Skip
,
1135 COMCAT_CLSID_IEnumGUID_Reset
,
1136 COMCAT_CLSID_IEnumGUID_Clone
1139 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*categories
)
1141 CLSID_IEnumGUIDImpl
*This
;
1143 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1145 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1147 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
1148 This
->categories
= categories
;
1149 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1151 return (LPENUMGUID
)This
;
1154 /**********************************************************************
1155 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1157 * This implementation is not thread-safe. The manager itself is, but
1158 * I can't imagine a valid use of an enumerator in several threads.
1162 const IEnumGUIDVtbl
*lpVtbl
;
1167 } CATID_IEnumGUIDImpl
;
1169 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
1171 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1174 return InterlockedIncrement(&This
->ref
);
1177 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
1182 TRACE("%s\n",debugstr_guid(riid
));
1184 if (ppvObj
== NULL
) return E_POINTER
;
1186 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1187 IsEqualGUID(riid
, &IID_IEnumGUID
))
1190 COMCAT_CATID_IEnumGUID_AddRef(iface
);
1194 return E_NOINTERFACE
;
1197 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
1199 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1204 ref
= InterlockedDecrement(&This
->ref
);
1206 if (This
->key
) RegCloseKey(This
->key
);
1207 HeapFree(GetProcessHeap(), 0, This
);
1213 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
1217 ULONG
*pceltFetched
)
1219 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1224 if (rgelt
== NULL
) return E_POINTER
;
1226 if (This
->key
) while (fetched
< celt
) {
1232 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1233 NULL
, NULL
, NULL
, NULL
);
1234 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1235 ++(This
->next_index
);
1237 hr
= CLSIDFromString(catid
, rgelt
);
1238 if (FAILED(hr
)) continue;
1244 if (pceltFetched
) *pceltFetched
= fetched
;
1245 return fetched
== celt
? S_OK
: S_FALSE
;
1248 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
1252 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1256 This
->next_index
+= celt
;
1257 FIXME("Never returns S_FALSE\n");
1261 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
1263 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1267 This
->next_index
= 0;
1271 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
1275 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1276 CATID_IEnumGUIDImpl
*new_this
;
1280 if (ppenum
== NULL
) return E_POINTER
;
1282 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1283 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1285 new_this
->lpVtbl
= This
->lpVtbl
;
1287 lstrcpyW(new_this
->keyname
, This
->keyname
);
1288 /* FIXME: could we more efficiently use DuplicateHandle? */
1289 open_classes_key(HKEY_CLASSES_ROOT
, new_this
->keyname
, KEY_READ
, &new_this
->key
);
1290 new_this
->next_index
= This
->next_index
;
1292 *ppenum
= (LPENUMGUID
)new_this
;
1296 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
1298 COMCAT_CATID_IEnumGUID_QueryInterface
,
1299 COMCAT_CATID_IEnumGUID_AddRef
,
1300 COMCAT_CATID_IEnumGUID_Release
,
1301 COMCAT_CATID_IEnumGUID_Next
,
1302 COMCAT_CATID_IEnumGUID_Skip
,
1303 COMCAT_CATID_IEnumGUID_Reset
,
1304 COMCAT_CATID_IEnumGUID_Clone
1307 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
1308 REFCLSID rclsid
, LPCWSTR postfix
)
1310 CATID_IEnumGUIDImpl
*This
;
1312 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1314 WCHAR prefix
[] = { 'C', 'L', 'S', 'I', 'D', '\\' };
1316 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
1317 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
1318 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
1319 lstrcpyW(This
->keyname
+ 44, postfix
);
1320 open_classes_key(HKEY_CLASSES_ROOT
, This
->keyname
, KEY_READ
, &This
->key
);
1322 return (LPENUMGUID
)This
;