[OLE32]
[reactos.git] / reactos / dll / win32 / ole32 / comcat.c
1 /*
2 * Comcat implementation
3 *
4 * Copyright (C) 2002 John K. Hohm
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "precomp.h"
22
23 WINE_DEFAULT_DEBUG_CHANNEL(ole);
24
25 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl;
26 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl;
27
28 typedef struct
29 {
30 ICatRegister ICatRegister_iface;
31 ICatInformation ICatInformation_iface;
32 } ComCatMgrImpl;
33
34 /* static ComCatMgr instance */
35 static ComCatMgrImpl COMCAT_ComCatMgr =
36 {
37 { &COMCAT_ICatRegister_Vtbl },
38 { &COMCAT_ICatInformation_Vtbl }
39 };
40
41 struct class_categories {
42 LPCWSTR impl_strings;
43 LPCWSTR req_strings;
44 };
45
46 static IEnumCATEGORYINFO *COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid);
47 static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(struct class_categories *class_categories);
48 static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(REFCLSID rclsid, LPCWSTR impl_req);
49
50 /**********************************************************************
51 * File-scope string constants
52 */
53 static const WCHAR comcat_keyname[] = {
54 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
55 static const WCHAR impl_keyname[] = {
56 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
57 static const WCHAR req_keyname[] = {
58 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
59 static const WCHAR clsid_keyname[] = { 'C','L','S','I','D',0 };
60
61
62 /**********************************************************************
63 * COMCAT_RegisterClassCategories
64 */
65 static HRESULT COMCAT_RegisterClassCategories(
66 REFCLSID rclsid,
67 LPCWSTR type,
68 ULONG cCategories,
69 const CATID *rgcatid)
70 {
71 WCHAR keyname[39];
72 HRESULT res;
73 HKEY clsid_key, class_key, type_key;
74
75 if (cCategories && rgcatid == NULL) return E_POINTER;
76
77 /* Format the class key name. */
78 res = StringFromGUID2(rclsid, keyname, 39);
79 if (FAILED(res)) return res;
80
81 /* Create (or open) the CLSID key. */
82 res = create_classes_key(HKEY_CLASSES_ROOT, clsid_keyname, KEY_READ|KEY_WRITE, &clsid_key);
83 if (res != ERROR_SUCCESS) return E_FAIL;
84
85 /* Create (or open) the class key. */
86 res = create_classes_key(clsid_key, keyname, KEY_READ|KEY_WRITE, &class_key);
87 if (res == ERROR_SUCCESS) {
88 /* Create (or open) the category type key. */
89 res = create_classes_key(class_key, type, KEY_READ|KEY_WRITE, &type_key);
90 if (res == ERROR_SUCCESS) {
91 for (; cCategories; --cCategories, ++rgcatid) {
92 HKEY key;
93
94 /* Format the category key name. */
95 res = StringFromGUID2(rgcatid, keyname, 39);
96 if (FAILED(res)) continue;
97
98 /* Do the register. */
99 res = create_classes_key(type_key, keyname, KEY_READ|KEY_WRITE, &key);
100 if (res == ERROR_SUCCESS) RegCloseKey(key);
101 }
102 res = S_OK;
103 } else res = E_FAIL;
104 RegCloseKey(class_key);
105 } else res = E_FAIL;
106 RegCloseKey(clsid_key);
107
108 return res;
109 }
110
111 /**********************************************************************
112 * COMCAT_UnRegisterClassCategories
113 */
114 static HRESULT COMCAT_UnRegisterClassCategories(
115 REFCLSID rclsid,
116 LPCWSTR type,
117 ULONG cCategories,
118 const CATID *rgcatid)
119 {
120 WCHAR keyname[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
121 HRESULT res;
122 HKEY type_key;
123
124 if (cCategories && rgcatid == NULL) return E_POINTER;
125
126 /* Format the class category type key name. */
127 res = StringFromGUID2(rclsid, keyname + 6, 39);
128 if (FAILED(res)) return res;
129 keyname[44] = '\\';
130 lstrcpyW(keyname + 45, type);
131
132 /* Open the class category type key. */
133 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ|KEY_WRITE, &type_key);
134 if (res != ERROR_SUCCESS) return E_FAIL;
135
136 for (; cCategories; --cCategories, ++rgcatid) {
137 /* Format the category key name. */
138 res = StringFromGUID2(rgcatid, keyname, 39);
139 if (FAILED(res)) continue;
140
141 /* Do the unregister. */
142 RegDeleteKeyW(type_key, keyname);
143 }
144 RegCloseKey(type_key);
145
146 return S_OK;
147 }
148
149 /**********************************************************************
150 * COMCAT_GetCategoryDesc
151 */
152 static HRESULT COMCAT_GetCategoryDesc(HKEY key, LCID lcid, PWCHAR pszDesc,
153 ULONG buf_wchars)
154 {
155 static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
156 WCHAR valname[5];
157 HRESULT res;
158 DWORD type, size = (buf_wchars - 1) * sizeof(WCHAR);
159
160 if (pszDesc == NULL) return E_INVALIDARG;
161
162 /* FIXME: lcid comparisons are more complex than this! */
163 wsprintfW(valname, fmt, lcid);
164 res = RegQueryValueExW(key, valname, 0, &type, (LPBYTE)pszDesc, &size);
165 if (res != ERROR_SUCCESS || type != REG_SZ) {
166 FIXME("Simplified lcid comparison\n");
167 return CAT_E_NODESCRIPTION;
168 }
169 pszDesc[size / sizeof(WCHAR)] = 0;
170
171 return S_OK;
172 }
173
174 /**********************************************************************
175 * COMCAT_PrepareClassCategories
176 */
177 static struct class_categories *COMCAT_PrepareClassCategories(
178 ULONG impl_count, const CATID *impl_catids, ULONG req_count, const CATID *req_catids)
179 {
180 struct class_categories *categories;
181 WCHAR *strings;
182
183 categories = HeapAlloc(
184 GetProcessHeap(), HEAP_ZERO_MEMORY,
185 sizeof(struct class_categories) +
186 ((impl_count + req_count) * 39 + 2) * sizeof(WCHAR));
187 if (categories == NULL) return categories;
188
189 strings = (WCHAR *)(categories + 1);
190 categories->impl_strings = strings;
191 while (impl_count--) {
192 StringFromGUID2(impl_catids++, strings, 39);
193 strings += 39;
194 }
195 *strings++ = 0;
196
197 categories->req_strings = strings;
198 while (req_count--) {
199 StringFromGUID2(req_catids++, strings, 39);
200 strings += 39;
201 }
202 *strings++ = 0;
203
204 return categories;
205 }
206
207 /**********************************************************************
208 * COMCAT_IsClassOfCategories
209 */
210 static HRESULT COMCAT_IsClassOfCategories(
211 HKEY key,
212 struct class_categories const* categories)
213 {
214 HKEY subkey;
215 HRESULT res;
216 DWORD index;
217 LPCWSTR string;
218
219 /* Check that every given category is implemented by class. */
220 if (*categories->impl_strings) {
221 res = open_classes_key(key, impl_keyname, KEY_READ, &subkey);
222 if (res != ERROR_SUCCESS) return S_FALSE;
223 for (string = categories->impl_strings; *string; string += 39) {
224 HKEY catkey;
225 res = open_classes_key(subkey, string, 0, &catkey);
226 if (res != ERROR_SUCCESS) {
227 RegCloseKey(subkey);
228 return S_FALSE;
229 }
230 RegCloseKey(catkey);
231 }
232 RegCloseKey(subkey);
233 }
234
235 /* Check that all categories required by class are given. */
236 res = open_classes_key(key, req_keyname, KEY_READ, &subkey);
237 if (res == ERROR_SUCCESS) {
238 for (index = 0; ; ++index) {
239 WCHAR keyname[39];
240 DWORD size = 39;
241
242 res = RegEnumKeyExW(subkey, index, keyname, &size,
243 NULL, NULL, NULL, NULL);
244 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
245 if (size != 38) continue; /* bogus catid in registry */
246 for (string = categories->req_strings; *string; string += 39)
247 if (!strcmpiW(string, keyname)) break;
248 if (!*string) {
249 RegCloseKey(subkey);
250 return S_FALSE;
251 }
252 }
253 RegCloseKey(subkey);
254 }
255
256 return S_OK;
257 }
258
259 /**********************************************************************
260 * COMCAT_ICatRegister_QueryInterface
261 */
262 static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface(
263 LPCATREGISTER iface,
264 REFIID riid,
265 LPVOID *ppvObj)
266 {
267 TRACE("%s\n",debugstr_guid(riid));
268
269 if (ppvObj == NULL) return E_POINTER;
270
271 if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ICatRegister)) {
272 *ppvObj = iface;
273 ICatRegister_AddRef(iface);
274 return S_OK;
275 }
276
277 if (IsEqualGUID(riid, &IID_ICatInformation)) {
278 *ppvObj = &COMCAT_ComCatMgr.ICatInformation_iface;
279 ICatRegister_AddRef(iface);
280 return S_OK;
281 }
282
283 return E_NOINTERFACE;
284 }
285
286 /**********************************************************************
287 * COMCAT_ICatRegister_AddRef
288 */
289 static ULONG WINAPI COMCAT_ICatRegister_AddRef(LPCATREGISTER iface)
290 {
291 return 2; /* non-heap based object */
292 }
293
294 /**********************************************************************
295 * COMCAT_ICatRegister_Release
296 */
297 static ULONG WINAPI COMCAT_ICatRegister_Release(LPCATREGISTER iface)
298 {
299 return 1; /* non-heap based object */
300 }
301
302 /**********************************************************************
303 * COMCAT_ICatRegister_RegisterCategories
304 */
305 static HRESULT WINAPI COMCAT_ICatRegister_RegisterCategories(
306 LPCATREGISTER iface,
307 ULONG cCategories,
308 CATEGORYINFO *rgci)
309 {
310 HKEY comcat_key;
311 HRESULT res;
312
313 TRACE("\n");
314
315 if (cCategories && rgci == NULL)
316 return E_POINTER;
317
318 /* Create (or open) the component categories key. */
319 res = create_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ|KEY_WRITE, &comcat_key);
320 if (res != ERROR_SUCCESS) return E_FAIL;
321
322 for (; cCategories; --cCategories, ++rgci) {
323 static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
324 WCHAR keyname[39];
325 WCHAR valname[9];
326 HKEY cat_key;
327
328 /* Create (or open) the key for this category. */
329 if (!StringFromGUID2(&rgci->catid, keyname, 39)) continue;
330 res = create_classes_key(comcat_key, keyname, KEY_READ|KEY_WRITE, &cat_key);
331 if (res != ERROR_SUCCESS) continue;
332
333 /* Set the value for this locale's description. */
334 wsprintfW(valname, fmt, rgci->lcid);
335 RegSetValueExW(cat_key, valname, 0, REG_SZ,
336 (CONST BYTE*)(rgci->szDescription),
337 (lstrlenW(rgci->szDescription) + 1) * sizeof(WCHAR));
338
339 RegCloseKey(cat_key);
340 }
341
342 RegCloseKey(comcat_key);
343 return S_OK;
344 }
345
346 /**********************************************************************
347 * COMCAT_ICatRegister_UnRegisterCategories
348 */
349 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterCategories(
350 LPCATREGISTER iface,
351 ULONG cCategories,
352 CATID *rgcatid)
353 {
354 HKEY comcat_key;
355 HRESULT res;
356
357 TRACE("\n");
358
359 if (cCategories && rgcatid == NULL)
360 return E_POINTER;
361
362 /* Open the component categories key. */
363 res = open_classes_key(HKEY_CLASSES_ROOT, comcat_keyname, KEY_READ|KEY_WRITE, &comcat_key);
364 if (res != ERROR_SUCCESS) return E_FAIL;
365
366 for (; cCategories; --cCategories, ++rgcatid) {
367 WCHAR keyname[39];
368
369 /* Delete the key for this category. */
370 if (!StringFromGUID2(rgcatid, keyname, 39)) continue;
371 RegDeleteKeyW(comcat_key, keyname);
372 }
373
374 RegCloseKey(comcat_key);
375 return S_OK;
376 }
377
378 /**********************************************************************
379 * COMCAT_ICatRegister_RegisterClassImplCategories
380 */
381 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassImplCategories(
382 LPCATREGISTER iface,
383 REFCLSID rclsid,
384 ULONG cCategories,
385 CATID *rgcatid)
386 {
387 TRACE("\n");
388
389 return COMCAT_RegisterClassCategories(
390 rclsid, impl_keyname, cCategories, rgcatid);
391 }
392
393 /**********************************************************************
394 * COMCAT_ICatRegister_UnRegisterClassImplCategories
395 */
396 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassImplCategories(
397 LPCATREGISTER iface,
398 REFCLSID rclsid,
399 ULONG cCategories,
400 CATID *rgcatid)
401 {
402 TRACE("\n");
403
404 return COMCAT_UnRegisterClassCategories(
405 rclsid, impl_keyname, cCategories, rgcatid);
406 }
407
408 /**********************************************************************
409 * COMCAT_ICatRegister_RegisterClassReqCategories
410 */
411 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassReqCategories(
412 LPCATREGISTER iface,
413 REFCLSID rclsid,
414 ULONG cCategories,
415 CATID *rgcatid)
416 {
417 TRACE("\n");
418
419 return COMCAT_RegisterClassCategories(
420 rclsid, req_keyname, cCategories, rgcatid);
421 }
422
423 /**********************************************************************
424 * COMCAT_ICatRegister_UnRegisterClassReqCategories
425 */
426 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassReqCategories(
427 LPCATREGISTER iface,
428 REFCLSID rclsid,
429 ULONG cCategories,
430 CATID *rgcatid)
431 {
432 TRACE("\n");
433
434 return COMCAT_UnRegisterClassCategories(
435 rclsid, req_keyname, cCategories, rgcatid);
436 }
437
438 /**********************************************************************
439 * COMCAT_ICatInformation_QueryInterface
440 */
441 static HRESULT WINAPI COMCAT_ICatInformation_QueryInterface(
442 LPCATINFORMATION iface,
443 REFIID riid,
444 LPVOID *ppvObj)
445 {
446 return ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
447 }
448
449 /**********************************************************************
450 * COMCAT_ICatInformation_AddRef
451 */
452 static ULONG WINAPI COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface)
453 {
454 return ICatRegister_AddRef(&COMCAT_ComCatMgr.ICatRegister_iface);
455 }
456
457 /**********************************************************************
458 * COMCAT_ICatInformation_Release
459 */
460 static ULONG WINAPI COMCAT_ICatInformation_Release(LPCATINFORMATION iface)
461 {
462 return ICatRegister_Release(&COMCAT_ComCatMgr.ICatRegister_iface);
463 }
464
465 /**********************************************************************
466 * COMCAT_ICatInformation_EnumCategories
467 */
468 static HRESULT WINAPI COMCAT_ICatInformation_EnumCategories(
469 LPCATINFORMATION iface,
470 LCID lcid,
471 IEnumCATEGORYINFO **ppenumCatInfo)
472 {
473 TRACE("\n");
474
475 if (ppenumCatInfo == NULL) return E_POINTER;
476
477 *ppenumCatInfo = COMCAT_IEnumCATEGORYINFO_Construct(lcid);
478 if (*ppenumCatInfo == NULL) return E_OUTOFMEMORY;
479 IEnumCATEGORYINFO_AddRef(*ppenumCatInfo);
480 return S_OK;
481 }
482
483 /**********************************************************************
484 * COMCAT_ICatInformation_GetCategoryDesc
485 */
486 static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc(
487 LPCATINFORMATION iface,
488 REFCATID rcatid,
489 LCID lcid,
490 PWCHAR *ppszDesc)
491 {
492 WCHAR keyname[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
493 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
494 'r', 'i', 'e', 's', '\\', 0 };
495 HKEY key;
496 HRESULT res;
497
498 TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid), lcid);
499
500 if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG;
501
502 /* Open the key for this category. */
503 if (!StringFromGUID2(rcatid, keyname + 21, 39)) return E_FAIL;
504 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &key);
505 if (res != ERROR_SUCCESS) return CAT_E_CATIDNOEXIST;
506
507 /* Allocate a sensible amount of memory for the description. */
508 *ppszDesc = CoTaskMemAlloc(128 * sizeof(WCHAR));
509 if (*ppszDesc == NULL) {
510 RegCloseKey(key);
511 return E_OUTOFMEMORY;
512 }
513
514 /* Get the description, and make sure it's null terminated. */
515 res = COMCAT_GetCategoryDesc(key, lcid, *ppszDesc, 128);
516 RegCloseKey(key);
517 if (FAILED(res)) {
518 CoTaskMemFree(*ppszDesc);
519 return res;
520 }
521
522 return S_OK;
523 }
524
525 /**********************************************************************
526 * COMCAT_ICatInformation_EnumClassesOfCategories
527 */
528 static HRESULT WINAPI COMCAT_ICatInformation_EnumClassesOfCategories(
529 LPCATINFORMATION iface,
530 ULONG cImplemented,
531 CATID *rgcatidImpl,
532 ULONG cRequired,
533 CATID *rgcatidReq,
534 LPENUMCLSID *ppenumCLSID)
535 {
536 struct class_categories *categories;
537
538 TRACE("\n");
539
540 if (cImplemented == (ULONG)-1)
541 cImplemented = 0;
542 if (cRequired == (ULONG)-1)
543 cRequired = 0;
544
545 if (ppenumCLSID == NULL ||
546 (cImplemented && rgcatidImpl == NULL) ||
547 (cRequired && rgcatidReq == NULL)) return E_POINTER;
548
549 categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
550 cRequired, rgcatidReq);
551 if (categories == NULL) return E_OUTOFMEMORY;
552 *ppenumCLSID = COMCAT_CLSID_IEnumGUID_Construct(categories);
553 if (*ppenumCLSID == NULL) {
554 HeapFree(GetProcessHeap(), 0, categories);
555 return E_OUTOFMEMORY;
556 }
557 IEnumGUID_AddRef(*ppenumCLSID);
558 return S_OK;
559 }
560
561 /**********************************************************************
562 * COMCAT_ICatInformation_IsClassOfCategories
563 */
564 static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories(
565 LPCATINFORMATION iface,
566 REFCLSID rclsid,
567 ULONG cImplemented,
568 CATID *rgcatidImpl,
569 ULONG cRequired,
570 CATID *rgcatidReq)
571 {
572 WCHAR keyname[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
573 HRESULT res;
574 struct class_categories *categories;
575 HKEY key;
576
577 if (TRACE_ON(ole)) {
578 ULONG count;
579 TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid),cImplemented);
580 for (count = 0; count < cImplemented; ++count)
581 TRACE(" %s\n",debugstr_guid(&rgcatidImpl[count]));
582 TRACE("Required %u\n",cRequired);
583 for (count = 0; count < cRequired; ++count)
584 TRACE(" %s\n",debugstr_guid(&rgcatidReq[count]));
585 }
586
587 if ((cImplemented && rgcatidImpl == NULL) ||
588 (cRequired && rgcatidReq == NULL)) return E_POINTER;
589
590 res = StringFromGUID2(rclsid, keyname + 6, 39);
591 if (FAILED(res)) return res;
592
593 categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
594 cRequired, rgcatidReq);
595 if (categories == NULL) return E_OUTOFMEMORY;
596
597 res = open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &key);
598 if (res == ERROR_SUCCESS) {
599 res = COMCAT_IsClassOfCategories(key, categories);
600 RegCloseKey(key);
601 } else res = S_FALSE;
602
603 HeapFree(GetProcessHeap(), 0, categories);
604
605 return res;
606 }
607
608 /**********************************************************************
609 * COMCAT_ICatInformation_EnumImplCategoriesOfClass
610 */
611 static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass(
612 LPCATINFORMATION iface,
613 REFCLSID rclsid,
614 LPENUMCATID *ppenumCATID)
615 {
616 static const WCHAR postfix[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
617 'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
618 'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
619
620 TRACE("%s\n",debugstr_guid(rclsid));
621
622 if (rclsid == NULL || ppenumCATID == NULL)
623 return E_POINTER;
624
625 *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
626 if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
627 return S_OK;
628 }
629
630 /**********************************************************************
631 * COMCAT_ICatInformation_EnumReqCategoriesOfClass
632 */
633 static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass(
634 LPCATINFORMATION iface,
635 REFCLSID rclsid,
636 LPENUMCATID *ppenumCATID)
637 {
638 static const WCHAR postfix[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
639 'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
640 'r', 'i', 'e', 's', 0 };
641
642 TRACE("%s\n",debugstr_guid(rclsid));
643
644 if (rclsid == NULL || ppenumCATID == NULL)
645 return E_POINTER;
646
647 *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
648 if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
649 return S_OK;
650 }
651
652 /**********************************************************************
653 * COMCAT_ICatRegister_Vtbl
654 */
655 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl =
656 {
657 COMCAT_ICatRegister_QueryInterface,
658 COMCAT_ICatRegister_AddRef,
659 COMCAT_ICatRegister_Release,
660 COMCAT_ICatRegister_RegisterCategories,
661 COMCAT_ICatRegister_UnRegisterCategories,
662 COMCAT_ICatRegister_RegisterClassImplCategories,
663 COMCAT_ICatRegister_UnRegisterClassImplCategories,
664 COMCAT_ICatRegister_RegisterClassReqCategories,
665 COMCAT_ICatRegister_UnRegisterClassReqCategories
666 };
667
668
669 /**********************************************************************
670 * COMCAT_ICatInformation_Vtbl
671 */
672 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl =
673 {
674 COMCAT_ICatInformation_QueryInterface,
675 COMCAT_ICatInformation_AddRef,
676 COMCAT_ICatInformation_Release,
677 COMCAT_ICatInformation_EnumCategories,
678 COMCAT_ICatInformation_GetCategoryDesc,
679 COMCAT_ICatInformation_EnumClassesOfCategories,
680 COMCAT_ICatInformation_IsClassOfCategories,
681 COMCAT_ICatInformation_EnumImplCategoriesOfClass,
682 COMCAT_ICatInformation_EnumReqCategoriesOfClass
683 };
684
685 /**********************************************************************
686 * COMCAT_IClassFactory_QueryInterface (also IUnknown)
687 */
688 static HRESULT WINAPI COMCAT_IClassFactory_QueryInterface(
689 LPCLASSFACTORY iface,
690 REFIID riid,
691 LPVOID *ppvObj)
692 {
693 TRACE("%s\n",debugstr_guid(riid));
694
695 if (ppvObj == NULL) return E_POINTER;
696
697 if (IsEqualGUID(riid, &IID_IUnknown) ||
698 IsEqualGUID(riid, &IID_IClassFactory))
699 {
700 *ppvObj = iface;
701 IClassFactory_AddRef(iface);
702 return S_OK;
703 }
704
705 return E_NOINTERFACE;
706 }
707
708 /**********************************************************************
709 * COMCAT_IClassFactory_AddRef (also IUnknown)
710 */
711 static ULONG WINAPI COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface)
712 {
713 return 2; /* non-heap based object */
714 }
715
716 /**********************************************************************
717 * COMCAT_IClassFactory_Release (also IUnknown)
718 */
719 static ULONG WINAPI COMCAT_IClassFactory_Release(LPCLASSFACTORY iface)
720 {
721 return 1; /* non-heap based object */
722 }
723
724 /**********************************************************************
725 * COMCAT_IClassFactory_CreateInstance
726 */
727 static HRESULT WINAPI COMCAT_IClassFactory_CreateInstance(
728 LPCLASSFACTORY iface,
729 LPUNKNOWN pUnkOuter,
730 REFIID riid,
731 LPVOID *ppvObj)
732 {
733 HRESULT res;
734 TRACE("%s\n",debugstr_guid(riid));
735
736 if (ppvObj == NULL) return E_POINTER;
737
738 /* Don't support aggregation (Windows doesn't) */
739 if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
740
741 res = ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
742 if (SUCCEEDED(res)) {
743 return res;
744 }
745
746 return CLASS_E_CLASSNOTAVAILABLE;
747 }
748
749 /**********************************************************************
750 * COMCAT_IClassFactory_LockServer
751 */
752 static HRESULT WINAPI COMCAT_IClassFactory_LockServer(
753 LPCLASSFACTORY iface,
754 BOOL fLock)
755 {
756 FIXME("(%d), stub!\n",fLock);
757 return S_OK;
758 }
759
760 /**********************************************************************
761 * static ClassFactory instance
762 */
763 static const IClassFactoryVtbl ComCatCFVtbl =
764 {
765 COMCAT_IClassFactory_QueryInterface,
766 COMCAT_IClassFactory_AddRef,
767 COMCAT_IClassFactory_Release,
768 COMCAT_IClassFactory_CreateInstance,
769 COMCAT_IClassFactory_LockServer
770 };
771
772 static const IClassFactoryVtbl *ComCatCF = &ComCatCFVtbl;
773
774 HRESULT ComCatCF_Create(REFIID riid, LPVOID *ppv)
775 {
776 return IClassFactory_QueryInterface((IClassFactory *)&ComCatCF, riid, ppv);
777 }
778
779 /**********************************************************************
780 * IEnumCATEGORYINFO implementation
781 *
782 * This implementation is not thread-safe. The manager itself is, but
783 * I can't imagine a valid use of an enumerator in several threads.
784 */
785 typedef struct
786 {
787 IEnumCATEGORYINFO IEnumCATEGORYINFO_iface;
788 LONG ref;
789 LCID lcid;
790 HKEY key;
791 DWORD next_index;
792 } IEnumCATEGORYINFOImpl;
793
794 static inline IEnumCATEGORYINFOImpl *impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO *iface)
795 {
796 return CONTAINING_RECORD(iface, IEnumCATEGORYINFOImpl, IEnumCATEGORYINFO_iface);
797 }
798
799 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO *iface)
800 {
801 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
802
803 TRACE("\n");
804
805 return InterlockedIncrement(&This->ref);
806 }
807
808 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface(
809 IEnumCATEGORYINFO *iface,
810 REFIID riid,
811 LPVOID *ppvObj)
812 {
813 TRACE("%s\n",debugstr_guid(riid));
814
815 if (ppvObj == NULL) return E_POINTER;
816
817 if (IsEqualGUID(riid, &IID_IUnknown) ||
818 IsEqualGUID(riid, &IID_IEnumCATEGORYINFO))
819 {
820 *ppvObj = iface;
821 COMCAT_IEnumCATEGORYINFO_AddRef(iface);
822 return S_OK;
823 }
824
825 return E_NOINTERFACE;
826 }
827
828 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO *iface)
829 {
830 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
831 ULONG ref;
832
833 TRACE("\n");
834
835 ref = InterlockedDecrement(&This->ref);
836 if (ref == 0) {
837 if (This->key) RegCloseKey(This->key);
838 HeapFree(GetProcessHeap(), 0, This);
839 return 0;
840 }
841 return ref;
842 }
843
844 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Next(
845 IEnumCATEGORYINFO *iface,
846 ULONG celt,
847 CATEGORYINFO *rgelt,
848 ULONG *pceltFetched)
849 {
850 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
851 ULONG fetched = 0;
852
853 TRACE("\n");
854
855 if (rgelt == NULL) return E_POINTER;
856
857 if (This->key) while (fetched < celt) {
858 LSTATUS res;
859 HRESULT hr;
860 WCHAR catid[39];
861 DWORD cName = 39;
862 HKEY subkey;
863
864 res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
865 NULL, NULL, NULL, NULL);
866 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
867 ++(This->next_index);
868
869 hr = CLSIDFromString(catid, &rgelt->catid);
870 if (FAILED(hr)) continue;
871
872 res = open_classes_key(This->key, catid, KEY_READ, &subkey);
873 if (res != ERROR_SUCCESS) continue;
874
875 hr = COMCAT_GetCategoryDesc(subkey, This->lcid,
876 rgelt->szDescription, 128);
877 RegCloseKey(subkey);
878 if (FAILED(hr)) continue;
879
880 rgelt->lcid = This->lcid;
881 ++fetched;
882 ++rgelt;
883 }
884
885 if (pceltFetched) *pceltFetched = fetched;
886 return fetched == celt ? S_OK : S_FALSE;
887 }
888
889 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Skip(
890 IEnumCATEGORYINFO *iface,
891 ULONG celt)
892 {
893 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
894
895 TRACE("\n");
896
897 This->next_index += celt;
898 /* This should return S_FALSE when there aren't celt elems to skip. */
899 return S_OK;
900 }
901
902 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO *iface)
903 {
904 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
905
906 TRACE("\n");
907
908 This->next_index = 0;
909 return S_OK;
910 }
911
912 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Clone(
913 IEnumCATEGORYINFO *iface,
914 IEnumCATEGORYINFO **ppenum)
915 {
916 IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
917 static const WCHAR keyname[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
918 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
919 'r', 'i', 'e', 's', 0 };
920 IEnumCATEGORYINFOImpl *new_this;
921
922 TRACE("\n");
923
924 if (ppenum == NULL) return E_POINTER;
925
926 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
927 if (new_this == NULL) return E_OUTOFMEMORY;
928
929 new_this->IEnumCATEGORYINFO_iface = This->IEnumCATEGORYINFO_iface;
930 new_this->ref = 1;
931 new_this->lcid = This->lcid;
932 /* FIXME: could we more efficiently use DuplicateHandle? */
933 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &new_this->key);
934 new_this->next_index = This->next_index;
935
936 *ppenum = &new_this->IEnumCATEGORYINFO_iface;
937 return S_OK;
938 }
939
940 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl =
941 {
942 COMCAT_IEnumCATEGORYINFO_QueryInterface,
943 COMCAT_IEnumCATEGORYINFO_AddRef,
944 COMCAT_IEnumCATEGORYINFO_Release,
945 COMCAT_IEnumCATEGORYINFO_Next,
946 COMCAT_IEnumCATEGORYINFO_Skip,
947 COMCAT_IEnumCATEGORYINFO_Reset,
948 COMCAT_IEnumCATEGORYINFO_Clone
949 };
950
951 static IEnumCATEGORYINFO *COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid)
952 {
953 IEnumCATEGORYINFOImpl *This;
954
955 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
956 if (This) {
957 static const WCHAR keyname[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
958 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
959 'r', 'i', 'e', 's', 0 };
960
961 This->IEnumCATEGORYINFO_iface.lpVtbl = &COMCAT_IEnumCATEGORYINFO_Vtbl;
962 This->lcid = lcid;
963 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &This->key);
964 }
965 return &This->IEnumCATEGORYINFO_iface;
966 }
967
968 /**********************************************************************
969 * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
970 *
971 * This implementation is not thread-safe. The manager itself is, but
972 * I can't imagine a valid use of an enumerator in several threads.
973 */
974 typedef struct
975 {
976 const IEnumGUIDVtbl *lpVtbl;
977 LONG ref;
978 struct class_categories *categories;
979 HKEY key;
980 DWORD next_index;
981 } CLSID_IEnumGUIDImpl;
982
983 static ULONG WINAPI COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface)
984 {
985 CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
986 TRACE("\n");
987
988 return InterlockedIncrement(&This->ref);
989 }
990
991 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_QueryInterface(
992 LPENUMGUID iface,
993 REFIID riid,
994 LPVOID *ppvObj)
995 {
996 TRACE("%s\n",debugstr_guid(riid));
997
998 if (ppvObj == NULL) return E_POINTER;
999
1000 if (IsEqualGUID(riid, &IID_IUnknown) ||
1001 IsEqualGUID(riid, &IID_IEnumGUID))
1002 {
1003 *ppvObj = iface;
1004 COMCAT_CLSID_IEnumGUID_AddRef(iface);
1005 return S_OK;
1006 }
1007
1008 return E_NOINTERFACE;
1009 }
1010
1011 static ULONG WINAPI COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface)
1012 {
1013 CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
1014 ULONG ref;
1015
1016 TRACE("\n");
1017
1018 ref = InterlockedDecrement(&This->ref);
1019 if (ref == 0) {
1020 if (This->key) RegCloseKey(This->key);
1021 HeapFree(GetProcessHeap(), 0, This->categories);
1022 HeapFree(GetProcessHeap(), 0, This);
1023 return 0;
1024 }
1025 return ref;
1026 }
1027
1028 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Next(
1029 LPENUMGUID iface,
1030 ULONG celt,
1031 GUID *rgelt,
1032 ULONG *pceltFetched)
1033 {
1034 CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
1035 ULONG fetched = 0;
1036
1037 TRACE("\n");
1038
1039 if (rgelt == NULL) return E_POINTER;
1040
1041 if (This->key) while (fetched < celt) {
1042 LSTATUS res;
1043 HRESULT hr;
1044 WCHAR clsid[39];
1045 DWORD cName = 39;
1046 HKEY subkey;
1047
1048 res = RegEnumKeyExW(This->key, This->next_index, clsid, &cName,
1049 NULL, NULL, NULL, NULL);
1050 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
1051 ++(This->next_index);
1052
1053 hr = CLSIDFromString(clsid, rgelt);
1054 if (FAILED(hr)) continue;
1055
1056 res = open_classes_key(This->key, clsid, KEY_READ, &subkey);
1057 if (res != ERROR_SUCCESS) continue;
1058
1059 hr = COMCAT_IsClassOfCategories(subkey, This->categories);
1060 RegCloseKey(subkey);
1061 if (hr != S_OK) continue;
1062
1063 ++fetched;
1064 ++rgelt;
1065 }
1066
1067 if (pceltFetched) *pceltFetched = fetched;
1068 return fetched == celt ? S_OK : S_FALSE;
1069 }
1070
1071 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Skip(
1072 LPENUMGUID iface,
1073 ULONG celt)
1074 {
1075 CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
1076
1077 TRACE("\n");
1078
1079 This->next_index += celt;
1080 FIXME("Never returns S_FALSE\n");
1081 return S_OK;
1082 }
1083
1084 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface)
1085 {
1086 CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
1087
1088 TRACE("\n");
1089
1090 This->next_index = 0;
1091 return S_OK;
1092 }
1093
1094 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Clone(
1095 LPENUMGUID iface,
1096 IEnumGUID **ppenum)
1097 {
1098 CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
1099 static const WCHAR keyname[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1100 CLSID_IEnumGUIDImpl *new_this;
1101 DWORD size;
1102
1103 TRACE("\n");
1104
1105 if (ppenum == NULL) return E_POINTER;
1106
1107 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
1108 if (new_this == NULL) return E_OUTOFMEMORY;
1109
1110 new_this->lpVtbl = This->lpVtbl;
1111 new_this->ref = 1;
1112 size = HeapSize(GetProcessHeap(), 0, This->categories);
1113 new_this->categories =
1114 HeapAlloc(GetProcessHeap(), 0, size);
1115 if (new_this->categories == NULL) {
1116 HeapFree(GetProcessHeap(), 0, new_this);
1117 return E_OUTOFMEMORY;
1118 }
1119 memcpy(new_this->categories, This->categories, size);
1120 /* FIXME: could we more efficiently use DuplicateHandle? */
1121 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &new_this->key);
1122 new_this->next_index = This->next_index;
1123
1124 *ppenum = (LPENUMGUID)new_this;
1125 return S_OK;
1126 }
1127
1128 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl =
1129 {
1130 COMCAT_CLSID_IEnumGUID_QueryInterface,
1131 COMCAT_CLSID_IEnumGUID_AddRef,
1132 COMCAT_CLSID_IEnumGUID_Release,
1133 COMCAT_CLSID_IEnumGUID_Next,
1134 COMCAT_CLSID_IEnumGUID_Skip,
1135 COMCAT_CLSID_IEnumGUID_Reset,
1136 COMCAT_CLSID_IEnumGUID_Clone
1137 };
1138
1139 static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(struct class_categories *categories)
1140 {
1141 CLSID_IEnumGUIDImpl *This;
1142
1143 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
1144 if (This) {
1145 static const WCHAR keyname[] = { 'C', 'L', 'S', 'I', 'D', 0 };
1146
1147 This->lpVtbl = &COMCAT_CLSID_IEnumGUID_Vtbl;
1148 This->categories = categories;
1149 open_classes_key(HKEY_CLASSES_ROOT, keyname, KEY_READ, &This->key);
1150 }
1151 return (LPENUMGUID)This;
1152 }
1153
1154 /**********************************************************************
1155 * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
1156 *
1157 * This implementation is not thread-safe. The manager itself is, but
1158 * I can't imagine a valid use of an enumerator in several threads.
1159 */
1160 typedef struct
1161 {
1162 const IEnumGUIDVtbl *lpVtbl;
1163 LONG ref;
1164 WCHAR keyname[68];
1165 HKEY key;
1166 DWORD next_index;
1167 } CATID_IEnumGUIDImpl;
1168
1169 static ULONG WINAPI COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface)
1170 {
1171 CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
1172 TRACE("\n");
1173
1174 return InterlockedIncrement(&This->ref);
1175 }
1176
1177 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_QueryInterface(
1178 LPENUMGUID iface,
1179 REFIID riid,
1180 LPVOID *ppvObj)
1181 {
1182 TRACE("%s\n",debugstr_guid(riid));
1183
1184 if (ppvObj == NULL) return E_POINTER;
1185
1186 if (IsEqualGUID(riid, &IID_IUnknown) ||
1187 IsEqualGUID(riid, &IID_IEnumGUID))
1188 {
1189 *ppvObj = iface;
1190 COMCAT_CATID_IEnumGUID_AddRef(iface);
1191 return S_OK;
1192 }
1193
1194 return E_NOINTERFACE;
1195 }
1196
1197 static ULONG WINAPI COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface)
1198 {
1199 CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
1200 ULONG ref;
1201
1202 TRACE("\n");
1203
1204 ref = InterlockedDecrement(&This->ref);
1205 if (ref == 0) {
1206 if (This->key) RegCloseKey(This->key);
1207 HeapFree(GetProcessHeap(), 0, This);
1208 return 0;
1209 }
1210 return ref;
1211 }
1212
1213 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Next(
1214 LPENUMGUID iface,
1215 ULONG celt,
1216 GUID *rgelt,
1217 ULONG *pceltFetched)
1218 {
1219 CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
1220 ULONG fetched = 0;
1221
1222 TRACE("\n");
1223
1224 if (rgelt == NULL) return E_POINTER;
1225
1226 if (This->key) while (fetched < celt) {
1227 LSTATUS res;
1228 HRESULT hr;
1229 WCHAR catid[39];
1230 DWORD cName = 39;
1231
1232 res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
1233 NULL, NULL, NULL, NULL);
1234 if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
1235 ++(This->next_index);
1236
1237 hr = CLSIDFromString(catid, rgelt);
1238 if (FAILED(hr)) continue;
1239
1240 ++fetched;
1241 ++rgelt;
1242 }
1243
1244 if (pceltFetched) *pceltFetched = fetched;
1245 return fetched == celt ? S_OK : S_FALSE;
1246 }
1247
1248 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Skip(
1249 LPENUMGUID iface,
1250 ULONG celt)
1251 {
1252 CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
1253
1254 TRACE("\n");
1255
1256 This->next_index += celt;
1257 FIXME("Never returns S_FALSE\n");
1258 return S_OK;
1259 }
1260
1261 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface)
1262 {
1263 CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
1264
1265 TRACE("\n");
1266
1267 This->next_index = 0;
1268 return S_OK;
1269 }
1270
1271 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Clone(
1272 LPENUMGUID iface,
1273 IEnumGUID **ppenum)
1274 {
1275 CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
1276 CATID_IEnumGUIDImpl *new_this;
1277
1278 TRACE("\n");
1279
1280 if (ppenum == NULL) return E_POINTER;
1281
1282 new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
1283 if (new_this == NULL) return E_OUTOFMEMORY;
1284
1285 new_this->lpVtbl = This->lpVtbl;
1286 new_this->ref = 1;
1287 lstrcpyW(new_this->keyname, This->keyname);
1288 /* FIXME: could we more efficiently use DuplicateHandle? */
1289 open_classes_key(HKEY_CLASSES_ROOT, new_this->keyname, KEY_READ, &new_this->key);
1290 new_this->next_index = This->next_index;
1291
1292 *ppenum = (LPENUMGUID)new_this;
1293 return S_OK;
1294 }
1295
1296 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl =
1297 {
1298 COMCAT_CATID_IEnumGUID_QueryInterface,
1299 COMCAT_CATID_IEnumGUID_AddRef,
1300 COMCAT_CATID_IEnumGUID_Release,
1301 COMCAT_CATID_IEnumGUID_Next,
1302 COMCAT_CATID_IEnumGUID_Skip,
1303 COMCAT_CATID_IEnumGUID_Reset,
1304 COMCAT_CATID_IEnumGUID_Clone
1305 };
1306
1307 static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(
1308 REFCLSID rclsid, LPCWSTR postfix)
1309 {
1310 CATID_IEnumGUIDImpl *This;
1311
1312 This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
1313 if (This) {
1314 WCHAR prefix[] = { 'C', 'L', 'S', 'I', 'D', '\\' };
1315
1316 This->lpVtbl = &COMCAT_CATID_IEnumGUID_Vtbl;
1317 memcpy(This->keyname, prefix, sizeof(prefix));
1318 StringFromGUID2(rclsid, This->keyname + 6, 39);
1319 lstrcpyW(This->keyname + 44, postfix);
1320 open_classes_key(HKEY_CLASSES_ROOT, This->keyname, KEY_READ, &This->key);
1321 }
1322 return (LPENUMGUID)This;
1323 }