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