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 "wine/unicode.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
39 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
;
40 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
;
44 ICatRegister ICatRegister_iface
;
45 ICatInformation ICatInformation_iface
;
48 /* static ComCatMgr instance */
49 static ComCatMgrImpl COMCAT_ComCatMgr
=
51 { &COMCAT_ICatRegister_Vtbl
},
52 { &COMCAT_ICatInformation_Vtbl
}
55 struct class_categories
{
60 static IEnumCATEGORYINFO
*COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
);
61 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*class_categories
);
62 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR impl_req
);
64 /**********************************************************************
65 * File-scope string constants
67 static const WCHAR comcat_keyname
[] = {
68 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
69 static const WCHAR impl_keyname
[] = {
70 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
71 static const WCHAR req_keyname
[] = {
72 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
73 static const WCHAR clsid_keyname
[] = { 'C','L','S','I','D',0 };
76 /**********************************************************************
77 * COMCAT_RegisterClassCategories
79 static HRESULT
COMCAT_RegisterClassCategories(
87 HKEY clsid_key
, class_key
, type_key
;
89 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
91 /* Format the class key name. */
92 res
= StringFromGUID2(rclsid
, keyname
, 39);
93 if (FAILED(res
)) return res
;
95 /* Create (or open) the CLSID key. */
96 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
97 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
98 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
100 /* Create (or open) the class key. */
101 res
= RegCreateKeyExW(clsid_key
, keyname
, 0, NULL
, 0,
102 KEY_READ
| KEY_WRITE
, NULL
, &class_key
, NULL
);
103 if (res
== ERROR_SUCCESS
) {
104 /* Create (or open) the category type key. */
105 res
= RegCreateKeyExW(class_key
, type
, 0, NULL
, 0,
106 KEY_READ
| KEY_WRITE
, NULL
, &type_key
, NULL
);
107 if (res
== ERROR_SUCCESS
) {
108 for (; cCategories
; --cCategories
, ++rgcatid
) {
111 /* Format the category key name. */
112 res
= StringFromGUID2(rgcatid
, keyname
, 39);
113 if (FAILED(res
)) continue;
115 /* Do the register. */
116 res
= RegCreateKeyExW(type_key
, keyname
, 0, NULL
, 0,
117 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
118 if (res
== ERROR_SUCCESS
) RegCloseKey(key
);
122 RegCloseKey(class_key
);
124 RegCloseKey(clsid_key
);
129 /**********************************************************************
130 * COMCAT_UnRegisterClassCategories
132 static HRESULT
COMCAT_UnRegisterClassCategories(
136 const CATID
*rgcatid
)
138 WCHAR keyname
[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
142 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
144 /* Format the class category type key name. */
145 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
146 if (FAILED(res
)) return res
;
148 lstrcpyW(keyname
+ 45, type
);
150 /* Open the class category type key. */
151 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0,
152 KEY_READ
| KEY_WRITE
, &type_key
);
153 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
155 for (; cCategories
; --cCategories
, ++rgcatid
) {
156 /* Format the category key name. */
157 res
= StringFromGUID2(rgcatid
, keyname
, 39);
158 if (FAILED(res
)) continue;
160 /* Do the unregister. */
161 RegDeleteKeyW(type_key
, keyname
);
163 RegCloseKey(type_key
);
168 /**********************************************************************
169 * COMCAT_GetCategoryDesc
171 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
174 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
177 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
179 if (pszDesc
== NULL
) return E_INVALIDARG
;
181 /* FIXME: lcid comparisons are more complex than this! */
182 wsprintfW(valname
, fmt
, lcid
);
183 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
184 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
185 FIXME("Simplified lcid comparison\n");
186 return CAT_E_NODESCRIPTION
;
188 pszDesc
[size
/ sizeof(WCHAR
)] = 0;
193 /**********************************************************************
194 * COMCAT_PrepareClassCategories
196 static struct class_categories
*COMCAT_PrepareClassCategories(
197 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
199 struct class_categories
*categories
;
202 categories
= HeapAlloc(
203 GetProcessHeap(), HEAP_ZERO_MEMORY
,
204 sizeof(struct class_categories
) +
205 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
206 if (categories
== NULL
) return categories
;
208 strings
= (WCHAR
*)(categories
+ 1);
209 categories
->impl_strings
= strings
;
210 while (impl_count
--) {
211 StringFromGUID2(impl_catids
++, strings
, 39);
216 categories
->req_strings
= strings
;
217 while (req_count
--) {
218 StringFromGUID2(req_catids
++, strings
, 39);
226 /**********************************************************************
227 * COMCAT_IsClassOfCategories
229 static HRESULT
COMCAT_IsClassOfCategories(
231 struct class_categories
const* categories
)
238 /* Check that every given category is implemented by class. */
239 if (*categories
->impl_strings
) {
240 res
= RegOpenKeyExW(key
, impl_keyname
, 0, KEY_READ
, &subkey
);
241 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
242 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
244 res
= RegOpenKeyExW(subkey
, string
, 0, 0, &catkey
);
245 if (res
!= ERROR_SUCCESS
) {
254 /* Check that all categories required by class are given. */
255 res
= RegOpenKeyExW(key
, req_keyname
, 0, KEY_READ
, &subkey
);
256 if (res
== ERROR_SUCCESS
) {
257 for (index
= 0; ; ++index
) {
261 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
262 NULL
, NULL
, NULL
, NULL
);
263 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
264 if (size
!= 38) continue; /* bogus catid in registry */
265 for (string
= categories
->req_strings
; *string
; string
+= 39)
266 if (!strcmpiW(string
, keyname
)) break;
278 /**********************************************************************
279 * COMCAT_ICatRegister_QueryInterface
281 static HRESULT WINAPI
COMCAT_ICatRegister_QueryInterface(
286 TRACE("%s\n",debugstr_guid(riid
));
288 if (ppvObj
== NULL
) return E_POINTER
;
290 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
292 ICatRegister_AddRef(iface
);
296 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
297 *ppvObj
= &COMCAT_ComCatMgr
.ICatInformation_iface
;
298 ICatRegister_AddRef(iface
);
302 return E_NOINTERFACE
;
305 /**********************************************************************
306 * COMCAT_ICatRegister_AddRef
308 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
310 return 2; /* non-heap based object */
313 /**********************************************************************
314 * COMCAT_ICatRegister_Release
316 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
318 return 1; /* non-heap based object */
321 /**********************************************************************
322 * COMCAT_ICatRegister_RegisterCategories
324 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
334 if (cCategories
&& rgci
== NULL
)
337 /* Create (or open) the component categories key. */
338 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, comcat_keyname
, 0, NULL
, 0,
339 KEY_READ
| KEY_WRITE
, NULL
, &comcat_key
, NULL
);
340 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
342 for (; cCategories
; --cCategories
, ++rgci
) {
343 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
348 /* Create (or open) the key for this category. */
349 if (!StringFromGUID2(&rgci
->catid
, keyname
, 39)) continue;
350 res
= RegCreateKeyExW(comcat_key
, keyname
, 0, NULL
, 0,
351 KEY_READ
| KEY_WRITE
, NULL
, &cat_key
, NULL
);
352 if (res
!= ERROR_SUCCESS
) continue;
354 /* Set the value for this locale's description. */
355 wsprintfW(valname
, fmt
, rgci
->lcid
);
356 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
,
357 (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
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, comcat_keyname
, 0,
385 KEY_READ
| KEY_WRITE
, &comcat_key
);
386 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
388 for (; cCategories
; --cCategories
, ++rgcatid
) {
391 /* Delete the key for this category. */
392 if (!StringFromGUID2(rgcatid
, keyname
, 39)) continue;
393 RegDeleteKeyW(comcat_key
, keyname
);
396 RegCloseKey(comcat_key
);
400 /**********************************************************************
401 * COMCAT_ICatRegister_RegisterClassImplCategories
403 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassImplCategories(
411 return COMCAT_RegisterClassCategories(
412 rclsid
, impl_keyname
, cCategories
, rgcatid
);
415 /**********************************************************************
416 * COMCAT_ICatRegister_UnRegisterClassImplCategories
418 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassImplCategories(
426 return COMCAT_UnRegisterClassCategories(
427 rclsid
, impl_keyname
, cCategories
, rgcatid
);
430 /**********************************************************************
431 * COMCAT_ICatRegister_RegisterClassReqCategories
433 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassReqCategories(
441 return COMCAT_RegisterClassCategories(
442 rclsid
, req_keyname
, cCategories
, rgcatid
);
445 /**********************************************************************
446 * COMCAT_ICatRegister_UnRegisterClassReqCategories
448 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassReqCategories(
456 return COMCAT_UnRegisterClassCategories(
457 rclsid
, req_keyname
, cCategories
, rgcatid
);
460 /**********************************************************************
461 * COMCAT_ICatInformation_QueryInterface
463 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
464 LPCATINFORMATION iface
,
468 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
471 /**********************************************************************
472 * COMCAT_ICatInformation_AddRef
474 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
476 return ICatRegister_AddRef(&COMCAT_ComCatMgr
.ICatRegister_iface
);
479 /**********************************************************************
480 * COMCAT_ICatInformation_Release
482 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
484 return ICatRegister_Release(&COMCAT_ComCatMgr
.ICatRegister_iface
);
487 /**********************************************************************
488 * COMCAT_ICatInformation_EnumCategories
490 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
491 LPCATINFORMATION iface
,
493 IEnumCATEGORYINFO
**ppenumCatInfo
)
497 if (ppenumCatInfo
== NULL
) return E_POINTER
;
499 *ppenumCatInfo
= COMCAT_IEnumCATEGORYINFO_Construct(lcid
);
500 if (*ppenumCatInfo
== NULL
) return E_OUTOFMEMORY
;
501 IEnumCATEGORYINFO_AddRef(*ppenumCatInfo
);
505 /**********************************************************************
506 * COMCAT_ICatInformation_GetCategoryDesc
508 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
509 LPCATINFORMATION iface
,
514 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
515 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
516 'r', 'i', 'e', 's', '\\', 0 };
520 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid
), lcid
);
522 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
524 /* Open the key for this category. */
525 if (!StringFromGUID2(rcatid
, keyname
+ 21, 39)) return E_FAIL
;
526 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
527 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
529 /* Allocate a sensible amount of memory for the description. */
530 *ppszDesc
= CoTaskMemAlloc(128 * sizeof(WCHAR
));
531 if (*ppszDesc
== NULL
) {
533 return E_OUTOFMEMORY
;
536 /* Get the description, and make sure it's null terminated. */
537 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
540 CoTaskMemFree(*ppszDesc
);
547 /**********************************************************************
548 * COMCAT_ICatInformation_EnumClassesOfCategories
550 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
551 LPCATINFORMATION iface
,
556 LPENUMCLSID
*ppenumCLSID
)
558 struct class_categories
*categories
;
562 if (cImplemented
== (ULONG
)-1)
564 if (cRequired
== (ULONG
)-1)
567 if (ppenumCLSID
== NULL
||
568 (cImplemented
&& rgcatidImpl
== NULL
) ||
569 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
571 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
572 cRequired
, rgcatidReq
);
573 if (categories
== NULL
) return E_OUTOFMEMORY
;
574 *ppenumCLSID
= COMCAT_CLSID_IEnumGUID_Construct(categories
);
575 if (*ppenumCLSID
== NULL
) {
576 HeapFree(GetProcessHeap(), 0, categories
);
577 return E_OUTOFMEMORY
;
579 IEnumGUID_AddRef(*ppenumCLSID
);
583 /**********************************************************************
584 * COMCAT_ICatInformation_IsClassOfCategories
586 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
587 LPCATINFORMATION iface
,
594 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
596 struct class_categories
*categories
;
601 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid
),cImplemented
);
602 for (count
= 0; count
< cImplemented
; ++count
)
603 TRACE(" %s\n",debugstr_guid(&rgcatidImpl
[count
]));
604 TRACE("Required %u\n",cRequired
);
605 for (count
= 0; count
< cRequired
; ++count
)
606 TRACE(" %s\n",debugstr_guid(&rgcatidReq
[count
]));
609 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
610 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
612 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
613 if (FAILED(res
)) return res
;
615 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
616 cRequired
, rgcatidReq
);
617 if (categories
== NULL
) return E_OUTOFMEMORY
;
619 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
620 if (res
== ERROR_SUCCESS
) {
621 res
= COMCAT_IsClassOfCategories(key
, categories
);
623 } else res
= S_FALSE
;
625 HeapFree(GetProcessHeap(), 0, categories
);
630 /**********************************************************************
631 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
633 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
634 LPCATINFORMATION iface
,
636 LPENUMCATID
*ppenumCATID
)
638 static const WCHAR postfix
[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
639 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
640 'e', 'g', 'o', '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_ICatInformation_EnumReqCategoriesOfClass
655 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
656 LPCATINFORMATION iface
,
658 LPENUMCATID
*ppenumCATID
)
660 static const WCHAR postfix
[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
661 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
662 'r', 'i', 'e', 's', 0 };
664 TRACE("%s\n",debugstr_guid(rclsid
));
666 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
669 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
670 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
674 /**********************************************************************
675 * COMCAT_ICatRegister_Vtbl
677 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
679 COMCAT_ICatRegister_QueryInterface
,
680 COMCAT_ICatRegister_AddRef
,
681 COMCAT_ICatRegister_Release
,
682 COMCAT_ICatRegister_RegisterCategories
,
683 COMCAT_ICatRegister_UnRegisterCategories
,
684 COMCAT_ICatRegister_RegisterClassImplCategories
,
685 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
686 COMCAT_ICatRegister_RegisterClassReqCategories
,
687 COMCAT_ICatRegister_UnRegisterClassReqCategories
691 /**********************************************************************
692 * COMCAT_ICatInformation_Vtbl
694 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
696 COMCAT_ICatInformation_QueryInterface
,
697 COMCAT_ICatInformation_AddRef
,
698 COMCAT_ICatInformation_Release
,
699 COMCAT_ICatInformation_EnumCategories
,
700 COMCAT_ICatInformation_GetCategoryDesc
,
701 COMCAT_ICatInformation_EnumClassesOfCategories
,
702 COMCAT_ICatInformation_IsClassOfCategories
,
703 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
704 COMCAT_ICatInformation_EnumReqCategoriesOfClass
707 /**********************************************************************
708 * COMCAT_IClassFactory_QueryInterface (also IUnknown)
710 static HRESULT WINAPI
COMCAT_IClassFactory_QueryInterface(
711 LPCLASSFACTORY iface
,
715 TRACE("%s\n",debugstr_guid(riid
));
717 if (ppvObj
== NULL
) return E_POINTER
;
719 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
720 IsEqualGUID(riid
, &IID_IClassFactory
))
723 IUnknown_AddRef(iface
);
727 return E_NOINTERFACE
;
730 /**********************************************************************
731 * COMCAT_IClassFactory_AddRef (also IUnknown)
733 static ULONG WINAPI
COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface
)
735 return 2; /* non-heap based object */
738 /**********************************************************************
739 * COMCAT_IClassFactory_Release (also IUnknown)
741 static ULONG WINAPI
COMCAT_IClassFactory_Release(LPCLASSFACTORY iface
)
743 return 1; /* non-heap based object */
746 /**********************************************************************
747 * COMCAT_IClassFactory_CreateInstance
749 static HRESULT WINAPI
COMCAT_IClassFactory_CreateInstance(
750 LPCLASSFACTORY iface
,
756 TRACE("%s\n",debugstr_guid(riid
));
758 if (ppvObj
== NULL
) return E_POINTER
;
760 /* Don't support aggregation (Windows doesn't) */
761 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
763 res
= ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
764 if (SUCCEEDED(res
)) {
768 return CLASS_E_CLASSNOTAVAILABLE
;
771 /**********************************************************************
772 * COMCAT_IClassFactory_LockServer
774 static HRESULT WINAPI
COMCAT_IClassFactory_LockServer(
775 LPCLASSFACTORY iface
,
778 FIXME("(%d), stub!\n",fLock
);
782 /**********************************************************************
783 * static ClassFactory instance
785 static const IClassFactoryVtbl ComCatCFVtbl
=
787 COMCAT_IClassFactory_QueryInterface
,
788 COMCAT_IClassFactory_AddRef
,
789 COMCAT_IClassFactory_Release
,
790 COMCAT_IClassFactory_CreateInstance
,
791 COMCAT_IClassFactory_LockServer
794 static const IClassFactoryVtbl
*ComCatCF
= &ComCatCFVtbl
;
796 HRESULT
ComCatCF_Create(REFIID riid
, LPVOID
*ppv
)
798 return IClassFactory_QueryInterface((IClassFactory
*)&ComCatCF
, riid
, ppv
);
801 /**********************************************************************
802 * IEnumCATEGORYINFO implementation
804 * This implementation is not thread-safe. The manager itself is, but
805 * I can't imagine a valid use of an enumerator in several threads.
809 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface
;
814 } IEnumCATEGORYINFOImpl
;
816 static inline IEnumCATEGORYINFOImpl
*impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO
*iface
)
818 return CONTAINING_RECORD(iface
, IEnumCATEGORYINFOImpl
, IEnumCATEGORYINFO_iface
);
821 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO
*iface
)
823 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
827 return InterlockedIncrement(&This
->ref
);
830 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
831 IEnumCATEGORYINFO
*iface
,
835 TRACE("%s\n",debugstr_guid(riid
));
837 if (ppvObj
== NULL
) return E_POINTER
;
839 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
840 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
843 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
847 return E_NOINTERFACE
;
850 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO
*iface
)
852 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
857 ref
= InterlockedDecrement(&This
->ref
);
859 if (This
->key
) RegCloseKey(This
->key
);
860 HeapFree(GetProcessHeap(), 0, This
);
866 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
867 IEnumCATEGORYINFO
*iface
,
872 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
877 if (rgelt
== NULL
) return E_POINTER
;
879 if (This
->key
) while (fetched
< celt
) {
886 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
887 NULL
, NULL
, NULL
, NULL
);
888 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
889 ++(This
->next_index
);
891 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
892 if (FAILED(hr
)) continue;
894 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
895 if (res
!= ERROR_SUCCESS
) continue;
897 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
898 rgelt
->szDescription
, 128);
900 if (FAILED(hr
)) continue;
902 rgelt
->lcid
= This
->lcid
;
907 if (pceltFetched
) *pceltFetched
= fetched
;
908 return fetched
== celt
? S_OK
: S_FALSE
;
911 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
912 IEnumCATEGORYINFO
*iface
,
915 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
919 This
->next_index
+= celt
;
920 /* This should return S_FALSE when there aren't celt elems to skip. */
924 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO
*iface
)
926 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
930 This
->next_index
= 0;
934 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
935 IEnumCATEGORYINFO
*iface
,
936 IEnumCATEGORYINFO
**ppenum
)
938 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
939 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
940 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
941 'r', 'i', 'e', 's', 0 };
942 IEnumCATEGORYINFOImpl
*new_this
;
946 if (ppenum
== NULL
) return E_POINTER
;
948 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
949 if (new_this
== NULL
) return E_OUTOFMEMORY
;
951 new_this
->IEnumCATEGORYINFO_iface
= This
->IEnumCATEGORYINFO_iface
;
953 new_this
->lcid
= This
->lcid
;
954 /* FIXME: could we more efficiently use DuplicateHandle? */
955 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
956 new_this
->next_index
= This
->next_index
;
958 *ppenum
= &new_this
->IEnumCATEGORYINFO_iface
;
962 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
964 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
965 COMCAT_IEnumCATEGORYINFO_AddRef
,
966 COMCAT_IEnumCATEGORYINFO_Release
,
967 COMCAT_IEnumCATEGORYINFO_Next
,
968 COMCAT_IEnumCATEGORYINFO_Skip
,
969 COMCAT_IEnumCATEGORYINFO_Reset
,
970 COMCAT_IEnumCATEGORYINFO_Clone
973 static IEnumCATEGORYINFO
*COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
975 IEnumCATEGORYINFOImpl
*This
;
977 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
979 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
980 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
981 'r', 'i', 'e', 's', 0 };
983 This
->IEnumCATEGORYINFO_iface
.lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
985 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
987 return &This
->IEnumCATEGORYINFO_iface
;
990 /**********************************************************************
991 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
993 * This implementation is not thread-safe. The manager itself is, but
994 * I can't imagine a valid use of an enumerator in several threads.
998 const IEnumGUIDVtbl
*lpVtbl
;
1000 struct class_categories
*categories
;
1003 } CLSID_IEnumGUIDImpl
;
1005 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
1007 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1010 return InterlockedIncrement(&This
->ref
);
1013 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
1018 TRACE("%s\n",debugstr_guid(riid
));
1020 if (ppvObj
== NULL
) return E_POINTER
;
1022 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1023 IsEqualGUID(riid
, &IID_IEnumGUID
))
1026 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
1030 return E_NOINTERFACE
;
1033 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
1035 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1040 ref
= InterlockedDecrement(&This
->ref
);
1042 if (This
->key
) RegCloseKey(This
->key
);
1043 HeapFree(GetProcessHeap(), 0, This
->categories
);
1044 HeapFree(GetProcessHeap(), 0, This
);
1050 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
1054 ULONG
*pceltFetched
)
1056 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1061 if (rgelt
== NULL
) return E_POINTER
;
1063 if (This
->key
) while (fetched
< celt
) {
1070 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
1071 NULL
, NULL
, NULL
, NULL
);
1072 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1073 ++(This
->next_index
);
1075 hr
= CLSIDFromString(clsid
, rgelt
);
1076 if (FAILED(hr
)) continue;
1078 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
1079 if (res
!= ERROR_SUCCESS
) continue;
1081 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
1082 RegCloseKey(subkey
);
1083 if (hr
!= S_OK
) continue;
1089 if (pceltFetched
) *pceltFetched
= fetched
;
1090 return fetched
== celt
? S_OK
: S_FALSE
;
1093 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
1097 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1101 This
->next_index
+= celt
;
1102 FIXME("Never returns S_FALSE\n");
1106 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
1108 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1112 This
->next_index
= 0;
1116 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
1120 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1121 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1122 CLSID_IEnumGUIDImpl
*new_this
;
1127 if (ppenum
== NULL
) return E_POINTER
;
1129 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1130 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1132 new_this
->lpVtbl
= This
->lpVtbl
;
1134 size
= HeapSize(GetProcessHeap(), 0, This
->categories
);
1135 new_this
->categories
=
1136 HeapAlloc(GetProcessHeap(), 0, size
);
1137 if (new_this
->categories
== NULL
) {
1138 HeapFree(GetProcessHeap(), 0, new_this
);
1139 return E_OUTOFMEMORY
;
1141 memcpy(new_this
->categories
, This
->categories
, size
);
1142 /* FIXME: could we more efficiently use DuplicateHandle? */
1143 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
1144 new_this
->next_index
= This
->next_index
;
1146 *ppenum
= (LPENUMGUID
)new_this
;
1150 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
1152 COMCAT_CLSID_IEnumGUID_QueryInterface
,
1153 COMCAT_CLSID_IEnumGUID_AddRef
,
1154 COMCAT_CLSID_IEnumGUID_Release
,
1155 COMCAT_CLSID_IEnumGUID_Next
,
1156 COMCAT_CLSID_IEnumGUID_Skip
,
1157 COMCAT_CLSID_IEnumGUID_Reset
,
1158 COMCAT_CLSID_IEnumGUID_Clone
1161 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*categories
)
1163 CLSID_IEnumGUIDImpl
*This
;
1165 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1167 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1169 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
1170 This
->categories
= categories
;
1171 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
1173 return (LPENUMGUID
)This
;
1176 /**********************************************************************
1177 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1179 * This implementation is not thread-safe. The manager itself is, but
1180 * I can't imagine a valid use of an enumerator in several threads.
1184 const IEnumGUIDVtbl
*lpVtbl
;
1189 } CATID_IEnumGUIDImpl
;
1191 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
1193 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1196 return InterlockedIncrement(&This
->ref
);
1199 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
1204 TRACE("%s\n",debugstr_guid(riid
));
1206 if (ppvObj
== NULL
) return E_POINTER
;
1208 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1209 IsEqualGUID(riid
, &IID_IEnumGUID
))
1212 COMCAT_CATID_IEnumGUID_AddRef(iface
);
1216 return E_NOINTERFACE
;
1219 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
1221 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1226 ref
= InterlockedDecrement(&This
->ref
);
1228 if (This
->key
) RegCloseKey(This
->key
);
1229 HeapFree(GetProcessHeap(), 0, This
);
1235 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
1239 ULONG
*pceltFetched
)
1241 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1246 if (rgelt
== NULL
) return E_POINTER
;
1248 if (This
->key
) while (fetched
< celt
) {
1254 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1255 NULL
, NULL
, NULL
, NULL
);
1256 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1257 ++(This
->next_index
);
1259 hr
= CLSIDFromString(catid
, rgelt
);
1260 if (FAILED(hr
)) continue;
1266 if (pceltFetched
) *pceltFetched
= fetched
;
1267 return fetched
== celt
? S_OK
: S_FALSE
;
1270 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
1274 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1278 This
->next_index
+= celt
;
1279 FIXME("Never returns S_FALSE\n");
1283 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
1285 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1289 This
->next_index
= 0;
1293 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
1297 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1298 CATID_IEnumGUIDImpl
*new_this
;
1302 if (ppenum
== NULL
) return E_POINTER
;
1304 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1305 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1307 new_this
->lpVtbl
= This
->lpVtbl
;
1309 lstrcpyW(new_this
->keyname
, This
->keyname
);
1310 /* FIXME: could we more efficiently use DuplicateHandle? */
1311 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
1312 new_this
->next_index
= This
->next_index
;
1314 *ppenum
= (LPENUMGUID
)new_this
;
1318 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
1320 COMCAT_CATID_IEnumGUID_QueryInterface
,
1321 COMCAT_CATID_IEnumGUID_AddRef
,
1322 COMCAT_CATID_IEnumGUID_Release
,
1323 COMCAT_CATID_IEnumGUID_Next
,
1324 COMCAT_CATID_IEnumGUID_Skip
,
1325 COMCAT_CATID_IEnumGUID_Reset
,
1326 COMCAT_CATID_IEnumGUID_Clone
1329 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
1330 REFCLSID rclsid
, LPCWSTR postfix
)
1332 CATID_IEnumGUIDImpl
*This
;
1334 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1336 WCHAR prefix
[] = { 'C', 'L', 'S', 'I', 'D', '\\' };
1338 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
1339 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
1340 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
1341 lstrcpyW(This
->keyname
+ 44, postfix
);
1342 RegOpenKeyExW(HKEY_CLASSES_ROOT
, This
->keyname
, 0, KEY_READ
, &This
->key
);
1344 return (LPENUMGUID
)This
;