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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 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 735 static inline IEnumCATEGORYINFOImpl *impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO *iface) 736 { 737 return CONTAINING_RECORD(iface, IEnumCATEGORYINFOImpl, IEnumCATEGORYINFO_iface); 738 } 739 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 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 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 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 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 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 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 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 926 static inline CLSID_IEnumGUIDImpl *impl_from_IEnumCLSID(IEnumGUID *iface) 927 { 928 return CONTAINING_RECORD(iface, CLSID_IEnumGUIDImpl, IEnumGUID_iface); 929 } 930 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 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 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 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 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 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 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 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 1123 static inline CATID_IEnumGUIDImpl *impl_from_IEnumCATID(IEnumGUID *iface) 1124 { 1125 return CONTAINING_RECORD(iface, CATID_IEnumGUIDImpl, IEnumGUID_iface); 1126 } 1127 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 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 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 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 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 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 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 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