dxgi/tests: Fix output ownership test failures on Win10 1909.
[wine.git] / dlls / ole32 / comcat.c
blob467724c5ba3b92dae4b5a92098784ab57fb95666
1 /*
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
21 #include <string.h>
22 #include <stdarg.h>
24 #define COBJMACROS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winreg.h"
30 #include "winerror.h"
32 #include "ole2.h"
33 #include "comcat.h"
34 #include "compobj_private.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(ole);
40 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl;
41 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl;
43 typedef struct
45 ICatRegister ICatRegister_iface;
46 ICatInformation ICatInformation_iface;
47 } ComCatMgrImpl;
49 /* static ComCatMgr instance */
50 static ComCatMgrImpl COMCAT_ComCatMgr =
52 { &COMCAT_ICatRegister_Vtbl },
53 { &COMCAT_ICatInformation_Vtbl }
56 struct class_categories
58 ULONG size; /* total length, including structure itself */
59 ULONG impl_offset;
60 ULONG req_offset;
63 static HRESULT EnumCATEGORYINFO_Construct(LCID lcid, IEnumCATEGORYINFO **ret);
64 static HRESULT CLSIDEnumGUID_Construct(struct class_categories *class_categories, IEnumCLSID **ret);
65 static HRESULT CATIDEnumGUID_Construct(REFCLSID rclsid, LPCWSTR impl_req, IEnumCATID **ret);
67 /**********************************************************************
68 * File-scope string constants
70 static const WCHAR comcat_keyname[] = {
71 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
72 static const WCHAR impl_keyname[] = {
73 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
74 static const WCHAR req_keyname[] = {
75 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
76 static const WCHAR clsid_keyname[] = { 'C','L','S','I','D',0 };
79 /**********************************************************************
80 * COMCAT_RegisterClassCategories
82 static HRESULT COMCAT_RegisterClassCategories(
83 REFCLSID rclsid,
84 LPCWSTR type,
85 ULONG cCategories,
86 const CATID *rgcatid)
88 WCHAR keyname[CHARS_IN_GUID];
89 HRESULT res;
90 HKEY clsid_key, class_key, type_key;
92 if (cCategories && rgcatid == NULL) return E_POINTER;
94 /* Format the class key name. */
95 res = StringFromGUID2(rclsid, keyname, CHARS_IN_GUID);
96 if (FAILED(res)) return res;
98 /* Create (or open) the CLSID key. */
99 res = create_classes_key(HKEY_CLASSES_ROOT, clsid_keyname, KEY_READ|KEY_WRITE, &clsid_key);
100 if (res != ERROR_SUCCESS) return E_FAIL;
102 /* Create (or open) the class key. */
103 res = create_classes_key(clsid_key, keyname, KEY_READ|KEY_WRITE, &class_key);
104 if (res == ERROR_SUCCESS) {
105 /* Create (or open) the category type key. */
106 res = create_classes_key(class_key, type, KEY_READ|KEY_WRITE, &type_key);
107 if (res == ERROR_SUCCESS) {
108 for (; cCategories; --cCategories, ++rgcatid) {
109 HKEY key;
111 /* Format the category key name. */
112 res = StringFromGUID2(rgcatid, keyname, CHARS_IN_GUID);
113 if (FAILED(res)) continue;
115 /* Do the register. */
116 res = create_classes_key(type_key, keyname, KEY_READ|KEY_WRITE, &key);
117 if (res == ERROR_SUCCESS) RegCloseKey(key);
119 res = S_OK;
120 } else res = E_FAIL;
121 RegCloseKey(class_key);
122 } else res = E_FAIL;
123 RegCloseKey(clsid_key);
125 return res;
128 /**********************************************************************
129 * COMCAT_UnRegisterClassCategories
131 static HRESULT COMCAT_UnRegisterClassCategories(
132 REFCLSID rclsid,
133 LPCWSTR type,
134 ULONG cCategories,
135 const CATID *rgcatid)
137 WCHAR keyname[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
138 HRESULT res;
139 HKEY type_key;
141 if (cCategories && rgcatid == NULL) return E_POINTER;
143 /* Format the class category type key name. */
144 res = StringFromGUID2(rclsid, keyname + 6, CHARS_IN_GUID);
145 if (FAILED(res)) return res;
146 keyname[44] = '\\';
147 lstrcpyW(keyname + 45, type);
149 /* Open the class category type key. */
150 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ|KEY_WRITE, &type_key);
151 if (res != ERROR_SUCCESS) return E_FAIL;
153 for (; cCategories; --cCategories, ++rgcatid) {
154 /* Format the category key name. */
155 res = StringFromGUID2(rgcatid, keyname, CHARS_IN_GUID);
156 if (FAILED(res)) continue;
158 /* Do the unregister. */
159 RegDeleteKeyW(type_key, keyname);
161 RegCloseKey(type_key);
163 return S_OK;
166 /**********************************************************************
167 * COMCAT_GetCategoryDesc
169 static HRESULT COMCAT_GetCategoryDesc(HKEY key, LCID lcid, PWCHAR pszDesc,
170 ULONG buf_wchars)
172 static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
173 WCHAR valname[5];
174 HRESULT res;
175 DWORD type, size = (buf_wchars - 1) * sizeof(WCHAR);
177 if (pszDesc == NULL) return E_INVALIDARG;
179 /* FIXME: lcid comparisons are more complex than this! */
180 wsprintfW(valname, fmt, lcid);
181 res = RegQueryValueExW(key, valname, 0, &type, (LPBYTE)pszDesc, &size);
182 if (res != ERROR_SUCCESS || type != REG_SZ) {
183 FIXME("Simplified lcid comparison\n");
184 return CAT_E_NODESCRIPTION;
186 pszDesc[size / sizeof(WCHAR)] = 0;
188 return S_OK;
191 /**********************************************************************
192 * COMCAT_PrepareClassCategories
194 static struct class_categories *COMCAT_PrepareClassCategories(
195 ULONG impl_count, const CATID *impl_catids, ULONG req_count, const CATID *req_catids)
197 struct class_categories *categories;
198 WCHAR *strings;
199 ULONG size;
201 size = sizeof(struct class_categories) + ((impl_count + req_count)*CHARS_IN_GUID + 2)*sizeof(WCHAR);
202 categories = HeapAlloc(GetProcessHeap(), 0, size);
203 if (categories == NULL) return categories;
205 categories->size = size;
206 categories->impl_offset = sizeof(struct class_categories);
207 categories->req_offset = categories->impl_offset + (impl_count*CHARS_IN_GUID + 1)*sizeof(WCHAR);
209 strings = (WCHAR *)(categories + 1);
210 while (impl_count--) {
211 StringFromGUID2(impl_catids++, strings, CHARS_IN_GUID);
212 strings += CHARS_IN_GUID;
214 *strings++ = 0;
216 while (req_count--) {
217 StringFromGUID2(req_catids++, strings, CHARS_IN_GUID);
218 strings += CHARS_IN_GUID;
220 *strings++ = 0;
222 return categories;
225 /**********************************************************************
226 * COMCAT_IsClassOfCategories
228 static HRESULT COMCAT_IsClassOfCategories(
229 HKEY key,
230 struct class_categories const* categories)
232 const WCHAR *impl_strings, *req_strings;
233 HKEY subkey;
234 HRESULT res;
235 DWORD index;
236 LPCWSTR string;
238 impl_strings = (WCHAR*)((BYTE*)categories + categories->impl_offset);
239 req_strings = (WCHAR*)((BYTE*)categories + categories->req_offset);
241 /* Check that every given category is implemented by class. */
242 if (*impl_strings) {
243 res = open_classes_key(key, impl_keyname, KEY_READ, &subkey);
244 if (res != ERROR_SUCCESS) return S_FALSE;
245 for (string = impl_strings; *string; string += CHARS_IN_GUID) {
246 HKEY catkey;
247 res = open_classes_key(subkey, string, READ_CONTROL, &catkey);
248 if (res != ERROR_SUCCESS) {
249 RegCloseKey(subkey);
250 return S_FALSE;
252 RegCloseKey(catkey);
254 RegCloseKey(subkey);
257 /* Check that all categories required by class are given. */
258 res = open_classes_key(key, req_keyname, KEY_READ, &subkey);
259 if (res == ERROR_SUCCESS) {
260 for (index = 0; ; ++index) {
261 WCHAR keyname[CHARS_IN_GUID];
262 DWORD size = CHARS_IN_GUID;
264 res = RegEnumKeyExW(subkey, index, keyname, &size,
265 NULL, NULL, NULL, NULL);
266 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
267 if (size != CHARS_IN_GUID-1) continue; /* bogus catid in registry */
268 for (string = req_strings; *string; string += CHARS_IN_GUID)
269 if (!wcsicmp(string, keyname)) break;
270 if (!*string) {
271 RegCloseKey(subkey);
272 return S_FALSE;
275 RegCloseKey(subkey);
278 return S_OK;
281 /**********************************************************************
282 * COMCAT_ICatRegister_QueryInterface
284 static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface(
285 LPCATREGISTER iface,
286 REFIID riid,
287 LPVOID *ppvObj)
289 TRACE("%s\n",debugstr_guid(riid));
291 if (ppvObj == NULL) return E_POINTER;
293 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ICatRegister)) {
294 *ppvObj = iface;
295 ICatRegister_AddRef(iface);
296 return S_OK;
299 if (IsEqualGUID(riid, &IID_ICatInformation)) {
300 *ppvObj = &COMCAT_ComCatMgr.ICatInformation_iface;
301 ICatRegister_AddRef(iface);
302 return S_OK;
305 return E_NOINTERFACE;
308 /**********************************************************************
309 * COMCAT_ICatRegister_AddRef
311 static ULONG WINAPI COMCAT_ICatRegister_AddRef(LPCATREGISTER iface)
313 return 2; /* non-heap based object */
316 /**********************************************************************
317 * COMCAT_ICatRegister_Release
319 static ULONG WINAPI COMCAT_ICatRegister_Release(LPCATREGISTER iface)
321 return 1; /* non-heap based object */
324 /**********************************************************************
325 * COMCAT_ICatRegister_RegisterCategories
327 static HRESULT WINAPI COMCAT_ICatRegister_RegisterCategories(
328 LPCATREGISTER iface,
329 ULONG cCategories,
330 CATEGORYINFO *rgci)
332 HKEY comcat_key;
333 HRESULT res;
335 TRACE("\n");
337 if (cCategories && rgci == NULL)
338 return E_POINTER;
340 /* Create (or open) the component categories key. */
341 res = create_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ|KEY_WRITE, &comcat_key);
342 if (res != ERROR_SUCCESS) return E_FAIL;
344 for (; cCategories; --cCategories, ++rgci) {
345 static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
346 WCHAR keyname[CHARS_IN_GUID];
347 WCHAR valname[9];
348 HKEY cat_key;
350 /* Create (or open) the key for this category. */
351 if (!StringFromGUID2(&rgci->catid, keyname, CHARS_IN_GUID)) continue;
352 res = create_classes_key(comcat_key, keyname, KEY_READ|KEY_WRITE, &cat_key);
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, (const BYTE*)rgci->szDescription,
358 (lstrlenW(rgci->szDescription) + 1) * sizeof(WCHAR));
360 RegCloseKey(cat_key);
363 RegCloseKey(comcat_key);
364 return S_OK;
367 /**********************************************************************
368 * COMCAT_ICatRegister_UnRegisterCategories
370 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterCategories(
371 LPCATREGISTER iface,
372 ULONG cCategories,
373 CATID *rgcatid)
375 HKEY comcat_key;
376 HRESULT res;
378 TRACE("\n");
380 if (cCategories && rgcatid == NULL)
381 return E_POINTER;
383 /* Open the component categories key. */
384 res = open_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ|KEY_WRITE, &comcat_key);
385 if (res != ERROR_SUCCESS) return E_FAIL;
387 for (; cCategories; --cCategories, ++rgcatid) {
388 WCHAR keyname[CHARS_IN_GUID];
390 /* Delete the key for this category. */
391 if (!StringFromGUID2(rgcatid, keyname, CHARS_IN_GUID)) continue;
392 RegDeleteKeyW(comcat_key, keyname);
395 RegCloseKey(comcat_key);
396 return S_OK;
399 /**********************************************************************
400 * COMCAT_ICatRegister_RegisterClassImplCategories
402 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassImplCategories(
403 LPCATREGISTER iface,
404 REFCLSID rclsid,
405 ULONG cCategories,
406 CATID *rgcatid)
408 TRACE("\n");
410 return COMCAT_RegisterClassCategories(
411 rclsid, impl_keyname, cCategories, rgcatid);
414 /**********************************************************************
415 * COMCAT_ICatRegister_UnRegisterClassImplCategories
417 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassImplCategories(
418 LPCATREGISTER iface,
419 REFCLSID rclsid,
420 ULONG cCategories,
421 CATID *rgcatid)
423 TRACE("\n");
425 return COMCAT_UnRegisterClassCategories(
426 rclsid, impl_keyname, cCategories, rgcatid);
429 /**********************************************************************
430 * COMCAT_ICatRegister_RegisterClassReqCategories
432 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassReqCategories(
433 LPCATREGISTER iface,
434 REFCLSID rclsid,
435 ULONG cCategories,
436 CATID *rgcatid)
438 TRACE("\n");
440 return COMCAT_RegisterClassCategories(
441 rclsid, req_keyname, cCategories, rgcatid);
444 /**********************************************************************
445 * COMCAT_ICatRegister_UnRegisterClassReqCategories
447 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassReqCategories(
448 LPCATREGISTER iface,
449 REFCLSID rclsid,
450 ULONG cCategories,
451 CATID *rgcatid)
453 TRACE("\n");
455 return COMCAT_UnRegisterClassCategories(
456 rclsid, req_keyname, cCategories, rgcatid);
459 /**********************************************************************
460 * COMCAT_ICatInformation_QueryInterface
462 static HRESULT WINAPI COMCAT_ICatInformation_QueryInterface(
463 LPCATINFORMATION iface,
464 REFIID riid,
465 LPVOID *ppvObj)
467 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
470 /**********************************************************************
471 * COMCAT_ICatInformation_AddRef
473 static ULONG WINAPI COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface)
475 return ICatRegister_AddRef(&COMCAT_ComCatMgr.ICatRegister_iface);
478 /**********************************************************************
479 * COMCAT_ICatInformation_Release
481 static ULONG WINAPI COMCAT_ICatInformation_Release(LPCATINFORMATION iface)
483 return ICatRegister_Release(&COMCAT_ComCatMgr.ICatRegister_iface);
486 /**********************************************************************
487 * COMCAT_ICatInformation_EnumCategories
489 static HRESULT WINAPI COMCAT_ICatInformation_EnumCategories(
490 LPCATINFORMATION iface,
491 LCID lcid,
492 IEnumCATEGORYINFO **ppenumCatInfo)
494 TRACE("\n");
496 if (ppenumCatInfo == NULL) return E_POINTER;
498 return EnumCATEGORYINFO_Construct(lcid, ppenumCatInfo);
501 /**********************************************************************
502 * COMCAT_ICatInformation_GetCategoryDesc
504 static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc(
505 LPCATINFORMATION iface,
506 REFCATID rcatid,
507 LCID lcid,
508 PWCHAR *ppszDesc)
510 WCHAR keyname[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
511 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
512 'r', 'i', 'e', 's', '\\', 0 };
513 HKEY key;
514 HRESULT res;
516 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid), lcid);
518 if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG;
520 /* Open the key for this category. */
521 if (!StringFromGUID2(rcatid, keyname + 21, CHARS_IN_GUID)) return E_FAIL;
522 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &key);
523 if (res != ERROR_SUCCESS) return CAT_E_CATIDNOEXIST;
525 /* Allocate a sensible amount of memory for the description. */
526 *ppszDesc = CoTaskMemAlloc(128 * sizeof(WCHAR));
527 if (*ppszDesc == NULL) {
528 RegCloseKey(key);
529 return E_OUTOFMEMORY;
532 /* Get the description, and make sure it's null terminated. */
533 res = COMCAT_GetCategoryDesc(key, lcid, *ppszDesc, 128);
534 RegCloseKey(key);
535 if (FAILED(res)) {
536 CoTaskMemFree(*ppszDesc);
537 return res;
540 return S_OK;
543 /**********************************************************************
544 * COMCAT_ICatInformation_EnumClassesOfCategories
546 static HRESULT WINAPI COMCAT_ICatInformation_EnumClassesOfCategories(
547 LPCATINFORMATION iface,
548 ULONG cImplemented,
549 CATID *rgcatidImpl,
550 ULONG cRequired,
551 CATID *rgcatidReq,
552 LPENUMCLSID *ppenumCLSID)
554 struct class_categories *categories;
555 HRESULT hr;
557 TRACE("\n");
559 if (cImplemented == (ULONG)-1)
560 cImplemented = 0;
561 if (cRequired == (ULONG)-1)
562 cRequired = 0;
564 if (ppenumCLSID == NULL ||
565 (cImplemented && rgcatidImpl == NULL) ||
566 (cRequired && rgcatidReq == NULL)) return E_POINTER;
568 categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
569 cRequired, rgcatidReq);
570 if (categories == NULL) return E_OUTOFMEMORY;
572 hr = CLSIDEnumGUID_Construct(categories, ppenumCLSID);
573 if (FAILED(hr))
575 HeapFree(GetProcessHeap(), 0, categories);
576 return hr;
579 return hr;
582 /**********************************************************************
583 * COMCAT_ICatInformation_IsClassOfCategories
585 static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories(
586 LPCATINFORMATION iface,
587 REFCLSID rclsid,
588 ULONG cImplemented,
589 CATID *rgcatidImpl,
590 ULONG cRequired,
591 CATID *rgcatidReq)
593 WCHAR keyname[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
594 HRESULT res;
595 struct class_categories *categories;
596 HKEY key;
598 if (TRACE_ON(ole)) {
599 ULONG count;
600 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid),cImplemented);
601 for (count = 0; count < cImplemented; ++count)
602 TRACE(" %s\n",debugstr_guid(&rgcatidImpl[count]));
603 TRACE("Required %u\n",cRequired);
604 for (count = 0; count < cRequired; ++count)
605 TRACE(" %s\n",debugstr_guid(&rgcatidReq[count]));
608 if ((cImplemented && rgcatidImpl == NULL) ||
609 (cRequired && rgcatidReq == NULL)) return E_POINTER;
611 res = StringFromGUID2(rclsid, keyname + 6, CHARS_IN_GUID);
612 if (FAILED(res)) return res;
614 categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
615 cRequired, rgcatidReq);
616 if (categories == NULL) return E_OUTOFMEMORY;
618 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &key);
619 if (res == ERROR_SUCCESS) {
620 res = COMCAT_IsClassOfCategories(key, categories);
621 RegCloseKey(key);
622 } else res = S_FALSE;
624 HeapFree(GetProcessHeap(), 0, categories);
626 return res;
629 /**********************************************************************
630 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
632 static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass(
633 LPCATINFORMATION iface,
634 REFCLSID rclsid,
635 LPENUMCATID *ppenumCATID)
637 static const WCHAR postfix[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
638 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
639 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
641 TRACE("%s\n",debugstr_guid(rclsid));
643 if (rclsid == NULL || ppenumCATID == NULL)
644 return E_POINTER;
646 return CATIDEnumGUID_Construct(rclsid, postfix, ppenumCATID);
649 /**********************************************************************
650 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
652 static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass(
653 LPCATINFORMATION iface,
654 REFCLSID rclsid,
655 LPENUMCATID *ppenumCATID)
657 static const WCHAR postfix[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
658 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
659 'r', 'i', 'e', 's', 0 };
661 TRACE("%s\n",debugstr_guid(rclsid));
663 if (rclsid == NULL || ppenumCATID == NULL)
664 return E_POINTER;
666 return CATIDEnumGUID_Construct(rclsid, postfix, ppenumCATID);
669 /**********************************************************************
670 * COMCAT_ICatRegister_Vtbl
672 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl =
674 COMCAT_ICatRegister_QueryInterface,
675 COMCAT_ICatRegister_AddRef,
676 COMCAT_ICatRegister_Release,
677 COMCAT_ICatRegister_RegisterCategories,
678 COMCAT_ICatRegister_UnRegisterCategories,
679 COMCAT_ICatRegister_RegisterClassImplCategories,
680 COMCAT_ICatRegister_UnRegisterClassImplCategories,
681 COMCAT_ICatRegister_RegisterClassReqCategories,
682 COMCAT_ICatRegister_UnRegisterClassReqCategories
686 /**********************************************************************
687 * COMCAT_ICatInformation_Vtbl
689 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl =
691 COMCAT_ICatInformation_QueryInterface,
692 COMCAT_ICatInformation_AddRef,
693 COMCAT_ICatInformation_Release,
694 COMCAT_ICatInformation_EnumCategories,
695 COMCAT_ICatInformation_GetCategoryDesc,
696 COMCAT_ICatInformation_EnumClassesOfCategories,
697 COMCAT_ICatInformation_IsClassOfCategories,
698 COMCAT_ICatInformation_EnumImplCategoriesOfClass,
699 COMCAT_ICatInformation_EnumReqCategoriesOfClass
702 HRESULT WINAPI ComCat_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
704 HRESULT res;
705 TRACE("%s\n",debugstr_guid(riid));
707 if (ppvObj == NULL) return E_POINTER;
709 /* Don't support aggregation (Windows doesn't) */
710 if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
712 res = ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
713 if (SUCCEEDED(res)) {
714 return res;
717 return CLASS_E_CLASSNOTAVAILABLE;
720 /**********************************************************************
721 * IEnumCATEGORYINFO implementation
723 * This implementation is not thread-safe. The manager itself is, but
724 * I can't imagine a valid use of an enumerator in several threads.
726 typedef struct
728 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface;
729 LONG ref;
730 LCID lcid;
731 HKEY key;
732 DWORD next_index;
733 } IEnumCATEGORYINFOImpl;
735 static inline IEnumCATEGORYINFOImpl *impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO *iface)
737 return CONTAINING_RECORD(iface, IEnumCATEGORYINFOImpl, IEnumCATEGORYINFO_iface);
740 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO *iface)
742 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
744 TRACE("\n");
746 return InterlockedIncrement(&This->ref);
749 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface(
750 IEnumCATEGORYINFO *iface,
751 REFIID riid,
752 LPVOID *ppvObj)
754 TRACE("%s\n",debugstr_guid(riid));
756 if (ppvObj == NULL) return E_POINTER;
758 if (IsEqualGUID(riid, &IID_IUnknown) ||
759 IsEqualGUID(riid, &IID_IEnumCATEGORYINFO))
761 *ppvObj = iface;
762 COMCAT_IEnumCATEGORYINFO_AddRef(iface);
763 return S_OK;
766 return E_NOINTERFACE;
769 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO *iface)
771 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
772 ULONG ref;
774 TRACE("\n");
776 ref = InterlockedDecrement(&This->ref);
777 if (ref == 0) {
778 if (This->key) RegCloseKey(This->key);
779 HeapFree(GetProcessHeap(), 0, This);
780 return 0;
782 return ref;
785 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Next(
786 IEnumCATEGORYINFO *iface,
787 ULONG celt,
788 CATEGORYINFO *rgelt,
789 ULONG *pceltFetched)
791 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
792 ULONG fetched = 0;
794 TRACE("\n");
796 if (rgelt == NULL) return E_POINTER;
798 if (This->key) while (fetched < celt) {
799 LSTATUS res;
800 HRESULT hr;
801 WCHAR catid[CHARS_IN_GUID];
802 DWORD cName = CHARS_IN_GUID;
803 HKEY subkey;
805 res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
806 NULL, NULL, NULL, NULL);
807 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
808 ++(This->next_index);
810 hr = CLSIDFromString(catid, &rgelt->catid);
811 if (FAILED(hr)) continue;
813 res = open_classes_key(This->key, catid, KEY_READ, &subkey);
814 if (res != ERROR_SUCCESS) continue;
816 hr = COMCAT_GetCategoryDesc(subkey, This->lcid,
817 rgelt->szDescription, 128);
818 RegCloseKey(subkey);
819 if (FAILED(hr)) continue;
821 rgelt->lcid = This->lcid;
822 ++fetched;
823 ++rgelt;
826 if (pceltFetched) *pceltFetched = fetched;
827 return fetched == celt ? S_OK : S_FALSE;
830 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Skip(
831 IEnumCATEGORYINFO *iface,
832 ULONG celt)
834 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
836 TRACE("\n");
838 This->next_index += celt;
839 /* This should return S_FALSE when there aren't celt elems to skip. */
840 return S_OK;
843 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO *iface)
845 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
847 TRACE("\n");
849 This->next_index = 0;
850 return S_OK;
853 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Clone(
854 IEnumCATEGORYINFO *iface,
855 IEnumCATEGORYINFO **ppenum)
857 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
858 static const WCHAR keyname[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
859 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
860 'r', 'i', 'e', 's', 0 };
861 IEnumCATEGORYINFOImpl *new_this;
863 TRACE("\n");
865 if (ppenum == NULL) return E_POINTER;
867 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
868 if (new_this == NULL) return E_OUTOFMEMORY;
870 new_this->IEnumCATEGORYINFO_iface = This->IEnumCATEGORYINFO_iface;
871 new_this->ref = 1;
872 new_this->lcid = This->lcid;
873 /* FIXME: could we more efficiently use DuplicateHandle? */
874 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &new_this->key);
875 new_this->next_index = This->next_index;
877 *ppenum = &new_this->IEnumCATEGORYINFO_iface;
878 return S_OK;
881 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl =
883 COMCAT_IEnumCATEGORYINFO_QueryInterface,
884 COMCAT_IEnumCATEGORYINFO_AddRef,
885 COMCAT_IEnumCATEGORYINFO_Release,
886 COMCAT_IEnumCATEGORYINFO_Next,
887 COMCAT_IEnumCATEGORYINFO_Skip,
888 COMCAT_IEnumCATEGORYINFO_Reset,
889 COMCAT_IEnumCATEGORYINFO_Clone
892 static HRESULT EnumCATEGORYINFO_Construct(LCID lcid, IEnumCATEGORYINFO **ret)
894 static const WCHAR keyname[] = {'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0};
895 IEnumCATEGORYINFOImpl *This;
897 *ret = NULL;
899 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
900 if (!This) return E_OUTOFMEMORY;
902 This->IEnumCATEGORYINFO_iface.lpVtbl = &COMCAT_IEnumCATEGORYINFO_Vtbl;
903 This->ref = 1;
904 This->lcid = lcid;
905 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &This->key);
907 *ret = &This->IEnumCATEGORYINFO_iface;
908 return S_OK;
911 /**********************************************************************
912 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
914 * This implementation is not thread-safe. The manager itself is, but
915 * I can't imagine a valid use of an enumerator in several threads.
917 typedef struct
919 IEnumGUID IEnumGUID_iface;
920 LONG ref;
921 struct class_categories *categories;
922 HKEY key;
923 DWORD next_index;
924 } CLSID_IEnumGUIDImpl;
926 static inline CLSID_IEnumGUIDImpl *impl_from_IEnumCLSID(IEnumGUID *iface)
928 return CONTAINING_RECORD(iface, CLSID_IEnumGUIDImpl, IEnumGUID_iface);
931 static HRESULT WINAPI CLSIDEnumGUID_QueryInterface(
932 IEnumGUID *iface,
933 REFIID riid,
934 LPVOID *ppvObj)
936 TRACE("%s\n",debugstr_guid(riid));
938 if (ppvObj == NULL) return E_POINTER;
940 if (IsEqualGUID(riid, &IID_IUnknown) ||
941 IsEqualGUID(riid, &IID_IEnumGUID))
943 *ppvObj = iface;
944 IEnumGUID_AddRef(iface);
945 return S_OK;
948 return E_NOINTERFACE;
951 static ULONG WINAPI CLSIDEnumGUID_AddRef(IEnumGUID *iface)
953 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
954 TRACE("\n");
956 return InterlockedIncrement(&This->ref);
959 static ULONG WINAPI CLSIDEnumGUID_Release(IEnumGUID *iface)
961 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
962 ULONG ref;
964 TRACE("\n");
966 ref = InterlockedDecrement(&This->ref);
967 if (ref == 0) {
968 if (This->key) RegCloseKey(This->key);
969 HeapFree(GetProcessHeap(), 0, This->categories);
970 HeapFree(GetProcessHeap(), 0, This);
971 return 0;
973 return ref;
976 static HRESULT WINAPI CLSIDEnumGUID_Next(
977 IEnumGUID *iface,
978 ULONG celt,
979 GUID *rgelt,
980 ULONG *pceltFetched)
982 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
983 ULONG fetched = 0;
985 TRACE("\n");
987 if (rgelt == NULL) return E_POINTER;
989 if (This->key) while (fetched < celt) {
990 LSTATUS res;
991 HRESULT hr;
992 WCHAR clsid[CHARS_IN_GUID];
993 DWORD cName = CHARS_IN_GUID;
994 HKEY subkey;
996 res = RegEnumKeyExW(This->key, This->next_index, clsid, &cName,
997 NULL, NULL, NULL, NULL);
998 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
999 ++(This->next_index);
1001 hr = CLSIDFromString(clsid, rgelt);
1002 if (FAILED(hr)) continue;
1004 res = open_classes_key(This->key, clsid, KEY_READ, &subkey);
1005 if (res != ERROR_SUCCESS) continue;
1007 hr = COMCAT_IsClassOfCategories(subkey, This->categories);
1008 RegCloseKey(subkey);
1009 if (hr != S_OK) continue;
1011 ++fetched;
1012 ++rgelt;
1015 if (pceltFetched) *pceltFetched = fetched;
1016 return fetched == celt ? S_OK : S_FALSE;
1019 static HRESULT WINAPI CLSIDEnumGUID_Skip(
1020 IEnumGUID *iface,
1021 ULONG celt)
1023 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
1025 TRACE("\n");
1027 This->next_index += celt;
1028 FIXME("Never returns S_FALSE\n");
1029 return S_OK;
1032 static HRESULT WINAPI CLSIDEnumGUID_Reset(IEnumGUID *iface)
1034 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
1036 TRACE("\n");
1038 This->next_index = 0;
1039 return S_OK;
1042 static HRESULT WINAPI CLSIDEnumGUID_Clone(
1043 IEnumGUID *iface,
1044 IEnumGUID **ppenum)
1046 static const WCHAR keynameW[] = {'C','L','S','I','D',0};
1047 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
1048 CLSID_IEnumGUIDImpl *cloned;
1050 TRACE("(%p)->(%p)\n", This, ppenum);
1052 if (ppenum == NULL) return E_POINTER;
1054 *ppenum = NULL;
1056 cloned = HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID_IEnumGUIDImpl));
1057 if (cloned == NULL) return E_OUTOFMEMORY;
1059 cloned->IEnumGUID_iface.lpVtbl = This->IEnumGUID_iface.lpVtbl;
1060 cloned->ref = 1;
1062 cloned->categories = HeapAlloc(GetProcessHeap(), 0, This->categories->size);
1063 if (cloned->categories == NULL) {
1064 HeapFree(GetProcessHeap(), 0, cloned);
1065 return E_OUTOFMEMORY;
1067 memcpy(cloned->categories, This->categories, This->categories->size);
1069 cloned->key = NULL;
1070 open_classes_key(HKEY_CLASSES_ROOT, keynameW, KEY_READ, &cloned->key);
1071 cloned->next_index = This->next_index;
1073 *ppenum = &cloned->IEnumGUID_iface;
1074 return S_OK;
1077 static const IEnumGUIDVtbl CLSIDEnumGUIDVtbl =
1079 CLSIDEnumGUID_QueryInterface,
1080 CLSIDEnumGUID_AddRef,
1081 CLSIDEnumGUID_Release,
1082 CLSIDEnumGUID_Next,
1083 CLSIDEnumGUID_Skip,
1084 CLSIDEnumGUID_Reset,
1085 CLSIDEnumGUID_Clone
1088 static HRESULT CLSIDEnumGUID_Construct(struct class_categories *categories, IEnumCLSID **ret)
1090 static const WCHAR keyname[] = {'C','L','S','I','D',0};
1091 CLSID_IEnumGUIDImpl *This;
1093 *ret = NULL;
1095 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
1096 if (!This) return E_OUTOFMEMORY;
1098 This->IEnumGUID_iface.lpVtbl = &CLSIDEnumGUIDVtbl;
1099 This->ref = 1;
1100 This->categories = categories;
1101 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &This->key);
1103 *ret = &This->IEnumGUID_iface;
1105 return S_OK;
1108 /**********************************************************************
1109 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1111 * This implementation is not thread-safe. The manager itself is, but
1112 * I can't imagine a valid use of an enumerator in several threads.
1114 typedef struct
1116 IEnumGUID IEnumGUID_iface;
1117 LONG ref;
1118 WCHAR keyname[68];
1119 HKEY key;
1120 DWORD next_index;
1121 } CATID_IEnumGUIDImpl;
1123 static inline CATID_IEnumGUIDImpl *impl_from_IEnumCATID(IEnumGUID *iface)
1125 return CONTAINING_RECORD(iface, CATID_IEnumGUIDImpl, IEnumGUID_iface);
1128 static HRESULT WINAPI CATIDEnumGUID_QueryInterface(
1129 IEnumGUID *iface,
1130 REFIID riid,
1131 LPVOID *ppvObj)
1133 TRACE("%s\n",debugstr_guid(riid));
1135 if (ppvObj == NULL) return E_POINTER;
1137 if (IsEqualGUID(riid, &IID_IUnknown) ||
1138 IsEqualGUID(riid, &IID_IEnumGUID))
1140 *ppvObj = iface;
1141 IEnumGUID_AddRef(iface);
1142 return S_OK;
1145 return E_NOINTERFACE;
1148 static ULONG WINAPI CATIDEnumGUID_AddRef(IEnumGUID *iface)
1150 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1151 TRACE("\n");
1153 return InterlockedIncrement(&This->ref);
1156 static ULONG WINAPI CATIDEnumGUID_Release(IEnumGUID *iface)
1158 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1159 ULONG ref;
1161 TRACE("\n");
1163 ref = InterlockedDecrement(&This->ref);
1164 if (ref == 0) {
1165 if (This->key) RegCloseKey(This->key);
1166 HeapFree(GetProcessHeap(), 0, This);
1167 return 0;
1169 return ref;
1172 static HRESULT WINAPI CATIDEnumGUID_Next(
1173 IEnumGUID *iface,
1174 ULONG celt,
1175 GUID *rgelt,
1176 ULONG *pceltFetched)
1178 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1179 ULONG fetched = 0;
1181 TRACE("\n");
1183 if (rgelt == NULL) return E_POINTER;
1185 if (This->key) while (fetched < celt) {
1186 LSTATUS res;
1187 HRESULT hr;
1188 WCHAR catid[CHARS_IN_GUID];
1189 DWORD cName = CHARS_IN_GUID;
1191 res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
1192 NULL, NULL, NULL, NULL);
1193 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
1194 ++(This->next_index);
1196 hr = CLSIDFromString(catid, rgelt);
1197 if (FAILED(hr)) continue;
1199 ++fetched;
1200 ++rgelt;
1203 if (pceltFetched) *pceltFetched = fetched;
1204 return fetched == celt ? S_OK : S_FALSE;
1207 static HRESULT WINAPI CATIDEnumGUID_Skip(
1208 IEnumGUID *iface,
1209 ULONG celt)
1211 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1213 TRACE("\n");
1215 This->next_index += celt;
1216 FIXME("Never returns S_FALSE\n");
1217 return S_OK;
1220 static HRESULT WINAPI CATIDEnumGUID_Reset(IEnumGUID *iface)
1222 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1224 TRACE("\n");
1226 This->next_index = 0;
1227 return S_OK;
1230 static HRESULT WINAPI CATIDEnumGUID_Clone(
1231 IEnumGUID *iface,
1232 IEnumGUID **ppenum)
1234 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1235 CATID_IEnumGUIDImpl *new_this;
1237 TRACE("\n");
1239 if (ppenum == NULL) return E_POINTER;
1241 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
1242 if (new_this == NULL) return E_OUTOFMEMORY;
1244 new_this->IEnumGUID_iface.lpVtbl = This->IEnumGUID_iface.lpVtbl;
1245 new_this->ref = 1;
1246 lstrcpyW(new_this->keyname, This->keyname);
1247 /* FIXME: could we more efficiently use DuplicateHandle? */
1248 open_classes_key(HKEY_CLASSES_ROOT, new_this->keyname, KEY_READ, &new_this->key);
1249 new_this->next_index = This->next_index;
1251 *ppenum = &new_this->IEnumGUID_iface;
1252 return S_OK;
1255 static const IEnumGUIDVtbl CATIDEnumGUIDVtbl =
1257 CATIDEnumGUID_QueryInterface,
1258 CATIDEnumGUID_AddRef,
1259 CATIDEnumGUID_Release,
1260 CATIDEnumGUID_Next,
1261 CATIDEnumGUID_Skip,
1262 CATIDEnumGUID_Reset,
1263 CATIDEnumGUID_Clone
1266 static HRESULT CATIDEnumGUID_Construct(REFCLSID rclsid, LPCWSTR postfix, IEnumGUID **ret)
1268 static const WCHAR prefixW[] = {'C','L','S','I','D','\\',0};
1269 WCHAR keyname[100], clsidW[CHARS_IN_GUID];
1270 CATID_IEnumGUIDImpl *This;
1272 *ret = NULL;
1274 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
1275 if (!This) return E_OUTOFMEMORY;
1277 StringFromGUID2(rclsid, clsidW, CHARS_IN_GUID);
1279 This->IEnumGUID_iface.lpVtbl = &CATIDEnumGUIDVtbl;
1280 This->ref = 1;
1281 lstrcpyW(keyname, prefixW);
1282 lstrcatW(keyname, clsidW);
1283 lstrcatW(keyname, postfix);
1285 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &This->key);
1287 *ret = &This->IEnumGUID_iface;
1288 return S_OK;