complete ICatInformation implementation

John K. Hohm jhohm at acm.org
Sat Jun 1 16:43:27 CDT 2002


Changelog:
John K. Hohm <jhohm at acm.org>
complete ICatInformation implementation
-------------- next part --------------
Index: dlls/comcat/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/comcat/Makefile.in,v
retrieving revision 1.3
diff -u -r1.3 Makefile.in
--- dlls/comcat/Makefile.in	29 May 2002 19:25:50 -0000	1.3
+++ dlls/comcat/Makefile.in	1 Jun 2002 21:38:20 -0000
@@ -4,7 +4,7 @@
 VPATH     = @srcdir@
 MODULE    = comcat.dll
 IMPORTS   = ole32 user32 advapi32 kernel32
-EXTRALIBS = $(LIBUUID)
+EXTRALIBS = $(LIBUNICODE) $(LIBUUID)
 
 LDDLLFLAGS = @LDDLLFLAGS@
 SYMBOLFILE = $(MODULE).tmp.o
Index: dlls/comcat/comcat.h
===================================================================
RCS file: /home/wine/wine/dlls/comcat/comcat.h,v
retrieving revision 1.3
diff -u -r1.3 comcat.h
--- dlls/comcat/comcat.h	29 May 2002 19:25:50 -0000	1.3
+++ dlls/comcat/comcat.h	1 Jun 2002 21:38:20 -0000
@@ -27,6 +27,7 @@
 #include "wine/obj_base.h"
 #include "wine/obj_enumguid.h"
 #include "wine/obj_comcat.h"
+#include "wine/unicode.h"
 
 /**********************************************************************
  * Dll lifetime tracking declaration for comcat.dll
Index: dlls/comcat/information.c
===================================================================
RCS file: /home/wine/wine/dlls/comcat/information.c,v
retrieving revision 1.3
diff -u -r1.3 information.c
--- dlls/comcat/information.c	29 May 2002 19:25:50 -0000	1.3
+++ dlls/comcat/information.c	1 Jun 2002 21:38:20 -0000
@@ -30,6 +30,20 @@
 static HRESULT COMCAT_GetCategoryDesc(HKEY key, LCID lcid, PWCHAR pszDesc,
 				      ULONG buf_wchars);
 
+struct class_categories {
+    LPCWSTR impl_strings;
+    LPCWSTR req_strings;
+};
+
+static struct class_categories *COMCAT_PrepareClassCategories(
+    ULONG impl_count, CATID *impl_catids, ULONG req_count, CATID *req_catids);
+static HRESULT COMCAT_IsClassOfCategories(
+    HKEY key, struct class_categories const* class_categories);
+static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(
+    struct class_categories const* class_categories);
+static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(
+    REFCLSID rclsid, LPCWSTR impl_req);
+
 /**********************************************************************
  * COMCAT_ICatInformation_QueryInterface
  */
@@ -146,9 +160,24 @@
     LPENUMCLSID *ppenumCLSID)
 {
 /*     ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
-    FIXME("(): stub\n");
+    struct class_categories *categories;
+
+    TRACE("\n");
 
-    return E_NOTIMPL;
+    if (iface == NULL || ppenumCLSID == NULL ||
+	(cImplemented && rgcatidImpl == NULL) ||
+	(cRequired && rgcatidReq == NULL)) return E_POINTER;
+
+    categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
+					       cRequired, rgcatidReq);
+    if (categories == NULL) return E_OUTOFMEMORY;
+    *ppenumCLSID = COMCAT_CLSID_IEnumGUID_Construct(categories);
+    if (*ppenumCLSID == NULL) {
+	HeapFree(GetProcessHeap(), 0, categories);
+	return E_OUTOFMEMORY;
+    }
+    IEnumGUID_AddRef(*ppenumCLSID);
+    return S_OK;
 }
 
 /**********************************************************************
@@ -163,9 +192,40 @@
     CATID *rgcatidReq)
 {
 /*     ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
-    FIXME("(): stub\n");
+    WCHAR keyname[45] = { 'C', 'L', 'S', 'I', 'D', '\\', 0 };
+    HRESULT res;
+    struct class_categories *categories;
+    HKEY key;
+
+    if (WINE_TRACE_ON(ole)) {
+	ULONG count;
+	TRACE("\n\tCLSID:\t%s\n\tImplemented %lu\n",debugstr_guid(rclsid),cImplemented);
+	for (count = 0; count < cImplemented; ++count)
+	    DPRINTF("\t\t%s\n",debugstr_guid(&rgcatidImpl[count]));
+	DPRINTF("\tRequired %lu\n",cRequired);
+	for (count = 0; count < cRequired; ++count)
+	    DPRINTF("\t\t%s\n",debugstr_guid(&rgcatidReq[count]));
+    }
+
+    if ((cImplemented && rgcatidImpl == NULL) ||
+	(cRequired && rgcatidReq == NULL)) return E_POINTER;
+
+    res = StringFromGUID2(rclsid, keyname + 6, 39);
+    if (FAILED(res)) return res;
+
+    categories = COMCAT_PrepareClassCategories(cImplemented, rgcatidImpl,
+					       cRequired, rgcatidReq);
+    if (categories == NULL) return E_OUTOFMEMORY;
+
+    res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key);
+    if (res == ERROR_SUCCESS) {
+	res = COMCAT_IsClassOfCategories(key, categories);
+	RegCloseKey(key);
+    } else res = S_FALSE;
+
+    HeapFree(GetProcessHeap(), 0, categories);
 
-    return E_NOTIMPL;
+    return res;
 }
 
 /**********************************************************************
@@ -177,9 +237,18 @@
     LPENUMCATID *ppenumCATID)
 {
 /*     ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
-    FIXME("(): stub\n");
+    WCHAR postfix[24] = { '\\', 'I', 'm', 'p', 'l', 'e', 'm', 'e',
+			  'n', 't', 'e', 'd', ' ', 'C', 'a', 't',
+			  'e', 'g', 'o', 'r', 'i', 'e', 's', 0 };
 
-    return E_NOTIMPL;
+    TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid));
+
+    if (iface == NULL || rclsid == NULL || ppenumCATID == NULL)
+	return E_POINTER;
+
+    *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
+    if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
+    return S_OK;
 }
 
 /**********************************************************************
@@ -191,9 +260,18 @@
     LPENUMCATID *ppenumCATID)
 {
 /*     ICOM_THIS_MULTI(ComCatMgrImpl, infVtbl, iface); */
-    FIXME("(): stub\n");
+    WCHAR postfix[21] = { '\\', 'R', 'e', 'q', 'u', 'i', 'r', 'e',
+			  'd', ' ', 'C', 'a', 't', 'e', 'g', 'o',
+			  'r', 'i', 'e', 's', 0 };
+
+    TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid));
+
+    if (iface == NULL || rclsid == NULL || ppenumCATID == NULL)
+	return E_POINTER;
 
-    return E_NOTIMPL;
+    *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
+    if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
+    return S_OK;
 }
 
 /**********************************************************************
@@ -322,28 +400,54 @@
     LPENUMCATEGORYINFO iface,
     ULONG celt)
 {
-/*     ICOM_THIS(IEnumCATEGORYINFOImpl, iface); */
-    FIXME("(): stub\n");
+    ICOM_THIS(IEnumCATEGORYINFOImpl, iface);
 
-    return E_NOTIMPL;
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+    This->next_index += celt;
+    /* This should return S_FALSE when there aren't celt elems to skip. */
+    return S_OK;
 }
 
 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Reset(LPENUMCATEGORYINFO iface)
 {
-/*     ICOM_THIS(IEnumCATEGORYINFOImpl, iface); */
-    FIXME("(): stub\n");
+    ICOM_THIS(IEnumCATEGORYINFOImpl, iface);
 
-    return E_NOTIMPL;
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+    This->next_index = 0;
+    return S_OK;
 }
 
 static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Clone(
     LPENUMCATEGORYINFO iface,
     IEnumCATEGORYINFO **ppenum)
 {
-/*     ICOM_THIS(IEnumCATEGORYINFOImpl, iface); */
-    FIXME("(): stub\n");
+    ICOM_THIS(IEnumCATEGORYINFOImpl, iface);
+    WCHAR keyname[21] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
+			  't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
+			  'r', 'i', 'e', 's', 0 };
+    IEnumCATEGORYINFOImpl *new_this;
+
+    TRACE("\n");
+
+    if (This == NULL || ppenum == NULL) return E_POINTER;
+
+    new_this = (IEnumCATEGORYINFOImpl *) HeapAlloc(
+	GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
+    if (new_this == NULL) return E_OUTOFMEMORY;
+
+    ICOM_VTBL(new_this) = ICOM_VTBL(This);
+    new_this->ref = 1;
+    new_this->lcid = This->lcid;
+    /* FIXME: could we more efficiently use DuplicateHandle? */
+    RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &new_this->key);
+    new_this->next_index = This->next_index;
 
-    return E_NOTIMPL;
+    *ppenum = (LPENUMCATEGORYINFO)new_this;
+    return S_OK;
 }
 
 ICOM_VTABLE(IEnumCATEGORYINFO) COMCAT_IEnumCATEGORYINFO_Vtbl =
@@ -392,8 +496,470 @@
     /* FIXME: lcid comparisons are more complex than this! */
     wsprintfW(valname, fmt, lcid);
     res = RegQueryValueExW(key, valname, 0, &type, (LPBYTE)pszDesc, &size);
-    if (res != ERROR_SUCCESS || type != REG_SZ) return CAT_E_NODESCRIPTION;
+    if (res != ERROR_SUCCESS || type != REG_SZ) {
+	FIXME("Simplified lcid comparison\n");
+	return CAT_E_NODESCRIPTION;
+    }
     pszDesc[size / sizeof(WCHAR)] = (WCHAR)0;
 
     return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_PrepareClassCategories
+ */
+static struct class_categories *COMCAT_PrepareClassCategories(
+    ULONG impl_count, CATID *impl_catids, ULONG req_count, CATID *req_catids)
+{
+    struct class_categories *categories;
+    WCHAR *strings;
+
+    categories = (struct class_categories *)HeapAlloc(
+	GetProcessHeap(), HEAP_ZERO_MEMORY,
+	sizeof(struct class_categories) +
+	((impl_count + req_count) * 39 + 2) * sizeof(WCHAR));
+    if (categories == NULL) return categories;
+
+    strings = (WCHAR *)(categories + 1);
+    categories->impl_strings = strings;
+    while (impl_count--) {
+	StringFromGUID2(impl_catids++, strings, 39);
+	strings += 39;
+    }
+    *strings++ = 0;
+
+    categories->req_strings = strings;
+    while (req_count--) {
+	StringFromGUID2(req_catids++, strings, 39);
+	strings += 39;
+    }
+    *strings++ = 0;
+
+    return categories;
+}
+
+/**********************************************************************
+ * COMCAT_IsClassOfCategories
+ */
+static HRESULT COMCAT_IsClassOfCategories(
+    HKEY key,
+    struct class_categories const* categories)
+{
+    WCHAR impl_keyname[23] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
+			       't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
+			       'g', 'o', 'r', 'i', 'e', 's', 0 };
+    WCHAR req_keyname[20] = { 'R', 'e', 'q', 'u', 'i', 'r', 'e', 'd', 
+			      ' ', 'C', 'a', 't', 'e', 'g', 'o', 'r',
+			      'i', 'e', 's', 0 };
+    HKEY subkey;
+    HRESULT res;
+    DWORD index;
+    LPCWSTR string;
+
+    /* Check that every given category is implemented by class. */
+    res = RegOpenKeyExW(key, impl_keyname, 0, KEY_READ, &subkey);
+    if (res != ERROR_SUCCESS) return S_FALSE;
+    for (string = categories->impl_strings; *string; string += 39) {
+	HKEY catkey;
+	res = RegOpenKeyExW(subkey, string, 0, 0, &catkey);
+	if (res != ERROR_SUCCESS) {
+	    RegCloseKey(subkey);
+	    return S_FALSE;
+	}
+	RegCloseKey(catkey);
+    }
+    RegCloseKey(subkey);
+
+    /* Check that all categories required by class are given. */
+    res = RegOpenKeyExW(key, req_keyname, 0, KEY_READ, &subkey);
+    if (res == ERROR_SUCCESS) {
+	for (index = 0; ; ++index) {
+	    WCHAR keyname[39];
+	    DWORD size = 39;
+
+	    res = RegEnumKeyExW(subkey, index, keyname, &size,
+				NULL, NULL, NULL, NULL);
+	    if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
+	    if (size != 38) continue; /* bogus catid in registry */
+	    for (string = categories->req_strings; *string; string += 39)
+		if (!strcmpiW(string, keyname)) break;
+	    if (!*string) {
+		RegCloseKey(subkey);
+		return S_FALSE;
+	    }
+	}
+	RegCloseKey(subkey);
+    }
+
+    return S_OK;
+}
+
+/**********************************************************************
+ * ClassesOfCategories IEnumCLSID (IEnumGUID) implementation
+ *
+ * This implementation is not thread-safe.  The manager itself is, but
+ * I can't imagine a valid use of an enumerator in several threads.
+ */
+typedef struct
+{
+    ICOM_VFIELD(IEnumGUID);
+    DWORD ref;
+    struct class_categories const *categories;
+    HKEY  key;
+    DWORD next_index;
+} CLSID_IEnumGUIDImpl;
+
+static ULONG WINAPI COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    return ++(This->ref);
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_QueryInterface(
+    LPENUMGUID iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+	IsEqualGUID(riid, &IID_IEnumGUID))
+    {
+	*ppvObj = (LPVOID)iface;
+	COMCAT_CLSID_IEnumGUID_AddRef(iface);
+	return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI COMCAT_CLSID_IEnumGUID_Release(LPENUMGUID iface)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    if (--(This->ref) == 0) {
+	if (This->key) RegCloseKey(This->key);
+	HeapFree(GetProcessHeap(), 0, (LPVOID)This->categories);
+	HeapFree(GetProcessHeap(), 0, This);
+	return 0;
+    }
+    return This->ref;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Next(
+    LPENUMGUID iface,
+    ULONG celt,
+    GUID *rgelt,
+    ULONG *pceltFetched)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+    ULONG fetched = 0;
+
+    TRACE("\n");
+
+    if (This == NULL || rgelt == NULL) return E_POINTER;
+
+    if (This->key) while (fetched < celt) {
+	HRESULT res;
+	WCHAR clsid[39];
+	DWORD cName = 39;
+	HKEY subkey;
+
+	res = RegEnumKeyExW(This->key, This->next_index, clsid, &cName,
+			    NULL, NULL, NULL, NULL);
+	if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
+	++(This->next_index);
+
+	res = CLSIDFromString(clsid, rgelt);
+	if (FAILED(res)) continue;
+
+	res = RegOpenKeyExW(This->key, clsid, 0, KEY_READ, &subkey);
+	if (res != ERROR_SUCCESS) continue;
+
+	res = COMCAT_IsClassOfCategories(subkey, This->categories);
+	RegCloseKey(subkey);
+	if (res != S_OK) continue;
+
+	++fetched;
+	++rgelt;
+    }
+
+    if (pceltFetched) *pceltFetched = fetched;
+    return fetched == celt ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Skip(
+    LPENUMGUID iface,
+    ULONG celt)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+    This->next_index += celt;
+    FIXME("Never returns S_FALSE\n");
+    return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+    This->next_index = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Clone(
+    LPENUMGUID iface,
+    IEnumGUID **ppenum)
+{
+    ICOM_THIS(CLSID_IEnumGUIDImpl, iface);
+    WCHAR keyname[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
+    CLSID_IEnumGUIDImpl *new_this;
+    DWORD size;
+
+    TRACE("\n");
+
+    if (This == NULL || ppenum == NULL) return E_POINTER;
+
+    new_this = (CLSID_IEnumGUIDImpl *) HeapAlloc(
+	GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
+    if (new_this == NULL) return E_OUTOFMEMORY;
+
+    ICOM_VTBL(new_this) = ICOM_VTBL(This);
+    new_this->ref = 1;
+    size = HeapSize(GetProcessHeap(), 0, (LPVOID)This->categories);
+    new_this->categories = (struct class_categories *)
+	HeapAlloc(GetProcessHeap(), 0, size);
+    if (new_this->categories == NULL) {
+	HeapFree(GetProcessHeap(), 0, new_this);
+	return E_OUTOFMEMORY;
+    }
+    memcpy((LPVOID)new_this->categories, This->categories, size);
+    /* FIXME: could we more efficiently use DuplicateHandle? */
+    RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &new_this->key);
+    new_this->next_index = This->next_index;
+
+    *ppenum = (LPENUMGUID)new_this;
+    return S_OK;
+}
+
+ICOM_VTABLE(IEnumGUID) COMCAT_CLSID_IEnumGUID_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    COMCAT_CLSID_IEnumGUID_QueryInterface,
+    COMCAT_CLSID_IEnumGUID_AddRef,
+    COMCAT_CLSID_IEnumGUID_Release,
+    COMCAT_CLSID_IEnumGUID_Next,
+    COMCAT_CLSID_IEnumGUID_Skip,
+    COMCAT_CLSID_IEnumGUID_Reset,
+    COMCAT_CLSID_IEnumGUID_Clone
+};
+
+static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(
+    struct class_categories const* categories)
+{
+    CLSID_IEnumGUIDImpl *This;
+
+    This = (CLSID_IEnumGUIDImpl *) HeapAlloc(
+	GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
+    if (This) {
+	WCHAR keyname[6] = { 'C', 'L', 'S', 'I', 'D', 0 };
+
+	ICOM_VTBL(This) = &COMCAT_CLSID_IEnumGUID_Vtbl;
+	This->categories = categories;
+	RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &This->key);
+    }
+    return (LPENUMGUID)This;
+}
+
+/**********************************************************************
+ * CategoriesOfClass IEnumCATID (IEnumGUID) implementation
+ *
+ * This implementation is not thread-safe.  The manager itself is, but
+ * I can't imagine a valid use of an enumerator in several threads.
+ */
+typedef struct
+{
+    ICOM_VFIELD(IEnumGUID);
+    DWORD ref;
+    WCHAR keyname[68];
+    HKEY  key;
+    DWORD next_index;
+} CATID_IEnumGUIDImpl;
+
+static ULONG WINAPI COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    return ++(This->ref);
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_QueryInterface(
+    LPENUMGUID iface,
+    REFIID riid,
+    LPVOID *ppvObj)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+    TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+    if (This == NULL || ppvObj == NULL) return E_POINTER;
+
+    if (IsEqualGUID(riid, &IID_IUnknown) ||
+	IsEqualGUID(riid, &IID_IEnumGUID))
+    {
+	*ppvObj = (LPVOID)iface;
+	COMCAT_CATID_IEnumGUID_AddRef(iface);
+	return S_OK;
+    }
+
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI COMCAT_CATID_IEnumGUID_Release(LPENUMGUID iface)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+
+    if (--(This->ref) == 0) {
+	if (This->key) RegCloseKey(This->key);
+	HeapFree(GetProcessHeap(), 0, This);
+	return 0;
+    }
+    return This->ref;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Next(
+    LPENUMGUID iface,
+    ULONG celt,
+    GUID *rgelt,
+    ULONG *pceltFetched)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+    ULONG fetched = 0;
+
+    TRACE("\n");
+
+    if (This == NULL || rgelt == NULL) return E_POINTER;
+
+    if (This->key) while (fetched < celt) {
+	HRESULT res;
+	WCHAR catid[39];
+	DWORD cName = 39;
+
+	res = RegEnumKeyExW(This->key, This->next_index, catid, &cName,
+			    NULL, NULL, NULL, NULL);
+	if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA) break;
+	++(This->next_index);
+
+	res = CLSIDFromString(catid, rgelt);
+	if (FAILED(res)) continue;
+
+	++fetched;
+	++rgelt;
+    }
+
+    if (pceltFetched) *pceltFetched = fetched;
+    return fetched == celt ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Skip(
+    LPENUMGUID iface,
+    ULONG celt)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+    This->next_index += celt;
+    FIXME("Never returns S_FALSE\n");
+    return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+
+    TRACE("\n");
+
+    if (This == NULL) return E_POINTER;
+    This->next_index = 0;
+    return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Clone(
+    LPENUMGUID iface,
+    IEnumGUID **ppenum)
+{
+    ICOM_THIS(CATID_IEnumGUIDImpl, iface);
+    CATID_IEnumGUIDImpl *new_this;
+
+    TRACE("\n");
+
+    if (This == NULL || ppenum == NULL) return E_POINTER;
+
+    new_this = (CATID_IEnumGUIDImpl *) HeapAlloc(
+	GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
+    if (new_this == NULL) return E_OUTOFMEMORY;
+
+    ICOM_VTBL(new_this) = ICOM_VTBL(This);
+    new_this->ref = 1;
+    lstrcpyW(new_this->keyname, This->keyname);
+    /* FIXME: could we more efficiently use DuplicateHandle? */
+    RegOpenKeyExW(HKEY_CLASSES_ROOT, new_this->keyname, 0, KEY_READ, &new_this->key);
+    new_this->next_index = This->next_index;
+
+    *ppenum = (LPENUMGUID)new_this;
+    return S_OK;
+}
+
+ICOM_VTABLE(IEnumGUID) COMCAT_CATID_IEnumGUID_Vtbl =
+{
+    ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
+    COMCAT_CATID_IEnumGUID_QueryInterface,
+    COMCAT_CATID_IEnumGUID_AddRef,
+    COMCAT_CATID_IEnumGUID_Release,
+    COMCAT_CATID_IEnumGUID_Next,
+    COMCAT_CATID_IEnumGUID_Skip,
+    COMCAT_CATID_IEnumGUID_Reset,
+    COMCAT_CATID_IEnumGUID_Clone
+};
+
+static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(
+    REFCLSID rclsid, LPCWSTR postfix)
+{
+    CATID_IEnumGUIDImpl *This;
+
+    This = (CATID_IEnumGUIDImpl *) HeapAlloc(
+	GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
+    if (This) {
+	WCHAR prefix[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
+
+	ICOM_VTBL(This) = &COMCAT_CATID_IEnumGUID_Vtbl;
+	memcpy(This->keyname, prefix, sizeof prefix);
+	StringFromGUID2(rclsid, This->keyname + 6, 39);
+	lstrcpyW(This->keyname + 44, postfix);
+	RegOpenKeyExW(HKEY_CLASSES_ROOT, This->keyname, 0, KEY_READ, &This->key);
+    }
+    return (LPENUMGUID)This;
 }


More information about the wine-patches mailing list