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
);
41 const ICatRegisterVtbl
*lpVtbl
;
42 const ICatInformationVtbl
*infVtbl
;
45 struct class_categories
{
50 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
);
51 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*class_categories
);
52 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR impl_req
);
54 /**********************************************************************
55 * File-scope string constants
57 static const WCHAR comcat_keyname
[] = {
58 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
59 static const WCHAR impl_keyname
[] = {
60 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
61 static const WCHAR req_keyname
[] = {
62 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
63 static const WCHAR clsid_keyname
[] = { 'C','L','S','I','D',0 };
66 static inline ComCatMgrImpl
*impl_from_ICatInformation( ICatInformation
*iface
)
68 return (ComCatMgrImpl
*)((char*)iface
- FIELD_OFFSET(ComCatMgrImpl
, infVtbl
));
72 /**********************************************************************
73 * COMCAT_RegisterClassCategories
75 static HRESULT
COMCAT_RegisterClassCategories(
83 HKEY clsid_key
, class_key
, type_key
;
85 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
87 /* Format the class key name. */
88 res
= StringFromGUID2(rclsid
, keyname
, 39);
89 if (FAILED(res
)) return res
;
91 /* Create (or open) the CLSID key. */
92 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, clsid_keyname
, 0, NULL
, 0,
93 KEY_READ
| KEY_WRITE
, NULL
, &clsid_key
, NULL
);
94 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
96 /* Create (or open) the class key. */
97 res
= RegCreateKeyExW(clsid_key
, keyname
, 0, NULL
, 0,
98 KEY_READ
| KEY_WRITE
, NULL
, &class_key
, NULL
);
99 if (res
== ERROR_SUCCESS
) {
100 /* Create (or open) the category type key. */
101 res
= RegCreateKeyExW(class_key
, type
, 0, NULL
, 0,
102 KEY_READ
| KEY_WRITE
, NULL
, &type_key
, NULL
);
103 if (res
== ERROR_SUCCESS
) {
104 for (; cCategories
; --cCategories
, ++rgcatid
) {
107 /* Format the category key name. */
108 res
= StringFromGUID2(rgcatid
, keyname
, 39);
109 if (FAILED(res
)) continue;
111 /* Do the register. */
112 res
= RegCreateKeyExW(type_key
, keyname
, 0, NULL
, 0,
113 KEY_READ
| KEY_WRITE
, NULL
, &key
, NULL
);
114 if (res
== ERROR_SUCCESS
) RegCloseKey(key
);
118 RegCloseKey(class_key
);
120 RegCloseKey(clsid_key
);
125 /**********************************************************************
126 * COMCAT_UnRegisterClassCategories
128 static HRESULT
COMCAT_UnRegisterClassCategories(
132 const CATID
*rgcatid
)
134 WCHAR keyname
[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
138 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
140 /* Format the class category type key name. */
141 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
142 if (FAILED(res
)) return res
;
144 lstrcpyW(keyname
+ 45, type
);
146 /* Open the class category type key. */
147 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0,
148 KEY_READ
| KEY_WRITE
, &type_key
);
149 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
151 for (; cCategories
; --cCategories
, ++rgcatid
) {
152 /* Format the category key name. */
153 res
= StringFromGUID2(rgcatid
, keyname
, 39);
154 if (FAILED(res
)) continue;
156 /* Do the unregister. */
157 RegDeleteKeyW(type_key
, keyname
);
159 RegCloseKey(type_key
);
164 /**********************************************************************
165 * COMCAT_GetCategoryDesc
167 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
170 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
173 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
175 if (pszDesc
== NULL
) return E_INVALIDARG
;
177 /* FIXME: lcid comparisons are more complex than this! */
178 wsprintfW(valname
, fmt
, lcid
);
179 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
180 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
181 FIXME("Simplified lcid comparison\n");
182 return CAT_E_NODESCRIPTION
;
184 pszDesc
[size
/ sizeof(WCHAR
)] = (WCHAR
)0;
189 /**********************************************************************
190 * COMCAT_PrepareClassCategories
192 static struct class_categories
*COMCAT_PrepareClassCategories(
193 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
195 struct class_categories
*categories
;
198 categories
= HeapAlloc(
199 GetProcessHeap(), HEAP_ZERO_MEMORY
,
200 sizeof(struct class_categories
) +
201 ((impl_count
+ req_count
) * 39 + 2) * sizeof(WCHAR
));
202 if (categories
== NULL
) return categories
;
204 strings
= (WCHAR
*)(categories
+ 1);
205 categories
->impl_strings
= strings
;
206 while (impl_count
--) {
207 StringFromGUID2(impl_catids
++, strings
, 39);
212 categories
->req_strings
= strings
;
213 while (req_count
--) {
214 StringFromGUID2(req_catids
++, strings
, 39);
222 /**********************************************************************
223 * COMCAT_IsClassOfCategories
225 static HRESULT
COMCAT_IsClassOfCategories(
227 struct class_categories
const* categories
)
229 static const WCHAR impl_keyname
[] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
230 't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
231 'g', 'o', 'r', 'i', 'e', 's', 0 };
232 static const WCHAR req_keyname
[] = { 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'd',
233 ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r',
240 /* Check that every given category is implemented by class. */
241 res
= RegOpenKeyExW(key
, impl_keyname
, 0, KEY_READ
, &subkey
);
242 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
243 for (string
= categories
->impl_strings
; *string
; string
+= 39) {
245 res
= RegOpenKeyExW(subkey
, string
, 0, 0, &catkey
);
246 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 ComCatMgrImpl
*This
= (ComCatMgrImpl
*)iface
;
287 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
289 if (ppvObj
== NULL
) return E_POINTER
;
291 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
293 IUnknown_AddRef(iface
);
297 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
298 *ppvObj
= &This
->infVtbl
;
299 IUnknown_AddRef(iface
);
303 return E_NOINTERFACE
;
306 /**********************************************************************
307 * COMCAT_ICatRegister_AddRef
309 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
311 return 2; /* non-heap based object */
314 /**********************************************************************
315 * COMCAT_ICatRegister_Release
317 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
319 return 1; /* non-heap based object */
322 /**********************************************************************
323 * COMCAT_ICatRegister_RegisterCategories
325 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
335 if (cCategories
&& rgci
== NULL
)
338 /* Create (or open) the component categories key. */
339 res
= RegCreateKeyExW(HKEY_CLASSES_ROOT
, comcat_keyname
, 0, NULL
, 0,
340 KEY_READ
| KEY_WRITE
, NULL
, &comcat_key
, NULL
);
341 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
343 for (; cCategories
; --cCategories
, ++rgci
) {
344 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
349 /* Create (or open) the key for this category. */
350 if (!StringFromGUID2(&rgci
->catid
, keyname
, 39)) continue;
351 res
= RegCreateKeyExW(comcat_key
, keyname
, 0, NULL
, 0,
352 KEY_READ
| KEY_WRITE
, NULL
, &cat_key
, NULL
);
353 if (res
!= ERROR_SUCCESS
) continue;
355 /* Set the value for this locale's description. */
356 wsprintfW(valname
, fmt
, rgci
->lcid
);
357 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
,
358 (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
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, comcat_keyname
, 0,
386 KEY_READ
| KEY_WRITE
, &comcat_key
);
387 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
389 for (; cCategories
; --cCategories
, ++rgcatid
) {
392 /* Delete the key for this category. */
393 if (!StringFromGUID2(rgcatid
, keyname
, 39)) continue;
394 RegDeleteKeyW(comcat_key
, keyname
);
397 RegCloseKey(comcat_key
);
401 /**********************************************************************
402 * COMCAT_ICatRegister_RegisterClassImplCategories
404 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassImplCategories(
412 return COMCAT_RegisterClassCategories(
413 rclsid
, impl_keyname
, cCategories
, rgcatid
);
416 /**********************************************************************
417 * COMCAT_ICatRegister_UnRegisterClassImplCategories
419 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassImplCategories(
427 return COMCAT_UnRegisterClassCategories(
428 rclsid
, impl_keyname
, cCategories
, rgcatid
);
431 /**********************************************************************
432 * COMCAT_ICatRegister_RegisterClassReqCategories
434 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassReqCategories(
442 return COMCAT_RegisterClassCategories(
443 rclsid
, req_keyname
, cCategories
, rgcatid
);
446 /**********************************************************************
447 * COMCAT_ICatRegister_UnRegisterClassReqCategories
449 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassReqCategories(
457 return COMCAT_UnRegisterClassCategories(
458 rclsid
, req_keyname
, cCategories
, rgcatid
);
461 /**********************************************************************
462 * COMCAT_ICatInformation_QueryInterface
464 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
465 LPCATINFORMATION iface
,
469 ComCatMgrImpl
*This
= impl_from_ICatInformation( iface
);
470 return IUnknown_QueryInterface((LPUNKNOWN
)This
, riid
, ppvObj
);
473 /**********************************************************************
474 * COMCAT_ICatInformation_AddRef
476 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
478 ComCatMgrImpl
*This
= impl_from_ICatInformation( iface
);
479 return IUnknown_AddRef((LPUNKNOWN
)This
);
482 /**********************************************************************
483 * COMCAT_ICatInformation_Release
485 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
487 ComCatMgrImpl
*This
= impl_from_ICatInformation( iface
);
488 return IUnknown_Release((LPUNKNOWN
)This
);
491 /**********************************************************************
492 * COMCAT_ICatInformation_EnumCategories
494 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
495 LPCATINFORMATION iface
,
497 LPENUMCATEGORYINFO
*ppenumCatInfo
)
501 if (ppenumCatInfo
== NULL
) return E_POINTER
;
503 *ppenumCatInfo
= COMCAT_IEnumCATEGORYINFO_Construct(lcid
);
504 if (*ppenumCatInfo
== NULL
) return E_OUTOFMEMORY
;
505 IEnumCATEGORYINFO_AddRef(*ppenumCatInfo
);
509 /**********************************************************************
510 * COMCAT_ICatInformation_GetCategoryDesc
512 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
513 LPCATINFORMATION iface
,
518 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
519 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
520 'r', 'i', 'e', 's', '\\', 0 };
524 TRACE("\n\tCATID:\t%s\n\tLCID:\t%X\n",debugstr_guid(rcatid
), lcid
);
526 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
528 /* Open the key for this category. */
529 if (!StringFromGUID2(rcatid
, keyname
+ 21, 39)) return E_FAIL
;
530 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
531 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
533 /* Allocate a sensible amount of memory for the description. */
534 *ppszDesc
= (PWCHAR
) CoTaskMemAlloc(128 * sizeof(WCHAR
));
535 if (*ppszDesc
== NULL
) {
537 return E_OUTOFMEMORY
;
540 /* Get the description, and make sure it's null terminated. */
541 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
544 CoTaskMemFree(*ppszDesc
);
551 /**********************************************************************
552 * COMCAT_ICatInformation_EnumClassesOfCategories
554 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
555 LPCATINFORMATION iface
,
560 LPENUMCLSID
*ppenumCLSID
)
562 struct class_categories
*categories
;
566 if (cImplemented
== (ULONG
)-1)
568 if (cRequired
== (ULONG
)-1)
571 if (ppenumCLSID
== NULL
||
572 (cImplemented
&& rgcatidImpl
== NULL
) ||
573 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
575 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
576 cRequired
, rgcatidReq
);
577 if (categories
== NULL
) return E_OUTOFMEMORY
;
578 *ppenumCLSID
= COMCAT_CLSID_IEnumGUID_Construct(categories
);
579 if (*ppenumCLSID
== NULL
) {
580 HeapFree(GetProcessHeap(), 0, categories
);
581 return E_OUTOFMEMORY
;
583 IEnumGUID_AddRef(*ppenumCLSID
);
587 /**********************************************************************
588 * COMCAT_ICatInformation_IsClassOfCategories
590 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
591 LPCATINFORMATION iface
,
598 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
600 struct class_categories
*categories
;
603 if (WINE_TRACE_ON(ole
)) {
605 TRACE("\n\tCLSID:\t%s\n\tImplemented %u\n",debugstr_guid(rclsid
),cImplemented
);
606 for (count
= 0; count
< cImplemented
; ++count
)
607 TRACE("\t\t%s\n",debugstr_guid(&rgcatidImpl
[count
]));
608 TRACE("\tRequired %u\n",cRequired
);
609 for (count
= 0; count
< cRequired
; ++count
)
610 TRACE("\t\t%s\n",debugstr_guid(&rgcatidReq
[count
]));
613 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
614 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
616 res
= StringFromGUID2(rclsid
, keyname
+ 6, 39);
617 if (FAILED(res
)) return res
;
619 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
620 cRequired
, rgcatidReq
);
621 if (categories
== NULL
) return E_OUTOFMEMORY
;
623 res
= RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &key
);
624 if (res
== ERROR_SUCCESS
) {
625 res
= COMCAT_IsClassOfCategories(key
, categories
);
627 } else res
= S_FALSE
;
629 HeapFree(GetProcessHeap(), 0, categories
);
634 /**********************************************************************
635 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
637 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
638 LPCATINFORMATION iface
,
640 LPENUMCATID
*ppenumCATID
)
642 static const WCHAR postfix
[24] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
643 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
644 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
646 TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid
));
648 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
651 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
652 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
656 /**********************************************************************
657 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
659 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
660 LPCATINFORMATION iface
,
662 LPENUMCATID
*ppenumCATID
)
664 static const WCHAR postfix
[21] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
665 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
666 'r', 'i', 'e', 's', 0 };
668 TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid
));
670 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
673 *ppenumCATID
= COMCAT_CATID_IEnumGUID_Construct(rclsid
, postfix
);
674 if (*ppenumCATID
== NULL
) return E_OUTOFMEMORY
;
678 /**********************************************************************
679 * COMCAT_ICatRegister_Vtbl
681 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
683 COMCAT_ICatRegister_QueryInterface
,
684 COMCAT_ICatRegister_AddRef
,
685 COMCAT_ICatRegister_Release
,
686 COMCAT_ICatRegister_RegisterCategories
,
687 COMCAT_ICatRegister_UnRegisterCategories
,
688 COMCAT_ICatRegister_RegisterClassImplCategories
,
689 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
690 COMCAT_ICatRegister_RegisterClassReqCategories
,
691 COMCAT_ICatRegister_UnRegisterClassReqCategories
695 /**********************************************************************
696 * COMCAT_ICatInformation_Vtbl
698 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
700 COMCAT_ICatInformation_QueryInterface
,
701 COMCAT_ICatInformation_AddRef
,
702 COMCAT_ICatInformation_Release
,
703 COMCAT_ICatInformation_EnumCategories
,
704 COMCAT_ICatInformation_GetCategoryDesc
,
705 COMCAT_ICatInformation_EnumClassesOfCategories
,
706 COMCAT_ICatInformation_IsClassOfCategories
,
707 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
708 COMCAT_ICatInformation_EnumReqCategoriesOfClass
711 /**********************************************************************
712 * static ComCatMgr instance
714 static ComCatMgrImpl COMCAT_ComCatMgr
=
716 &COMCAT_ICatRegister_Vtbl
,
717 &COMCAT_ICatInformation_Vtbl
720 /**********************************************************************
721 * COMCAT_IClassFactory_QueryInterface (also IUnknown)
723 static HRESULT WINAPI
COMCAT_IClassFactory_QueryInterface(
724 LPCLASSFACTORY iface
,
728 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
730 if (ppvObj
== NULL
) return E_POINTER
;
732 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
733 IsEqualGUID(riid
, &IID_IClassFactory
))
735 *ppvObj
= (LPVOID
)iface
;
736 IUnknown_AddRef(iface
);
740 return E_NOINTERFACE
;
743 /**********************************************************************
744 * COMCAT_IClassFactory_AddRef (also IUnknown)
746 static ULONG WINAPI
COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface
)
748 return 2; /* non-heap based object */
751 /**********************************************************************
752 * COMCAT_IClassFactory_Release (also IUnknown)
754 static ULONG WINAPI
COMCAT_IClassFactory_Release(LPCLASSFACTORY iface
)
756 return 1; /* non-heap based object */
759 /**********************************************************************
760 * COMCAT_IClassFactory_CreateInstance
762 static HRESULT WINAPI
COMCAT_IClassFactory_CreateInstance(
763 LPCLASSFACTORY iface
,
769 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
771 if (ppvObj
== NULL
) return E_POINTER
;
773 /* Don't support aggregation (Windows doesn't) */
774 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
776 res
= IUnknown_QueryInterface((LPUNKNOWN
)&COMCAT_ComCatMgr
, riid
, ppvObj
);
777 if (SUCCEEDED(res
)) {
781 return CLASS_E_CLASSNOTAVAILABLE
;
784 /**********************************************************************
785 * COMCAT_IClassFactory_LockServer
787 static HRESULT WINAPI
COMCAT_IClassFactory_LockServer(
788 LPCLASSFACTORY iface
,
791 FIXME("(%d), stub!\n",fLock
);
795 /**********************************************************************
796 * static ClassFactory instance
798 static const IClassFactoryVtbl ComCatCFVtbl
=
800 COMCAT_IClassFactory_QueryInterface
,
801 COMCAT_IClassFactory_AddRef
,
802 COMCAT_IClassFactory_Release
,
803 COMCAT_IClassFactory_CreateInstance
,
804 COMCAT_IClassFactory_LockServer
807 static const IClassFactoryVtbl
*ComCatCF
= &ComCatCFVtbl
;
809 HRESULT
ComCatCF_Create(REFIID riid
, LPVOID
*ppv
)
811 return IClassFactory_QueryInterface((IClassFactory
*)&ComCatCF
, riid
, ppv
);
814 /**********************************************************************
815 * IEnumCATEGORYINFO implementation
817 * This implementation is not thread-safe. The manager itself is, but
818 * I can't imagine a valid use of an enumerator in several threads.
822 const IEnumCATEGORYINFOVtbl
*lpVtbl
;
827 } IEnumCATEGORYINFOImpl
;
829 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(LPENUMCATEGORYINFO iface
)
831 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
835 return InterlockedIncrement(&This
->ref
);
838 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
839 LPENUMCATEGORYINFO iface
,
843 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
845 if (ppvObj
== NULL
) return E_POINTER
;
847 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
848 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
850 *ppvObj
= (LPVOID
)iface
;
851 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
855 return E_NOINTERFACE
;
858 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(LPENUMCATEGORYINFO iface
)
860 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
865 ref
= InterlockedDecrement(&This
->ref
);
867 if (This
->key
) RegCloseKey(This
->key
);
868 HeapFree(GetProcessHeap(), 0, This
);
874 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
875 LPENUMCATEGORYINFO iface
,
880 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
885 if (rgelt
== NULL
) return E_POINTER
;
887 if (This
->key
) while (fetched
< celt
) {
894 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
895 NULL
, NULL
, NULL
, NULL
);
896 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
897 ++(This
->next_index
);
899 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
900 if (FAILED(hr
)) continue;
902 res
= RegOpenKeyExW(This
->key
, catid
, 0, KEY_READ
, &subkey
);
903 if (res
!= ERROR_SUCCESS
) continue;
905 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
906 rgelt
->szDescription
, 128);
908 if (FAILED(hr
)) continue;
910 rgelt
->lcid
= This
->lcid
;
915 if (pceltFetched
) *pceltFetched
= fetched
;
916 return fetched
== celt
? S_OK
: S_FALSE
;
919 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
920 LPENUMCATEGORYINFO iface
,
923 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
927 This
->next_index
+= celt
;
928 /* This should return S_FALSE when there aren't celt elems to skip. */
932 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface
)
934 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
938 This
->next_index
= 0;
942 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
943 LPENUMCATEGORYINFO iface
,
944 IEnumCATEGORYINFO
**ppenum
)
946 IEnumCATEGORYINFOImpl
*This
= (IEnumCATEGORYINFOImpl
*)iface
;
947 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
948 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
949 'r', 'i', 'e', 's', 0 };
950 IEnumCATEGORYINFOImpl
*new_this
;
954 if (ppenum
== NULL
) return E_POINTER
;
956 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
957 if (new_this
== NULL
) return E_OUTOFMEMORY
;
959 new_this
->lpVtbl
= This
->lpVtbl
;
961 new_this
->lcid
= This
->lcid
;
962 /* FIXME: could we more efficiently use DuplicateHandle? */
963 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
964 new_this
->next_index
= This
->next_index
;
966 *ppenum
= (LPENUMCATEGORYINFO
)new_this
;
970 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
972 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
973 COMCAT_IEnumCATEGORYINFO_AddRef
,
974 COMCAT_IEnumCATEGORYINFO_Release
,
975 COMCAT_IEnumCATEGORYINFO_Next
,
976 COMCAT_IEnumCATEGORYINFO_Skip
,
977 COMCAT_IEnumCATEGORYINFO_Reset
,
978 COMCAT_IEnumCATEGORYINFO_Clone
981 static LPENUMCATEGORYINFO
COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid
)
983 IEnumCATEGORYINFOImpl
*This
;
985 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
987 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
988 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
989 'r', 'i', 'e', 's', 0 };
991 This
->lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
993 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
995 return (LPENUMCATEGORYINFO
)This
;
998 /**********************************************************************
999 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
1001 * This implementation is not thread-safe. The manager itself is, but
1002 * I can't imagine a valid use of an enumerator in several threads.
1006 const IEnumGUIDVtbl
*lpVtbl
;
1008 struct class_categories
*categories
;
1011 } CLSID_IEnumGUIDImpl
;
1013 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface
)
1015 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1018 return InterlockedIncrement(&This
->ref
);
1021 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_QueryInterface(
1026 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
1028 if (ppvObj
== NULL
) return E_POINTER
;
1030 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1031 IsEqualGUID(riid
, &IID_IEnumGUID
))
1033 *ppvObj
= (LPVOID
)iface
;
1034 COMCAT_CLSID_IEnumGUID_AddRef(iface
);
1038 return E_NOINTERFACE
;
1041 static ULONG WINAPI
COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface
)
1043 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1048 ref
= InterlockedDecrement(&This
->ref
);
1050 if (This
->key
) RegCloseKey(This
->key
);
1051 HeapFree(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
1052 HeapFree(GetProcessHeap(), 0, This
);
1058 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Next(
1062 ULONG
*pceltFetched
)
1064 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1069 if (rgelt
== NULL
) return E_POINTER
;
1071 if (This
->key
) while (fetched
< celt
) {
1078 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
1079 NULL
, NULL
, NULL
, NULL
);
1080 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1081 ++(This
->next_index
);
1083 hr
= CLSIDFromString(clsid
, rgelt
);
1084 if (FAILED(hr
)) continue;
1086 res
= RegOpenKeyExW(This
->key
, clsid
, 0, KEY_READ
, &subkey
);
1087 if (res
!= ERROR_SUCCESS
) continue;
1089 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
1090 RegCloseKey(subkey
);
1091 if (hr
!= S_OK
) continue;
1097 if (pceltFetched
) *pceltFetched
= fetched
;
1098 return fetched
== celt
? S_OK
: S_FALSE
;
1101 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Skip(
1105 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1109 This
->next_index
+= celt
;
1110 FIXME("Never returns S_FALSE\n");
1114 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface
)
1116 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1120 This
->next_index
= 0;
1124 static HRESULT WINAPI
COMCAT_CLSID_IEnumGUID_Clone(
1128 CLSID_IEnumGUIDImpl
*This
= (CLSID_IEnumGUIDImpl
*)iface
;
1129 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1130 CLSID_IEnumGUIDImpl
*new_this
;
1135 if (ppenum
== NULL
) return E_POINTER
;
1137 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1138 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1140 new_this
->lpVtbl
= This
->lpVtbl
;
1142 size
= HeapSize(GetProcessHeap(), 0, (LPVOID
)This
->categories
);
1143 new_this
->categories
=
1144 HeapAlloc(GetProcessHeap(), 0, size
);
1145 if (new_this
->categories
== NULL
) {
1146 HeapFree(GetProcessHeap(), 0, new_this
);
1147 return E_OUTOFMEMORY
;
1149 memcpy((LPVOID
)new_this
->categories
, This
->categories
, size
);
1150 /* FIXME: could we more efficiently use DuplicateHandle? */
1151 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &new_this
->key
);
1152 new_this
->next_index
= This
->next_index
;
1154 *ppenum
= (LPENUMGUID
)new_this
;
1158 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl
=
1160 COMCAT_CLSID_IEnumGUID_QueryInterface
,
1161 COMCAT_CLSID_IEnumGUID_AddRef
,
1162 COMCAT_CLSID_IEnumGUID_Release
,
1163 COMCAT_CLSID_IEnumGUID_Next
,
1164 COMCAT_CLSID_IEnumGUID_Skip
,
1165 COMCAT_CLSID_IEnumGUID_Reset
,
1166 COMCAT_CLSID_IEnumGUID_Clone
1169 static LPENUMGUID
COMCAT_CLSID_IEnumGUID_Construct(struct class_categories
*categories
)
1171 CLSID_IEnumGUIDImpl
*This
;
1173 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1175 static const WCHAR keyname
[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1177 This
->lpVtbl
= &COMCAT_CLSID_IEnumGUID_Vtbl
;
1178 This
->categories
= categories
;
1179 RegOpenKeyExW(HKEY_CLASSES_ROOT
, keyname
, 0, KEY_READ
, &This
->key
);
1181 return (LPENUMGUID
)This
;
1184 /**********************************************************************
1185 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1187 * This implementation is not thread-safe. The manager itself is, but
1188 * I can't imagine a valid use of an enumerator in several threads.
1192 const IEnumGUIDVtbl
*lpVtbl
;
1197 } CATID_IEnumGUIDImpl
;
1199 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface
)
1201 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1204 return InterlockedIncrement(&This
->ref
);
1207 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_QueryInterface(
1212 TRACE("\n\tIID:\t%s\n",debugstr_guid(riid
));
1214 if (ppvObj
== NULL
) return E_POINTER
;
1216 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1217 IsEqualGUID(riid
, &IID_IEnumGUID
))
1219 *ppvObj
= (LPVOID
)iface
;
1220 COMCAT_CATID_IEnumGUID_AddRef(iface
);
1224 return E_NOINTERFACE
;
1227 static ULONG WINAPI
COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface
)
1229 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1234 ref
= InterlockedDecrement(&This
->ref
);
1236 if (This
->key
) RegCloseKey(This
->key
);
1237 HeapFree(GetProcessHeap(), 0, This
);
1243 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Next(
1247 ULONG
*pceltFetched
)
1249 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1254 if (rgelt
== NULL
) return E_POINTER
;
1256 if (This
->key
) while (fetched
< celt
) {
1262 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1263 NULL
, NULL
, NULL
, NULL
);
1264 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1265 ++(This
->next_index
);
1267 hr
= CLSIDFromString(catid
, rgelt
);
1268 if (FAILED(hr
)) continue;
1274 if (pceltFetched
) *pceltFetched
= fetched
;
1275 return fetched
== celt
? S_OK
: S_FALSE
;
1278 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Skip(
1282 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1286 This
->next_index
+= celt
;
1287 FIXME("Never returns S_FALSE\n");
1291 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface
)
1293 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1297 This
->next_index
= 0;
1301 static HRESULT WINAPI
COMCAT_CATID_IEnumGUID_Clone(
1305 CATID_IEnumGUIDImpl
*This
= (CATID_IEnumGUIDImpl
*)iface
;
1306 CATID_IEnumGUIDImpl
*new_this
;
1310 if (ppenum
== NULL
) return E_POINTER
;
1312 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1313 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1315 new_this
->lpVtbl
= This
->lpVtbl
;
1317 lstrcpyW(new_this
->keyname
, This
->keyname
);
1318 /* FIXME: could we more efficiently use DuplicateHandle? */
1319 RegOpenKeyExW(HKEY_CLASSES_ROOT
, new_this
->keyname
, 0, KEY_READ
, &new_this
->key
);
1320 new_this
->next_index
= This
->next_index
;
1322 *ppenum
= (LPENUMGUID
)new_this
;
1326 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl
=
1328 COMCAT_CATID_IEnumGUID_QueryInterface
,
1329 COMCAT_CATID_IEnumGUID_AddRef
,
1330 COMCAT_CATID_IEnumGUID_Release
,
1331 COMCAT_CATID_IEnumGUID_Next
,
1332 COMCAT_CATID_IEnumGUID_Skip
,
1333 COMCAT_CATID_IEnumGUID_Reset
,
1334 COMCAT_CATID_IEnumGUID_Clone
1337 static LPENUMGUID
COMCAT_CATID_IEnumGUID_Construct(
1338 REFCLSID rclsid
, LPCWSTR postfix
)
1340 CATID_IEnumGUIDImpl
*This
;
1342 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1344 WCHAR prefix
[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
1346 This
->lpVtbl
= &COMCAT_CATID_IEnumGUID_Vtbl
;
1347 memcpy(This
->keyname
, prefix
, sizeof(prefix
));
1348 StringFromGUID2(rclsid
, This
->keyname
+ 6, 39);
1349 lstrcpyW(This
->keyname
+ 44, postfix
);
1350 RegOpenKeyExW(HKEY_CLASSES_ROOT
, This
->keyname
, 0, KEY_READ
, &This
->key
);
1352 return (LPENUMGUID
)This
;