mscoree/tests: Test querying interfaces with generated GUID.
[wine.git] / dlls / ole32 / comcat.c
blobe258f8835b04c16b05a6ab71cabf827ef50c7471
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[] = L"Component Categories";
71 static const WCHAR impl_keyname[] = L"Implemented Categories";
72 static const WCHAR req_keyname[] = L"Required Categories";
74 /**********************************************************************
75 * COMCAT_RegisterClassCategories
77 static HRESULT COMCAT_RegisterClassCategories(
78 REFCLSID rclsid,
79 LPCWSTR type,
80 ULONG cCategories,
81 const CATID *rgcatid)
83 WCHAR keyname[CHARS_IN_GUID];
84 HRESULT res;
85 HKEY clsid_key, class_key, type_key;
87 if (cCategories && rgcatid == NULL) return E_POINTER;
89 /* Format the class key name. */
90 res = StringFromGUID2(rclsid, keyname, CHARS_IN_GUID);
91 if (FAILED(res)) return res;
93 /* Create (or open) the CLSID key. */
94 res = create_classes_key(HKEY_CLASSES_ROOT, L"CLSID", KEY_READ|KEY_WRITE, &clsid_key);
95 if (res != ERROR_SUCCESS) return E_FAIL;
97 /* Create (or open) the class key. */
98 res = create_classes_key(clsid_key, keyname, KEY_READ|KEY_WRITE, &class_key);
99 if (res == ERROR_SUCCESS) {
100 /* Create (or open) the category type key. */
101 res = create_classes_key(class_key, type, KEY_READ|KEY_WRITE, &type_key);
102 if (res == ERROR_SUCCESS) {
103 for (; cCategories; --cCategories, ++rgcatid) {
104 HKEY key;
106 /* Format the category key name. */
107 res = StringFromGUID2(rgcatid, keyname, CHARS_IN_GUID);
108 if (FAILED(res)) continue;
110 /* Do the register. */
111 res = create_classes_key(type_key, keyname, KEY_READ|KEY_WRITE, &key);
112 if (res == ERROR_SUCCESS) RegCloseKey(key);
114 res = S_OK;
115 } else res = E_FAIL;
116 RegCloseKey(class_key);
117 } else res = E_FAIL;
118 RegCloseKey(clsid_key);
120 return res;
123 /**********************************************************************
124 * COMCAT_UnRegisterClassCategories
126 static HRESULT COMCAT_UnRegisterClassCategories(
127 REFCLSID rclsid,
128 LPCWSTR type,
129 ULONG cCategories,
130 const CATID *rgcatid)
132 WCHAR keyname[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
133 HRESULT res;
134 HKEY type_key;
136 if (cCategories && rgcatid == NULL) return E_POINTER;
138 /* Format the class category type key name. */
139 res = StringFromGUID2(rclsid, keyname + 6, CHARS_IN_GUID);
140 if (FAILED(res)) return res;
141 keyname[44] = '\\';
142 lstrcpyW(keyname + 45, type);
144 /* Open the class category type key. */
145 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ|KEY_WRITE, &type_key);
146 if (res != ERROR_SUCCESS) return E_FAIL;
148 for (; cCategories; --cCategories, ++rgcatid) {
149 /* Format the category key name. */
150 res = StringFromGUID2(rgcatid, keyname, CHARS_IN_GUID);
151 if (FAILED(res)) continue;
153 /* Do the unregister. */
154 RegDeleteKeyW(type_key, keyname);
156 RegCloseKey(type_key);
158 return S_OK;
161 /**********************************************************************
162 * COMCAT_GetCategoryDesc
164 static HRESULT COMCAT_GetCategoryDesc(HKEY key, LCID lcid, PWCHAR pszDesc,
165 ULONG buf_wchars)
167 WCHAR valname[5];
168 HRESULT res;
169 DWORD type, size = (buf_wchars - 1) * sizeof(WCHAR);
171 if (pszDesc == NULL) return E_INVALIDARG;
173 /* FIXME: lcid comparisons are more complex than this! */
174 wsprintfW(valname, L"%lX", lcid);
175 res = RegQueryValueExW(key, valname, 0, &type, (LPBYTE)pszDesc, &size);
176 if (res != ERROR_SUCCESS || type != REG_SZ) {
177 FIXME("Simplified lcid comparison\n");
178 return CAT_E_NODESCRIPTION;
180 pszDesc[size / sizeof(WCHAR)] = 0;
182 return S_OK;
185 /**********************************************************************
186 * COMCAT_PrepareClassCategories
188 static struct class_categories *COMCAT_PrepareClassCategories(
189 ULONG impl_count, const CATID *impl_catids, ULONG req_count, const CATID *req_catids)
191 struct class_categories *categories;
192 WCHAR *strings;
193 ULONG size;
195 size = sizeof(struct class_categories) + ((impl_count + req_count)*CHARS_IN_GUID + 2)*sizeof(WCHAR);
196 categories = HeapAlloc(GetProcessHeap(), 0, size);
197 if (categories == NULL) return categories;
199 categories->size = size;
200 categories->impl_offset = sizeof(struct class_categories);
201 categories->req_offset = categories->impl_offset + (impl_count*CHARS_IN_GUID + 1)*sizeof(WCHAR);
203 strings = (WCHAR *)(categories + 1);
204 while (impl_count--) {
205 StringFromGUID2(impl_catids++, strings, CHARS_IN_GUID);
206 strings += CHARS_IN_GUID;
208 *strings++ = 0;
210 while (req_count--) {
211 StringFromGUID2(req_catids++, strings, CHARS_IN_GUID);
212 strings += CHARS_IN_GUID;
214 *strings++ = 0;
216 return categories;
219 /**********************************************************************
220 * COMCAT_IsClassOfCategories
222 static HRESULT COMCAT_IsClassOfCategories(
223 HKEY key,
224 struct class_categories const* categories)
226 const WCHAR *impl_strings, *req_strings;
227 HKEY subkey;
228 HRESULT res;
229 DWORD index;
230 LPCWSTR string;
232 impl_strings = (WCHAR*)((BYTE*)categories + categories->impl_offset);
233 req_strings = (WCHAR*)((BYTE*)categories + categories->req_offset);
235 /* Check that every given category is implemented by class. */
236 if (*impl_strings) {
237 res = open_classes_key(key, impl_keyname, KEY_READ, &subkey);
238 if (res != ERROR_SUCCESS) return S_FALSE;
239 for (string = impl_strings; *string; string += CHARS_IN_GUID) {
240 HKEY catkey;
241 res = open_classes_key(subkey, string, READ_CONTROL, &catkey);
242 if (res != ERROR_SUCCESS) {
243 RegCloseKey(subkey);
244 return S_FALSE;
246 RegCloseKey(catkey);
248 RegCloseKey(subkey);
251 /* Check that all categories required by class are given. */
252 res = open_classes_key(key, req_keyname, KEY_READ, &subkey);
253 if (res == ERROR_SUCCESS) {
254 for (index = 0; ; ++index) {
255 WCHAR keyname[CHARS_IN_GUID];
256 DWORD size = CHARS_IN_GUID;
258 res = RegEnumKeyExW(subkey, index, keyname, &size,
259 NULL, NULL, NULL, NULL);
260 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
261 if (size != CHARS_IN_GUID-1) continue; /* bogus catid in registry */
262 for (string = req_strings; *string; string += CHARS_IN_GUID)
263 if (!wcsicmp(string, keyname)) break;
264 if (!*string) {
265 RegCloseKey(subkey);
266 return S_FALSE;
269 RegCloseKey(subkey);
272 return S_OK;
275 /**********************************************************************
276 * COMCAT_ICatRegister_QueryInterface
278 static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface(
279 LPCATREGISTER iface,
280 REFIID riid,
281 LPVOID *ppvObj)
283 TRACE("%s\n",debugstr_guid(riid));
285 if (ppvObj == NULL) return E_POINTER;
287 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ICatRegister)) {
288 *ppvObj = iface;
289 ICatRegister_AddRef(iface);
290 return S_OK;
293 if (IsEqualGUID(riid, &IID_ICatInformation)) {
294 *ppvObj = &COMCAT_ComCatMgr.ICatInformation_iface;
295 ICatRegister_AddRef(iface);
296 return S_OK;
299 return E_NOINTERFACE;
302 /**********************************************************************
303 * COMCAT_ICatRegister_AddRef
305 static ULONG WINAPI COMCAT_ICatRegister_AddRef(LPCATREGISTER iface)
307 return 2; /* non-heap based object */
310 /**********************************************************************
311 * COMCAT_ICatRegister_Release
313 static ULONG WINAPI COMCAT_ICatRegister_Release(LPCATREGISTER iface)
315 return 1; /* non-heap based object */
318 /**********************************************************************
319 * COMCAT_ICatRegister_RegisterCategories
321 static HRESULT WINAPI COMCAT_ICatRegister_RegisterCategories(
322 LPCATREGISTER iface,
323 ULONG cCategories,
324 CATEGORYINFO *rgci)
326 HKEY comcat_key;
327 HRESULT res;
329 TRACE("\n");
331 if (cCategories && rgci == NULL)
332 return E_POINTER;
334 /* Create (or open) the component categories key. */
335 res = create_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ|KEY_WRITE, &comcat_key);
336 if (res != ERROR_SUCCESS) return E_FAIL;
338 for (; cCategories; --cCategories, ++rgci)
340 WCHAR keyname[CHARS_IN_GUID];
341 WCHAR valname[9];
342 HKEY cat_key;
344 /* Create (or open) the key for this category. */
345 if (!StringFromGUID2(&rgci->catid, keyname, CHARS_IN_GUID)) continue;
346 res = create_classes_key(comcat_key, keyname, KEY_READ|KEY_WRITE, &cat_key);
347 if (res != ERROR_SUCCESS) continue;
349 /* Set the value for this locale's description. */
350 wsprintfW(valname, L"%lX", rgci->lcid);
351 RegSetValueExW(cat_key, valname, 0, REG_SZ, (const BYTE*)rgci->szDescription,
352 (lstrlenW(rgci->szDescription) + 1) * sizeof(WCHAR));
354 RegCloseKey(cat_key);
357 RegCloseKey(comcat_key);
358 return S_OK;
361 /**********************************************************************
362 * COMCAT_ICatRegister_UnRegisterCategories
364 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterCategories(
365 LPCATREGISTER iface,
366 ULONG cCategories,
367 CATID *rgcatid)
369 HKEY comcat_key;
370 HRESULT res;
372 TRACE("\n");
374 if (cCategories && rgcatid == NULL)
375 return E_POINTER;
377 /* Open the component categories key. */
378 res = open_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ|KEY_WRITE, &comcat_key);
379 if (res != ERROR_SUCCESS) return E_FAIL;
381 for (; cCategories; --cCategories, ++rgcatid) {
382 WCHAR keyname[CHARS_IN_GUID];
384 /* Delete the key for this category. */
385 if (!StringFromGUID2(rgcatid, keyname, CHARS_IN_GUID)) continue;
386 RegDeleteKeyW(comcat_key, keyname);
389 RegCloseKey(comcat_key);
390 return S_OK;
393 /**********************************************************************
394 * COMCAT_ICatRegister_RegisterClassImplCategories
396 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassImplCategories(
397 LPCATREGISTER iface,
398 REFCLSID rclsid,
399 ULONG cCategories,
400 CATID *rgcatid)
402 TRACE("\n");
404 return COMCAT_RegisterClassCategories(
405 rclsid, impl_keyname, cCategories, rgcatid);
408 /**********************************************************************
409 * COMCAT_ICatRegister_UnRegisterClassImplCategories
411 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassImplCategories(
412 LPCATREGISTER iface,
413 REFCLSID rclsid,
414 ULONG cCategories,
415 CATID *rgcatid)
417 TRACE("\n");
419 return COMCAT_UnRegisterClassCategories(
420 rclsid, impl_keyname, cCategories, rgcatid);
423 /**********************************************************************
424 * COMCAT_ICatRegister_RegisterClassReqCategories
426 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassReqCategories(
427 LPCATREGISTER iface,
428 REFCLSID rclsid,
429 ULONG cCategories,
430 CATID *rgcatid)
432 TRACE("\n");
434 return COMCAT_RegisterClassCategories(
435 rclsid, req_keyname, cCategories, rgcatid);
438 /**********************************************************************
439 * COMCAT_ICatRegister_UnRegisterClassReqCategories
441 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassReqCategories(
442 LPCATREGISTER iface,
443 REFCLSID rclsid,
444 ULONG cCategories,
445 CATID *rgcatid)
447 TRACE("\n");
449 return COMCAT_UnRegisterClassCategories(
450 rclsid, req_keyname, cCategories, rgcatid);
453 /**********************************************************************
454 * COMCAT_ICatInformation_QueryInterface
456 static HRESULT WINAPI COMCAT_ICatInformation_QueryInterface(
457 LPCATINFORMATION iface,
458 REFIID riid,
459 LPVOID *ppvObj)
461 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
464 /**********************************************************************
465 * COMCAT_ICatInformation_AddRef
467 static ULONG WINAPI COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface)
469 return ICatRegister_AddRef(&COMCAT_ComCatMgr.ICatRegister_iface);
472 /**********************************************************************
473 * COMCAT_ICatInformation_Release
475 static ULONG WINAPI COMCAT_ICatInformation_Release(LPCATINFORMATION iface)
477 return ICatRegister_Release(&COMCAT_ComCatMgr.ICatRegister_iface);
480 /**********************************************************************
481 * COMCAT_ICatInformation_EnumCategories
483 static HRESULT WINAPI COMCAT_ICatInformation_EnumCategories(
484 LPCATINFORMATION iface,
485 LCID lcid,
486 IEnumCATEGORYINFO **ppenumCatInfo)
488 TRACE("\n");
490 if (ppenumCatInfo == NULL) return E_POINTER;
492 return EnumCATEGORYINFO_Construct(lcid, ppenumCatInfo);
495 /**********************************************************************
496 * COMCAT_ICatInformation_GetCategoryDesc
498 static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc(
499 LPCATINFORMATION iface,
500 REFCATID rcatid,
501 LCID lcid,
502 PWCHAR *ppszDesc)
504 WCHAR keyname[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
505 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
506 'r', 'i', 'e', 's', '\\', 0 };
507 HKEY key;
508 HRESULT res;
510 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid), lcid);
512 if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG;
514 /* Open the key for this category. */
515 if (!StringFromGUID2(rcatid, keyname + 21, CHARS_IN_GUID)) return E_FAIL;
516 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &key);
517 if (res != ERROR_SUCCESS) return CAT_E_CATIDNOEXIST;
519 /* Allocate a sensible amount of memory for the description. */
520 *ppszDesc = CoTaskMemAlloc(128 * sizeof(WCHAR));
521 if (*ppszDesc == NULL) {
522 RegCloseKey(key);
523 return E_OUTOFMEMORY;
526 /* Get the description, and make sure it's null terminated. */
527 res = COMCAT_GetCategoryDesc(key, lcid, *ppszDesc, 128);
528 RegCloseKey(key);
529 if (FAILED(res)) {
530 CoTaskMemFree(*ppszDesc);
531 return res;
534 return S_OK;
537 /**********************************************************************
538 * COMCAT_ICatInformation_EnumClassesOfCategories
540 static HRESULT WINAPI COMCAT_ICatInformation_EnumClassesOfCategories(
541 LPCATINFORMATION iface,
542 ULONG cImplemented,
543 CATID *rgcatidImpl,
544 ULONG cRequired,
545 CATID *rgcatidReq,
546 LPENUMCLSID *ppenumCLSID)
548 struct class_categories *categories;
549 HRESULT hr;
551 TRACE("\n");
553 if (cImplemented == (ULONG)-1)
554 cImplemented = 0;
555 if (cRequired == (ULONG)-1)
556 cRequired = 0;
558 if (ppenumCLSID == NULL ||
559 (cImplemented && rgcatidImpl == NULL) ||
560 (cRequired && rgcatidReq == NULL)) return E_POINTER;
562 categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
563 cRequired, rgcatidReq);
564 if (categories == NULL) return E_OUTOFMEMORY;
566 hr = CLSIDEnumGUID_Construct(categories, ppenumCLSID);
567 if (FAILED(hr))
569 HeapFree(GetProcessHeap(), 0, categories);
570 return hr;
573 return hr;
576 /**********************************************************************
577 * COMCAT_ICatInformation_IsClassOfCategories
579 static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories(
580 LPCATINFORMATION iface,
581 REFCLSID rclsid,
582 ULONG cImplemented,
583 CATID *rgcatidImpl,
584 ULONG cRequired,
585 CATID *rgcatidReq)
587 WCHAR keyname[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
588 HRESULT res;
589 struct class_categories *categories;
590 HKEY key;
592 if (TRACE_ON(ole)) {
593 ULONG count;
594 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid),cImplemented);
595 for (count = 0; count < cImplemented; ++count)
596 TRACE(" %s\n",debugstr_guid(&rgcatidImpl[count]));
597 TRACE("Required %u\n",cRequired);
598 for (count = 0; count < cRequired; ++count)
599 TRACE(" %s\n",debugstr_guid(&rgcatidReq[count]));
602 if ((cImplemented && rgcatidImpl == NULL) ||
603 (cRequired && rgcatidReq == NULL)) return E_POINTER;
605 res = StringFromGUID2(rclsid, keyname + 6, CHARS_IN_GUID);
606 if (FAILED(res)) return res;
608 categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
609 cRequired, rgcatidReq);
610 if (categories == NULL) return E_OUTOFMEMORY;
612 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &key);
613 if (res == ERROR_SUCCESS) {
614 res = COMCAT_IsClassOfCategories(key, categories);
615 RegCloseKey(key);
616 } else res = S_FALSE;
618 HeapFree(GetProcessHeap(), 0, categories);
620 return res;
623 /**********************************************************************
624 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
626 static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass(
627 LPCATINFORMATION iface,
628 REFCLSID rclsid,
629 LPENUMCATID *ppenumCATID)
631 TRACE("%s\n",debugstr_guid(rclsid));
633 if (rclsid == NULL || ppenumCATID == NULL)
634 return E_POINTER;
636 return CATIDEnumGUID_Construct(rclsid, L"\\Implemented Categories", ppenumCATID);
639 /**********************************************************************
640 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
642 static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass(
643 LPCATINFORMATION iface,
644 REFCLSID rclsid,
645 LPENUMCATID *ppenumCATID)
647 TRACE("%s\n",debugstr_guid(rclsid));
649 if (rclsid == NULL || ppenumCATID == NULL)
650 return E_POINTER;
652 return CATIDEnumGUID_Construct(rclsid, L"\\Required Categories", ppenumCATID);
655 /**********************************************************************
656 * COMCAT_ICatRegister_Vtbl
658 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl =
660 COMCAT_ICatRegister_QueryInterface,
661 COMCAT_ICatRegister_AddRef,
662 COMCAT_ICatRegister_Release,
663 COMCAT_ICatRegister_RegisterCategories,
664 COMCAT_ICatRegister_UnRegisterCategories,
665 COMCAT_ICatRegister_RegisterClassImplCategories,
666 COMCAT_ICatRegister_UnRegisterClassImplCategories,
667 COMCAT_ICatRegister_RegisterClassReqCategories,
668 COMCAT_ICatRegister_UnRegisterClassReqCategories
672 /**********************************************************************
673 * COMCAT_ICatInformation_Vtbl
675 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl =
677 COMCAT_ICatInformation_QueryInterface,
678 COMCAT_ICatInformation_AddRef,
679 COMCAT_ICatInformation_Release,
680 COMCAT_ICatInformation_EnumCategories,
681 COMCAT_ICatInformation_GetCategoryDesc,
682 COMCAT_ICatInformation_EnumClassesOfCategories,
683 COMCAT_ICatInformation_IsClassOfCategories,
684 COMCAT_ICatInformation_EnumImplCategoriesOfClass,
685 COMCAT_ICatInformation_EnumReqCategoriesOfClass
688 HRESULT WINAPI ComCat_CreateInstance(IClassFactory *iface, IUnknown *pUnkOuter, REFIID riid, void **ppvObj)
690 HRESULT res;
691 TRACE("%s\n",debugstr_guid(riid));
693 if (ppvObj == NULL) return E_POINTER;
695 /* Don't support aggregation (Windows doesn't) */
696 if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
698 res = ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
699 if (SUCCEEDED(res)) {
700 return res;
703 return CLASS_E_CLASSNOTAVAILABLE;
706 /**********************************************************************
707 * IEnumCATEGORYINFO implementation
709 * This implementation is not thread-safe. The manager itself is, but
710 * I can't imagine a valid use of an enumerator in several threads.
712 typedef struct
714 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface;
715 LONG ref;
716 LCID lcid;
717 HKEY key;
718 DWORD next_index;
719 } IEnumCATEGORYINFOImpl;
721 static inline IEnumCATEGORYINFOImpl *impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO *iface)
723 return CONTAINING_RECORD(iface, IEnumCATEGORYINFOImpl, IEnumCATEGORYINFO_iface);
726 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO *iface)
728 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
730 TRACE("\n");
732 return InterlockedIncrement(&This->ref);
735 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface(
736 IEnumCATEGORYINFO *iface,
737 REFIID riid,
738 LPVOID *ppvObj)
740 TRACE("%s\n",debugstr_guid(riid));
742 if (ppvObj == NULL) return E_POINTER;
744 if (IsEqualGUID(riid, &IID_IUnknown) ||
745 IsEqualGUID(riid, &IID_IEnumCATEGORYINFO))
747 *ppvObj = iface;
748 COMCAT_IEnumCATEGORYINFO_AddRef(iface);
749 return S_OK;
752 return E_NOINTERFACE;
755 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO *iface)
757 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
758 ULONG ref;
760 TRACE("\n");
762 ref = InterlockedDecrement(&This->ref);
763 if (ref == 0) {
764 if (This->key) RegCloseKey(This->key);
765 HeapFree(GetProcessHeap(), 0, This);
766 return 0;
768 return ref;
771 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Next(
772 IEnumCATEGORYINFO *iface,
773 ULONG celt,
774 CATEGORYINFO *rgelt,
775 ULONG *pceltFetched)
777 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
778 ULONG fetched = 0;
780 TRACE("\n");
782 if (rgelt == NULL) return E_POINTER;
784 if (This->key) while (fetched < celt) {
785 LSTATUS res;
786 HRESULT hr;
787 WCHAR catid[CHARS_IN_GUID];
788 DWORD cName = CHARS_IN_GUID;
789 HKEY subkey;
791 res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
792 NULL, NULL, NULL, NULL);
793 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
794 ++(This->next_index);
796 hr = CLSIDFromString(catid, &rgelt->catid);
797 if (FAILED(hr)) continue;
799 res = open_classes_key(This->key, catid, KEY_READ, &subkey);
800 if (res != ERROR_SUCCESS) continue;
802 hr = COMCAT_GetCategoryDesc(subkey, This->lcid,
803 rgelt->szDescription, 128);
804 RegCloseKey(subkey);
805 if (FAILED(hr)) continue;
807 rgelt->lcid = This->lcid;
808 ++fetched;
809 ++rgelt;
812 if (pceltFetched) *pceltFetched = fetched;
813 return fetched == celt ? S_OK : S_FALSE;
816 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Skip(
817 IEnumCATEGORYINFO *iface,
818 ULONG celt)
820 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
822 TRACE("\n");
824 This->next_index += celt;
825 /* This should return S_FALSE when there aren't celt elems to skip. */
826 return S_OK;
829 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO *iface)
831 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
833 TRACE("\n");
835 This->next_index = 0;
836 return S_OK;
839 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Clone(
840 IEnumCATEGORYINFO *iface,
841 IEnumCATEGORYINFO **ppenum)
843 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
844 IEnumCATEGORYINFOImpl *new_this;
846 TRACE("\n");
848 if (ppenum == NULL) return E_POINTER;
850 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
851 if (new_this == NULL) return E_OUTOFMEMORY;
853 new_this->IEnumCATEGORYINFO_iface = This->IEnumCATEGORYINFO_iface;
854 new_this->ref = 1;
855 new_this->lcid = This->lcid;
856 /* FIXME: could we more efficiently use DuplicateHandle? */
857 open_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ, &new_this->key);
858 new_this->next_index = This->next_index;
860 *ppenum = &new_this->IEnumCATEGORYINFO_iface;
861 return S_OK;
864 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl =
866 COMCAT_IEnumCATEGORYINFO_QueryInterface,
867 COMCAT_IEnumCATEGORYINFO_AddRef,
868 COMCAT_IEnumCATEGORYINFO_Release,
869 COMCAT_IEnumCATEGORYINFO_Next,
870 COMCAT_IEnumCATEGORYINFO_Skip,
871 COMCAT_IEnumCATEGORYINFO_Reset,
872 COMCAT_IEnumCATEGORYINFO_Clone
875 static HRESULT EnumCATEGORYINFO_Construct(LCID lcid, IEnumCATEGORYINFO **ret)
877 IEnumCATEGORYINFOImpl *This;
879 *ret = NULL;
881 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
882 if (!This) return E_OUTOFMEMORY;
884 This->IEnumCATEGORYINFO_iface.lpVtbl = &COMCAT_IEnumCATEGORYINFO_Vtbl;
885 This->ref = 1;
886 This->lcid = lcid;
887 open_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ, &This->key);
889 *ret = &This->IEnumCATEGORYINFO_iface;
890 return S_OK;
893 /**********************************************************************
894 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
896 * This implementation is not thread-safe. The manager itself is, but
897 * I can't imagine a valid use of an enumerator in several threads.
899 typedef struct
901 IEnumGUID IEnumGUID_iface;
902 LONG ref;
903 struct class_categories *categories;
904 HKEY key;
905 DWORD next_index;
906 } CLSID_IEnumGUIDImpl;
908 static inline CLSID_IEnumGUIDImpl *impl_from_IEnumCLSID(IEnumGUID *iface)
910 return CONTAINING_RECORD(iface, CLSID_IEnumGUIDImpl, IEnumGUID_iface);
913 static HRESULT WINAPI CLSIDEnumGUID_QueryInterface(
914 IEnumGUID *iface,
915 REFIID riid,
916 LPVOID *ppvObj)
918 TRACE("%s\n",debugstr_guid(riid));
920 if (ppvObj == NULL) return E_POINTER;
922 if (IsEqualGUID(riid, &IID_IUnknown) ||
923 IsEqualGUID(riid, &IID_IEnumGUID))
925 *ppvObj = iface;
926 IEnumGUID_AddRef(iface);
927 return S_OK;
930 return E_NOINTERFACE;
933 static ULONG WINAPI CLSIDEnumGUID_AddRef(IEnumGUID *iface)
935 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
936 TRACE("\n");
938 return InterlockedIncrement(&This->ref);
941 static ULONG WINAPI CLSIDEnumGUID_Release(IEnumGUID *iface)
943 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
944 ULONG ref;
946 TRACE("\n");
948 ref = InterlockedDecrement(&This->ref);
949 if (ref == 0) {
950 if (This->key) RegCloseKey(This->key);
951 HeapFree(GetProcessHeap(), 0, This->categories);
952 HeapFree(GetProcessHeap(), 0, This);
953 return 0;
955 return ref;
958 static HRESULT WINAPI CLSIDEnumGUID_Next(
959 IEnumGUID *iface,
960 ULONG celt,
961 GUID *rgelt,
962 ULONG *pceltFetched)
964 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
965 ULONG fetched = 0;
967 TRACE("\n");
969 if (rgelt == NULL) return E_POINTER;
971 if (This->key) while (fetched < celt) {
972 LSTATUS res;
973 HRESULT hr;
974 WCHAR clsid[CHARS_IN_GUID];
975 DWORD cName = CHARS_IN_GUID;
976 HKEY subkey;
978 res = RegEnumKeyExW(This->key, This->next_index, clsid, &cName,
979 NULL, NULL, NULL, NULL);
980 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
981 ++(This->next_index);
983 hr = CLSIDFromString(clsid, rgelt);
984 if (FAILED(hr)) continue;
986 res = open_classes_key(This->key, clsid, KEY_READ, &subkey);
987 if (res != ERROR_SUCCESS) continue;
989 hr = COMCAT_IsClassOfCategories(subkey, This->categories);
990 RegCloseKey(subkey);
991 if (hr != S_OK) continue;
993 ++fetched;
994 ++rgelt;
997 if (pceltFetched) *pceltFetched = fetched;
998 return fetched == celt ? S_OK : S_FALSE;
1001 static HRESULT WINAPI CLSIDEnumGUID_Skip(
1002 IEnumGUID *iface,
1003 ULONG celt)
1005 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
1007 TRACE("\n");
1009 This->next_index += celt;
1010 FIXME("Never returns S_FALSE\n");
1011 return S_OK;
1014 static HRESULT WINAPI CLSIDEnumGUID_Reset(IEnumGUID *iface)
1016 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
1018 TRACE("\n");
1020 This->next_index = 0;
1021 return S_OK;
1024 static HRESULT WINAPI CLSIDEnumGUID_Clone(
1025 IEnumGUID *iface,
1026 IEnumGUID **ppenum)
1028 CLSID_IEnumGUIDImpl *This = impl_from_IEnumCLSID(iface);
1029 CLSID_IEnumGUIDImpl *cloned;
1031 TRACE("(%p)->(%p)\n", This, ppenum);
1033 if (ppenum == NULL) return E_POINTER;
1035 *ppenum = NULL;
1037 cloned = HeapAlloc(GetProcessHeap(), 0, sizeof(CLSID_IEnumGUIDImpl));
1038 if (cloned == NULL) return E_OUTOFMEMORY;
1040 cloned->IEnumGUID_iface.lpVtbl = This->IEnumGUID_iface.lpVtbl;
1041 cloned->ref = 1;
1043 cloned->categories = HeapAlloc(GetProcessHeap(), 0, This->categories->size);
1044 if (cloned->categories == NULL) {
1045 HeapFree(GetProcessHeap(), 0, cloned);
1046 return E_OUTOFMEMORY;
1048 memcpy(cloned->categories, This->categories, This->categories->size);
1050 cloned->key = NULL;
1051 open_classes_key(HKEY_CLASSES_ROOT, L"CLSID", KEY_READ, &cloned->key);
1052 cloned->next_index = This->next_index;
1054 *ppenum = &cloned->IEnumGUID_iface;
1055 return S_OK;
1058 static const IEnumGUIDVtbl CLSIDEnumGUIDVtbl =
1060 CLSIDEnumGUID_QueryInterface,
1061 CLSIDEnumGUID_AddRef,
1062 CLSIDEnumGUID_Release,
1063 CLSIDEnumGUID_Next,
1064 CLSIDEnumGUID_Skip,
1065 CLSIDEnumGUID_Reset,
1066 CLSIDEnumGUID_Clone
1069 static HRESULT CLSIDEnumGUID_Construct(struct class_categories *categories, IEnumCLSID **ret)
1071 CLSID_IEnumGUIDImpl *This;
1073 *ret = NULL;
1075 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
1076 if (!This) return E_OUTOFMEMORY;
1078 This->IEnumGUID_iface.lpVtbl = &CLSIDEnumGUIDVtbl;
1079 This->ref = 1;
1080 This->categories = categories;
1081 open_classes_key(HKEY_CLASSES_ROOT, L"CLSID", KEY_READ, &This->key);
1083 *ret = &This->IEnumGUID_iface;
1085 return S_OK;
1088 /**********************************************************************
1089 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1091 * This implementation is not thread-safe. The manager itself is, but
1092 * I can't imagine a valid use of an enumerator in several threads.
1094 typedef struct
1096 IEnumGUID IEnumGUID_iface;
1097 LONG ref;
1098 WCHAR keyname[68];
1099 HKEY key;
1100 DWORD next_index;
1101 } CATID_IEnumGUIDImpl;
1103 static inline CATID_IEnumGUIDImpl *impl_from_IEnumCATID(IEnumGUID *iface)
1105 return CONTAINING_RECORD(iface, CATID_IEnumGUIDImpl, IEnumGUID_iface);
1108 static HRESULT WINAPI CATIDEnumGUID_QueryInterface(
1109 IEnumGUID *iface,
1110 REFIID riid,
1111 LPVOID *ppvObj)
1113 TRACE("%s\n",debugstr_guid(riid));
1115 if (ppvObj == NULL) return E_POINTER;
1117 if (IsEqualGUID(riid, &IID_IUnknown) ||
1118 IsEqualGUID(riid, &IID_IEnumGUID))
1120 *ppvObj = iface;
1121 IEnumGUID_AddRef(iface);
1122 return S_OK;
1125 return E_NOINTERFACE;
1128 static ULONG WINAPI CATIDEnumGUID_AddRef(IEnumGUID *iface)
1130 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1131 TRACE("\n");
1133 return InterlockedIncrement(&This->ref);
1136 static ULONG WINAPI CATIDEnumGUID_Release(IEnumGUID *iface)
1138 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1139 ULONG ref;
1141 TRACE("\n");
1143 ref = InterlockedDecrement(&This->ref);
1144 if (ref == 0) {
1145 if (This->key) RegCloseKey(This->key);
1146 HeapFree(GetProcessHeap(), 0, This);
1147 return 0;
1149 return ref;
1152 static HRESULT WINAPI CATIDEnumGUID_Next(
1153 IEnumGUID *iface,
1154 ULONG celt,
1155 GUID *rgelt,
1156 ULONG *pceltFetched)
1158 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1159 ULONG fetched = 0;
1161 TRACE("\n");
1163 if (rgelt == NULL) return E_POINTER;
1165 if (This->key) while (fetched < celt) {
1166 LSTATUS res;
1167 HRESULT hr;
1168 WCHAR catid[CHARS_IN_GUID];
1169 DWORD cName = CHARS_IN_GUID;
1171 res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
1172 NULL, NULL, NULL, NULL);
1173 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
1174 ++(This->next_index);
1176 hr = CLSIDFromString(catid, rgelt);
1177 if (FAILED(hr)) continue;
1179 ++fetched;
1180 ++rgelt;
1183 if (pceltFetched) *pceltFetched = fetched;
1184 return fetched == celt ? S_OK : S_FALSE;
1187 static HRESULT WINAPI CATIDEnumGUID_Skip(
1188 IEnumGUID *iface,
1189 ULONG celt)
1191 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1193 TRACE("\n");
1195 This->next_index += celt;
1196 FIXME("Never returns S_FALSE\n");
1197 return S_OK;
1200 static HRESULT WINAPI CATIDEnumGUID_Reset(IEnumGUID *iface)
1202 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1204 TRACE("\n");
1206 This->next_index = 0;
1207 return S_OK;
1210 static HRESULT WINAPI CATIDEnumGUID_Clone(
1211 IEnumGUID *iface,
1212 IEnumGUID **ppenum)
1214 CATID_IEnumGUIDImpl *This = impl_from_IEnumCATID(iface);
1215 CATID_IEnumGUIDImpl *new_this;
1217 TRACE("\n");
1219 if (ppenum == NULL) return E_POINTER;
1221 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
1222 if (new_this == NULL) return E_OUTOFMEMORY;
1224 new_this->IEnumGUID_iface.lpVtbl = This->IEnumGUID_iface.lpVtbl;
1225 new_this->ref = 1;
1226 lstrcpyW(new_this->keyname, This->keyname);
1227 /* FIXME: could we more efficiently use DuplicateHandle? */
1228 open_classes_key(HKEY_CLASSES_ROOT, new_this->keyname, KEY_READ, &new_this->key);
1229 new_this->next_index = This->next_index;
1231 *ppenum = &new_this->IEnumGUID_iface;
1232 return S_OK;
1235 static const IEnumGUIDVtbl CATIDEnumGUIDVtbl =
1237 CATIDEnumGUID_QueryInterface,
1238 CATIDEnumGUID_AddRef,
1239 CATIDEnumGUID_Release,
1240 CATIDEnumGUID_Next,
1241 CATIDEnumGUID_Skip,
1242 CATIDEnumGUID_Reset,
1243 CATIDEnumGUID_Clone
1246 static HRESULT CATIDEnumGUID_Construct(REFCLSID rclsid, LPCWSTR postfix, IEnumGUID **ret)
1248 WCHAR keyname[100], clsidW[CHARS_IN_GUID];
1249 CATID_IEnumGUIDImpl *This;
1251 *ret = NULL;
1253 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
1254 if (!This) return E_OUTOFMEMORY;
1256 StringFromGUID2(rclsid, clsidW, CHARS_IN_GUID);
1258 This->IEnumGUID_iface.lpVtbl = &CATIDEnumGUIDVtbl;
1259 This->ref = 1;
1260 lstrcpyW(keyname, L"CLSID\\");
1261 lstrcatW(keyname, clsidW);
1262 lstrcatW(keyname, postfix);
1264 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &This->key);
1266 *ret = &This->IEnumGUID_iface;
1267 return S_OK;