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/unicode.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
41 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
;
42 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
;
46 ICatRegister ICatRegister_iface
;
47 ICatInformation ICatInformation_iface
;
50 /* static ComCatMgr instance */
51 static ComCatMgrImpl COMCAT_ComCatMgr
=
53 { &COMCAT_ICatRegister_Vtbl
},
54 { &COMCAT_ICatInformation_Vtbl
}
57 struct class_categories
59 ULONG size
; /* total length, including structure itself */
64 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
);
65 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*class_categories
, IEnumCLSID
**ret
);
66 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR impl_req
, IEnumCATID
**ret
);
68 /**********************************************************************
69 * File-scope string constants
71 static const WCHAR comcat_keyname
[] = {
72 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
73 static const WCHAR impl_keyname
[] = {
74 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
75 static const WCHAR req_keyname
[] = {
76 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
77 static const WCHAR clsid_keyname
[] = { 'C','L','S','I','D',0 };
80 /**********************************************************************
81 * COMCAT_RegisterClassCategories
83 static HRESULT
COMCAT_RegisterClassCategories(
89 WCHAR keyname
[CHARS_IN_GUID
];
91 HKEY clsid_key
, class_key
, type_key
;
93 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
95 /* Format the class key name. */
96 res
= StringFromGUID2(rclsid
, keyname
, CHARS_IN_GUID
);
97 if (FAILED(res
)) return res
;
99 /* Create (or open) the CLSID key. */
100 res
= create_classes_key(HKEY_CLASSES_ROOT
, clsid_keyname
, KEY_READ
|KEY_WRITE
, &clsid_key
);
101 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
103 /* Create (or open) the class key. */
104 res
= create_classes_key(clsid_key
, keyname
, KEY_READ
|KEY_WRITE
, &class_key
);
105 if (res
== ERROR_SUCCESS
) {
106 /* Create (or open) the category type key. */
107 res
= create_classes_key(class_key
, type
, KEY_READ
|KEY_WRITE
, &type_key
);
108 if (res
== ERROR_SUCCESS
) {
109 for (; cCategories
; --cCategories
, ++rgcatid
) {
112 /* Format the category key name. */
113 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
114 if (FAILED(res
)) continue;
116 /* Do the register. */
117 res
= create_classes_key(type_key
, keyname
, KEY_READ
|KEY_WRITE
, &key
);
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, CHARS_IN_GUID
);
146 if (FAILED(res
)) return res
;
148 lstrcpyW(keyname
+ 45, type
);
150 /* Open the class category type key. */
151 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
|KEY_WRITE
, &type_key
);
152 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
154 for (; cCategories
; --cCategories
, ++rgcatid
) {
155 /* Format the category key name. */
156 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
157 if (FAILED(res
)) continue;
159 /* Do the unregister. */
160 RegDeleteKeyW(type_key
, keyname
);
162 RegCloseKey(type_key
);
167 /**********************************************************************
168 * COMCAT_GetCategoryDesc
170 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
173 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
176 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
178 if (pszDesc
== NULL
) return E_INVALIDARG
;
180 /* FIXME: lcid comparisons are more complex than this! */
181 wsprintfW(valname
, fmt
, lcid
);
182 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
183 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
184 FIXME("Simplified lcid comparison\n");
185 return CAT_E_NODESCRIPTION
;
187 pszDesc
[size
/ sizeof(WCHAR
)] = 0;
192 /**********************************************************************
193 * COMCAT_PrepareClassCategories
195 static struct class_categories
*COMCAT_PrepareClassCategories(
196 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
198 struct class_categories
*categories
;
202 size
= sizeof(struct class_categories
) + ((impl_count
+ req_count
)*CHARS_IN_GUID
+ 2)*sizeof(WCHAR
);
203 categories
= HeapAlloc(GetProcessHeap(), 0, size
);
204 if (categories
== NULL
) return categories
;
206 categories
->size
= size
;
207 categories
->impl_offset
= sizeof(struct class_categories
);
208 categories
->req_offset
= categories
->impl_offset
+ (impl_count
*CHARS_IN_GUID
+ 1)*sizeof(WCHAR
);
210 strings
= (WCHAR
*)(categories
+ 1);
211 while (impl_count
--) {
212 StringFromGUID2(impl_catids
++, strings
, CHARS_IN_GUID
);
213 strings
+= CHARS_IN_GUID
;
217 while (req_count
--) {
218 StringFromGUID2(req_catids
++, strings
, CHARS_IN_GUID
);
219 strings
+= CHARS_IN_GUID
;
226 /**********************************************************************
227 * COMCAT_IsClassOfCategories
229 static HRESULT
COMCAT_IsClassOfCategories(
231 struct class_categories
const* categories
)
233 const WCHAR
*impl_strings
, *req_strings
;
239 impl_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->impl_offset
);
240 req_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->req_offset
);
242 /* Check that every given category is implemented by class. */
244 res
= open_classes_key(key
, impl_keyname
, KEY_READ
, &subkey
);
245 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
246 for (string
= impl_strings
; *string
; string
+= CHARS_IN_GUID
) {
248 res
= open_classes_key(subkey
, string
, READ_CONTROL
, &catkey
);
249 if (res
!= ERROR_SUCCESS
) {
258 /* Check that all categories required by class are given. */
259 res
= open_classes_key(key
, req_keyname
, KEY_READ
, &subkey
);
260 if (res
== ERROR_SUCCESS
) {
261 for (index
= 0; ; ++index
) {
262 WCHAR keyname
[CHARS_IN_GUID
];
263 DWORD size
= CHARS_IN_GUID
;
265 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
266 NULL
, NULL
, NULL
, NULL
);
267 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
268 if (size
!= CHARS_IN_GUID
-1) continue; /* bogus catid in registry */
269 for (string
= req_strings
; *string
; string
+= CHARS_IN_GUID
)
270 if (!strcmpiW(string
, keyname
)) break;
282 /**********************************************************************
283 * COMCAT_ICatRegister_QueryInterface
285 static HRESULT WINAPI
COMCAT_ICatRegister_QueryInterface(
290 TRACE("%s\n",debugstr_guid(riid
));
292 if (ppvObj
== NULL
) return E_POINTER
;
294 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
296 ICatRegister_AddRef(iface
);
300 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
301 *ppvObj
= &COMCAT_ComCatMgr
.ICatInformation_iface
;
302 ICatRegister_AddRef(iface
);
306 return E_NOINTERFACE
;
309 /**********************************************************************
310 * COMCAT_ICatRegister_AddRef
312 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
314 return 2; /* non-heap based object */
317 /**********************************************************************
318 * COMCAT_ICatRegister_Release
320 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
322 return 1; /* non-heap based object */
325 /**********************************************************************
326 * COMCAT_ICatRegister_RegisterCategories
328 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
338 if (cCategories
&& rgci
== NULL
)
341 /* Create (or open) the component categories key. */
342 res
= create_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
343 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
345 for (; cCategories
; --cCategories
, ++rgci
) {
346 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
347 WCHAR keyname
[CHARS_IN_GUID
];
351 /* Create (or open) the key for this category. */
352 if (!StringFromGUID2(&rgci
->catid
, keyname
, CHARS_IN_GUID
)) continue;
353 res
= create_classes_key(comcat_key
, keyname
, KEY_READ
|KEY_WRITE
, &cat_key
);
354 if (res
!= ERROR_SUCCESS
) continue;
356 /* Set the value for this locale's description. */
357 wsprintfW(valname
, fmt
, rgci
->lcid
);
358 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
, (const BYTE
*)rgci
->szDescription
,
359 (lstrlenW(rgci
->szDescription
) + 1) * sizeof(WCHAR
));
361 RegCloseKey(cat_key
);
364 RegCloseKey(comcat_key
);
368 /**********************************************************************
369 * COMCAT_ICatRegister_UnRegisterCategories
371 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterCategories(
381 if (cCategories
&& rgcatid
== NULL
)
384 /* Open the component categories key. */
385 res
= open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
386 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
388 for (; cCategories
; --cCategories
, ++rgcatid
) {
389 WCHAR keyname
[CHARS_IN_GUID
];
391 /* Delete the key for this category. */
392 if (!StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
)) 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 return EnumCATEGORYINFO_Construct(lcid
, ppenumCatInfo
);
502 /**********************************************************************
503 * COMCAT_ICatInformation_GetCategoryDesc
505 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
506 LPCATINFORMATION iface
,
511 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
512 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
513 'r', 'i', 'e', 's', '\\', 0 };
517 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid
), lcid
);
519 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
521 /* Open the key for this category. */
522 if (!StringFromGUID2(rcatid
, keyname
+ 21, CHARS_IN_GUID
)) return E_FAIL
;
523 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
524 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
526 /* Allocate a sensible amount of memory for the description. */
527 *ppszDesc
= CoTaskMemAlloc(128 * sizeof(WCHAR
));
528 if (*ppszDesc
== NULL
) {
530 return E_OUTOFMEMORY
;
533 /* Get the description, and make sure it's null terminated. */
534 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
537 CoTaskMemFree(*ppszDesc
);
544 /**********************************************************************
545 * COMCAT_ICatInformation_EnumClassesOfCategories
547 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
548 LPCATINFORMATION iface
,
553 LPENUMCLSID
*ppenumCLSID
)
555 struct class_categories
*categories
;
560 if (cImplemented
== (ULONG
)-1)
562 if (cRequired
== (ULONG
)-1)
565 if (ppenumCLSID
== NULL
||
566 (cImplemented
&& rgcatidImpl
== NULL
) ||
567 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
569 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
570 cRequired
, rgcatidReq
);
571 if (categories
== NULL
) return E_OUTOFMEMORY
;
573 hr
= CLSIDEnumGUID_Construct(categories
, ppenumCLSID
);
576 HeapFree(GetProcessHeap(), 0, categories
);
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, CHARS_IN_GUID
);
613 if (FAILED(res
)) return res
;
615 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
616 cRequired
, rgcatidReq
);
617 if (categories
== NULL
) return E_OUTOFMEMORY
;
619 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, 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 return CATIDEnumGUID_Construct(rclsid
, postfix
, ppenumCATID
);
650 /**********************************************************************
651 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
653 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
654 LPCATINFORMATION iface
,
656 LPENUMCATID
*ppenumCATID
)
658 static const WCHAR postfix
[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
659 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
660 'r', 'i', 'e', 's', 0 };
662 TRACE("%s\n",debugstr_guid(rclsid
));
664 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
667 return CATIDEnumGUID_Construct(rclsid
, postfix
, ppenumCATID
);
670 /**********************************************************************
671 * COMCAT_ICatRegister_Vtbl
673 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
675 COMCAT_ICatRegister_QueryInterface
,
676 COMCAT_ICatRegister_AddRef
,
677 COMCAT_ICatRegister_Release
,
678 COMCAT_ICatRegister_RegisterCategories
,
679 COMCAT_ICatRegister_UnRegisterCategories
,
680 COMCAT_ICatRegister_RegisterClassImplCategories
,
681 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
682 COMCAT_ICatRegister_RegisterClassReqCategories
,
683 COMCAT_ICatRegister_UnRegisterClassReqCategories
687 /**********************************************************************
688 * COMCAT_ICatInformation_Vtbl
690 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
692 COMCAT_ICatInformation_QueryInterface
,
693 COMCAT_ICatInformation_AddRef
,
694 COMCAT_ICatInformation_Release
,
695 COMCAT_ICatInformation_EnumCategories
,
696 COMCAT_ICatInformation_GetCategoryDesc
,
697 COMCAT_ICatInformation_EnumClassesOfCategories
,
698 COMCAT_ICatInformation_IsClassOfCategories
,
699 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
700 COMCAT_ICatInformation_EnumReqCategoriesOfClass
703 /**********************************************************************
704 * COMCAT_IClassFactory_QueryInterface (also IUnknown)
706 static HRESULT WINAPI
COMCAT_IClassFactory_QueryInterface(
707 LPCLASSFACTORY iface
,
711 TRACE("%s\n",debugstr_guid(riid
));
713 if (ppvObj
== NULL
) return E_POINTER
;
715 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
716 IsEqualGUID(riid
, &IID_IClassFactory
))
719 IClassFactory_AddRef(iface
);
723 return E_NOINTERFACE
;
726 /**********************************************************************
727 * COMCAT_IClassFactory_AddRef (also IUnknown)
729 static ULONG WINAPI
COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface
)
731 return 2; /* non-heap based object */
734 /**********************************************************************
735 * COMCAT_IClassFactory_Release (also IUnknown)
737 static ULONG WINAPI
COMCAT_IClassFactory_Release(LPCLASSFACTORY iface
)
739 return 1; /* non-heap based object */
742 /**********************************************************************
743 * COMCAT_IClassFactory_CreateInstance
745 static HRESULT WINAPI
COMCAT_IClassFactory_CreateInstance(
746 LPCLASSFACTORY iface
,
752 TRACE("%s\n",debugstr_guid(riid
));
754 if (ppvObj
== NULL
) return E_POINTER
;
756 /* Don't support aggregation (Windows doesn't) */
757 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
759 res
= ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
760 if (SUCCEEDED(res
)) {
764 return CLASS_E_CLASSNOTAVAILABLE
;
767 /**********************************************************************
768 * COMCAT_IClassFactory_LockServer
770 static HRESULT WINAPI
COMCAT_IClassFactory_LockServer(
771 LPCLASSFACTORY iface
,
774 FIXME("(%d), stub!\n",fLock
);
778 /**********************************************************************
779 * static ClassFactory instance
781 static const IClassFactoryVtbl ComCatCFVtbl
=
783 COMCAT_IClassFactory_QueryInterface
,
784 COMCAT_IClassFactory_AddRef
,
785 COMCAT_IClassFactory_Release
,
786 COMCAT_IClassFactory_CreateInstance
,
787 COMCAT_IClassFactory_LockServer
790 static const IClassFactoryVtbl
*ComCatCF
= &ComCatCFVtbl
;
792 HRESULT
ComCatCF_Create(REFIID riid
, LPVOID
*ppv
)
794 return IClassFactory_QueryInterface((IClassFactory
*)&ComCatCF
, riid
, ppv
);
797 /**********************************************************************
798 * IEnumCATEGORYINFO implementation
800 * This implementation is not thread-safe. The manager itself is, but
801 * I can't imagine a valid use of an enumerator in several threads.
805 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface
;
810 } IEnumCATEGORYINFOImpl
;
812 static inline IEnumCATEGORYINFOImpl
*impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO
*iface
)
814 return CONTAINING_RECORD(iface
, IEnumCATEGORYINFOImpl
, IEnumCATEGORYINFO_iface
);
817 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO
*iface
)
819 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
823 return InterlockedIncrement(&This
->ref
);
826 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
827 IEnumCATEGORYINFO
*iface
,
831 TRACE("%s\n",debugstr_guid(riid
));
833 if (ppvObj
== NULL
) return E_POINTER
;
835 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
836 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
839 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
843 return E_NOINTERFACE
;
846 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO
*iface
)
848 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
853 ref
= InterlockedDecrement(&This
->ref
);
855 if (This
->key
) RegCloseKey(This
->key
);
856 HeapFree(GetProcessHeap(), 0, This
);
862 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
863 IEnumCATEGORYINFO
*iface
,
868 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
873 if (rgelt
== NULL
) return E_POINTER
;
875 if (This
->key
) while (fetched
< celt
) {
878 WCHAR catid
[CHARS_IN_GUID
];
879 DWORD cName
= CHARS_IN_GUID
;
882 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
883 NULL
, NULL
, NULL
, NULL
);
884 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
885 ++(This
->next_index
);
887 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
888 if (FAILED(hr
)) continue;
890 res
= open_classes_key(This
->key
, catid
, KEY_READ
, &subkey
);
891 if (res
!= ERROR_SUCCESS
) continue;
893 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
894 rgelt
->szDescription
, 128);
896 if (FAILED(hr
)) continue;
898 rgelt
->lcid
= This
->lcid
;
903 if (pceltFetched
) *pceltFetched
= fetched
;
904 return fetched
== celt
? S_OK
: S_FALSE
;
907 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
908 IEnumCATEGORYINFO
*iface
,
911 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
915 This
->next_index
+= celt
;
916 /* This should return S_FALSE when there aren't celt elems to skip. */
920 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO
*iface
)
922 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
926 This
->next_index
= 0;
930 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
931 IEnumCATEGORYINFO
*iface
,
932 IEnumCATEGORYINFO
**ppenum
)
934 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
935 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
936 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
937 'r', 'i', 'e', 's', 0 };
938 IEnumCATEGORYINFOImpl
*new_this
;
942 if (ppenum
== NULL
) return E_POINTER
;
944 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
945 if (new_this
== NULL
) return E_OUTOFMEMORY
;
947 new_this
->IEnumCATEGORYINFO_iface
= This
->IEnumCATEGORYINFO_iface
;
949 new_this
->lcid
= This
->lcid
;
950 /* FIXME: could we more efficiently use DuplicateHandle? */
951 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &new_this
->key
);
952 new_this
->next_index
= This
->next_index
;
954 *ppenum
= &new_this
->IEnumCATEGORYINFO_iface
;
958 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
960 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
961 COMCAT_IEnumCATEGORYINFO_AddRef
,
962 COMCAT_IEnumCATEGORYINFO_Release
,
963 COMCAT_IEnumCATEGORYINFO_Next
,
964 COMCAT_IEnumCATEGORYINFO_Skip
,
965 COMCAT_IEnumCATEGORYINFO_Reset
,
966 COMCAT_IEnumCATEGORYINFO_Clone
969 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
)
971 static const WCHAR keyname
[] = {'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0};
972 IEnumCATEGORYINFOImpl
*This
;
976 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
977 if (!This
) return E_OUTOFMEMORY
;
979 This
->IEnumCATEGORYINFO_iface
.lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
982 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
984 *ret
= &This
->IEnumCATEGORYINFO_iface
;
988 /**********************************************************************
989 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
991 * This implementation is not thread-safe. The manager itself is, but
992 * I can't imagine a valid use of an enumerator in several threads.
996 IEnumGUID IEnumGUID_iface
;
998 struct class_categories
*categories
;
1001 } CLSID_IEnumGUIDImpl
;
1003 static inline CLSID_IEnumGUIDImpl
*impl_from_IEnumCLSID(IEnumGUID
*iface
)
1005 return CONTAINING_RECORD(iface
, CLSID_IEnumGUIDImpl
, IEnumGUID_iface
);
1008 static HRESULT WINAPI
CLSIDEnumGUID_QueryInterface(
1013 TRACE("%s\n",debugstr_guid(riid
));
1015 if (ppvObj
== NULL
) return E_POINTER
;
1017 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1018 IsEqualGUID(riid
, &IID_IEnumGUID
))
1021 IEnumGUID_AddRef(iface
);
1025 return E_NOINTERFACE
;
1028 static ULONG WINAPI
CLSIDEnumGUID_AddRef(IEnumGUID
*iface
)
1030 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1033 return InterlockedIncrement(&This
->ref
);
1036 static ULONG WINAPI
CLSIDEnumGUID_Release(IEnumGUID
*iface
)
1038 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1043 ref
= InterlockedDecrement(&This
->ref
);
1045 if (This
->key
) RegCloseKey(This
->key
);
1046 HeapFree(GetProcessHeap(), 0, This
->categories
);
1047 HeapFree(GetProcessHeap(), 0, This
);
1053 static HRESULT WINAPI
CLSIDEnumGUID_Next(
1057 ULONG
*pceltFetched
)
1059 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1064 if (rgelt
== NULL
) return E_POINTER
;
1066 if (This
->key
) while (fetched
< celt
) {
1069 WCHAR clsid
[CHARS_IN_GUID
];
1070 DWORD cName
= CHARS_IN_GUID
;
1073 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
1074 NULL
, NULL
, NULL
, NULL
);
1075 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1076 ++(This
->next_index
);
1078 hr
= CLSIDFromString(clsid
, rgelt
);
1079 if (FAILED(hr
)) continue;
1081 res
= open_classes_key(This
->key
, clsid
, KEY_READ
, &subkey
);
1082 if (res
!= ERROR_SUCCESS
) continue;
1084 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
1085 RegCloseKey(subkey
);
1086 if (hr
!= S_OK
) continue;
1092 if (pceltFetched
) *pceltFetched
= fetched
;
1093 return fetched
== celt
? S_OK
: S_FALSE
;
1096 static HRESULT WINAPI
CLSIDEnumGUID_Skip(
1100 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1104 This
->next_index
+= celt
;
1105 FIXME("Never returns S_FALSE\n");
1109 static HRESULT WINAPI
CLSIDEnumGUID_Reset(IEnumGUID
*iface
)
1111 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1115 This
->next_index
= 0;
1119 static HRESULT WINAPI
CLSIDEnumGUID_Clone(
1123 static const WCHAR keynameW
[] = {'C','L','S','I','D',0};
1124 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1125 CLSID_IEnumGUIDImpl
*cloned
;
1127 TRACE("(%p)->(%p)\n", This
, ppenum
);
1129 if (ppenum
== NULL
) return E_POINTER
;
1133 cloned
= HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID_IEnumGUIDImpl
));
1134 if (cloned
== NULL
) return E_OUTOFMEMORY
;
1136 cloned
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1139 cloned
->categories
= HeapAlloc(GetProcessHeap(), 0, This
->categories
->size
);
1140 if (cloned
->categories
== NULL
) {
1141 HeapFree(GetProcessHeap(), 0, cloned
);
1142 return E_OUTOFMEMORY
;
1144 memcpy(cloned
->categories
, This
->categories
, This
->categories
->size
);
1147 open_classes_key(HKEY_CLASSES_ROOT
, keynameW
, KEY_READ
, &cloned
->key
);
1148 cloned
->next_index
= This
->next_index
;
1150 *ppenum
= &cloned
->IEnumGUID_iface
;
1154 static const IEnumGUIDVtbl CLSIDEnumGUIDVtbl
=
1156 CLSIDEnumGUID_QueryInterface
,
1157 CLSIDEnumGUID_AddRef
,
1158 CLSIDEnumGUID_Release
,
1161 CLSIDEnumGUID_Reset
,
1165 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*categories
, IEnumCLSID
**ret
)
1167 static const WCHAR keyname
[] = {'C','L','S','I','D',0};
1168 CLSID_IEnumGUIDImpl
*This
;
1172 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1173 if (!This
) return E_OUTOFMEMORY
;
1175 This
->IEnumGUID_iface
.lpVtbl
= &CLSIDEnumGUIDVtbl
;
1177 This
->categories
= categories
;
1178 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1180 *ret
= &This
->IEnumGUID_iface
;
1185 /**********************************************************************
1186 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1188 * This implementation is not thread-safe. The manager itself is, but
1189 * I can't imagine a valid use of an enumerator in several threads.
1193 IEnumGUID IEnumGUID_iface
;
1198 } CATID_IEnumGUIDImpl
;
1200 static inline CATID_IEnumGUIDImpl
*impl_from_IEnumCATID(IEnumGUID
*iface
)
1202 return CONTAINING_RECORD(iface
, CATID_IEnumGUIDImpl
, IEnumGUID_iface
);
1205 static HRESULT WINAPI
CATIDEnumGUID_QueryInterface(
1210 TRACE("%s\n",debugstr_guid(riid
));
1212 if (ppvObj
== NULL
) return E_POINTER
;
1214 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1215 IsEqualGUID(riid
, &IID_IEnumGUID
))
1218 IEnumGUID_AddRef(iface
);
1222 return E_NOINTERFACE
;
1225 static ULONG WINAPI
CATIDEnumGUID_AddRef(IEnumGUID
*iface
)
1227 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1230 return InterlockedIncrement(&This
->ref
);
1233 static ULONG WINAPI
CATIDEnumGUID_Release(IEnumGUID
*iface
)
1235 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1240 ref
= InterlockedDecrement(&This
->ref
);
1242 if (This
->key
) RegCloseKey(This
->key
);
1243 HeapFree(GetProcessHeap(), 0, This
);
1249 static HRESULT WINAPI
CATIDEnumGUID_Next(
1253 ULONG
*pceltFetched
)
1255 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1260 if (rgelt
== NULL
) return E_POINTER
;
1262 if (This
->key
) while (fetched
< celt
) {
1265 WCHAR catid
[CHARS_IN_GUID
];
1266 DWORD cName
= CHARS_IN_GUID
;
1268 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1269 NULL
, NULL
, NULL
, NULL
);
1270 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1271 ++(This
->next_index
);
1273 hr
= CLSIDFromString(catid
, rgelt
);
1274 if (FAILED(hr
)) continue;
1280 if (pceltFetched
) *pceltFetched
= fetched
;
1281 return fetched
== celt
? S_OK
: S_FALSE
;
1284 static HRESULT WINAPI
CATIDEnumGUID_Skip(
1288 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1292 This
->next_index
+= celt
;
1293 FIXME("Never returns S_FALSE\n");
1297 static HRESULT WINAPI
CATIDEnumGUID_Reset(IEnumGUID
*iface
)
1299 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1303 This
->next_index
= 0;
1307 static HRESULT WINAPI
CATIDEnumGUID_Clone(
1311 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1312 CATID_IEnumGUIDImpl
*new_this
;
1316 if (ppenum
== NULL
) return E_POINTER
;
1318 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1319 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1321 new_this
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1323 lstrcpyW(new_this
->keyname
, This
->keyname
);
1324 /* FIXME: could we more efficiently use DuplicateHandle? */
1325 open_classes_key(HKEY_CLASSES_ROOT
, new_this
->keyname
, KEY_READ
, &new_this
->key
);
1326 new_this
->next_index
= This
->next_index
;
1328 *ppenum
= &new_this
->IEnumGUID_iface
;
1332 static const IEnumGUIDVtbl CATIDEnumGUIDVtbl
=
1334 CATIDEnumGUID_QueryInterface
,
1335 CATIDEnumGUID_AddRef
,
1336 CATIDEnumGUID_Release
,
1339 CATIDEnumGUID_Reset
,
1343 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR postfix
, IEnumGUID
**ret
)
1345 static const WCHAR prefixW
[] = {'C','L','S','I','D','\\',0};
1346 WCHAR keyname
[100], clsidW
[CHARS_IN_GUID
];
1347 CATID_IEnumGUIDImpl
*This
;
1351 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1352 if (!This
) return E_OUTOFMEMORY
;
1354 StringFromGUID2(rclsid
, clsidW
, CHARS_IN_GUID
);
1356 This
->IEnumGUID_iface
.lpVtbl
= &CATIDEnumGUIDVtbl
;
1358 strcpyW(keyname
, prefixW
);
1359 strcatW(keyname
, clsidW
);
1360 strcatW(keyname
, postfix
);
1362 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1364 *ret
= &This
->IEnumGUID_iface
;