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