- Remove epm server building from rpcrt4, it belongs to rpcss.
svn path=/trunk/; revision=37240
/* Get the metafile picture out of it */
- if (!FAILED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
+ if (SUCCEEDED(hr = IDataObject_GetData(theOleClipboard->pIDataObjectSrc, &fmt2, &std2)))
{
mfp = (METAFILEPICT *)GlobalLock(std2.u.hGlobal);
}
--- /dev/null
+/*
+ * Comcat implementation
+ *
+ * Copyright (C) 2002 John K. Hohm
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <string.h>
+#include <stdarg.h>
+
+#define COBJMACROS
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "winreg.h"
+#include "winerror.h"
+
+#include "ole2.h"
+#include "comcat.h"
+#include "wine/unicode.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+
+typedef struct
+{
+ const ICatRegisterVtbl *lpVtbl;
+ const ICatInformationVtbl *infVtbl;
+} ComCatMgrImpl;
+
+struct class_categories {
+ LPCWSTR impl_strings;
+ LPCWSTR req_strings;
+};
+
+static LPENUMCATEGORYINFO COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid);
+static LPENUMGUID COMCAT_CLSID_IEnumGUID_Construct(struct class_categories *class_categories);
+static LPENUMGUID COMCAT_CATID_IEnumGUID_Construct(REFCLSID rclsid, LPCWSTR impl_req);
+
+/**********************************************************************
+ * File-scope string constants
+ */
+static const WCHAR comcat_keyname[] = {
+ 'C','o','m','p','o','n','e','n','t',' ','C','a','t','e','g','o','r','i','e','s',0 };
+static const WCHAR impl_keyname[] = {
+ 'I','m','p','l','e','m','e','n','t','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
+static const WCHAR req_keyname[] = {
+ 'R','e','q','u','i','r','e','d',' ','C','a','t','e','g','o','r','i','e','s',0 };
+static const WCHAR clsid_keyname[] = { 'C','L','S','I','D',0 };
+
+
+static inline ComCatMgrImpl *impl_from_ICatInformation( ICatInformation *iface )
+{
+ return (ComCatMgrImpl *)((char*)iface - FIELD_OFFSET(ComCatMgrImpl, infVtbl));
+}
+
+
+/**********************************************************************
+ * COMCAT_RegisterClassCategories
+ */
+static HRESULT COMCAT_RegisterClassCategories(
+ REFCLSID rclsid,
+ LPCWSTR type,
+ ULONG cCategories,
+ const CATID *rgcatid)
+{
+ WCHAR keyname[39];
+ HRESULT res;
+ HKEY clsid_key, class_key, type_key;
+
+ if (cCategories && rgcatid == NULL) return E_POINTER;
+
+ /* Format the class key name. */
+ res = StringFromGUID2(rclsid, keyname, 39);
+ if (FAILED(res)) return res;
+
+ /* Create (or open) the CLSID key. */
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, clsid_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &clsid_key, NULL);
+ if (res != ERROR_SUCCESS) return E_FAIL;
+
+ /* Create (or open) the class key. */
+ res = RegCreateKeyExW(clsid_key, keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &class_key, NULL);
+ if (res == ERROR_SUCCESS) {
+ /* Create (or open) the category type key. */
+ res = RegCreateKeyExW(class_key, type, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &type_key, NULL);
+ if (res == ERROR_SUCCESS) {
+ for (; cCategories; --cCategories, ++rgcatid) {
+ HKEY key;
+
+ /* Format the category key name. */
+ res = StringFromGUID2(rgcatid, keyname, 39);
+ if (FAILED(res)) continue;
+
+ /* Do the register. */
+ res = RegCreateKeyExW(type_key, keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &key, NULL);
+ if (res == ERROR_SUCCESS) RegCloseKey(key);
+ }
+ res = S_OK;
+ } else res = E_FAIL;
+ RegCloseKey(class_key);
+ } else res = E_FAIL;
+ RegCloseKey(clsid_key);
+
+ return res;
+}
+
+/**********************************************************************
+ * COMCAT_UnRegisterClassCategories
+ */
+static HRESULT COMCAT_UnRegisterClassCategories(
+ REFCLSID rclsid,
+ LPCWSTR type,
+ ULONG cCategories,
+ const CATID *rgcatid)
+{
+ WCHAR keyname[68] = { 'C', 'L', 'S', 'I', 'D', '\\' };
+ HRESULT res;
+ HKEY type_key;
+
+ if (cCategories && rgcatid == NULL) return E_POINTER;
+
+ /* Format the class category type key name. */
+ res = StringFromGUID2(rclsid, keyname + 6, 39);
+ if (FAILED(res)) return res;
+ keyname[44] = '\\';
+ lstrcpyW(keyname + 45, type);
+
+ /* Open the class category type key. */
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0,
+ KEY_READ | KEY_WRITE, &type_key);
+ if (res != ERROR_SUCCESS) return E_FAIL;
+
+ for (; cCategories; --cCategories, ++rgcatid) {
+ /* Format the category key name. */
+ res = StringFromGUID2(rgcatid, keyname, 39);
+ if (FAILED(res)) continue;
+
+ /* Do the unregister. */
+ RegDeleteKeyW(type_key, keyname);
+ }
+ RegCloseKey(type_key);
+
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_GetCategoryDesc
+ */
+static HRESULT COMCAT_GetCategoryDesc(HKEY key, LCID lcid, PWCHAR pszDesc,
+ ULONG buf_wchars)
+{
+ static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
+ WCHAR valname[5];
+ HRESULT res;
+ DWORD type, size = (buf_wchars - 1) * sizeof(WCHAR);
+
+ if (pszDesc == NULL) return E_INVALIDARG;
+
+ /* 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) {
+ 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, const CATID *impl_catids, ULONG req_count, const CATID *req_catids)
+{
+ struct class_categories *categories;
+ WCHAR *strings;
+
+ 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)
+{
+ static const WCHAR impl_keyname[] = { 'I', 'm', 'p', 'l', 'e', 'm', 'e', 'n',
+ 't', 'e', 'd', ' ', 'C', 'a', 't', 'e',
+ 'g', 'o', 'r', 'i', 'e', 's', 0 };
+ static const WCHAR req_keyname[] = { '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;
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_QueryInterface
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_QueryInterface(
+ LPCATREGISTER iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ ComCatMgrImpl *This = (ComCatMgrImpl *)iface;
+ TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+ if (ppvObj == NULL) return E_POINTER;
+
+ if (IsEqualGUID(riid, &IID_IUnknown) || IsEqualGUID(riid, &IID_ICatRegister)) {
+ *ppvObj = iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ if (IsEqualGUID(riid, &IID_ICatInformation)) {
+ *ppvObj = &This->infVtbl;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_AddRef
+ */
+static ULONG WINAPI COMCAT_ICatRegister_AddRef(LPCATREGISTER iface)
+{
+ return 2; /* non-heap based object */
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_Release
+ */
+static ULONG WINAPI COMCAT_ICatRegister_Release(LPCATREGISTER iface)
+{
+ return 1; /* non-heap based object */
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_RegisterCategories
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_RegisterCategories(
+ LPCATREGISTER iface,
+ ULONG cCategories,
+ CATEGORYINFO *rgci)
+{
+ HKEY comcat_key;
+ HRESULT res;
+
+ TRACE("\n");
+
+ if (cCategories && rgci == NULL)
+ return E_POINTER;
+
+ /* Create (or open) the component categories key. */
+ res = RegCreateKeyExW(HKEY_CLASSES_ROOT, comcat_keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &comcat_key, NULL);
+ if (res != ERROR_SUCCESS) return E_FAIL;
+
+ for (; cCategories; --cCategories, ++rgci) {
+ static const WCHAR fmt[] = { '%', 'l', 'X', 0 };
+ WCHAR keyname[39];
+ WCHAR valname[9];
+ HKEY cat_key;
+
+ /* Create (or open) the key for this category. */
+ if (!StringFromGUID2(&rgci->catid, keyname, 39)) continue;
+ res = RegCreateKeyExW(comcat_key, keyname, 0, NULL, 0,
+ KEY_READ | KEY_WRITE, NULL, &cat_key, NULL);
+ if (res != ERROR_SUCCESS) continue;
+
+ /* Set the value for this locale's description. */
+ wsprintfW(valname, fmt, rgci->lcid);
+ RegSetValueExW(cat_key, valname, 0, REG_SZ,
+ (CONST BYTE*)(rgci->szDescription),
+ (lstrlenW(rgci->szDescription) + 1) * sizeof(WCHAR));
+
+ RegCloseKey(cat_key);
+ }
+
+ RegCloseKey(comcat_key);
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_UnRegisterCategories
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterCategories(
+ LPCATREGISTER iface,
+ ULONG cCategories,
+ CATID *rgcatid)
+{
+ HKEY comcat_key;
+ HRESULT res;
+
+ TRACE("\n");
+
+ if (cCategories && rgcatid == NULL)
+ return E_POINTER;
+
+ /* Open the component categories key. */
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, comcat_keyname, 0,
+ KEY_READ | KEY_WRITE, &comcat_key);
+ if (res != ERROR_SUCCESS) return E_FAIL;
+
+ for (; cCategories; --cCategories, ++rgcatid) {
+ WCHAR keyname[39];
+
+ /* Delete the key for this category. */
+ if (!StringFromGUID2(rgcatid, keyname, 39)) continue;
+ RegDeleteKeyW(comcat_key, keyname);
+ }
+
+ RegCloseKey(comcat_key);
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_RegisterClassImplCategories
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassImplCategories(
+ LPCATREGISTER iface,
+ REFCLSID rclsid,
+ ULONG cCategories,
+ CATID *rgcatid)
+{
+ TRACE("\n");
+
+ return COMCAT_RegisterClassCategories(
+ rclsid, impl_keyname, cCategories, rgcatid);
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_UnRegisterClassImplCategories
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassImplCategories(
+ LPCATREGISTER iface,
+ REFCLSID rclsid,
+ ULONG cCategories,
+ CATID *rgcatid)
+{
+ TRACE("\n");
+
+ return COMCAT_UnRegisterClassCategories(
+ rclsid, impl_keyname, cCategories, rgcatid);
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_RegisterClassReqCategories
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_RegisterClassReqCategories(
+ LPCATREGISTER iface,
+ REFCLSID rclsid,
+ ULONG cCategories,
+ CATID *rgcatid)
+{
+ TRACE("\n");
+
+ return COMCAT_RegisterClassCategories(
+ rclsid, req_keyname, cCategories, rgcatid);
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_UnRegisterClassReqCategories
+ */
+static HRESULT WINAPI COMCAT_ICatRegister_UnRegisterClassReqCategories(
+ LPCATREGISTER iface,
+ REFCLSID rclsid,
+ ULONG cCategories,
+ CATID *rgcatid)
+{
+ TRACE("\n");
+
+ return COMCAT_UnRegisterClassCategories(
+ rclsid, req_keyname, cCategories, rgcatid);
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_QueryInterface
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_QueryInterface(
+ LPCATINFORMATION iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ ComCatMgrImpl *This = impl_from_ICatInformation( iface );
+ return IUnknown_QueryInterface((LPUNKNOWN)This, riid, ppvObj);
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_AddRef
+ */
+static ULONG WINAPI COMCAT_ICatInformation_AddRef(LPCATINFORMATION iface)
+{
+ ComCatMgrImpl *This = impl_from_ICatInformation( iface );
+ return IUnknown_AddRef((LPUNKNOWN)This);
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_Release
+ */
+static ULONG WINAPI COMCAT_ICatInformation_Release(LPCATINFORMATION iface)
+{
+ ComCatMgrImpl *This = impl_from_ICatInformation( iface );
+ return IUnknown_Release((LPUNKNOWN)This);
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_EnumCategories
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_EnumCategories(
+ LPCATINFORMATION iface,
+ LCID lcid,
+ LPENUMCATEGORYINFO *ppenumCatInfo)
+{
+ TRACE("\n");
+
+ if (ppenumCatInfo == NULL) return E_POINTER;
+
+ *ppenumCatInfo = COMCAT_IEnumCATEGORYINFO_Construct(lcid);
+ if (*ppenumCatInfo == NULL) return E_OUTOFMEMORY;
+ IEnumCATEGORYINFO_AddRef(*ppenumCatInfo);
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_GetCategoryDesc
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_GetCategoryDesc(
+ LPCATINFORMATION iface,
+ REFCATID rcatid,
+ LCID lcid,
+ PWCHAR *ppszDesc)
+{
+ WCHAR keyname[60] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
+ 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
+ 'r', 'i', 'e', 's', '\\', 0 };
+ HKEY key;
+ HRESULT res;
+
+ TRACE("\n\tCATID:\t%s\n\tLCID:\t%X\n",debugstr_guid(rcatid), lcid);
+
+ if (rcatid == NULL || ppszDesc == NULL) return E_INVALIDARG;
+
+ /* Open the key for this category. */
+ if (!StringFromGUID2(rcatid, keyname + 21, 39)) return E_FAIL;
+ res = RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &key);
+ if (res != ERROR_SUCCESS) return CAT_E_CATIDNOEXIST;
+
+ /* Allocate a sensible amount of memory for the description. */
+ *ppszDesc = (PWCHAR) CoTaskMemAlloc(128 * sizeof(WCHAR));
+ if (*ppszDesc == NULL) {
+ RegCloseKey(key);
+ return E_OUTOFMEMORY;
+ }
+
+ /* Get the description, and make sure it's null terminated. */
+ res = COMCAT_GetCategoryDesc(key, lcid, *ppszDesc, 128);
+ RegCloseKey(key);
+ if (FAILED(res)) {
+ CoTaskMemFree(*ppszDesc);
+ return res;
+ }
+
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_EnumClassesOfCategories
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_EnumClassesOfCategories(
+ LPCATINFORMATION iface,
+ ULONG cImplemented,
+ CATID *rgcatidImpl,
+ ULONG cRequired,
+ CATID *rgcatidReq,
+ LPENUMCLSID *ppenumCLSID)
+{
+ struct class_categories *categories;
+
+ TRACE("\n");
+
+ if (cImplemented == (ULONG)-1)
+ cImplemented = 0;
+ if (cRequired == (ULONG)-1)
+ cRequired = 0;
+
+ if (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;
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_IsClassOfCategories
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_IsClassOfCategories(
+ LPCATINFORMATION iface,
+ REFCLSID rclsid,
+ ULONG cImplemented,
+ CATID *rgcatidImpl,
+ ULONG cRequired,
+ CATID *rgcatidReq)
+{
+ 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 %u\n",debugstr_guid(rclsid),cImplemented);
+ for (count = 0; count < cImplemented; ++count)
+ TRACE("\t\t%s\n",debugstr_guid(&rgcatidImpl[count]));
+ TRACE("\tRequired %u\n",cRequired);
+ for (count = 0; count < cRequired; ++count)
+ TRACE("\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 res;
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_EnumImplCategoriesOfClass
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_EnumImplCategoriesOfClass(
+ LPCATINFORMATION iface,
+ REFCLSID rclsid,
+ LPENUMCATID *ppenumCATID)
+{
+ static const 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 };
+
+ TRACE("\n\tCLSID:\t%s\n",debugstr_guid(rclsid));
+
+ if (rclsid == NULL || ppenumCATID == NULL)
+ return E_POINTER;
+
+ *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
+ if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_ICatInformation_EnumReqCategoriesOfClass
+ */
+static HRESULT WINAPI COMCAT_ICatInformation_EnumReqCategoriesOfClass(
+ LPCATINFORMATION iface,
+ REFCLSID rclsid,
+ LPENUMCATID *ppenumCATID)
+{
+ static const 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 (rclsid == NULL || ppenumCATID == NULL)
+ return E_POINTER;
+
+ *ppenumCATID = COMCAT_CATID_IEnumGUID_Construct(rclsid, postfix);
+ if (*ppenumCATID == NULL) return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+/**********************************************************************
+ * COMCAT_ICatRegister_Vtbl
+ */
+static const ICatRegisterVtbl COMCAT_ICatRegister_Vtbl =
+{
+ COMCAT_ICatRegister_QueryInterface,
+ COMCAT_ICatRegister_AddRef,
+ COMCAT_ICatRegister_Release,
+ COMCAT_ICatRegister_RegisterCategories,
+ COMCAT_ICatRegister_UnRegisterCategories,
+ COMCAT_ICatRegister_RegisterClassImplCategories,
+ COMCAT_ICatRegister_UnRegisterClassImplCategories,
+ COMCAT_ICatRegister_RegisterClassReqCategories,
+ COMCAT_ICatRegister_UnRegisterClassReqCategories
+};
+
+
+/**********************************************************************
+ * COMCAT_ICatInformation_Vtbl
+ */
+static const ICatInformationVtbl COMCAT_ICatInformation_Vtbl =
+{
+ COMCAT_ICatInformation_QueryInterface,
+ COMCAT_ICatInformation_AddRef,
+ COMCAT_ICatInformation_Release,
+ COMCAT_ICatInformation_EnumCategories,
+ COMCAT_ICatInformation_GetCategoryDesc,
+ COMCAT_ICatInformation_EnumClassesOfCategories,
+ COMCAT_ICatInformation_IsClassOfCategories,
+ COMCAT_ICatInformation_EnumImplCategoriesOfClass,
+ COMCAT_ICatInformation_EnumReqCategoriesOfClass
+};
+
+/**********************************************************************
+ * static ComCatMgr instance
+ */
+static ComCatMgrImpl COMCAT_ComCatMgr =
+{
+ &COMCAT_ICatRegister_Vtbl,
+ &COMCAT_ICatInformation_Vtbl
+};
+
+/**********************************************************************
+ * COMCAT_IClassFactory_QueryInterface (also IUnknown)
+ */
+static HRESULT WINAPI COMCAT_IClassFactory_QueryInterface(
+ LPCLASSFACTORY iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+ if (ppvObj == NULL) return E_POINTER;
+
+ if (IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IClassFactory))
+ {
+ *ppvObj = (LPVOID)iface;
+ IUnknown_AddRef(iface);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+/**********************************************************************
+ * COMCAT_IClassFactory_AddRef (also IUnknown)
+ */
+static ULONG WINAPI COMCAT_IClassFactory_AddRef(LPCLASSFACTORY iface)
+{
+ return 2; /* non-heap based object */
+}
+
+/**********************************************************************
+ * COMCAT_IClassFactory_Release (also IUnknown)
+ */
+static ULONG WINAPI COMCAT_IClassFactory_Release(LPCLASSFACTORY iface)
+{
+ return 1; /* non-heap based object */
+}
+
+/**********************************************************************
+ * COMCAT_IClassFactory_CreateInstance
+ */
+static HRESULT WINAPI COMCAT_IClassFactory_CreateInstance(
+ LPCLASSFACTORY iface,
+ LPUNKNOWN pUnkOuter,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ HRESULT res;
+ TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+ if (ppvObj == NULL) return E_POINTER;
+
+ /* Don't support aggregation (Windows doesn't) */
+ if (pUnkOuter != NULL) return CLASS_E_NOAGGREGATION;
+
+ res = IUnknown_QueryInterface((LPUNKNOWN)&COMCAT_ComCatMgr, riid, ppvObj);
+ if (SUCCEEDED(res)) {
+ return res;
+ }
+
+ return CLASS_E_CLASSNOTAVAILABLE;
+}
+
+/**********************************************************************
+ * COMCAT_IClassFactory_LockServer
+ */
+static HRESULT WINAPI COMCAT_IClassFactory_LockServer(
+ LPCLASSFACTORY iface,
+ BOOL fLock)
+{
+ FIXME("(%d), stub!\n",fLock);
+ return S_OK;
+}
+
+/**********************************************************************
+ * static ClassFactory instance
+ */
+static const IClassFactoryVtbl ComCatCFVtbl =
+{
+ COMCAT_IClassFactory_QueryInterface,
+ COMCAT_IClassFactory_AddRef,
+ COMCAT_IClassFactory_Release,
+ COMCAT_IClassFactory_CreateInstance,
+ COMCAT_IClassFactory_LockServer
+};
+
+static const IClassFactoryVtbl *ComCatCF = &ComCatCFVtbl;
+
+HRESULT ComCatCF_Create(REFIID riid, LPVOID *ppv)
+{
+ return IClassFactory_QueryInterface((IClassFactory *)&ComCatCF, riid, ppv);
+}
+
+/**********************************************************************
+ * IEnumCATEGORYINFO 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
+{
+ const IEnumCATEGORYINFOVtbl *lpVtbl;
+ LONG ref;
+ LCID lcid;
+ HKEY key;
+ DWORD next_index;
+} IEnumCATEGORYINFOImpl;
+
+static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_AddRef(LPENUMCATEGORYINFO iface)
+{
+ IEnumCATEGORYINFOImpl *This = (IEnumCATEGORYINFOImpl *)iface;
+
+ TRACE("\n");
+
+ return InterlockedIncrement(&This->ref);
+}
+
+static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_QueryInterface(
+ LPENUMCATEGORYINFO iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+ if (ppvObj == NULL) return E_POINTER;
+
+ if (IsEqualGUID(riid, &IID_IUnknown) ||
+ IsEqualGUID(riid, &IID_IEnumCATEGORYINFO))
+ {
+ *ppvObj = (LPVOID)iface;
+ COMCAT_IEnumCATEGORYINFO_AddRef(iface);
+ return S_OK;
+ }
+
+ return E_NOINTERFACE;
+}
+
+static ULONG WINAPI COMCAT_IEnumCATEGORYINFO_Release(LPENUMCATEGORYINFO iface)
+{
+ IEnumCATEGORYINFOImpl *This = (IEnumCATEGORYINFOImpl *)iface;
+ ULONG ref;
+
+ TRACE("\n");
+
+ ref = InterlockedDecrement(&This->ref);
+ if (ref == 0) {
+ if (This->key) RegCloseKey(This->key);
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+ }
+ return ref;
+}
+
+static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Next(
+ LPENUMCATEGORYINFO iface,
+ ULONG celt,
+ CATEGORYINFO *rgelt,
+ ULONG *pceltFetched)
+{
+ IEnumCATEGORYINFOImpl *This = (IEnumCATEGORYINFOImpl *)iface;
+ ULONG fetched = 0;
+
+ TRACE("\n");
+
+ if (rgelt == NULL) return E_POINTER;
+
+ if (This->key) while (fetched < celt) {
+ LSTATUS res;
+ HRESULT hr;
+ WCHAR catid[39];
+ DWORD cName = 39;
+ HKEY subkey;
+
+ 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);
+
+ hr = CLSIDFromString(catid, &rgelt->catid);
+ if (FAILED(hr)) continue;
+
+ res = RegOpenKeyExW(This->key, catid, 0, KEY_READ, &subkey);
+ if (res != ERROR_SUCCESS) continue;
+
+ hr = COMCAT_GetCategoryDesc(subkey, This->lcid,
+ rgelt->szDescription, 128);
+ RegCloseKey(subkey);
+ if (FAILED(hr)) continue;
+
+ rgelt->lcid = This->lcid;
+ ++fetched;
+ ++rgelt;
+ }
+
+ if (pceltFetched) *pceltFetched = fetched;
+ return fetched == celt ? S_OK : S_FALSE;
+}
+
+static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Skip(
+ LPENUMCATEGORYINFO iface,
+ ULONG celt)
+{
+ IEnumCATEGORYINFOImpl *This = (IEnumCATEGORYINFOImpl *)iface;
+
+ TRACE("\n");
+
+ 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)
+{
+ IEnumCATEGORYINFOImpl *This = (IEnumCATEGORYINFOImpl *)iface;
+
+ TRACE("\n");
+
+ This->next_index = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_IEnumCATEGORYINFO_Clone(
+ LPENUMCATEGORYINFO iface,
+ IEnumCATEGORYINFO **ppenum)
+{
+ IEnumCATEGORYINFOImpl *This = (IEnumCATEGORYINFOImpl *)iface;
+ static const WCHAR keyname[] = { '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 (ppenum == NULL) return E_POINTER;
+
+ new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
+ if (new_this == NULL) return E_OUTOFMEMORY;
+
+ new_this->lpVtbl = This->lpVtbl;
+ 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;
+
+ *ppenum = (LPENUMCATEGORYINFO)new_this;
+ return S_OK;
+}
+
+static const IEnumCATEGORYINFOVtbl COMCAT_IEnumCATEGORYINFO_Vtbl =
+{
+ COMCAT_IEnumCATEGORYINFO_QueryInterface,
+ COMCAT_IEnumCATEGORYINFO_AddRef,
+ COMCAT_IEnumCATEGORYINFO_Release,
+ COMCAT_IEnumCATEGORYINFO_Next,
+ COMCAT_IEnumCATEGORYINFO_Skip,
+ COMCAT_IEnumCATEGORYINFO_Reset,
+ COMCAT_IEnumCATEGORYINFO_Clone
+};
+
+static LPENUMCATEGORYINFO COMCAT_IEnumCATEGORYINFO_Construct(LCID lcid)
+{
+ IEnumCATEGORYINFOImpl *This;
+
+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(IEnumCATEGORYINFOImpl));
+ if (This) {
+ static const WCHAR keyname[] = { 'C', 'o', 'm', 'p', 'o', 'n', 'e', 'n',
+ 't', ' ', 'C', 'a', 't', 'e', 'g', 'o',
+ 'r', 'i', 'e', 's', 0 };
+
+ This->lpVtbl = &COMCAT_IEnumCATEGORYINFO_Vtbl;
+ This->lcid = lcid;
+ RegOpenKeyExW(HKEY_CLASSES_ROOT, keyname, 0, KEY_READ, &This->key);
+ }
+ return (LPENUMCATEGORYINFO)This;
+}
+
+/**********************************************************************
+ * 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
+{
+ const IEnumGUIDVtbl *lpVtbl;
+ LONG ref;
+ struct class_categories *categories;
+ HKEY key;
+ DWORD next_index;
+} CLSID_IEnumGUIDImpl;
+
+static ULONG WINAPI COMCAT_CLSID_IEnumGUID_AddRef(LPENUMGUID iface)
+{
+ CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
+ TRACE("\n");
+
+ return InterlockedIncrement(&This->ref);
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_QueryInterface(
+ LPENUMGUID iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+ if (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)
+{
+ CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
+ ULONG ref;
+
+ TRACE("\n");
+
+ ref = InterlockedDecrement(&This->ref);
+ if (ref == 0) {
+ if (This->key) RegCloseKey(This->key);
+ HeapFree(GetProcessHeap(), 0, (LPVOID)This->categories);
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+ }
+ return ref;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Next(
+ LPENUMGUID iface,
+ ULONG celt,
+ GUID *rgelt,
+ ULONG *pceltFetched)
+{
+ CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
+ ULONG fetched = 0;
+
+ TRACE("\n");
+
+ if (rgelt == NULL) return E_POINTER;
+
+ if (This->key) while (fetched < celt) {
+ LSTATUS res;
+ HRESULT hr;
+ 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);
+
+ hr = CLSIDFromString(clsid, rgelt);
+ if (FAILED(hr)) continue;
+
+ res = RegOpenKeyExW(This->key, clsid, 0, KEY_READ, &subkey);
+ if (res != ERROR_SUCCESS) continue;
+
+ hr = COMCAT_IsClassOfCategories(subkey, This->categories);
+ RegCloseKey(subkey);
+ if (hr != 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)
+{
+ CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
+
+ TRACE("\n");
+
+ This->next_index += celt;
+ FIXME("Never returns S_FALSE\n");
+ return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Reset(LPENUMGUID iface)
+{
+ CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
+
+ TRACE("\n");
+
+ This->next_index = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CLSID_IEnumGUID_Clone(
+ LPENUMGUID iface,
+ IEnumGUID **ppenum)
+{
+ CLSID_IEnumGUIDImpl *This = (CLSID_IEnumGUIDImpl *)iface;
+ static const WCHAR keyname[] = { 'C', 'L', 'S', 'I', 'D', 0 };
+ CLSID_IEnumGUIDImpl *new_this;
+ DWORD size;
+
+ TRACE("\n");
+
+ if (ppenum == NULL) return E_POINTER;
+
+ new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
+ if (new_this == NULL) return E_OUTOFMEMORY;
+
+ new_this->lpVtbl = This->lpVtbl;
+ new_this->ref = 1;
+ size = HeapSize(GetProcessHeap(), 0, (LPVOID)This->categories);
+ new_this->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;
+}
+
+static const IEnumGUIDVtbl COMCAT_CLSID_IEnumGUID_Vtbl =
+{
+ 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 *categories)
+{
+ CLSID_IEnumGUIDImpl *This;
+
+ This = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CLSID_IEnumGUIDImpl));
+ if (This) {
+ static const WCHAR keyname[] = { 'C', 'L', 'S', 'I', 'D', 0 };
+
+ This->lpVtbl = &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
+{
+ const IEnumGUIDVtbl *lpVtbl;
+ LONG ref;
+ WCHAR keyname[68];
+ HKEY key;
+ DWORD next_index;
+} CATID_IEnumGUIDImpl;
+
+static ULONG WINAPI COMCAT_CATID_IEnumGUID_AddRef(LPENUMGUID iface)
+{
+ CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
+ TRACE("\n");
+
+ return InterlockedIncrement(&This->ref);
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_QueryInterface(
+ LPENUMGUID iface,
+ REFIID riid,
+ LPVOID *ppvObj)
+{
+ TRACE("\n\tIID:\t%s\n",debugstr_guid(riid));
+
+ if (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)
+{
+ CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
+ ULONG ref;
+
+ TRACE("\n");
+
+ ref = InterlockedDecrement(&This->ref);
+ if (ref == 0) {
+ if (This->key) RegCloseKey(This->key);
+ HeapFree(GetProcessHeap(), 0, This);
+ return 0;
+ }
+ return ref;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Next(
+ LPENUMGUID iface,
+ ULONG celt,
+ GUID *rgelt,
+ ULONG *pceltFetched)
+{
+ CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
+ ULONG fetched = 0;
+
+ TRACE("\n");
+
+ if (rgelt == NULL) return E_POINTER;
+
+ if (This->key) while (fetched < celt) {
+ LSTATUS res;
+ HRESULT hr;
+ 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);
+
+ hr = CLSIDFromString(catid, rgelt);
+ if (FAILED(hr)) 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)
+{
+ CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
+
+ TRACE("\n");
+
+ This->next_index += celt;
+ FIXME("Never returns S_FALSE\n");
+ return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Reset(LPENUMGUID iface)
+{
+ CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
+
+ TRACE("\n");
+
+ This->next_index = 0;
+ return S_OK;
+}
+
+static HRESULT WINAPI COMCAT_CATID_IEnumGUID_Clone(
+ LPENUMGUID iface,
+ IEnumGUID **ppenum)
+{
+ CATID_IEnumGUIDImpl *This = (CATID_IEnumGUIDImpl *)iface;
+ CATID_IEnumGUIDImpl *new_this;
+
+ TRACE("\n");
+
+ if (ppenum == NULL) return E_POINTER;
+
+ new_this = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
+ if (new_this == NULL) return E_OUTOFMEMORY;
+
+ new_this->lpVtbl = This->lpVtbl;
+ 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;
+}
+
+static const IEnumGUIDVtbl COMCAT_CATID_IEnumGUID_Vtbl =
+{
+ 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 = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CATID_IEnumGUIDImpl));
+ if (This) {
+ WCHAR prefix[6] = { 'C', 'L', 'S', 'I', 'D', '\\' };
+
+ This->lpVtbl = &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;
+}
* - Implement the OXID resolver so we don't need magic endpoint names for
* clients and servers to meet up
*
- * - Make all ole interface marshaling use NDR to be wire compatible with
- * native DCOM
- *
*/
#include "config.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
-HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
+HINSTANCE OLE32_hInstance = 0;
#define ARRAYSIZE(array) (sizeof(array)/sizeof((array)[0]))
/****************************************************************************
* This section defines variables internal to the COM module.
- *
- * TODO: Most of these things will have to be made thread-safe.
*/
static HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
* objects.
*
* TODO: Make this data structure aware of inter-process communication. This
- * means that parts of this will be exported to the Wine Server.
+ * means that parts of this will be exported to rpcss.
*/
typedef struct tagRegisteredClass
{
* following class is created. The *caller* of CoMarshalInterface (i.e., the
* application) is responsible for pumping the message loop in that thread.
* The WM_USER messages which point to the RPCs are then dispatched to
- * COM_AptWndProc by the user's code from the apartment in which the interface
- * was unmarshalled.
+ * apartment_wndproc by the user's code from the apartment in which the
+ * interface was unmarshalled.
*/
memset(&wclass, 0, sizeof(wclass));
wclass.lpfnWndProc = apartment_wndproc;
HWND apartment_hwnd;
};
+/* thread for hosting an object to allow an object to appear to be created in
+ * an apartment with an incompatible threading model */
static DWORD CALLBACK apartment_hostobject_thread(LPVOID p)
{
struct host_thread_params *params = p;
return S_OK;
}
-static HRESULT apartment_hostobject_in_hostapt(struct apartment *apt, BOOL multi_threaded, BOOL main_apartment, HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
+/* finds or creates a host apartment, creates the object inside it and returns
+ * a proxy to it so that the object can be used in the apartment of the
+ * caller of this function */
+static HRESULT apartment_hostobject_in_hostapt(
+ struct apartment *apt, BOOL multi_threaded, BOOL main_apartment,
+ HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv)
{
struct host_object_params params;
HWND apartment_hwnd = NULL;
return hr;
}
+/* create a window for the apartment or return the current one if one has
+ * already been created */
HRESULT apartment_createwindowifneeded(struct apartment *apt)
{
if (apt->multi_threaded)
return S_OK;
}
+/* retrieves the window for the main- or apartment-threaded apartment */
HWND apartment_getwindow(const struct apartment *apt)
{
assert(!apt->multi_threaded);
COM_CurrentInfo()->apt = MTA;
}
+/* gets the specified class object by loading the appropriate DLL, if
+ * necessary and calls the DllGetClassObject function for the DLL */
static HRESULT apartment_getclassobject(struct apartment *apt, LPCWSTR dllpath,
BOOL apartment_threaded,
REFCLSID rclsid, REFIID riid, void **ppv)
return hr;
}
+/* frees unused libraries loaded by apartment_getclassobject by calling the
+ * DLL's DllCanUnloadNow entry point */
static void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
{
struct apartment_loaded_dll *entry, *next;
if (real_delay == INFINITE)
{
+ /* DLLs that return multi-threaded objects aren't unloaded
+ * straight away to cope for programs that have races between
+ * last object destruction and threads in the DLLs that haven't
+ * finished, despite DllCanUnloadNow returning S_OK */
if (entry->multi_threaded)
real_delay = 10 * 60 * 1000; /* 10 minutes */
else
* Copyright 1999 Francis Beaudet
* Copyright 1999 Sylvain St-Germain
* Copyright 2002 Marcus Meissner
- * Copyright 2003 Ove Kåven, TransGaming Technologies
+ * Copyright 2003 Ove Kåven, TransGaming Technologies
* Copyright 2004 Mike Hearn, Rob Shearman, CodeWeavers Inc
*
* This library is free software; you can redistribute it and/or
/*
- * Copyright 2003 Ove Kåven, TransGaming Technologies
+ * Copyright 2003 Ove Kåven, TransGaming Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
WINE_DEFAULT_DEBUG_CHANNEL(ole);
+enum storage_state
+{
+ storage_state_uninitialised,
+ storage_state_initialised,
+ storage_state_loaded
+};
+
/****************************************************************************
* DefaultHandler
*
/* connection cookie for the advise on the delegate OLE object */
DWORD dwAdvConn;
+
+ /* storage passed to Load or InitNew */
+ IStorage *storage;
+ enum storage_state storage_state;
};
typedef struct DefaultHandler DefaultHandler;
-/*
- * Here, I define utility functions to help with the casting of the
- * "This" parameter.
- * There is a version to accommodate all of the VTables implemented
- * by this object.
- */
static inline DefaultHandler *impl_from_IOleObject( IOleObject *iface )
{
return (DefaultHandler *)((char*)iface - FIELD_OFFSET(DefaultHandler, lpVtbl));
{
DefaultHandler *This = impl_from_NDIUnknown(iface);
- /* Perform a sanity check on the parameters. */
if (!ppvObject)
return E_INVALIDARG;
DefaultHandler *This = impl_from_NDIUnknown(iface);
ULONG ref;
- /* Decrease the reference count on this object. */
ref = InterlockedDecrement(&This->ref);
if (!ref) DefaultHandler_Destroy(This);
{
DefaultHandler *This = impl_from_IOleObject(iface);
- /* Sanity check. */
if (!ppClientSite)
return E_POINTER;
HeapFree( GetProcessHeap(), 0, This->containerObj );
This->containerObj = NULL;
- /* Copy the string supplied. */
if (szContainerApp)
{
if ((This->containerApp = HeapAlloc( GetProcessHeap(), 0,
return S_OK;
}
-/* undos the work done by DefaultHandler_Run */
-static void WINAPI DefaultHandler_Stop(DefaultHandler *This)
+/* undoes the work done by DefaultHandler_Run */
+static void DefaultHandler_Stop(DefaultHandler *This)
{
if (!object_is_running(This))
return;
static HRESULT WINAPI DefaultHandler_Update(
IOleObject* iface)
{
- FIXME(": Stub\n");
- return E_NOTIMPL;
+ DefaultHandler *This = impl_from_IOleObject(iface);
+ TRACE("(%p)\n", iface);
+
+ if (!object_is_running(This))
+ {
+ FIXME("Should run object\n");
+ return E_NOTIMPL;
+ }
+ return IOleObject_Update(This->pOleDelegate);
}
/************************************************************************
static HRESULT WINAPI DefaultHandler_IsUpToDate(
IOleObject* iface)
{
- TRACE("(%p)\n", iface);
+ DefaultHandler *This = impl_from_IOleObject(iface);
+ TRACE("(%p)\n", iface);
- return OLE_E_NOTRUNNING;
+ if (object_is_running(This))
+ return IOleObject_IsUpToDate(This->pOleDelegate);
+
+ return OLE_E_NOTRUNNING;
}
/************************************************************************
if (object_is_running(This))
return IOleObject_GetUserClassID(This->pOleDelegate, pClsid);
- /* Sanity check. */
if (!pClsid)
return E_POINTER;
DefaultHandler *This = impl_from_IOleObject(iface);
TRACE("(%p, %d, %p)\n", iface, dwFormOfType, pszUserType);
+ if (object_is_running(This))
+ return IOleObject_GetUserType(This->pOleDelegate, dwFormOfType, pszUserType);
return OleRegGetUserType(&This->clsid, dwFormOfType, pszUserType);
}
targetDevice,
psizel);
- /*
- * Cleanup
- */
IViewObject2_Release(cacheView);
return hres;
TRACE("(%p, %p)\n", iface, ppenumAdvise);
- /* Sanity check */
if (!ppenumAdvise)
return E_POINTER;
TRACE("(%p, %p)\n", iface, ppenumAdvise);
- /* Sanity check */
if (!ppenumAdvise)
return E_POINTER;
IOleObject_QueryInterface(This->pOleDelegate, &IID_IPersistStorage,
(void **)&This->pPSDelegate);
if (This->pPSDelegate)
- hr = IPersistStorage_InitNew(This->pPSDelegate, NULL);
+ {
+ if(This->storage_state == storage_state_initialised)
+ hr = IPersistStorage_InitNew(This->pPSDelegate, This->storage);
+ else if(This->storage_state == storage_state_loaded)
+ hr = IPersistStorage_Load(This->pPSDelegate, This->storage);
+ }
}
if (SUCCEEDED(hr) && This->containerApp)
IPersistStorage* iface,
CLSID* clsid)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n", iface, clsid);
+
+ if(object_is_running(This))
+ hr = IPersistStorage_GetClassID(This->pPSDelegate, clsid);
+ else
+ hr = IPersistStorage_GetClassID(This->dataCache_PersistStg, clsid);
- return IPersistStorage_GetClassID(This->dataCache_PersistStg, clsid);
+ return hr;
}
/************************************************************************
static HRESULT WINAPI DefaultHandler_IPersistStorage_IsDirty(
IPersistStorage* iface)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
+
+ TRACE("(%p)\n", iface);
+
+ hr = IPersistStorage_IsDirty(This->dataCache_PersistStg);
+ if(hr != S_FALSE) return hr;
+
+ if(object_is_running(This))
+ hr = IPersistStorage_IsDirty(This->pPSDelegate);
+
+ return hr;
+}
+
+/***********************************************************************
+ * init_ole_stream
+ *
+ * Creates the '\1Ole' stream.
+ * The format of this stream is as follows:
+ *
+ * DWORD Version == 0x02000001
+ * DWORD Flags - low bit set indicates the object is a link otherwise it's embedded.
+ * DWORD LinkupdateOption - [MS-OLEDS describes this as an implementation specific hint
+ * supplied by the app that creates the data structure. May be
+ * ignored on processing].
+ *
+ * DWORD Reserved == 0
+ * DWORD MonikerStreamSize - size of the rest of the data (ie CLSID + moniker stream data).
+ * CLSID clsid - class id of object capable of processing the moniker
+ * BYTE data[] - moniker data for a link
+ */
+
+static const WCHAR OleStream[] = {1,'O','l','e',0};
+typedef struct
+{
+ DWORD version;
+ DWORD flags;
+ DWORD link_update_opt;
+ DWORD res;
+ DWORD moniker_size;
+} ole_stream_header_t;
+static const DWORD ole_stream_version = 0x02000001;
+
+static void init_ole_stream(IStorage *storage)
+{
+ HRESULT hr;
+ IStream *stream;
+
+ hr = IStorage_CreateStream(storage, OleStream, STGM_READWRITE | STGM_SHARE_EXCLUSIVE, 0, 0, &stream);
+ if(SUCCEEDED(hr))
+ {
+ DWORD written;
+ ole_stream_header_t header;
+
+ header.version = ole_stream_version;
+ header.flags = 0;
+ header.link_update_opt = 0;
+ header.res = 0;
+ header.moniker_size = 0;
+
+ IStream_Write(stream, &header, sizeof(header), &written);
+ IStream_Release(stream);
+ }
+ return;
+}
+
+static HRESULT load_ole_stream(DefaultHandler *This, IStorage *storage)
+{
+ IStream *stream;
+ HRESULT hr;
+
+ hr = IStorage_OpenStream(storage, OleStream, NULL, STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &stream);
- return IPersistStorage_IsDirty(This->dataCache_PersistStg);
+ if(SUCCEEDED(hr))
+ {
+ DWORD read;
+ ole_stream_header_t header;
+
+ hr = IStream_Read(stream, &header, sizeof(header), &read);
+ if(hr == S_OK && read == sizeof(header) && header.version == ole_stream_version)
+ {
+ if(header.flags & 1)
+ {
+ /* FIXME: Read the moniker and deal with the link */
+ FIXME("Linked objects are not supported yet\n");
+ }
+ }
+ else
+ {
+ WARN("Incorrect OleStream header\n");
+ hr = DV_E_CLIPFORMAT;
+ }
+ IStream_Release(stream);
+ }
+ else
+ {
+ init_ole_stream(storage);
+ hr = S_OK;
+ }
+ return hr;
}
/************************************************************************
IPersistStorage* iface,
IStorage* pStg)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n", iface, pStg);
+ init_ole_stream(pStg);
- return IPersistStorage_InitNew(This->dataCache_PersistStg, pStg);
+ hr = IPersistStorage_InitNew(This->dataCache_PersistStg, pStg);
+
+ if(SUCCEEDED(hr) && object_is_running(This))
+ hr = IPersistStorage_InitNew(This->pPSDelegate, pStg);
+
+ if(SUCCEEDED(hr))
+ {
+ IStorage_AddRef(pStg);
+ This->storage = pStg;
+ This->storage_state = storage_state_initialised;
+ }
+
+ return hr;
}
IPersistStorage* iface,
IStorage* pStg)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n", iface, pStg);
+
+ hr = load_ole_stream(This, pStg);
- return IPersistStorage_Load(This->dataCache_PersistStg, pStg);
+ if(SUCCEEDED(hr))
+ hr = IPersistStorage_Load(This->dataCache_PersistStg, pStg);
+
+ if(SUCCEEDED(hr) && object_is_running(This))
+ hr = IPersistStorage_Load(This->pPSDelegate, pStg);
+
+ if(SUCCEEDED(hr))
+ {
+ IStorage_AddRef(pStg);
+ This->storage = pStg;
+ This->storage_state = storage_state_loaded;
+ }
+ return hr;
}
static HRESULT WINAPI DefaultHandler_IPersistStorage_Save(
IPersistStorage* iface,
IStorage* pStgSave,
- BOOL fSaveAsLoad)
+ BOOL fSameAsLoad)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
- return IPersistStorage_Save(This->dataCache_PersistStg, pStgSave, fSaveAsLoad);
+ TRACE("(%p)->(%p, %d)\n", iface, pStgSave, fSameAsLoad);
+
+ hr = IPersistStorage_Save(This->dataCache_PersistStg, pStgSave, fSameAsLoad);
+ if(SUCCEEDED(hr) && object_is_running(This))
+ hr = IPersistStorage_Save(This->pPSDelegate, pStgSave, fSameAsLoad);
+
+ return hr;
}
IPersistStorage* iface,
IStorage* pStgNew)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
+
+ TRACE("(%p)->(%p)\n", iface, pStgNew);
+
+ hr = IPersistStorage_SaveCompleted(This->dataCache_PersistStg, pStgNew);
+
+ if(SUCCEEDED(hr) && object_is_running(This))
+ hr = IPersistStorage_SaveCompleted(This->pPSDelegate, pStgNew);
+
+ if(pStgNew)
+ {
+ IStorage_AddRef(pStgNew);
+ if(This->storage) IStorage_Release(This->storage);
+ This->storage = pStgNew;
+ This->storage_state = storage_state_loaded;
+ }
- return IPersistStorage_SaveCompleted(This->dataCache_PersistStg, pStgNew);
+ return hr;
}
static HRESULT WINAPI DefaultHandler_IPersistStorage_HandsOffStorage(
IPersistStorage* iface)
{
- DefaultHandler *This = impl_from_IPersistStorage(iface);
+ DefaultHandler *This = impl_from_IPersistStorage(iface);
+ HRESULT hr;
+
+ TRACE("(%p)\n", iface);
+
+ hr = IPersistStorage_HandsOffStorage(This->dataCache_PersistStg);
+
+ if(SUCCEEDED(hr) && object_is_running(This))
+ hr = IPersistStorage_HandsOffStorage(This->pPSDelegate);
- return IPersistStorage_HandsOffStorage(This->dataCache_PersistStg);
+ if(This->storage) IStorage_Release(This->storage);
+ This->storage = NULL;
+ This->storage_state = storage_state_uninitialised;
+
+ return hr;
}
DefaultHandler* This = NULL;
HRESULT hr;
- /*
- * Allocate space for the object.
- */
This = HeapAlloc(GetProcessHeap(), 0, sizeof(DefaultHandler));
if (!This)
hr = IUnknown_QueryInterface(This->dataCache, &IID_IPersistStorage, (void**)&This->dataCache_PersistStg);
if(FAILED(hr))
ERR("Unexpected error creating data cache\n");
- /*
- * Initialize the other data members of the class.
- */
+
This->clsid = *clsid;
This->clientSite = NULL;
This->oleAdviseHolder = NULL;
This->pDataDelegate = NULL;
This->dwAdvConn = 0;
+ This->storage = NULL;
+ This->storage_state = storage_state_uninitialised;
return This;
}
/* release delegates */
DefaultHandler_Stop(This);
- /* Free the strings idenfitying the object */
HeapFree( GetProcessHeap(), 0, This->containerApp );
This->containerApp = NULL;
HeapFree( GetProcessHeap(), 0, This->containerObj );
This->containerObj = NULL;
- /* Release our reference to the data cache. */
if (This->dataCache)
{
IPersistStorage_Release(This->dataCache_PersistStg);
This->dataCache = NULL;
}
- /* Same thing for the client site. */
if (This->clientSite)
{
IOleClientSite_Release(This->clientSite);
This->clientSite = NULL;
}
- /* And the advise holder. */
if (This->oleAdviseHolder)
{
IOleAdviseHolder_Release(This->oleAdviseHolder);
This->oleAdviseHolder = NULL;
}
- /* And the data advise holder. */
if (This->dataAdviseHolder)
{
IDataAdviseHolder_Release(This->dataAdviseHolder);
This->dataAdviseHolder = NULL;
}
- /* Free the actual default handler structure. */
+ if (This->storage)
+ {
+ IStorage_Release(This->storage);
+ This->storage = NULL;
+ }
+
HeapFree(GetProcessHeap(), 0, This);
}
TRACE("(%s, %p, %s, %p)\n", debugstr_guid(clsid), pUnkOuter, debugstr_guid(riid), ppvObj);
- /*
- * Sanity check
- */
if (!ppvObj)
return E_POINTER;
/* write a 0 WORD */
res=IStream_Write(pStm,&ZERO,sizeof(WORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* write length of filePath string ( 0 included )*/
bytesA = WideCharToMultiByte( CP_ACP, 0, filePathW, -1, NULL, 0, NULL, NULL );
res=IStream_Write(pStm,&bytesA,sizeof(DWORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* write A string (with '\0') */
filePathA=HeapAlloc(GetProcessHeap(),0,bytesA);
WideCharToMultiByte( CP_ACP, 0, filePathW, -1, filePathA, bytesA, NULL, &bUsedDefault);
res=IStream_Write(pStm,filePathA,bytesA,NULL);
HeapFree(GetProcessHeap(),0,filePathA);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* write a DWORD 0xDEADFFFF */
res=IStream_Write(pStm,&DEADFFFF,sizeof(DWORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* write 5 zero DWORDs */
for(i=0;i<5;i++)
{
res=IStream_Write(pStm,&ZERO,sizeof(DWORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
}
/* Write the wide version if:
/* write bytes needed for the filepathW (without 0) + 6 */
bytesW = len*sizeof(WCHAR) + 6;
res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* try again, without the extra 6 */
bytesW -= 6;
res=IStream_Write(pStm,&bytesW,sizeof(DWORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* write a WORD 3 */
res=IStream_Write(pStm,&THREE,sizeof(WORD),NULL);
- if (!SUCCEEDED(res)) return res;
+ if (FAILED(res)) return res;
/* write W string (no 0) */
res=IStream_Write(pStm,filePathW,bytesW,NULL);
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
- *
- * TODO:
- * - IRunningObjectTable should work interprocess, but currently doesn't.
- * Native (on Win2k at least) uses an undocumented RPC interface, IROT, to
- * communicate with RPCSS which contains the table of marshalled data.
*/
-#include <assert.h>
+#include "config.h"
+#include "wine/port.h"
+
#include <stdarg.h>
#include <string.h>
#include "wine/list.h"
#include "wine/debug.h"
#include "wine/unicode.h"
+#include "wine/exception.h"
#include "compobj_private.h"
#include "moniker.h"
+#include "irot.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
/* see MSDN docs for IROTData::GetComparisonData, which states what this
- * constant is (http://msdn2.microsoft.com/en-us/library/ms693773.aspx) */
+ * constant is
+ */
#define MAX_COMPARISON_DATA 2048
+static LONG WINAPI rpc_filter(EXCEPTION_POINTERS *eptr)
+{
+ return I_RpcExceptionFilter(eptr->ExceptionRecord->ExceptionCode);
+}
+
/* define the structure of the running object table elements */
struct rot_entry
{
struct list entry;
- MInterfacePointer* object; /* marshaled running object*/
- MInterfacePointer* moniker; /* marshaled moniker that identifies this object */
- MInterfacePointer* moniker_data; /* moniker comparison data that identifies this object */
+ InterfaceData* object; /* marshaled running object*/
+ MonikerComparisonData* moniker_data; /* moniker comparison data that identifies this object */
DWORD cookie; /* cookie identifying this object */
FILETIME last_modified;
+ IrotContextHandle ctxt_handle;
};
/* define the RunningObjectTableImpl structure */
} RunningObjectTableImpl;
static RunningObjectTableImpl* runningObjectTableInstance = NULL;
-
-
-
-static inline HRESULT WINAPI
-IrotRegister(DWORD *cookie)
-{
- static LONG last_cookie = 1;
- *cookie = InterlockedIncrement(&last_cookie);
- return S_OK;
-}
+static IrotHandle irot_handle;
/* define the EnumMonikerImpl structure */
typedef struct EnumMonikerImpl
const IEnumMonikerVtbl *lpVtbl;
LONG ref;
- MInterfacePointer **monikers;
- ULONG moniker_count;
+ InterfaceList *moniker_list;
ULONG pos;
} EnumMonikerImpl;
/* IEnumMoniker Local functions*/
-static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers,
- ULONG moniker_count, ULONG pos, IEnumMoniker **ppenumMoniker);
+static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(InterfaceList *moniker_list,
+ ULONG pos, IEnumMoniker **ppenumMoniker);
+
+static IrotHandle get_irot_handle(void)
+{
+ if (!irot_handle)
+ {
+ RPC_STATUS status;
+ RPC_WSTR binding;
+ IrotHandle new_handle;
+ unsigned short ncacn_np[] = IROT_PROTSEQ;
+ unsigned short endpoint[] = IROT_ENDPOINT;
+ status = RpcStringBindingComposeW(NULL, ncacn_np, NULL, endpoint, NULL, &binding);
+ if (status == RPC_S_OK)
+ {
+ status = RpcBindingFromStringBindingW(binding, &new_handle);
+ RpcStringFreeW(&binding);
+ }
+ if (status != RPC_S_OK)
+ return NULL;
+ if (InterlockedCompareExchangePointer(&irot_handle, new_handle, NULL))
+ /* another thread beat us to it */
+ RpcBindingFree(&new_handle);
+ }
+ return irot_handle;
+}
-static HRESULT create_stream_on_mip_ro(const MInterfacePointer *mip, IStream **stream)
+static BOOL start_rpcss(void)
+{
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ static WCHAR cmd[6];
+ static const WCHAR rpcss[] = {'r','p','c','s','s',0};
+ BOOL rslt;
+
+ TRACE("\n");
+
+ ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
+ ZeroMemory(&si, sizeof(STARTUPINFOA));
+ si.cb = sizeof(STARTUPINFOA);
+
+ memcpy(cmd, rpcss, sizeof(rpcss));
+
+ rslt = CreateProcessW(
+ NULL, /* executable */
+ cmd, /* command line */
+ NULL, /* process security attributes */
+ NULL, /* primary thread security attributes */
+ FALSE, /* inherit handles */
+ 0, /* creation flags */
+ NULL, /* use parent's environment */
+ NULL, /* use parent's current directory */
+ &si, /* STARTUPINFO pointer */
+ &pi /* PROCESS_INFORMATION */
+ );
+
+ if (rslt)
+ {
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ Sleep(100);
+ }
+
+ return rslt;
+}
+
+static HRESULT create_stream_on_mip_ro(const InterfaceData *mip, IStream **stream)
{
HGLOBAL hglobal = GlobalAlloc(0, mip->ulCntData);
void *pv = GlobalLock(hglobal);
static inline void rot_entry_delete(struct rot_entry *rot_entry)
{
- /* FIXME: revoke entry from rpcss's copy of the ROT */
- if (rot_entry->object)
+ if (rot_entry->cookie)
{
- IStream *stream;
- HRESULT hr;
- hr = create_stream_on_mip_ro(rot_entry->object, &stream);
- if (hr == S_OK)
+ InterfaceData *object = NULL;
+ InterfaceData *moniker = NULL;
+ __TRY
{
- CoReleaseMarshalData(stream);
- IUnknown_Release(stream);
+ IrotRevoke(get_irot_handle(), rot_entry->cookie,
+ &rot_entry->ctxt_handle, &object, &moniker);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ }
+ __ENDTRY
+ MIDL_user_free(object);
+ if (moniker)
+ {
+ IStream *stream;
+ HRESULT hr;
+ hr = create_stream_on_mip_ro(moniker, &stream);
+ if (hr == S_OK)
+ {
+ CoReleaseMarshalData(stream);
+ IUnknown_Release(stream);
+ }
}
+ MIDL_user_free(moniker);
}
- if (rot_entry->moniker)
+ if (rot_entry->object)
{
IStream *stream;
HRESULT hr;
- hr = create_stream_on_mip_ro(rot_entry->moniker, &stream);
+ hr = create_stream_on_mip_ro(rot_entry->object, &stream);
if (hr == S_OK)
{
CoReleaseMarshalData(stream);
}
}
HeapFree(GetProcessHeap(), 0, rot_entry->object);
- HeapFree(GetProcessHeap(), 0, rot_entry->moniker);
HeapFree(GetProcessHeap(), 0, rot_entry->moniker_data);
HeapFree(GetProcessHeap(), 0, rot_entry);
}
/* moniker_data must be freed with HeapFree when no longer in use */
-static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MInterfacePointer **moniker_data)
+static HRESULT get_moniker_comparison_data(IMoniker *pMoniker, MonikerComparisonData **moniker_data)
{
HRESULT hr;
IROTData *pROTData = NULL;
if (SUCCEEDED(hr))
{
ULONG size = MAX_COMPARISON_DATA;
- *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
+ *moniker_data = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MonikerComparisonData, abData[size]));
+ if (!*moniker_data)
+ {
+ IROTData_Release(pROTData);
+ return E_OUTOFMEMORY;
+ }
hr = IROTData_GetComparisonData(pROTData, (*moniker_data)->abData, size, &size);
+ IROTData_Release(pROTData);
if (hr != S_OK)
{
ERR("Failed to copy comparison data into buffer, hr = 0x%08x\n", hr);
len = strlenW(pszDisplayName);
*moniker_data = HeapAlloc(GetProcessHeap(), 0,
- FIELD_OFFSET(MInterfacePointer, abData[sizeof(CLSID) + (len+1)*sizeof(WCHAR)]));
+ FIELD_OFFSET(MonikerComparisonData, abData[sizeof(CLSID) + (len+1)*sizeof(WCHAR)]));
if (!*moniker_data)
{
CoTaskMemFree(pszDisplayName);
memcpy(&(*moniker_data)->abData[0], &clsid, sizeof(clsid));
memcpy(&(*moniker_data)->abData[sizeof(clsid)], pszDisplayName, (len+1)*sizeof(WCHAR));
+ CoTaskMemFree(pszDisplayName);
}
return S_OK;
}
RunningObjectTableImpl_Destroy(void)
{
struct list *cursor, *cursor2;
+ IrotHandle old_handle;
TRACE("()\n");
HeapFree(GetProcessHeap(),0,runningObjectTableInstance);
runningObjectTableInstance = NULL;
+ old_handle = irot_handle;
+ irot_handle = NULL;
+ if (old_handle)
+ RpcBindingFree(&old_handle);
+
return S_OK;
}
IStream *pStream = NULL;
DWORD mshlflags;
IBindCtx *pbc;
+ InterfaceData *moniker = NULL;
TRACE("(%p,%d,%p,%p,%p)\n",This,grfFlags,punkObject,pmkObjectName,pdwRegister);
const void *pv = GlobalLock(hglobal);
rot_entry->object = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
rot_entry->object->ulCntData = size;
- memcpy(&rot_entry->object->abData, pv, size);
+ memcpy(rot_entry->object->abData, pv, size);
GlobalUnlock(hglobal);
}
}
{
SIZE_T size = GlobalSize(hglobal);
const void *pv = GlobalLock(hglobal);
- rot_entry->moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(MInterfacePointer, abData[size]));
- rot_entry->moniker->ulCntData = size;
- memcpy(&rot_entry->moniker->abData, pv, size);
+ moniker = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceData, abData[size]));
+ moniker->ulCntData = size;
+ memcpy(moniker->abData, pv, size);
GlobalUnlock(hglobal);
}
}
IMoniker_Release(pmkObjectName);
if (hr != S_OK)
{
+ HeapFree(GetProcessHeap(), 0, moniker);
rot_entry_delete(rot_entry);
return hr;
}
- /* FIXME: not the right signature of IrotRegister function */
- hr = IrotRegister(&rot_entry->cookie);
- if (hr != S_OK)
+
+ while (TRUE)
+ {
+ __TRY
+ {
+ hr = IrotRegister(get_irot_handle(), rot_entry->moniker_data,
+ rot_entry->object, moniker,
+ &rot_entry->last_modified, grfFlags,
+ &rot_entry->cookie, &rot_entry->ctxt_handle);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ hr = HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+ __ENDTRY
+ if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
+ {
+ if (start_rpcss())
+ continue;
+ }
+ break;
+ }
+ HeapFree(GetProcessHeap(), 0, moniker);
+ if (FAILED(hr))
{
rot_entry_delete(rot_entry);
return hr;
*pdwRegister = rot_entry->cookie;
EnterCriticalSection(&This->lock);
- /* FIXME: see if object was registered before and return MK_S_MONIKERALREADYREGISTERED */
list_add_tail(&This->rot, &rot_entry->entry);
LeaveCriticalSection(&This->lock);
RunningObjectTableImpl_IsRunning( IRunningObjectTable* iface, IMoniker *pmkObjectName)
{
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
- MInterfacePointer *moniker_data;
+ MonikerComparisonData *moniker_data;
HRESULT hr;
- struct rot_entry *rot_entry;
+ const struct rot_entry *rot_entry;
TRACE("(%p,%p)\n",This,pmkObjectName);
hr = S_FALSE;
EnterCriticalSection(&This->lock);
- LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
+ LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, const struct rot_entry, entry)
{
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
- !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
+ !memcmp(moniker_data->abData, rot_entry->moniker_data->abData, moniker_data->ulCntData))
{
hr = S_OK;
break;
}
LeaveCriticalSection(&This->lock);
- /* FIXME: call IrotIsRunning */
+ if (hr == S_FALSE)
+ {
+ while (TRUE)
+ {
+ __TRY
+ {
+ hr = IrotIsRunning(get_irot_handle(), moniker_data);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ hr = HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+ __ENDTRY
+ if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
+ {
+ if (start_rpcss())
+ continue;
+ }
+ break;
+ }
+ }
HeapFree(GetProcessHeap(), 0, moniker_data);
IMoniker *pmkObjectName, IUnknown **ppunkObject)
{
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
- MInterfacePointer *moniker_data;
+ MonikerComparisonData *moniker_data;
+ InterfaceData *object = NULL;
+ IrotCookie cookie;
HRESULT hr;
struct rot_entry *rot_entry;
LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
{
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
- !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
+ !memcmp(moniker_data->abData, rot_entry->moniker_data->abData, moniker_data->ulCntData))
{
IStream *pStream;
hr = create_stream_on_mip_ro(rot_entry->object, &pStream);
}
LeaveCriticalSection(&This->lock);
- /* FIXME: call IrotGetObject */
- WARN("Moniker unavailable - app may require interprocess running object table\n");
- hr = MK_E_UNAVAILABLE;
+ TRACE("moniker unavailable locally, calling SCM\n");
+
+ while (TRUE)
+ {
+ __TRY
+ {
+ hr = IrotGetObject(get_irot_handle(), moniker_data, &object, &cookie);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ hr = HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+ __ENDTRY
+ if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
+ {
+ if (start_rpcss())
+ continue;
+ }
+ break;
+ }
+
+ if (SUCCEEDED(hr))
+ {
+ IStream *pStream;
+ hr = create_stream_on_mip_ro(object, &pStream);
+ if (hr == S_OK)
+ {
+ hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)ppunkObject);
+ IStream_Release(pStream);
+ }
+ }
+ else
+ WARN("Moniker unavailable, IrotGetObject returned 0x%08x\n", hr);
HeapFree(GetProcessHeap(), 0, moniker_data);
{
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
struct rot_entry *rot_entry;
+ HRESULT hr = E_INVALIDARG;
TRACE("(%p,%d,%p)\n",This,dwRegister,pfiletime);
{
rot_entry->last_modified = *pfiletime;
LeaveCriticalSection(&This->lock);
- return S_OK;
+
+ while (TRUE)
+ {
+ __TRY
+ {
+ hr = IrotNoteChangeTime(get_irot_handle(), dwRegister, pfiletime);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ hr = HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+ __ENDTRY
+ if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
+ {
+ if (start_rpcss())
+ continue;
+ }
+ break;
+ }
+
+ goto done;
}
}
LeaveCriticalSection(&This->lock);
- /* FIXME: call IrotNoteChangeTime */
-
- return E_INVALIDARG;
+done:
+ TRACE("-- 0x08%x\n", hr);
+ return hr;
}
/***********************************************************************
{
HRESULT hr = MK_E_UNAVAILABLE;
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
- MInterfacePointer *moniker_data;
- struct rot_entry *rot_entry;
+ MonikerComparisonData *moniker_data;
+ const struct rot_entry *rot_entry;
TRACE("(%p,%p,%p)\n",This,pmkObjectName,pfiletime);
hr = MK_E_UNAVAILABLE;
EnterCriticalSection(&This->lock);
- LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, struct rot_entry, entry)
+ LIST_FOR_EACH_ENTRY(rot_entry, &This->rot, const struct rot_entry, entry)
{
if ((rot_entry->moniker_data->ulCntData == moniker_data->ulCntData) &&
- !memcmp(&moniker_data->abData, &rot_entry->moniker_data->abData, moniker_data->ulCntData))
+ !memcmp(moniker_data->abData, rot_entry->moniker_data->abData, moniker_data->ulCntData))
{
*pfiletime = rot_entry->last_modified;
hr = S_OK;
}
LeaveCriticalSection(&This->lock);
- /* FIXME: if (hr != S_OK) call IrotGetTimeOfLastChange */
+ if (hr != S_OK)
+ {
+ while (TRUE)
+ {
+ __TRY
+ {
+ hr = IrotGetTimeOfLastChange(get_irot_handle(), moniker_data, pfiletime);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ hr = HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+ __ENDTRY
+ if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
+ {
+ if (start_rpcss())
+ continue;
+ }
+ break;
+ }
+ }
HeapFree(GetProcessHeap(), 0, moniker_data);
+
+ TRACE("-- 0x%08x\n", hr);
return hr;
}
RunningObjectTableImpl_EnumRunning(IRunningObjectTable* iface,
IEnumMoniker **ppenumMoniker)
{
- HRESULT hr;
RunningObjectTableImpl *This = (RunningObjectTableImpl *)iface;
- MInterfacePointer **monikers;
- ULONG moniker_count = 0;
- const struct rot_entry *rot_entry;
- ULONG i = 0;
-
- EnterCriticalSection(&This->lock);
+ InterfaceList *interface_list = NULL;
+ HRESULT hr;
- LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry )
- moniker_count++;
+ TRACE("(%p, %p)\n", This, ppenumMoniker);
- monikers = HeapAlloc(GetProcessHeap(), 0, moniker_count * sizeof(*monikers));
+ *ppenumMoniker = NULL;
- LIST_FOR_EACH_ENTRY( rot_entry, &This->rot, const struct rot_entry, entry )
+ while (TRUE)
{
- SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[rot_entry->moniker->ulCntData]);
- monikers[i] = HeapAlloc(GetProcessHeap(), 0, size);
- memcpy(monikers[i], rot_entry->moniker, size);
- i++;
+ __TRY
+ {
+ hr = IrotEnumRunning(get_irot_handle(), &interface_list);
+ }
+ __EXCEPT(rpc_filter)
+ {
+ hr = HRESULT_FROM_WIN32(GetExceptionCode());
+ }
+ __ENDTRY
+ if (hr == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE))
+ {
+ if (start_rpcss())
+ continue;
+ }
+ break;
}
- LeaveCriticalSection(&This->lock);
-
- /* FIXME: call IrotEnumRunning and append data */
-
- hr = EnumMonikerImpl_CreateEnumROTMoniker(monikers, moniker_count, 0, ppenumMoniker);
+ if (SUCCEEDED(hr))
+ hr = EnumMonikerImpl_CreateEnumROTMoniker(interface_list,
+ 0, ppenumMoniker);
return hr;
}
/* initialize the virtual table function */
runningObjectTableInstance->lpVtbl = &VT_RunningObjectTableImpl;
- /* the initial reference is set to "1" ! because if set to "0" it will be not practis when */
- /* the ROT referred many times not in the same time (all the objects in the ROT will */
- /* be removed every time the ROT is removed ) */
+ /* the initial reference is set to "1" so that it isn't destroyed after its
+ * first use until the process is destroyed, as the running object table is
+ * a process-wide cache of a global table */
runningObjectTableInstance->ref = 1;
list_init(&runningObjectTableInstance->rot);
IParseDisplayName *pdn;
hr = IMoniker_BindToObject(class_moniker, pbc, NULL,
&IID_IParseDisplayName, (void **)&pdn);
+ /* fallback to using IClassFactory to get IParseDisplayName -
+ * adsldp.dll depends on this */
+ if (FAILED(hr))
+ {
+ IClassFactory *pcf;
+ hr = IMoniker_BindToObject(class_moniker, pbc, NULL,
+ &IID_IClassFactory, (void **)&pcf);
+ if (SUCCEEDED(hr))
+ {
+ hr = IClassFactory_CreateInstance(pcf, NULL,
+ &IID_IParseDisplayName,
+ (void **)&pdn);
+ IClassFactory_Release(pcf);
+ }
+ }
IMoniker_Release(class_moniker);
if (SUCCEEDED(hr))
{
return res;
}
- /* if the file is not a storage object then attemps to match various bits in the file against a
- pattern in the registry. this case is not frequently used ! so I present only the psodocode for
- this case
+ /* If the file is not a storage object then attempt to match various bits in the file against a
+ pattern in the registry. This case is not frequently used, so I present only the pseudocode for
+ this case.
for(i=0;i<nFileTypes;i++)
nbElm=FileMonikerImpl_DecomposePath(filePathName,&pathDec);
absFile=pathDec[nbElm-1];
- /* failed if the path represente a directory and not an absolute file name*/
+ /* failed if the path represents a directory and not an absolute file name*/
if (!lstrcmpW(absFile, bkslashW))
return MK_E_INVALIDEXTENSION;
TRACE("(%p) Deleting\n",This);
- for (i = 0; i < This->moniker_count; i++)
- HeapFree(GetProcessHeap(), 0, This->monikers[i]);
- HeapFree(GetProcessHeap(), 0, This->monikers);
+ for (i = 0; i < This->moniker_list->size; i++)
+ HeapFree(GetProcessHeap(), 0, This->moniker_list->interfaces[i]);
+ HeapFree(GetProcessHeap(), 0, This->moniker_list);
HeapFree(GetProcessHeap(), 0, This);
}
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
HRESULT hr = S_OK;
- TRACE("(%p) TabCurrentPos %d Tablastindx %d\n", This, This->pos, This->moniker_count);
+ TRACE("(%p) TabCurrentPos %d Tablastindx %d\n", This, This->pos, This->moniker_list->size);
/* retrieve the requested number of moniker from the current position */
- for(i = 0; (This->pos < This->moniker_count) && (i < celt); i++)
+ for(i = 0; (This->pos < This->moniker_list->size) && (i < celt); i++)
{
IStream *stream;
- hr = create_stream_on_mip_ro(This->monikers[This->pos++], &stream);
+ hr = create_stream_on_mip_ro(This->moniker_list->interfaces[This->pos++], &stream);
if (hr != S_OK) break;
hr = CoUnmarshalInterface(stream, &IID_IMoniker, (void **)&rgelt[i]);
IStream_Release(stream);
TRACE("(%p)\n",This);
- if (This->pos + celt >= This->moniker_count)
+ if (This->pos + celt >= This->moniker_list->size)
return S_FALSE;
This->pos += celt;
static HRESULT WINAPI EnumMonikerImpl_Clone(IEnumMoniker* iface, IEnumMoniker ** ppenum)
{
EnumMonikerImpl *This = (EnumMonikerImpl *)iface;
- MInterfacePointer **monikers = HeapAlloc(GetProcessHeap(), 0, sizeof(*monikers)*This->moniker_count);
+ InterfaceList *moniker_list;
ULONG i;
TRACE("(%p)\n",This);
- for (i = 0; i < This->moniker_count; i++)
+ *ppenum = NULL;
+
+ moniker_list = HeapAlloc(GetProcessHeap(), 0, FIELD_OFFSET(InterfaceList, interfaces[This->moniker_list->size]));
+ if (!moniker_list)
+ return E_OUTOFMEMORY;
+
+ moniker_list->size = This->moniker_list->size;
+ for (i = 0; i < This->moniker_list->size; i++)
{
- SIZE_T size = FIELD_OFFSET(MInterfacePointer, abData[This->monikers[i]->ulCntData]);
- monikers[i] = HeapAlloc(GetProcessHeap(), 0, size);
- memcpy(monikers[i], This->monikers[i], size);
+ SIZE_T size = FIELD_OFFSET(InterfaceData, abData[This->moniker_list->interfaces[i]->ulCntData]);
+ moniker_list->interfaces[i] = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!moniker_list->interfaces[i])
+ {
+ ULONG end = i;
+ for (i = 0; i < end; i++)
+ HeapFree(GetProcessHeap(), 0, moniker_list->interfaces[i]);
+ HeapFree(GetProcessHeap(), 0, moniker_list);
+ return E_OUTOFMEMORY;
+ }
+ memcpy(moniker_list->interfaces[i], This->moniker_list->interfaces[i], size);
}
/* copy the enum structure */
- return EnumMonikerImpl_CreateEnumROTMoniker(monikers, This->moniker_count,
- This->pos, ppenum);
+ return EnumMonikerImpl_CreateEnumROTMoniker(moniker_list, This->pos, ppenum);
}
/* Virtual function table for the IEnumMoniker class. */
* Used by EnumRunning to create the structure and EnumClone
* to copy the structure
*/
-static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(MInterfacePointer **monikers,
- ULONG moniker_count,
+static HRESULT WINAPI EnumMonikerImpl_CreateEnumROTMoniker(InterfaceList *moniker_list,
ULONG current_pos,
IEnumMoniker **ppenumMoniker)
{
/* the initial reference is set to "1" */
This->ref = 1; /* set the ref count to one */
This->pos = current_pos; /* Set the list start posn */
- This->moniker_count = moniker_count; /* Need the same size table as ROT */
- This->monikers = monikers;
+ This->moniker_list = moniker_list;
*ppenumMoniker = (IEnumMoniker*)This;
*outer = (IUnknown *)&This->lpVtbl;
return S_OK;
}
+
+void * __RPC_USER MIDL_user_allocate(size_t size)
+{
+ return HeapAlloc(GetProcessHeap(), 0, size);
+}
+
+void __RPC_USER MIDL_user_free(void *p)
+{
+ HeapFree(GetProcessHeap(), 0, p);
+}
HRESULT CompositeMonikerCF_Create(REFIID riid, LPVOID *ppv);
HRESULT ClassMonikerCF_Create(REFIID riid, LPVOID *ppv);
HRESULT PointerMonikerCF_Create(REFIID riid, LPVOID *ppv);
+HRESULT ComCatCF_Create(REFIID riid, LPVOID *ppv);
/* This function decomposes a String path to a String Table containing all the elements ("\" or "subDirectory" or "Directory" or "FileName") of the path */
int FileMonikerImpl_DecomposePath(LPCOLESTR str, LPOLESTR** stringTable);
*/
static BOOL OLEMenu_FindMainMenuIndex( HMENU hMainMenu, HMENU hPopupMenu, UINT *pnPos )
{
- UINT i, nItems;
+ INT i, nItems;
nItems = GetMenuItemCount( hMainMenu );
*
* Copyright 1995 Martin von Loewis
* Copyright 1998 David Lee Lambert
- * Copyright 2000 Julio César Gázquez
+ * Copyright 2000 Julio César Gázquez
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
return E_NOTIMPL;
}
+
+/***********************************************************************
+ * CoGetCallerTID [OLE32.@]
+ */
+HRESULT WINAPI CoGetCallerTID(LPDWORD lpdwTID)
+{
+ FIXME("stub!\n");
+ return E_NOTIMPL;
+}
<library>advapi32</library>
<library>user32</library>
<library>gdi32</library>
+ <library>ole32_irot_client</library>
<library>ole32_proxy</library>
<library>rpcrt4</library>
<library>kernel32</library>
<file>bindctx.c</file>
<file>classmoniker.c</file>
<file>clipboard.c</file>
+ <file>comcat.c</file>
<file>compobj.c</file>
<file>compositemoniker.c</file>
<file>datacache.c</file>
@ stdcall CoFreeUnusedLibraries()
@ stdcall CoFreeUnusedLibrariesEx(long long)
@ stdcall CoGetCallContext(ptr ptr)
-@ stub CoGetCallerTID
+@ stdcall CoGetCallerTID(ptr)
@ stdcall CoGetClassObject(ptr long ptr ptr ptr)
@ stdcall CoGetContextToken(ptr)
@ stub CoGetCurrentLogicalThreadId
* OLE32 proxy/stub handler
*
* Copyright 2002 Marcus Meissner
- * Copyright 2001 Ove Kåven, TransGaming Technologies
+ * Copyright 2001 Ove Kåven, TransGaming Technologies
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
#include "compobj_private.h"
#include "moniker.h"
+#include "comcat.h"
#include "wine/debug.h"
return ClassMonikerCF_Create(iid, ppv);
if (IsEqualCLSID(rclsid, &CLSID_PointerMoniker))
return PointerMonikerCF_Create(iid, ppv);
+ if (IsEqualGUID(rclsid, &CLSID_StdComponentCategoriesMgr))
+ return ComCatCF_Create(iid, ppv);
return NdrDllGetClassObject(rclsid, iid, ppv, OLE32_ProxyFileList,
&CLSID_PSFactoryBuffer, &PSFactoryBuffer);
#include "ole2.h"
#include "olectl.h"
+#include "comcat.h"
#include "initguid.h"
#include "compobj_private.h"
#include "moniker.h"
static GUID const CLSID_PackagerMoniker = {
0x00000308, 0x0000, 0x0000, {0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x46} };
+static GUID const CLSID_PSFactoryBuffer_actxprxy = {
+ 0xB8DA6310, 0xE19B, 0x11D0, {0x93,0x3C,0x00,0xA0,0xC9,0x0D,0xCA,0xA9} };
+
extern GUID const CLSID_Picture_Metafile;
extern GUID const CLSID_Picture_Dib;
"ole32.dll",
"Apartment"
},
+ { &CLSID_StdComponentCategoriesMgr,
+ "Component Categories Manager",
+ NULL,
+ "ole32.dll",
+ "Both"
+ },
{ NULL } /* list terminator */
};
#define INTERFACE_ENTRY(interface, base, clsid32, clsid16) { &IID_##interface, #interface, base, sizeof(interface##Vtbl)/sizeof(void*), clsid16, clsid32 }
#define BAS_INTERFACE_ENTRY(interface, base) INTERFACE_ENTRY(interface, &IID_##base, &CLSID_PSFactoryBuffer, NULL)
#define STD_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer, NULL)
+#define ACTX_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, &CLSID_PSFactoryBuffer_actxprxy, NULL)
#define LCL_INTERFACE_ENTRY(interface) INTERFACE_ENTRY(interface, NULL, NULL, NULL)
static const struct regsvr_interface interface_list[] = {
LCL_INTERFACE_ENTRY(IClientSecurity),
LCL_INTERFACE_ENTRY(IServerSecurity),
STD_INTERFACE_ENTRY(ISequentialStream),
+ ACTX_INTERFACE_ENTRY(IEnumGUID),
+ ACTX_INTERFACE_ENTRY(IEnumCATEGORYINFO),
+ ACTX_INTERFACE_ENTRY(ICatRegister),
+ ACTX_INTERFACE_ENTRY(ICatInformation),
{ NULL } /* list terminator */
};
/*
* RPC Manager
*
- * Copyright 2001 Ove Kåven, TransGaming Technologies
+ * Copyright 2001 Ove Kåven, TransGaming Technologies
* Copyright 2002 Marcus Meissner
* Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers
*
StorageImpl* const This = (StorageImpl*)iface;
HRESULT result = StorageBaseImpl_Stat( iface, pstatstg, grfStatFlag );
- if ( !FAILED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )
+ if ( SUCCEEDED(result) && ((grfStatFlag & STATFLAG_NONAME) == 0) && This->pwcsName )
{
CoTaskMemFree(pstatstg->pwcsName);
pstatstg->pwcsName = CoTaskMemAlloc((lstrlenW(This->pwcsName)+1)*sizeof(WCHAR));
return STG_E_INVALIDPARAMETER;
}
- return StgOpenStorage(pwcsName, NULL, grfMode, (SNB)NULL, 0, (IStorage **)ppObjectOpen);
+ return StgOpenStorage(pwcsName, NULL, grfMode, NULL, 0, (IStorage **)ppObjectOpen);
}
TRACE("(%p,%s,%p)\n",pStm,debugstr_guid(iidInterface),ppvObj);
res=ReadClassStm(pStm,&clsid);
- if (!SUCCEEDED(res))
+ if (FAILED(res))
return res;
res=CoCreateInstance(&clsid,NULL,CLSCTX_INPROC_SERVER,iidInterface,ppvObj);
- if (!SUCCEEDED(res))
+ if (FAILED(res))
return res;
res=IUnknown_QueryInterface((IUnknown*)*ppvObj,&IID_IPersistStream,(LPVOID*)&xstm);
- if (!SUCCEEDED(res)) {
+ if (FAILED(res)) {
IUnknown_Release((IUnknown*)*ppvObj);
return res;
}
int max_try = 6;
pData->pData = NULL;
- pData->pstrOleObjFileName = (CHAR *) NULL;
+ pData->pstrOleObjFileName = NULL;
for( nTryCnt=0;nTryCnt < max_try; nTryCnt++)
{
IUnknown **rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumUnknown_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumUnknown_Next_Stub(
IUnknown **rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ *pceltFetched = 0;
+ hr = IEnumUnknown_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
HRESULT CALLBACK IBindCtx_SetBindOptions_Proxy(
IMoniker **rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumMoniker_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumMoniker_Next_Stub(
IMoniker **rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ *pceltFetched = 0;
+ hr = IEnumMoniker_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
BOOL CALLBACK IRunnableObject_IsRunning_Proxy(
LPOLESTR *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumString_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumString_Next_Stub(
LPOLESTR *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ *pceltFetched = 0;
+ hr = IEnumString_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
HRESULT CALLBACK ISequentialStream_Read_Proxy(
STATSTG *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumSTATSTG_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumSTATSTG_Next_Stub(
STATSTG *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ *pceltFetched = 0;
+ hr = IEnumSTATSTG_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
HRESULT CALLBACK IStorage_OpenStream_Proxy(
FORMATETC *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumFORMATETC_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumFORMATETC_Next_Stub(
FORMATETC *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ *pceltFetched = 0;
+ hr = IEnumFORMATETC_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
HRESULT CALLBACK IEnumSTATDATA_Next_Proxy(
STATDATA *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumSTATDATA_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumSTATDATA_Next_Stub(
STATDATA *rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ *pceltFetched = 0;
+ hr = IEnumSTATDATA_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
void CALLBACK IAdviseSink_OnDataChange_Proxy(
LPOLEVERB rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ ULONG fetched;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ if (!pceltFetched) pceltFetched = &fetched;
+ return IEnumOLEVERB_RemoteNext_Proxy(This, celt, rgelt, pceltFetched);
}
HRESULT __RPC_STUB IEnumOLEVERB_Next_Stub(
LPOLEVERB rgelt,
ULONG *pceltFetched)
{
- FIXME(":stub\n");
- return E_NOTIMPL;
+ HRESULT hr;
+ TRACE("(%p)->(%d, %p, %p)\n", This, celt, rgelt, pceltFetched);
+ *pceltFetched = 0;
+ hr = IEnumOLEVERB_Next(This, celt, rgelt, pceltFetched);
+ if (hr == S_OK) *pceltFetched = celt;
+ return hr;
}
HRESULT CALLBACK IViewObject_Draw_Proxy(
<include base="rpcrt4" root="intermediate">.</include>
<file>rpcrt4.spec</file>
</module>
-<module name="rpcrt4_epm_server" type="rpcserver">
- <file>epm.idl</file>
-</module>
<module name="rpcrt4_epm_client" type="rpcclient">
<file>epm.idl</file>
</module>