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