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