ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

comcat.c
Go to the documentation of this file.
00001 /*
00002  * Comcat implementation
00003  *
00004  * Copyright (C) 2002 John K. Hohm
00005  *
00006  * This library is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU Lesser General Public
00008  * License as published by the Free Software Foundation; either
00009  * version 2.1 of the License, or (at your option) any later version.
00010  *
00011  * This library is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  * Lesser General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU Lesser General Public
00017  * License along with this library; if not, write to the Free Software
00018  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
00019  */
00020 
00021 #include <string.h>
00022 #include <stdarg.h>
00023 
00024 #define COBJMACROS
00025 
00026 #include "windef.h"
00027 #include "winbase.h"
00028 #include "winuser.h"
00029 #include "winreg.h"
00030 #include "winerror.h"
00031 
00032 #include "ole2.h"
00033 #include "comcat.h"
00034 #include "wine/unicode.h"
00035 #include "wine/debug.h"
00036 
00037 WINE_DEFAULT_DEBUG_CHANNEL(ole);
00038 
00039 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl;
00040 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl;
00041 
00042 typedef struct
00043 {
00044     ICatRegister ICatRegister_iface;
00045     ICatInformation ICatInformation_iface;
00046 } ComCatMgrImpl;
00047 
00048 /* static ComCatMgr instance */
00049 static ComCatMgrImpl COMCAT_ComCatMgr =
00050 {
00051     { &COMCAT_ICatRegister_Vtbl },
00052     { &COMCAT_ICatInformation_Vtbl }
00053 };
00054 
00055 struct class_categories {
00056     LPCWSTR impl_strings;
00057     LPCWSTR req_strings;
00058 };
00059 
00060 static IEnumCATEGORYINFO *COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid);
00061 static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(struct class_categories *class_categories);
00062 static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(REFCLSID rclsid, LPCWSTR impl_req);
00063 
00064 /**********************************************************************
00065  * File-scope string constants
00066  */
00067 static const WCHAR comcat_keyname[] = {
00068     'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
00069 static const WCHAR impl_keyname[] = {
00070     'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
00071 static const WCHAR req_keyname[] = {
00072     'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
00073 static const WCHAR clsid_keyname[] = { 'C','L','S','I','D',0 };
00074 
00075 
00076 /**********************************************************************
00077  * COMCAT_RegisterClassCategories
00078  */
00079 static HRESULT COMCAT_RegisterClassCategories(
00080     REFCLSID rclsid,
00081     LPCWSTR type,
00082     ULONG cCategories,
00083     const CATID *rgcatid)
00084 {
00085     WCHAR keyname[39];
00086     HRESULT res;
00087     HKEY clsid_key, class_key, type_key;
00088 
00089     if (cCategories && rgcatid == NULL) return E_POINTER;
00090 
00091     /* Format the class key name. */
00092     res = StringFromGUID2(rclsid, keyname, 39);
00093     if (FAILED(res)) return res;
00094 
00095     /* Create (or open) the CLSID key. */
00096     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
00097               KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
00098     if (res != ERROR_SUCCESS) return E_FAIL;
00099 
00100     /* Create (or open) the class key. */
00101     res = RegCreateKeyExW(clsid_key, keyname, 0, NULL, 0,
00102               KEY_READ | KEY_WRITE, NULL, &class_key, NULL);
00103     if (res == ERROR_SUCCESS) {
00104     /* Create (or open) the category type key. */
00105     res = RegCreateKeyExW(class_key, type, 0, NULL, 0,
00106                   KEY_READ | KEY_WRITE, NULL, &type_key, NULL);
00107     if (res == ERROR_SUCCESS) {
00108         for (; cCategories; --cCategories, ++rgcatid) {
00109         HKEY key;
00110 
00111         /* Format the category key name. */
00112         res = StringFromGUID2(rgcatid, keyname, 39);
00113         if (FAILED(res)) continue;
00114 
00115         /* Do the register. */
00116         res = RegCreateKeyExW(type_key, keyname, 0, NULL, 0,
00117                       KEY_READ | KEY_WRITE, NULL, &key, NULL);
00118         if (res == ERROR_SUCCESS) RegCloseKey(key);
00119         }
00120         res = S_OK;
00121     } else res = E_FAIL;
00122     RegCloseKey(class_key);
00123     } else res = E_FAIL;
00124     RegCloseKey(clsid_key);
00125 
00126     return res;
00127 }
00128 
00129 /**********************************************************************
00130  * COMCAT_UnRegisterClassCategories
00131  */
00132 static HRESULT COMCAT_UnRegisterClassCategories(
00133     REFCLSID rclsid,
00134     LPCWSTR type,
00135     ULONG cCategories,
00136     const CATID *rgcatid)
00137 {
00138     WCHAR keyname[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
00139     HRESULT res;
00140     HKEY type_key;
00141 
00142     if (cCategories && rgcatid == NULL) return E_POINTER;
00143 
00144     /* Format the class category type key name. */
00145     res = StringFromGUID2(rclsid, keyname + 6, 39);
00146     if (FAILED(res)) return res;
00147     keyname[44] = '\\';
00148     lstrcpyW(keyname + 45, type);
00149 
00150     /* Open the class category type key. */
00151     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0,
00152             KEY_READ | KEY_WRITE, &type_key);
00153     if (res != ERROR_SUCCESS) return E_FAIL;
00154 
00155     for (; cCategories; --cCategories, ++rgcatid) {
00156     /* Format the category key name. */
00157     res = StringFromGUID2(rgcatid, keyname, 39);
00158     if (FAILED(res)) continue;
00159 
00160     /* Do the unregister. */
00161     RegDeleteKeyW(type_key, keyname);
00162     }
00163     RegCloseKey(type_key);
00164 
00165     return S_OK;
00166 }
00167 
00168 /**********************************************************************
00169  * COMCAT_GetCategoryDesc
00170  */
00171 static HRESULT COMCAT_GetCategoryDesc(HKEY key, LCID lcid, PWCHAR pszDesc,
00172                       ULONG buf_wchars)
00173 {
00174     static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
00175     WCHAR valname[5];
00176     HRESULT res;
00177     DWORD type, size = (buf_wchars - 1) * sizeof(WCHAR);
00178 
00179     if (pszDesc == NULL) return E_INVALIDARG;
00180 
00181     /* FIXME: lcid comparisons are more complex than this! */
00182     wsprintfW(valname, fmt, lcid);
00183     res = RegQueryValueExW(key, valname, 0, &type, (LPBYTE)pszDesc, &size);
00184     if (res != ERROR_SUCCESS || type != REG_SZ) {
00185     FIXME("Simplified lcid comparison\n");
00186     return CAT_E_NODESCRIPTION;
00187     }
00188     pszDesc[size / sizeof(WCHAR)] = 0;
00189 
00190     return S_OK;
00191 }
00192 
00193 /**********************************************************************
00194  * COMCAT_PrepareClassCategories
00195  */
00196 static struct class_categories *COMCAT_PrepareClassCategories(
00197     ULONG impl_count, const CATID *impl_catids, ULONG req_count, const CATID *req_catids)
00198 {
00199     struct class_categories *categories;
00200     WCHAR *strings;
00201 
00202     categories = HeapAlloc(
00203     GetProcessHeap(), HEAP_ZERO_MEMORY,
00204     sizeof(struct class_categories) +
00205     ((impl_count + req_count) * 39 + 2) * sizeof(WCHAR));
00206     if (categories == NULL) return categories;
00207 
00208     strings = (WCHAR *)(categories + 1);
00209     categories->impl_strings = strings;
00210     while (impl_count--) {
00211     StringFromGUID2(impl_catids++, strings, 39);
00212     strings += 39;
00213     }
00214     *strings++ = 0;
00215 
00216     categories->req_strings = strings;
00217     while (req_count--) {
00218     StringFromGUID2(req_catids++, strings, 39);
00219     strings += 39;
00220     }
00221     *strings++ = 0;
00222 
00223     return categories;
00224 }
00225 
00226 /**********************************************************************
00227  * COMCAT_IsClassOfCategories
00228  */
00229 static HRESULT COMCAT_IsClassOfCategories(
00230     HKEY key,
00231     struct class_categories const* categories)
00232 {
00233     HKEY subkey;
00234     HRESULT res;
00235     DWORD index;
00236     LPCWSTR string;
00237 
00238     /* Check that every given category is implemented by class. */
00239     if (*categories->impl_strings) {
00240     res = RegOpenKeyExW(key, impl_keyname, 0, KEY_READ, &subkey);
00241     if (res != ERROR_SUCCESS) return S_FALSE;
00242     for (string = categories->impl_strings; *string; string += 39) {
00243         HKEY catkey;
00244         res = RegOpenKeyExW(subkey, string, 0, 0, &catkey);
00245         if (res != ERROR_SUCCESS) {
00246         RegCloseKey(subkey);
00247         return S_FALSE;
00248         }
00249         RegCloseKey(catkey);
00250     }
00251     RegCloseKey(subkey);
00252     }
00253 
00254     /* Check that all categories required by class are given. */
00255     res = RegOpenKeyExW(key, req_keyname, 0, KEY_READ, &subkey);
00256     if (res == ERROR_SUCCESS) {
00257     for (index = 0; ; ++index) {
00258         WCHAR keyname[39];
00259         DWORD size = 39;
00260 
00261         res = RegEnumKeyExW(subkey, index, keyname, &size,
00262                 NULL, NULL, NULL, NULL);
00263         if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
00264         if (size != 38) continue; /* bogus catid in registry */
00265         for (string = categories->req_strings; *string; string += 39)
00266         if (!strcmpiW(string, keyname)) break;
00267         if (!*string) {
00268         RegCloseKey(subkey);
00269         return S_FALSE;
00270         }
00271     }
00272     RegCloseKey(subkey);
00273     }
00274 
00275     return S_OK;
00276 }
00277 
00278 /**********************************************************************
00279  * COMCAT_ICatRegister_QueryInterface
00280  */
00281 static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface(
00282     LPCATREGISTER iface,
00283     REFIID riid,
00284     LPVOID *ppvObj)
00285 {
00286     TRACE("%s\n",debugstr_guid(riid));
00287 
00288     if (ppvObj == NULL) return E_POINTER;
00289 
00290     if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ICatRegister)) {
00291     *ppvObj = iface;
00292         ICatRegister_AddRef(iface);
00293     return S_OK;
00294     }
00295 
00296     if (IsEqualGUID(riid, &IID_ICatInformation)) {
00297         *ppvObj = &COMCAT_ComCatMgr.ICatInformation_iface;
00298         ICatRegister_AddRef(iface);
00299     return S_OK;
00300     }
00301 
00302     return E_NOINTERFACE;
00303 }
00304 
00305 /**********************************************************************
00306  * COMCAT_ICatRegister_AddRef
00307  */
00308 static ULONG WINAPI COMCAT_ICatRegister_AddRef(LPCATREGISTER iface)
00309 {
00310     return 2; /* non-heap based object */
00311 }
00312 
00313 /**********************************************************************
00314  * COMCAT_ICatRegister_Release
00315  */
00316 static ULONG WINAPI COMCAT_ICatRegister_Release(LPCATREGISTER iface)
00317 {
00318     return 1; /* non-heap based object */
00319 }
00320 
00321 /**********************************************************************
00322  * COMCAT_ICatRegister_RegisterCategories
00323  */
00324 static HRESULT WINAPI COMCAT_ICatRegister_RegisterCategories(
00325     LPCATREGISTER iface,
00326     ULONG cCategories,
00327     CATEGORYINFO *rgci)
00328 {
00329     HKEY comcat_key;
00330     HRESULT res;
00331 
00332     TRACE("\n");
00333 
00334     if (cCategories && rgci == NULL)
00335     return E_POINTER;
00336 
00337     /* Create (or open) the component categories key. */
00338     res = RegCreateKeyExW(HKEY_CLASSES_ROOT, comcat_keyname, 0, NULL, 0,
00339               KEY_READ | KEY_WRITE, NULL, &comcat_key, NULL);
00340     if (res != ERROR_SUCCESS) return E_FAIL;
00341 
00342     for (; cCategories; --cCategories, ++rgci) {
00343     static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
00344     WCHAR keyname[39];
00345     WCHAR valname[9];
00346     HKEY cat_key;
00347 
00348     /* Create (or open) the key for this category. */
00349     if (!StringFromGUID2(&rgci->catid, keyname, 39)) continue;
00350     res = RegCreateKeyExW(comcat_key, keyname, 0, NULL, 0,
00351                   KEY_READ | KEY_WRITE, NULL, &cat_key, NULL);
00352     if (res != ERROR_SUCCESS) continue;
00353 
00354     /* Set the value for this locale's description. */
00355     wsprintfW(valname, fmt, rgci->lcid);
00356     RegSetValueExW(cat_key, valname, 0, REG_SZ,
00357                (CONST BYTE*)(rgci->szDescription),
00358                (lstrlenW(rgci->szDescription) + 1) * sizeof(WCHAR));
00359 
00360     RegCloseKey(cat_key);
00361     }
00362 
00363     RegCloseKey(comcat_key);
00364     return S_OK;
00365 }
00366 
00367 /**********************************************************************
00368  * COMCAT_ICatRegister_UnRegisterCategories
00369  */
00370 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterCategories(
00371     LPCATREGISTER iface,
00372     ULONG cCategories,
00373     CATID *rgcatid)
00374 {
00375     HKEY comcat_key;
00376     HRESULT res;
00377 
00378     TRACE("\n");
00379 
00380     if (cCategories && rgcatid == NULL)
00381     return E_POINTER;
00382 
00383     /* Open the component categories key. */
00384     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, comcat_keyname, 0,
00385             KEY_READ | KEY_WRITE, &comcat_key);
00386     if (res != ERROR_SUCCESS) return E_FAIL;
00387 
00388     for (; cCategories; --cCategories, ++rgcatid) {
00389     WCHAR keyname[39];
00390 
00391     /* Delete the key for this category. */
00392     if (!StringFromGUID2(rgcatid, keyname, 39)) continue;
00393     RegDeleteKeyW(comcat_key, keyname);
00394     }
00395 
00396     RegCloseKey(comcat_key);
00397     return S_OK;
00398 }
00399 
00400 /**********************************************************************
00401  * COMCAT_ICatRegister_RegisterClassImplCategories
00402  */
00403 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassImplCategories(
00404     LPCATREGISTER iface,
00405     REFCLSID rclsid,
00406     ULONG cCategories,
00407     CATID *rgcatid)
00408 {
00409     TRACE("\n");
00410 
00411     return COMCAT_RegisterClassCategories(
00412     rclsid, impl_keyname, cCategories, rgcatid);
00413 }
00414 
00415 /**********************************************************************
00416  * COMCAT_ICatRegister_UnRegisterClassImplCategories
00417  */
00418 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassImplCategories(
00419     LPCATREGISTER iface,
00420     REFCLSID rclsid,
00421     ULONG cCategories,
00422     CATID *rgcatid)
00423 {
00424     TRACE("\n");
00425 
00426     return COMCAT_UnRegisterClassCategories(
00427     rclsid, impl_keyname, cCategories, rgcatid);
00428 }
00429 
00430 /**********************************************************************
00431  * COMCAT_ICatRegister_RegisterClassReqCategories
00432  */
00433 static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassReqCategories(
00434     LPCATREGISTER iface,
00435     REFCLSID rclsid,
00436     ULONG cCategories,
00437     CATID *rgcatid)
00438 {
00439     TRACE("\n");
00440 
00441     return COMCAT_RegisterClassCategories(
00442     rclsid, req_keyname, cCategories, rgcatid);
00443 }
00444 
00445 /**********************************************************************
00446  * COMCAT_ICatRegister_UnRegisterClassReqCategories
00447  */
00448 static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassReqCategories(
00449     LPCATREGISTER iface,
00450     REFCLSID rclsid,
00451     ULONG cCategories,
00452     CATID *rgcatid)
00453 {
00454     TRACE("\n");
00455 
00456     return COMCAT_UnRegisterClassCategories(
00457     rclsid, req_keyname, cCategories, rgcatid);
00458 }
00459 
00460 /**********************************************************************
00461  * COMCAT_ICatInformation_QueryInterface
00462  */
00463 static HRESULT WINAPI COMCAT_ICatInformation_QueryInterface(
00464     LPCATINFORMATION iface,
00465     REFIID riid,
00466     LPVOID *ppvObj)
00467 {
00468     return ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
00469 }
00470 
00471 /**********************************************************************
00472  * COMCAT_ICatInformation_AddRef
00473  */
00474 static ULONG WINAPI COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface)
00475 {
00476     return ICatRegister_AddRef(&COMCAT_ComCatMgr.ICatRegister_iface);
00477 }
00478 
00479 /**********************************************************************
00480  * COMCAT_ICatInformation_Release
00481  */
00482 static ULONG WINAPI COMCAT_ICatInformation_Release(LPCATINFORMATION iface)
00483 {
00484     return ICatRegister_Release(&COMCAT_ComCatMgr.ICatRegister_iface);
00485 }
00486 
00487 /**********************************************************************
00488  * COMCAT_ICatInformation_EnumCategories
00489  */
00490 static HRESULT WINAPI COMCAT_ICatInformation_EnumCategories(
00491     LPCATINFORMATION iface,
00492     LCID lcid,
00493     IEnumCATEGORYINFO **ppenumCatInfo)
00494 {
00495     TRACE("\n");
00496 
00497     if (ppenumCatInfo == NULL) return E_POINTER;
00498 
00499     *ppenumCatInfo = COMCAT_IEnumCATEGORYINFO_Construct(lcid);
00500     if (*ppenumCatInfo == NULL) return E_OUTOFMEMORY;
00501     IEnumCATEGORYINFO_AddRef(*ppenumCatInfo);
00502     return S_OK;
00503 }
00504 
00505 /**********************************************************************
00506  * COMCAT_ICatInformation_GetCategoryDesc
00507  */
00508 static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc(
00509     LPCATINFORMATION iface,
00510     REFCATID rcatid,
00511     LCID lcid,
00512     PWCHAR *ppszDesc)
00513 {
00514     WCHAR keyname[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
00515               't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
00516               'r', 'i', 'e', 's', '\\', 0 };
00517     HKEY key;
00518     HRESULT res;
00519 
00520     TRACE("CATID: %s LCID: %x\n",debugstr_guid(rcatid), lcid);
00521 
00522     if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG;
00523 
00524     /* Open the key for this category. */
00525     if (!StringFromGUID2(rcatid, keyname + 21, 39)) return E_FAIL;
00526     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key);
00527     if (res != ERROR_SUCCESS) return CAT_E_CATIDNOEXIST;
00528 
00529     /* Allocate a sensible amount of memory for the description. */
00530     *ppszDesc = CoTaskMemAlloc(128 * sizeof(WCHAR));
00531     if (*ppszDesc == NULL) {
00532     RegCloseKey(key);
00533     return E_OUTOFMEMORY;
00534     }
00535 
00536     /* Get the description, and make sure it's null terminated. */
00537     res = COMCAT_GetCategoryDesc(key, lcid, *ppszDesc, 128);
00538     RegCloseKey(key);
00539     if (FAILED(res)) {
00540     CoTaskMemFree(*ppszDesc);
00541     return res;
00542     }
00543 
00544     return S_OK;
00545 }
00546 
00547 /**********************************************************************
00548  * COMCAT_ICatInformation_EnumClassesOfCategories
00549  */
00550 static HRESULT WINAPI COMCAT_ICatInformation_EnumClassesOfCategories(
00551     LPCATINFORMATION iface,
00552     ULONG cImplemented,
00553     CATID *rgcatidImpl,
00554     ULONG cRequired,
00555     CATID *rgcatidReq,
00556     LPENUMCLSID *ppenumCLSID)
00557 {
00558     struct class_categories *categories;
00559 
00560     TRACE("\n");
00561 
00562     if (cImplemented == (ULONG)-1)
00563         cImplemented = 0;
00564     if (cRequired == (ULONG)-1)
00565         cRequired = 0;
00566 
00567     if (ppenumCLSID == NULL ||
00568     (cImplemented && rgcatidImpl == NULL) ||
00569     (cRequired && rgcatidReq == NULL)) return E_POINTER;
00570 
00571     categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
00572                            cRequired, rgcatidReq);
00573     if (categories == NULL) return E_OUTOFMEMORY;
00574     *ppenumCLSID = COMCAT_CLSID_IEnumGUID_Construct(categories);
00575     if (*ppenumCLSID == NULL) {
00576     HeapFree(GetProcessHeap(), 0, categories);
00577     return E_OUTOFMEMORY;
00578     }
00579     IEnumGUID_AddRef(*ppenumCLSID);
00580     return S_OK;
00581 }
00582 
00583 /**********************************************************************
00584  * COMCAT_ICatInformation_IsClassOfCategories
00585  */
00586 static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories(
00587     LPCATINFORMATION iface,
00588     REFCLSID rclsid,
00589     ULONG cImplemented,
00590     CATID *rgcatidImpl,
00591     ULONG cRequired,
00592     CATID *rgcatidReq)
00593 {
00594     WCHAR keyname[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
00595     HRESULT res;
00596     struct class_categories *categories;
00597     HKEY key;
00598 
00599     if (TRACE_ON(ole)) {
00600     ULONG count;
00601     TRACE("CLSID: %s Implemented %u\n",debugstr_guid(rclsid),cImplemented);
00602     for (count = 0; count < cImplemented; ++count)
00603         TRACE("    %s\n",debugstr_guid(&rgcatidImpl[count]));
00604     TRACE("Required %u\n",cRequired);
00605     for (count = 0; count < cRequired; ++count)
00606         TRACE("    %s\n",debugstr_guid(&rgcatidReq[count]));
00607     }
00608 
00609     if ((cImplemented && rgcatidImpl == NULL) ||
00610     (cRequired && rgcatidReq == NULL)) return E_POINTER;
00611 
00612     res = StringFromGUID2(rclsid, keyname + 6, 39);
00613     if (FAILED(res)) return res;
00614 
00615     categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
00616                            cRequired, rgcatidReq);
00617     if (categories == NULL) return E_OUTOFMEMORY;
00618 
00619     res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key);
00620     if (res == ERROR_SUCCESS) {
00621     res = COMCAT_IsClassOfCategories(key, categories);
00622     RegCloseKey(key);
00623     } else res = S_FALSE;
00624 
00625     HeapFree(GetProcessHeap(), 0, categories);
00626 
00627     return res;
00628 }
00629 
00630 /**********************************************************************
00631  * COMCAT_ICatInformation_EnumImplCategoriesOfClass
00632  */
00633 static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass(
00634     LPCATINFORMATION iface,
00635     REFCLSID rclsid,
00636     LPENUMCATID *ppenumCATID)
00637 {
00638     static const WCHAR postfix[] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
00639               'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
00640               'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
00641 
00642     TRACE("%s\n",debugstr_guid(rclsid));
00643 
00644     if (rclsid == NULL || ppenumCATID == NULL)
00645     return E_POINTER;
00646 
00647     *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
00648     if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
00649     return S_OK;
00650 }
00651 
00652 /**********************************************************************
00653  * COMCAT_ICatInformation_EnumReqCategoriesOfClass
00654  */
00655 static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass(
00656     LPCATINFORMATION iface,
00657     REFCLSID rclsid,
00658     LPENUMCATID *ppenumCATID)
00659 {
00660     static const WCHAR postfix[] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
00661               'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
00662               'r', 'i', 'e', 's', 0 };
00663 
00664     TRACE("%s\n",debugstr_guid(rclsid));
00665 
00666     if (rclsid == NULL || ppenumCATID == NULL)
00667     return E_POINTER;
00668 
00669     *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
00670     if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
00671     return S_OK;
00672 }
00673 
00674 /**********************************************************************
00675  * COMCAT_ICatRegister_Vtbl
00676  */
00677 static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl =
00678 {
00679     COMCAT_ICatRegister_QueryInterface,
00680     COMCAT_ICatRegister_AddRef,
00681     COMCAT_ICatRegister_Release,
00682     COMCAT_ICatRegister_RegisterCategories,
00683     COMCAT_ICatRegister_UnRegisterCategories,
00684     COMCAT_ICatRegister_RegisterClassImplCategories,
00685     COMCAT_ICatRegister_UnRegisterClassImplCategories,
00686     COMCAT_ICatRegister_RegisterClassReqCategories,
00687     COMCAT_ICatRegister_UnRegisterClassReqCategories
00688 };
00689 
00690 
00691 /**********************************************************************
00692  * COMCAT_ICatInformation_Vtbl
00693  */
00694 static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl =
00695 {
00696     COMCAT_ICatInformation_QueryInterface,
00697     COMCAT_ICatInformation_AddRef,
00698     COMCAT_ICatInformation_Release,
00699     COMCAT_ICatInformation_EnumCategories,
00700     COMCAT_ICatInformation_GetCategoryDesc,
00701     COMCAT_ICatInformation_EnumClassesOfCategories,
00702     COMCAT_ICatInformation_IsClassOfCategories,
00703     COMCAT_ICatInformation_EnumImplCategoriesOfClass,
00704     COMCAT_ICatInformation_EnumReqCategoriesOfClass
00705 };
00706 
00707 /**********************************************************************
00708  * COMCAT_IClassFactory_QueryInterface (also IUnknown)
00709  */
00710 static HRESULT WINAPI COMCAT_IClassFactory_QueryInterface(
00711     LPCLASSFACTORY iface,
00712     REFIID riid,
00713     LPVOID *ppvObj)
00714 {
00715     TRACE("%s\n",debugstr_guid(riid));
00716 
00717     if (ppvObj == NULL) return E_POINTER;
00718 
00719     if (IsEqualGUID(riid, &IID_IUnknown) ||
00720     IsEqualGUID(riid, &IID_IClassFactory))
00721     {
00722         *ppvObj = iface;
00723         IUnknown_AddRef(iface);
00724     return S_OK;
00725     }
00726 
00727     return E_NOINTERFACE;
00728 }
00729 
00730 /**********************************************************************
00731  * COMCAT_IClassFactory_AddRef (also IUnknown)
00732  */
00733 static ULONG WINAPI COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface)
00734 {
00735     return 2; /* non-heap based object */
00736 }
00737 
00738 /**********************************************************************
00739  * COMCAT_IClassFactory_Release (also IUnknown)
00740  */
00741 static ULONG WINAPI COMCAT_IClassFactory_Release(LPCLASSFACTORY iface)
00742 {
00743     return 1; /* non-heap based object */
00744 }
00745 
00746 /**********************************************************************
00747  * COMCAT_IClassFactory_CreateInstance
00748  */
00749 static HRESULT WINAPI COMCAT_IClassFactory_CreateInstance(
00750     LPCLASSFACTORY iface,
00751     LPUNKNOWN pUnkOuter,
00752     REFIID riid,
00753     LPVOID *ppvObj)
00754 {
00755     HRESULT res;
00756     TRACE("%s\n",debugstr_guid(riid));
00757 
00758     if (ppvObj == NULL) return E_POINTER;
00759 
00760     /* Don't support aggregation (Windows doesn't) */
00761     if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
00762 
00763     res = ICatRegister_QueryInterface(&COMCAT_ComCatMgr.ICatRegister_iface, riid, ppvObj);
00764     if (SUCCEEDED(res)) {
00765     return res;
00766     }
00767 
00768     return CLASS_E_CLASSNOTAVAILABLE;
00769 }
00770 
00771 /**********************************************************************
00772  * COMCAT_IClassFactory_LockServer
00773  */
00774 static HRESULT WINAPI COMCAT_IClassFactory_LockServer(
00775     LPCLASSFACTORY iface,
00776     BOOL fLock)
00777 {
00778     FIXME("(%d), stub!\n",fLock);
00779     return S_OK;
00780 }
00781 
00782 /**********************************************************************
00783  * static ClassFactory instance
00784  */
00785 static const IClassFactoryVtbl ComCatCFVtbl =
00786 {
00787     COMCAT_IClassFactory_QueryInterface,
00788     COMCAT_IClassFactory_AddRef,
00789     COMCAT_IClassFactory_Release,
00790     COMCAT_IClassFactory_CreateInstance,
00791     COMCAT_IClassFactory_LockServer
00792 };
00793 
00794 static const IClassFactoryVtbl *ComCatCF = &ComCatCFVtbl;
00795 
00796 HRESULT ComCatCF_Create(REFIID riid, LPVOID *ppv)
00797 {
00798     return IClassFactory_QueryInterface((IClassFactory *)&ComCatCF, riid, ppv);
00799 }
00800 
00801 /**********************************************************************
00802  * IEnumCATEGORYINFO implementation
00803  *
00804  * This implementation is not thread-safe.  The manager itself is, but
00805  * I can't imagine a valid use of an enumerator in several threads.
00806  */
00807 typedef struct
00808 {
00809     IEnumCATEGORYINFO IEnumCATEGORYINFO_iface;
00810     LONG  ref;
00811     LCID  lcid;
00812     HKEY  key;
00813     DWORD next_index;
00814 } IEnumCATEGORYINFOImpl;
00815 
00816 static inline IEnumCATEGORYINFOImpl *impl_from_IEnumCATEGORYINFO(IEnumCATEGORYINFO *iface)
00817 {
00818     return CONTAINING_RECORD(iface, IEnumCATEGORYINFOImpl, IEnumCATEGORYINFO_iface);
00819 }
00820 
00821 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_AddRef(IEnumCATEGORYINFO *iface)
00822 {
00823     IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
00824 
00825     TRACE("\n");
00826 
00827     return InterlockedIncrement(&This->ref);
00828 }
00829 
00830 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface(
00831     IEnumCATEGORYINFO *iface,
00832     REFIID riid,
00833     LPVOID *ppvObj)
00834 {
00835     TRACE("%s\n",debugstr_guid(riid));
00836 
00837     if (ppvObj == NULL) return E_POINTER;
00838 
00839     if (IsEqualGUID(riid, &IID_IUnknown) ||
00840     IsEqualGUID(riid, &IID_IEnumCATEGORYINFO))
00841     {
00842         *ppvObj = iface;
00843     COMCAT_IEnumCATEGORYINFO_AddRef(iface);
00844     return S_OK;
00845     }
00846 
00847     return E_NOINTERFACE;
00848 }
00849 
00850 static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_Release(IEnumCATEGORYINFO *iface)
00851 {
00852     IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
00853     ULONG ref;
00854 
00855     TRACE("\n");
00856 
00857     ref = InterlockedDecrement(&This->ref);
00858     if (ref == 0) {
00859     if (This->key) RegCloseKey(This->key);
00860     HeapFree(GetProcessHeap(), 0, This);
00861     return 0;
00862     }
00863     return ref;
00864 }
00865 
00866 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Next(
00867     IEnumCATEGORYINFO *iface,
00868     ULONG celt,
00869     CATEGORYINFO *rgelt,
00870     ULONG *pceltFetched)
00871 {
00872     IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
00873     ULONG fetched = 0;
00874 
00875     TRACE("\n");
00876 
00877     if (rgelt == NULL) return E_POINTER;
00878 
00879     if (This->key) while (fetched < celt) {
00880     LSTATUS res;
00881     HRESULT hr;
00882     WCHAR catid[39];
00883     DWORD cName = 39;
00884     HKEY subkey;
00885 
00886     res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
00887                 NULL, NULL, NULL, NULL);
00888     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
00889     ++(This->next_index);
00890 
00891     hr = CLSIDFromString(catid, &rgelt->catid);
00892     if (FAILED(hr)) continue;
00893 
00894     res = RegOpenKeyExW(This->key, catid, 0, KEY_READ, &subkey);
00895     if (res != ERROR_SUCCESS) continue;
00896 
00897     hr = COMCAT_GetCategoryDesc(subkey, This->lcid,
00898                     rgelt->szDescription, 128);
00899     RegCloseKey(subkey);
00900     if (FAILED(hr)) continue;
00901 
00902     rgelt->lcid = This->lcid;
00903     ++fetched;
00904     ++rgelt;
00905     }
00906 
00907     if (pceltFetched) *pceltFetched = fetched;
00908     return fetched == celt ? S_OK : S_FALSE;
00909 }
00910 
00911 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Skip(
00912     IEnumCATEGORYINFO *iface,
00913     ULONG celt)
00914 {
00915     IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
00916 
00917     TRACE("\n");
00918 
00919     This->next_index += celt;
00920     /* This should return S_FALSE when there aren't celt elems to skip. */
00921     return S_OK;
00922 }
00923 
00924 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Reset(IEnumCATEGORYINFO *iface)
00925 {
00926     IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
00927 
00928     TRACE("\n");
00929 
00930     This->next_index = 0;
00931     return S_OK;
00932 }
00933 
00934 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Clone(
00935     IEnumCATEGORYINFO *iface,
00936     IEnumCATEGORYINFO **ppenum)
00937 {
00938     IEnumCATEGORYINFOImpl *This = impl_from_IEnumCATEGORYINFO(iface);
00939     static const WCHAR keyname[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
00940                                      't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
00941                                      'r', 'i', 'e', 's', 0 };
00942     IEnumCATEGORYINFOImpl *new_this;
00943 
00944     TRACE("\n");
00945 
00946     if (ppenum == NULL) return E_POINTER;
00947 
00948     new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
00949     if (new_this == NULL) return E_OUTOFMEMORY;
00950 
00951     new_this->IEnumCATEGORYINFO_iface = This->IEnumCATEGORYINFO_iface;
00952     new_this->ref = 1;
00953     new_this->lcid = This->lcid;
00954     /* FIXME: could we more efficiently use DuplicateHandle? */
00955     RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &new_this->key);
00956     new_this->next_index = This->next_index;
00957 
00958     *ppenum = &new_this->IEnumCATEGORYINFO_iface;
00959     return S_OK;
00960 }
00961 
00962 static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl =
00963 {
00964     COMCAT_IEnumCATEGORYINFO_QueryInterface,
00965     COMCAT_IEnumCATEGORYINFO_AddRef,
00966     COMCAT_IEnumCATEGORYINFO_Release,
00967     COMCAT_IEnumCATEGORYINFO_Next,
00968     COMCAT_IEnumCATEGORYINFO_Skip,
00969     COMCAT_IEnumCATEGORYINFO_Reset,
00970     COMCAT_IEnumCATEGORYINFO_Clone
00971 };
00972 
00973 static IEnumCATEGORYINFO *COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid)
00974 {
00975     IEnumCATEGORYINFOImpl *This;
00976 
00977     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
00978     if (This) {
00979         static const WCHAR keyname[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
00980                                          't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
00981                                          'r', 'i', 'e', 's', 0 };
00982 
00983         This->IEnumCATEGORYINFO_iface.lpVtbl = &COMCAT_IEnumCATEGORYINFO_Vtbl;
00984     This->lcid = lcid;
00985     RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &This->key);
00986     }
00987     return &This->IEnumCATEGORYINFO_iface;
00988 }
00989 
00990 /**********************************************************************
00991  * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
00992  *
00993  * This implementation is not thread-safe.  The manager itself is, but
00994  * I can't imagine a valid use of an enumerator in several threads.
00995  */
00996 typedef struct
00997 {
00998     const IEnumGUIDVtbl *lpVtbl;
00999     LONG  ref;
01000     struct class_categories *categories;
01001     HKEY  key;
01002     DWORD next_index;
01003 } CLSID_IEnumGUIDImpl;
01004 
01005 static ULONG WINAPI COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface)
01006 {
01007     CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
01008     TRACE("\n");
01009 
01010     return InterlockedIncrement(&This->ref);
01011 }
01012 
01013 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_QueryInterface(
01014     LPENUMGUID iface,
01015     REFIID riid,
01016     LPVOID *ppvObj)
01017 {
01018     TRACE("%s\n",debugstr_guid(riid));
01019 
01020     if (ppvObj == NULL) return E_POINTER;
01021 
01022     if (IsEqualGUID(riid, &IID_IUnknown) ||
01023     IsEqualGUID(riid, &IID_IEnumGUID))
01024     {
01025         *ppvObj = iface;
01026     COMCAT_CLSID_IEnumGUID_AddRef(iface);
01027     return S_OK;
01028     }
01029 
01030     return E_NOINTERFACE;
01031 }
01032 
01033 static ULONG WINAPI COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface)
01034 {
01035     CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
01036     ULONG ref;
01037 
01038     TRACE("\n");
01039 
01040     ref = InterlockedDecrement(&This->ref);
01041     if (ref == 0) {
01042     if (This->key) RegCloseKey(This->key);
01043         HeapFree(GetProcessHeap(), 0, This->categories);
01044     HeapFree(GetProcessHeap(), 0, This);
01045     return 0;
01046     }
01047     return ref;
01048 }
01049 
01050 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Next(
01051     LPENUMGUID iface,
01052     ULONG celt,
01053     GUID *rgelt,
01054     ULONG *pceltFetched)
01055 {
01056     CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
01057     ULONG fetched = 0;
01058 
01059     TRACE("\n");
01060 
01061     if (rgelt == NULL) return E_POINTER;
01062 
01063     if (This->key) while (fetched < celt) {
01064     LSTATUS res;
01065     HRESULT hr;
01066     WCHAR clsid[39];
01067     DWORD cName = 39;
01068     HKEY subkey;
01069 
01070     res = RegEnumKeyExW(This->key, This->next_index, clsid, &cName,
01071                 NULL, NULL, NULL, NULL);
01072     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
01073     ++(This->next_index);
01074 
01075     hr = CLSIDFromString(clsid, rgelt);
01076     if (FAILED(hr)) continue;
01077 
01078     res = RegOpenKeyExW(This->key, clsid, 0, KEY_READ, &subkey);
01079     if (res != ERROR_SUCCESS) continue;
01080 
01081     hr = COMCAT_IsClassOfCategories(subkey, This->categories);
01082     RegCloseKey(subkey);
01083     if (hr != S_OK) continue;
01084 
01085     ++fetched;
01086     ++rgelt;
01087     }
01088 
01089     if (pceltFetched) *pceltFetched = fetched;
01090     return fetched == celt ? S_OK : S_FALSE;
01091 }
01092 
01093 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Skip(
01094     LPENUMGUID iface,
01095     ULONG celt)
01096 {
01097     CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
01098 
01099     TRACE("\n");
01100 
01101     This->next_index += celt;
01102     FIXME("Never returns S_FALSE\n");
01103     return S_OK;
01104 }
01105 
01106 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface)
01107 {
01108     CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
01109 
01110     TRACE("\n");
01111 
01112     This->next_index = 0;
01113     return S_OK;
01114 }
01115 
01116 static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Clone(
01117     LPENUMGUID iface,
01118     IEnumGUID **ppenum)
01119 {
01120     CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
01121     static const WCHAR keyname[] = { 'C', 'L', 'S', 'I', 'D', 0 };
01122     CLSID_IEnumGUIDImpl *new_this;
01123     DWORD size;
01124 
01125     TRACE("\n");
01126 
01127     if (ppenum == NULL) return E_POINTER;
01128 
01129     new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
01130     if (new_this == NULL) return E_OUTOFMEMORY;
01131 
01132     new_this->lpVtbl = This->lpVtbl;
01133     new_this->ref = 1;
01134     size = HeapSize(GetProcessHeap(), 0, This->categories);
01135     new_this->categories =
01136     HeapAlloc(GetProcessHeap(), 0, size);
01137     if (new_this->categories == NULL) {
01138     HeapFree(GetProcessHeap(), 0, new_this);
01139     return E_OUTOFMEMORY;
01140     }
01141     memcpy(new_this->categories, This->categories, size);
01142     /* FIXME: could we more efficiently use DuplicateHandle? */
01143     RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &new_this->key);
01144     new_this->next_index = This->next_index;
01145 
01146     *ppenum = (LPENUMGUID)new_this;
01147     return S_OK;
01148 }
01149 
01150 static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl =
01151 {
01152     COMCAT_CLSID_IEnumGUID_QueryInterface,
01153     COMCAT_CLSID_IEnumGUID_AddRef,
01154     COMCAT_CLSID_IEnumGUID_Release,
01155     COMCAT_CLSID_IEnumGUID_Next,
01156     COMCAT_CLSID_IEnumGUID_Skip,
01157     COMCAT_CLSID_IEnumGUID_Reset,
01158     COMCAT_CLSID_IEnumGUID_Clone
01159 };
01160 
01161 static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(struct class_categories *categories)
01162 {
01163     CLSID_IEnumGUIDImpl *This;
01164 
01165     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
01166     if (This) {
01167     static const WCHAR keyname[] = { 'C', 'L', 'S', 'I', 'D', 0 };
01168 
01169     This->lpVtbl = &COMCAT_CLSID_IEnumGUID_Vtbl;
01170     This->categories = categories;
01171     RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &This->key);
01172     }
01173     return (LPENUMGUID)This;
01174 }
01175 
01176 /**********************************************************************
01177  * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
01178  *
01179  * This implementation is not thread-safe.  The manager itself is, but
01180  * I can't imagine a valid use of an enumerator in several threads.
01181  */
01182 typedef struct
01183 {
01184     const IEnumGUIDVtbl *lpVtbl;
01185     LONG  ref;
01186     WCHAR keyname[68];
01187     HKEY  key;
01188     DWORD next_index;
01189 } CATID_IEnumGUIDImpl;
01190 
01191 static ULONG WINAPI COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface)
01192 {
01193     CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
01194     TRACE("\n");
01195 
01196     return InterlockedIncrement(&This->ref);
01197 }
01198 
01199 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_QueryInterface(
01200     LPENUMGUID iface,
01201     REFIID riid,
01202     LPVOID *ppvObj)
01203 {
01204     TRACE("%s\n",debugstr_guid(riid));
01205 
01206     if (ppvObj == NULL) return E_POINTER;
01207 
01208     if (IsEqualGUID(riid, &IID_IUnknown) ||
01209     IsEqualGUID(riid, &IID_IEnumGUID))
01210     {
01211         *ppvObj = iface;
01212     COMCAT_CATID_IEnumGUID_AddRef(iface);
01213     return S_OK;
01214     }
01215 
01216     return E_NOINTERFACE;
01217 }
01218 
01219 static ULONG WINAPI COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface)
01220 {
01221     CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
01222     ULONG ref;
01223 
01224     TRACE("\n");
01225 
01226     ref = InterlockedDecrement(&This->ref);
01227     if (ref == 0) {
01228     if (This->key) RegCloseKey(This->key);
01229     HeapFree(GetProcessHeap(), 0, This);
01230     return 0;
01231     }
01232     return ref;
01233 }
01234 
01235 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Next(
01236     LPENUMGUID iface,
01237     ULONG celt,
01238     GUID *rgelt,
01239     ULONG *pceltFetched)
01240 {
01241     CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
01242     ULONG fetched = 0;
01243 
01244     TRACE("\n");
01245 
01246     if (rgelt == NULL) return E_POINTER;
01247 
01248     if (This->key) while (fetched < celt) {
01249     LSTATUS res;
01250     HRESULT hr;
01251     WCHAR catid[39];
01252     DWORD cName = 39;
01253 
01254     res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
01255                 NULL, NULL, NULL, NULL);
01256     if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
01257     ++(This->next_index);
01258 
01259     hr = CLSIDFromString(catid, rgelt);
01260     if (FAILED(hr)) continue;
01261 
01262     ++fetched;
01263     ++rgelt;
01264     }
01265 
01266     if (pceltFetched) *pceltFetched = fetched;
01267     return fetched == celt ? S_OK : S_FALSE;
01268 }
01269 
01270 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Skip(
01271     LPENUMGUID iface,
01272     ULONG celt)
01273 {
01274     CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
01275 
01276     TRACE("\n");
01277 
01278     This->next_index += celt;
01279     FIXME("Never returns S_FALSE\n");
01280     return S_OK;
01281 }
01282 
01283 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface)
01284 {
01285     CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
01286 
01287     TRACE("\n");
01288 
01289     This->next_index = 0;
01290     return S_OK;
01291 }
01292 
01293 static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Clone(
01294     LPENUMGUID iface,
01295     IEnumGUID **ppenum)
01296 {
01297     CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
01298     CATID_IEnumGUIDImpl *new_this;
01299 
01300     TRACE("\n");
01301 
01302     if (ppenum == NULL) return E_POINTER;
01303 
01304     new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
01305     if (new_this == NULL) return E_OUTOFMEMORY;
01306 
01307     new_this->lpVtbl = This->lpVtbl;
01308     new_this->ref = 1;
01309     lstrcpyW(new_this->keyname, This->keyname);
01310     /* FIXME: could we more efficiently use DuplicateHandle? */
01311     RegOpenKeyExW(HKEY_CLASSES_ROOT, new_this->keyname, 0, KEY_READ, &new_this->key);
01312     new_this->next_index = This->next_index;
01313 
01314     *ppenum = (LPENUMGUID)new_this;
01315     return S_OK;
01316 }
01317 
01318 static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl =
01319 {
01320     COMCAT_CATID_IEnumGUID_QueryInterface,
01321     COMCAT_CATID_IEnumGUID_AddRef,
01322     COMCAT_CATID_IEnumGUID_Release,
01323     COMCAT_CATID_IEnumGUID_Next,
01324     COMCAT_CATID_IEnumGUID_Skip,
01325     COMCAT_CATID_IEnumGUID_Reset,
01326     COMCAT_CATID_IEnumGUID_Clone
01327 };
01328 
01329 static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(
01330     REFCLSID rclsid, LPCWSTR postfix)
01331 {
01332     CATID_IEnumGUIDImpl *This;
01333 
01334     This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
01335     if (This) {
01336     WCHAR prefix[] = { 'C', 'L', 'S', 'I', 'D', '\\' };
01337 
01338     This->lpVtbl = &COMCAT_CATID_IEnumGUID_Vtbl;
01339     memcpy(This->keyname, prefix, sizeof(prefix));
01340     StringFromGUID2(rclsid, This->keyname + 6, 39);
01341     lstrcpyW(This->keyname + 44, postfix);
01342     RegOpenKeyExW(HKEY_CLASSES_ROOT, This->keyname, 0, KEY_READ, &This->key);
01343     }
01344     return (LPENUMGUID)This;
01345 }

Generated on Fri May 25 2012 04:23:42 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.