2 * Comcat implementation
4 * Copyright (C) 2002 John K. Hohm
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23 WINE_DEFAULT_DEBUG_CHANNEL(ole
);
25 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
;
26 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
;
30 ICatRegister ICatRegister_iface
;
31 ICatInformation ICatInformation_iface
;
34 /* static ComCatMgr instance */
35 static ComCatMgrImpl COMCAT_ComCatMgr
=
37 { &COMCAT_ICatRegister_Vtbl
},
38 { &COMCAT_ICatInformation_Vtbl
}
41 struct class_categories
43 ULONG size
; /* total length, including structure itself */
48 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
);
49 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*class_categories
, IEnumCLSID
**ret
);
50 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR impl_req
, IEnumCATID
**ret
);
52 /**********************************************************************
53 * File-scope string constants
55 static const WCHAR comcat_keyname
[] = {
56 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
57 static const WCHAR impl_keyname
[] = {
58 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
59 static const WCHAR req_keyname
[] = {
60 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
61 static const WCHAR clsid_keyname
[] = { 'C','L','S','I','D',0 };
64 /**********************************************************************
65 * COMCAT_RegisterClassCategories
67 static HRESULT
COMCAT_RegisterClassCategories(
73 WCHAR keyname
[CHARS_IN_GUID
];
75 HKEY clsid_key
, class_key
, type_key
;
77 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
79 /* Format the class key name. */
80 res
= StringFromGUID2(rclsid
, keyname
, CHARS_IN_GUID
);
81 if (FAILED(res
)) return res
;
83 /* Create (or open) the CLSID key. */
84 res
= create_classes_key(HKEY_CLASSES_ROOT
, clsid_keyname
, KEY_READ
|KEY_WRITE
, &clsid_key
);
85 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
87 /* Create (or open) the class key. */
88 res
= create_classes_key(clsid_key
, keyname
, KEY_READ
|KEY_WRITE
, &class_key
);
89 if (res
== ERROR_SUCCESS
) {
90 /* Create (or open) the category type key. */
91 res
= create_classes_key(class_key
, type
, KEY_READ
|KEY_WRITE
, &type_key
);
92 if (res
== ERROR_SUCCESS
) {
93 for (; cCategories
; --cCategories
, ++rgcatid
) {
96 /* Format the category key name. */
97 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
98 if (FAILED(res
)) continue;
100 /* Do the register. */
101 res
= create_classes_key(type_key
, keyname
, KEY_READ
|KEY_WRITE
, &key
);
102 if (res
== ERROR_SUCCESS
) RegCloseKey(key
);
106 RegCloseKey(class_key
);
108 RegCloseKey(clsid_key
);
113 /**********************************************************************
114 * COMCAT_UnRegisterClassCategories
116 static HRESULT
COMCAT_UnRegisterClassCategories(
120 const CATID
*rgcatid
)
122 WCHAR keyname
[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
126 if (cCategories
&& rgcatid
== NULL
) return E_POINTER
;
128 /* Format the class category type key name. */
129 res
= StringFromGUID2(rclsid
, keyname
+ 6, CHARS_IN_GUID
);
130 if (FAILED(res
)) return res
;
132 lstrcpyW(keyname
+ 45, type
);
134 /* Open the class category type key. */
135 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
|KEY_WRITE
, &type_key
);
136 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
138 for (; cCategories
; --cCategories
, ++rgcatid
) {
139 /* Format the category key name. */
140 res
= StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
);
141 if (FAILED(res
)) continue;
143 /* Do the unregister. */
144 RegDeleteKeyW(type_key
, keyname
);
146 RegCloseKey(type_key
);
151 /**********************************************************************
152 * COMCAT_GetCategoryDesc
154 static HRESULT
COMCAT_GetCategoryDesc(HKEY key
, LCID lcid
, PWCHAR pszDesc
,
157 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
160 DWORD type
, size
= (buf_wchars
- 1) * sizeof(WCHAR
);
162 if (pszDesc
== NULL
) return E_INVALIDARG
;
164 /* FIXME: lcid comparisons are more complex than this! */
165 wsprintfW(valname
, fmt
, lcid
);
166 res
= RegQueryValueExW(key
, valname
, 0, &type
, (LPBYTE
)pszDesc
, &size
);
167 if (res
!= ERROR_SUCCESS
|| type
!= REG_SZ
) {
168 FIXME("Simplified lcid comparison\n");
169 return CAT_E_NODESCRIPTION
;
171 pszDesc
[size
/ sizeof(WCHAR
)] = 0;
176 /**********************************************************************
177 * COMCAT_PrepareClassCategories
179 static struct class_categories
*COMCAT_PrepareClassCategories(
180 ULONG impl_count
, const CATID
*impl_catids
, ULONG req_count
, const CATID
*req_catids
)
182 struct class_categories
*categories
;
186 size
= sizeof(struct class_categories
) + ((impl_count
+ req_count
)*CHARS_IN_GUID
+ 2)*sizeof(WCHAR
);
187 categories
= HeapAlloc(GetProcessHeap(), 0, size
);
188 if (categories
== NULL
) return categories
;
190 categories
->size
= size
;
191 categories
->impl_offset
= sizeof(struct class_categories
);
192 categories
->req_offset
= categories
->impl_offset
+ (impl_count
*CHARS_IN_GUID
+ 1)*sizeof(WCHAR
);
194 strings
= (WCHAR
*)(categories
+ 1);
195 while (impl_count
--) {
196 StringFromGUID2(impl_catids
++, strings
, CHARS_IN_GUID
);
197 strings
+= CHARS_IN_GUID
;
201 while (req_count
--) {
202 StringFromGUID2(req_catids
++, strings
, CHARS_IN_GUID
);
203 strings
+= CHARS_IN_GUID
;
210 /**********************************************************************
211 * COMCAT_IsClassOfCategories
213 static HRESULT
COMCAT_IsClassOfCategories(
215 struct class_categories
const* categories
)
217 const WCHAR
*impl_strings
, *req_strings
;
223 impl_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->impl_offset
);
224 req_strings
= (WCHAR
*)((BYTE
*)categories
+ categories
->req_offset
);
226 /* Check that every given category is implemented by class. */
228 res
= open_classes_key(key
, impl_keyname
, KEY_READ
, &subkey
);
229 if (res
!= ERROR_SUCCESS
) return S_FALSE
;
230 for (string
= impl_strings
; *string
; string
+= CHARS_IN_GUID
) {
232 res
= open_classes_key(subkey
, string
, READ_CONTROL
, &catkey
);
233 if (res
!= ERROR_SUCCESS
) {
242 /* Check that all categories required by class are given. */
243 res
= open_classes_key(key
, req_keyname
, KEY_READ
, &subkey
);
244 if (res
== ERROR_SUCCESS
) {
245 for (index
= 0; ; ++index
) {
246 WCHAR keyname
[CHARS_IN_GUID
];
247 DWORD size
= CHARS_IN_GUID
;
249 res
= RegEnumKeyExW(subkey
, index
, keyname
, &size
,
250 NULL
, NULL
, NULL
, NULL
);
251 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
252 if (size
!= CHARS_IN_GUID
-1) continue; /* bogus catid in registry */
253 for (string
= req_strings
; *string
; string
+= CHARS_IN_GUID
)
254 if (!strcmpiW(string
, keyname
)) break;
266 /**********************************************************************
267 * COMCAT_ICatRegister_QueryInterface
269 static HRESULT WINAPI
COMCAT_ICatRegister_QueryInterface(
274 TRACE("%s\n",debugstr_guid(riid
));
276 if (ppvObj
== NULL
) return E_POINTER
;
278 if (IsEqualGUID(riid
, &IID_IUnknown
) || IsEqualGUID(riid
, &IID_ICatRegister
)) {
280 ICatRegister_AddRef(iface
);
284 if (IsEqualGUID(riid
, &IID_ICatInformation
)) {
285 *ppvObj
= &COMCAT_ComCatMgr
.ICatInformation_iface
;
286 ICatRegister_AddRef(iface
);
290 return E_NOINTERFACE
;
293 /**********************************************************************
294 * COMCAT_ICatRegister_AddRef
296 static ULONG WINAPI
COMCAT_ICatRegister_AddRef(LPCATREGISTER iface
)
298 return 2; /* non-heap based object */
301 /**********************************************************************
302 * COMCAT_ICatRegister_Release
304 static ULONG WINAPI
COMCAT_ICatRegister_Release(LPCATREGISTER iface
)
306 return 1; /* non-heap based object */
309 /**********************************************************************
310 * COMCAT_ICatRegister_RegisterCategories
312 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterCategories(
322 if (cCategories
&& rgci
== NULL
)
325 /* Create (or open) the component categories key. */
326 res
= create_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
327 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
329 for (; cCategories
; --cCategories
, ++rgci
) {
330 static const WCHAR fmt
[] = { '%', 'l', 'X', 0 };
331 WCHAR keyname
[CHARS_IN_GUID
];
335 /* Create (or open) the key for this category. */
336 if (!StringFromGUID2(&rgci
->catid
, keyname
, CHARS_IN_GUID
)) continue;
337 res
= create_classes_key(comcat_key
, keyname
, KEY_READ
|KEY_WRITE
, &cat_key
);
338 if (res
!= ERROR_SUCCESS
) continue;
340 /* Set the value for this locale's description. */
341 wsprintfW(valname
, fmt
, rgci
->lcid
);
342 RegSetValueExW(cat_key
, valname
, 0, REG_SZ
, (const BYTE
*)rgci
->szDescription
,
343 (lstrlenW(rgci
->szDescription
) + 1) * sizeof(WCHAR
));
345 RegCloseKey(cat_key
);
348 RegCloseKey(comcat_key
);
352 /**********************************************************************
353 * COMCAT_ICatRegister_UnRegisterCategories
355 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterCategories(
365 if (cCategories
&& rgcatid
== NULL
)
368 /* Open the component categories key. */
369 res
= open_classes_key(HKEY_CLASSES_ROOT
, comcat_keyname
, KEY_READ
|KEY_WRITE
, &comcat_key
);
370 if (res
!= ERROR_SUCCESS
) return E_FAIL
;
372 for (; cCategories
; --cCategories
, ++rgcatid
) {
373 WCHAR keyname
[CHARS_IN_GUID
];
375 /* Delete the key for this category. */
376 if (!StringFromGUID2(rgcatid
, keyname
, CHARS_IN_GUID
)) continue;
377 RegDeleteKeyW(comcat_key
, keyname
);
380 RegCloseKey(comcat_key
);
384 /**********************************************************************
385 * COMCAT_ICatRegister_RegisterClassImplCategories
387 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassImplCategories(
395 return COMCAT_RegisterClassCategories(
396 rclsid
, impl_keyname
, cCategories
, rgcatid
);
399 /**********************************************************************
400 * COMCAT_ICatRegister_UnRegisterClassImplCategories
402 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassImplCategories(
410 return COMCAT_UnRegisterClassCategories(
411 rclsid
, impl_keyname
, cCategories
, rgcatid
);
414 /**********************************************************************
415 * COMCAT_ICatRegister_RegisterClassReqCategories
417 static HRESULT WINAPI
COMCAT_ICatRegister_RegisterClassReqCategories(
425 return COMCAT_RegisterClassCategories(
426 rclsid
, req_keyname
, cCategories
, rgcatid
);
429 /**********************************************************************
430 * COMCAT_ICatRegister_UnRegisterClassReqCategories
432 static HRESULT WINAPI
COMCAT_ICatRegister_UnRegisterClassReqCategories(
440 return COMCAT_UnRegisterClassCategories(
441 rclsid
, req_keyname
, cCategories
, rgcatid
);
444 /**********************************************************************
445 * COMCAT_ICatInformation_QueryInterface
447 static HRESULT WINAPI
COMCAT_ICatInformation_QueryInterface(
448 LPCATINFORMATION iface
,
452 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
455 /**********************************************************************
456 * COMCAT_ICatInformation_AddRef
458 static ULONG WINAPI
COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface
)
460 return ICatRegister_AddRef(&COMCAT_ComCatMgr
.ICatRegister_iface
);
463 /**********************************************************************
464 * COMCAT_ICatInformation_Release
466 static ULONG WINAPI
COMCAT_ICatInformation_Release(LPCATINFORMATION iface
)
468 return ICatRegister_Release(&COMCAT_ComCatMgr
.ICatRegister_iface
);
471 /**********************************************************************
472 * COMCAT_ICatInformation_EnumCategories
474 static HRESULT WINAPI
COMCAT_ICatInformation_EnumCategories(
475 LPCATINFORMATION iface
,
477 IEnumCATEGORYINFO
**ppenumCatInfo
)
481 if (ppenumCatInfo
== NULL
) return E_POINTER
;
483 return EnumCATEGORYINFO_Construct(lcid
, ppenumCatInfo
);
486 /**********************************************************************
487 * COMCAT_ICatInformation_GetCategoryDesc
489 static HRESULT WINAPI
COMCAT_ICatInformation_GetCategoryDesc(
490 LPCATINFORMATION iface
,
495 WCHAR keyname
[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
496 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
497 'r', 'i', 'e', 's', '\\', 0 };
501 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid
), lcid
);
503 if (rcatid
== NULL
|| ppszDesc
== NULL
) return E_INVALIDARG
;
505 /* Open the key for this category. */
506 if (!StringFromGUID2(rcatid
, keyname
+ 21, CHARS_IN_GUID
)) return E_FAIL
;
507 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
508 if (res
!= ERROR_SUCCESS
) return CAT_E_CATIDNOEXIST
;
510 /* Allocate a sensible amount of memory for the description. */
511 *ppszDesc
= CoTaskMemAlloc(128 * sizeof(WCHAR
));
512 if (*ppszDesc
== NULL
) {
514 return E_OUTOFMEMORY
;
517 /* Get the description, and make sure it's null terminated. */
518 res
= COMCAT_GetCategoryDesc(key
, lcid
, *ppszDesc
, 128);
521 CoTaskMemFree(*ppszDesc
);
528 /**********************************************************************
529 * COMCAT_ICatInformation_EnumClassesOfCategories
531 static HRESULT WINAPI
COMCAT_ICatInformation_EnumClassesOfCategories(
532 LPCATINFORMATION iface
,
537 LPENUMCLSID
*ppenumCLSID
)
539 struct class_categories
*categories
;
544 if (cImplemented
== (ULONG
)-1)
546 if (cRequired
== (ULONG
)-1)
549 if (ppenumCLSID
== NULL
||
550 (cImplemented
&& rgcatidImpl
== NULL
) ||
551 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
553 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
554 cRequired
, rgcatidReq
);
555 if (categories
== NULL
) return E_OUTOFMEMORY
;
557 hr
= CLSIDEnumGUID_Construct(categories
, ppenumCLSID
);
560 HeapFree(GetProcessHeap(), 0, categories
);
567 /**********************************************************************
568 * COMCAT_ICatInformation_IsClassOfCategories
570 static HRESULT WINAPI
COMCAT_ICatInformation_IsClassOfCategories(
571 LPCATINFORMATION iface
,
578 WCHAR keyname
[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
580 struct class_categories
*categories
;
585 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid
),cImplemented
);
586 for (count
= 0; count
< cImplemented
; ++count
)
587 TRACE(" %s\n",debugstr_guid(&rgcatidImpl
[count
]));
588 TRACE("Required %u\n",cRequired
);
589 for (count
= 0; count
< cRequired
; ++count
)
590 TRACE(" %s\n",debugstr_guid(&rgcatidReq
[count
]));
593 if ((cImplemented
&& rgcatidImpl
== NULL
) ||
594 (cRequired
&& rgcatidReq
== NULL
)) return E_POINTER
;
596 res
= StringFromGUID2(rclsid
, keyname
+ 6, CHARS_IN_GUID
);
597 if (FAILED(res
)) return res
;
599 categories
= COMCAT_PrepareClassCategories(cImplemented
, rgcatidImpl
,
600 cRequired
, rgcatidReq
);
601 if (categories
== NULL
) return E_OUTOFMEMORY
;
603 res
= open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &key
);
604 if (res
== ERROR_SUCCESS
) {
605 res
= COMCAT_IsClassOfCategories(key
, categories
);
607 } else res
= S_FALSE
;
609 HeapFree(GetProcessHeap(), 0, categories
);
614 /**********************************************************************
615 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
617 static HRESULT WINAPI
COMCAT_ICatInformation_EnumImplCategoriesOfClass(
618 LPCATINFORMATION iface
,
620 LPENUMCATID
*ppenumCATID
)
622 static const WCHAR postfix
[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
623 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
624 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
626 TRACE("%s\n",debugstr_guid(rclsid
));
628 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
631 return CATIDEnumGUID_Construct(rclsid
, postfix
, ppenumCATID
);
634 /**********************************************************************
635 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
637 static HRESULT WINAPI
COMCAT_ICatInformation_EnumReqCategoriesOfClass(
638 LPCATINFORMATION iface
,
640 LPENUMCATID
*ppenumCATID
)
642 static const WCHAR postfix
[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
643 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
644 'r', 'i', 'e', 's', 0 };
646 TRACE("%s\n",debugstr_guid(rclsid
));
648 if (rclsid
== NULL
|| ppenumCATID
== NULL
)
651 return CATIDEnumGUID_Construct(rclsid
, postfix
, ppenumCATID
);
654 /**********************************************************************
655 * COMCAT_ICatRegister_Vtbl
657 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl
=
659 COMCAT_ICatRegister_QueryInterface
,
660 COMCAT_ICatRegister_AddRef
,
661 COMCAT_ICatRegister_Release
,
662 COMCAT_ICatRegister_RegisterCategories
,
663 COMCAT_ICatRegister_UnRegisterCategories
,
664 COMCAT_ICatRegister_RegisterClassImplCategories
,
665 COMCAT_ICatRegister_UnRegisterClassImplCategories
,
666 COMCAT_ICatRegister_RegisterClassReqCategories
,
667 COMCAT_ICatRegister_UnRegisterClassReqCategories
671 /**********************************************************************
672 * COMCAT_ICatInformation_Vtbl
674 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl
=
676 COMCAT_ICatInformation_QueryInterface
,
677 COMCAT_ICatInformation_AddRef
,
678 COMCAT_ICatInformation_Release
,
679 COMCAT_ICatInformation_EnumCategories
,
680 COMCAT_ICatInformation_GetCategoryDesc
,
681 COMCAT_ICatInformation_EnumClassesOfCategories
,
682 COMCAT_ICatInformation_IsClassOfCategories
,
683 COMCAT_ICatInformation_EnumImplCategoriesOfClass
,
684 COMCAT_ICatInformation_EnumReqCategoriesOfClass
687 /**********************************************************************
688 * COMCAT_IClassFactory_QueryInterface (also IUnknown)
690 static HRESULT WINAPI
COMCAT_IClassFactory_QueryInterface(
691 LPCLASSFACTORY iface
,
695 TRACE("%s\n",debugstr_guid(riid
));
697 if (ppvObj
== NULL
) return E_POINTER
;
699 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
700 IsEqualGUID(riid
, &IID_IClassFactory
))
703 IClassFactory_AddRef(iface
);
707 return E_NOINTERFACE
;
710 /**********************************************************************
711 * COMCAT_IClassFactory_AddRef (also IUnknown)
713 static ULONG WINAPI
COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface
)
715 return 2; /* non-heap based object */
718 /**********************************************************************
719 * COMCAT_IClassFactory_Release (also IUnknown)
721 static ULONG WINAPI
COMCAT_IClassFactory_Release(LPCLASSFACTORY iface
)
723 return 1; /* non-heap based object */
726 /**********************************************************************
727 * COMCAT_IClassFactory_CreateInstance
729 static HRESULT WINAPI
COMCAT_IClassFactory_CreateInstance(
730 LPCLASSFACTORY iface
,
736 TRACE("%s\n",debugstr_guid(riid
));
738 if (ppvObj
== NULL
) return E_POINTER
;
740 /* Don't support aggregation (Windows doesn't) */
741 if (pUnkOuter
!= NULL
) return CLASS_E_NOAGGREGATION
;
743 res
= ICatRegister_QueryInterface(&COMCAT_ComCatMgr
.ICatRegister_iface
, riid
, ppvObj
);
744 if (SUCCEEDED(res
)) {
748 return CLASS_E_CLASSNOTAVAILABLE
;
751 /**********************************************************************
752 * COMCAT_IClassFactory_LockServer
754 static HRESULT WINAPI
COMCAT_IClassFactory_LockServer(
755 LPCLASSFACTORY iface
,
758 FIXME("(%d), stub!\n",fLock
);
762 /**********************************************************************
763 * static ClassFactory instance
765 static const IClassFactoryVtbl ComCatCFVtbl
=
767 COMCAT_IClassFactory_QueryInterface
,
768 COMCAT_IClassFactory_AddRef
,
769 COMCAT_IClassFactory_Release
,
770 COMCAT_IClassFactory_CreateInstance
,
771 COMCAT_IClassFactory_LockServer
774 static const IClassFactoryVtbl
*ComCatCF
= &ComCatCFVtbl
;
776 HRESULT
ComCatCF_Create(REFIID riid
, LPVOID
*ppv
)
778 return IClassFactory_QueryInterface((IClassFactory
*)&ComCatCF
, riid
, ppv
);
781 /**********************************************************************
782 * IEnumCATEGORYINFO implementation
784 * This implementation is not thread-safe. The manager itself is, but
785 * I can't imagine a valid use of an enumerator in several threads.
789 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface
;
794 } IEnumCATEGORYINFOImpl
;
796 static inline IEnumCATEGORYINFOImpl
*impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO
*iface
)
798 return CONTAINING_RECORD(iface
, IEnumCATEGORYINFOImpl
, IEnumCATEGORYINFO_iface
);
801 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO
*iface
)
803 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
807 return InterlockedIncrement(&This
->ref
);
810 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_QueryInterface(
811 IEnumCATEGORYINFO
*iface
,
815 TRACE("%s\n",debugstr_guid(riid
));
817 if (ppvObj
== NULL
) return E_POINTER
;
819 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
820 IsEqualGUID(riid
, &IID_IEnumCATEGORYINFO
))
823 COMCAT_IEnumCATEGORYINFO_AddRef(iface
);
827 return E_NOINTERFACE
;
830 static ULONG WINAPI
COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO
*iface
)
832 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
837 ref
= InterlockedDecrement(&This
->ref
);
839 if (This
->key
) RegCloseKey(This
->key
);
840 HeapFree(GetProcessHeap(), 0, This
);
846 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Next(
847 IEnumCATEGORYINFO
*iface
,
852 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
857 if (rgelt
== NULL
) return E_POINTER
;
859 if (This
->key
) while (fetched
< celt
) {
862 WCHAR catid
[CHARS_IN_GUID
];
863 DWORD cName
= CHARS_IN_GUID
;
866 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
867 NULL
, NULL
, NULL
, NULL
);
868 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
869 ++(This
->next_index
);
871 hr
= CLSIDFromString(catid
, &rgelt
->catid
);
872 if (FAILED(hr
)) continue;
874 res
= open_classes_key(This
->key
, catid
, KEY_READ
, &subkey
);
875 if (res
!= ERROR_SUCCESS
) continue;
877 hr
= COMCAT_GetCategoryDesc(subkey
, This
->lcid
,
878 rgelt
->szDescription
, 128);
880 if (FAILED(hr
)) continue;
882 rgelt
->lcid
= This
->lcid
;
887 if (pceltFetched
) *pceltFetched
= fetched
;
888 return fetched
== celt
? S_OK
: S_FALSE
;
891 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Skip(
892 IEnumCATEGORYINFO
*iface
,
895 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
899 This
->next_index
+= celt
;
900 /* This should return S_FALSE when there aren't celt elems to skip. */
904 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO
*iface
)
906 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
910 This
->next_index
= 0;
914 static HRESULT WINAPI
COMCAT_IEnumCATEGORYINFO_Clone(
915 IEnumCATEGORYINFO
*iface
,
916 IEnumCATEGORYINFO
**ppenum
)
918 IEnumCATEGORYINFOImpl
*This
= impl_from_IEnumCATEGORYINFO(iface
);
919 static const WCHAR keyname
[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
920 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
921 'r', 'i', 'e', 's', 0 };
922 IEnumCATEGORYINFOImpl
*new_this
;
926 if (ppenum
== NULL
) return E_POINTER
;
928 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
929 if (new_this
== NULL
) return E_OUTOFMEMORY
;
931 new_this
->IEnumCATEGORYINFO_iface
= This
->IEnumCATEGORYINFO_iface
;
933 new_this
->lcid
= This
->lcid
;
934 /* FIXME: could we more efficiently use DuplicateHandle? */
935 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &new_this
->key
);
936 new_this
->next_index
= This
->next_index
;
938 *ppenum
= &new_this
->IEnumCATEGORYINFO_iface
;
942 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl
=
944 COMCAT_IEnumCATEGORYINFO_QueryInterface
,
945 COMCAT_IEnumCATEGORYINFO_AddRef
,
946 COMCAT_IEnumCATEGORYINFO_Release
,
947 COMCAT_IEnumCATEGORYINFO_Next
,
948 COMCAT_IEnumCATEGORYINFO_Skip
,
949 COMCAT_IEnumCATEGORYINFO_Reset
,
950 COMCAT_IEnumCATEGORYINFO_Clone
953 static HRESULT
EnumCATEGORYINFO_Construct(LCID lcid
, IEnumCATEGORYINFO
**ret
)
955 static const WCHAR keyname
[] = {'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0};
956 IEnumCATEGORYINFOImpl
*This
;
960 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(IEnumCATEGORYINFOImpl
));
961 if (!This
) return E_OUTOFMEMORY
;
963 This
->IEnumCATEGORYINFO_iface
.lpVtbl
= &COMCAT_IEnumCATEGORYINFO_Vtbl
;
966 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
968 *ret
= &This
->IEnumCATEGORYINFO_iface
;
972 /**********************************************************************
973 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
975 * This implementation is not thread-safe. The manager itself is, but
976 * I can't imagine a valid use of an enumerator in several threads.
980 IEnumGUID IEnumGUID_iface
;
982 struct class_categories
*categories
;
985 } CLSID_IEnumGUIDImpl
;
987 static inline CLSID_IEnumGUIDImpl
*impl_from_IEnumCLSID(IEnumGUID
*iface
)
989 return CONTAINING_RECORD(iface
, CLSID_IEnumGUIDImpl
, IEnumGUID_iface
);
992 static HRESULT WINAPI
CLSIDEnumGUID_QueryInterface(
997 TRACE("%s\n",debugstr_guid(riid
));
999 if (ppvObj
== NULL
) return E_POINTER
;
1001 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1002 IsEqualGUID(riid
, &IID_IEnumGUID
))
1005 IEnumGUID_AddRef(iface
);
1009 return E_NOINTERFACE
;
1012 static ULONG WINAPI
CLSIDEnumGUID_AddRef(IEnumGUID
*iface
)
1014 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1017 return InterlockedIncrement(&This
->ref
);
1020 static ULONG WINAPI
CLSIDEnumGUID_Release(IEnumGUID
*iface
)
1022 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1027 ref
= InterlockedDecrement(&This
->ref
);
1029 if (This
->key
) RegCloseKey(This
->key
);
1030 HeapFree(GetProcessHeap(), 0, This
->categories
);
1031 HeapFree(GetProcessHeap(), 0, This
);
1037 static HRESULT WINAPI
CLSIDEnumGUID_Next(
1041 ULONG
*pceltFetched
)
1043 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1048 if (rgelt
== NULL
) return E_POINTER
;
1050 if (This
->key
) while (fetched
< celt
) {
1053 WCHAR clsid
[CHARS_IN_GUID
];
1054 DWORD cName
= CHARS_IN_GUID
;
1057 res
= RegEnumKeyExW(This
->key
, This
->next_index
, clsid
, &cName
,
1058 NULL
, NULL
, NULL
, NULL
);
1059 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1060 ++(This
->next_index
);
1062 hr
= CLSIDFromString(clsid
, rgelt
);
1063 if (FAILED(hr
)) continue;
1065 res
= open_classes_key(This
->key
, clsid
, KEY_READ
, &subkey
);
1066 if (res
!= ERROR_SUCCESS
) continue;
1068 hr
= COMCAT_IsClassOfCategories(subkey
, This
->categories
);
1069 RegCloseKey(subkey
);
1070 if (hr
!= S_OK
) continue;
1076 if (pceltFetched
) *pceltFetched
= fetched
;
1077 return fetched
== celt
? S_OK
: S_FALSE
;
1080 static HRESULT WINAPI
CLSIDEnumGUID_Skip(
1084 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1088 This
->next_index
+= celt
;
1089 FIXME("Never returns S_FALSE\n");
1093 static HRESULT WINAPI
CLSIDEnumGUID_Reset(IEnumGUID
*iface
)
1095 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1099 This
->next_index
= 0;
1103 static HRESULT WINAPI
CLSIDEnumGUID_Clone(
1107 static const WCHAR keynameW
[] = {'C','L','S','I','D',0};
1108 CLSID_IEnumGUIDImpl
*This
= impl_from_IEnumCLSID(iface
);
1109 CLSID_IEnumGUIDImpl
*cloned
;
1111 TRACE("(%p)->(%p)\n", This
, ppenum
);
1113 if (ppenum
== NULL
) return E_POINTER
;
1117 cloned
= HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID_IEnumGUIDImpl
));
1118 if (cloned
== NULL
) return E_OUTOFMEMORY
;
1120 cloned
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1123 cloned
->categories
= HeapAlloc(GetProcessHeap(), 0, This
->categories
->size
);
1124 if (cloned
->categories
== NULL
) {
1125 HeapFree(GetProcessHeap(), 0, cloned
);
1126 return E_OUTOFMEMORY
;
1128 memcpy(cloned
->categories
, This
->categories
, This
->categories
->size
);
1131 open_classes_key(HKEY_CLASSES_ROOT
, keynameW
, KEY_READ
, &cloned
->key
);
1132 cloned
->next_index
= This
->next_index
;
1134 *ppenum
= &cloned
->IEnumGUID_iface
;
1138 static const IEnumGUIDVtbl CLSIDEnumGUIDVtbl
=
1140 CLSIDEnumGUID_QueryInterface
,
1141 CLSIDEnumGUID_AddRef
,
1142 CLSIDEnumGUID_Release
,
1145 CLSIDEnumGUID_Reset
,
1149 static HRESULT
CLSIDEnumGUID_Construct(struct class_categories
*categories
, IEnumCLSID
**ret
)
1151 static const WCHAR keyname
[] = {'C','L','S','I','D',0};
1152 CLSID_IEnumGUIDImpl
*This
;
1156 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CLSID_IEnumGUIDImpl
));
1157 if (!This
) return E_OUTOFMEMORY
;
1159 This
->IEnumGUID_iface
.lpVtbl
= &CLSIDEnumGUIDVtbl
;
1161 This
->categories
= categories
;
1162 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1164 *ret
= &This
->IEnumGUID_iface
;
1169 /**********************************************************************
1170 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1172 * This implementation is not thread-safe. The manager itself is, but
1173 * I can't imagine a valid use of an enumerator in several threads.
1177 IEnumGUID IEnumGUID_iface
;
1182 } CATID_IEnumGUIDImpl
;
1184 static inline CATID_IEnumGUIDImpl
*impl_from_IEnumCATID(IEnumGUID
*iface
)
1186 return CONTAINING_RECORD(iface
, CATID_IEnumGUIDImpl
, IEnumGUID_iface
);
1189 static HRESULT WINAPI
CATIDEnumGUID_QueryInterface(
1194 TRACE("%s\n",debugstr_guid(riid
));
1196 if (ppvObj
== NULL
) return E_POINTER
;
1198 if (IsEqualGUID(riid
, &IID_IUnknown
) ||
1199 IsEqualGUID(riid
, &IID_IEnumGUID
))
1202 IEnumGUID_AddRef(iface
);
1206 return E_NOINTERFACE
;
1209 static ULONG WINAPI
CATIDEnumGUID_AddRef(IEnumGUID
*iface
)
1211 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1214 return InterlockedIncrement(&This
->ref
);
1217 static ULONG WINAPI
CATIDEnumGUID_Release(IEnumGUID
*iface
)
1219 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1224 ref
= InterlockedDecrement(&This
->ref
);
1226 if (This
->key
) RegCloseKey(This
->key
);
1227 HeapFree(GetProcessHeap(), 0, This
);
1233 static HRESULT WINAPI
CATIDEnumGUID_Next(
1237 ULONG
*pceltFetched
)
1239 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1244 if (rgelt
== NULL
) return E_POINTER
;
1246 if (This
->key
) while (fetched
< celt
) {
1249 WCHAR catid
[CHARS_IN_GUID
];
1250 DWORD cName
= CHARS_IN_GUID
;
1252 res
= RegEnumKeyExW(This
->key
, This
->next_index
, catid
, &cName
,
1253 NULL
, NULL
, NULL
, NULL
);
1254 if (res
!= ERROR_SUCCESS
&& res
!= ERROR_MORE_DATA
) break;
1255 ++(This
->next_index
);
1257 hr
= CLSIDFromString(catid
, rgelt
);
1258 if (FAILED(hr
)) continue;
1264 if (pceltFetched
) *pceltFetched
= fetched
;
1265 return fetched
== celt
? S_OK
: S_FALSE
;
1268 static HRESULT WINAPI
CATIDEnumGUID_Skip(
1272 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1276 This
->next_index
+= celt
;
1277 FIXME("Never returns S_FALSE\n");
1281 static HRESULT WINAPI
CATIDEnumGUID_Reset(IEnumGUID
*iface
)
1283 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1287 This
->next_index
= 0;
1291 static HRESULT WINAPI
CATIDEnumGUID_Clone(
1295 CATID_IEnumGUIDImpl
*This
= impl_from_IEnumCATID(iface
);
1296 CATID_IEnumGUIDImpl
*new_this
;
1300 if (ppenum
== NULL
) return E_POINTER
;
1302 new_this
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1303 if (new_this
== NULL
) return E_OUTOFMEMORY
;
1305 new_this
->IEnumGUID_iface
.lpVtbl
= This
->IEnumGUID_iface
.lpVtbl
;
1307 lstrcpyW(new_this
->keyname
, This
->keyname
);
1308 /* FIXME: could we more efficiently use DuplicateHandle? */
1309 open_classes_key(HKEY_CLASSES_ROOT
, new_this
->keyname
, KEY_READ
, &new_this
->key
);
1310 new_this
->next_index
= This
->next_index
;
1312 *ppenum
= &new_this
->IEnumGUID_iface
;
1316 static const IEnumGUIDVtbl CATIDEnumGUIDVtbl
=
1318 CATIDEnumGUID_QueryInterface
,
1319 CATIDEnumGUID_AddRef
,
1320 CATIDEnumGUID_Release
,
1323 CATIDEnumGUID_Reset
,
1327 static HRESULT
CATIDEnumGUID_Construct(REFCLSID rclsid
, LPCWSTR postfix
, IEnumGUID
**ret
)
1329 static const WCHAR prefixW
[] = {'C','L','S','I','D','\\',0};
1330 WCHAR keyname
[100], clsidW
[CHARS_IN_GUID
];
1331 CATID_IEnumGUIDImpl
*This
;
1335 This
= HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY
, sizeof(CATID_IEnumGUIDImpl
));
1336 if (!This
) return E_OUTOFMEMORY
;
1338 StringFromGUID2(rclsid
, clsidW
, CHARS_IN_GUID
);
1340 This
->IEnumGUID_iface
.lpVtbl
= &CATIDEnumGUIDVtbl
;
1342 strcpyW(keyname
, prefixW
);
1343 strcatW(keyname
, clsidW
);
1344 strcatW(keyname
, postfix
);
1346 open_classes_key(HKEY_CLASSES_ROOT
, keyname
, KEY_READ
, &This
->key
);
1348 *ret
= &This
->IEnumGUID_iface
;