[PATCH 5/6] combase: Move CoGetClassObject().

Nikolay Sivov nsivov at codeweavers.com
Thu Aug 27 03:37:48 CDT 2020


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/combase/apartment.c       |  23 +---
 dlls/combase/combase.c         | 209 ++++++++++++++++++++++++++++-
 dlls/combase/combase.spec      |   3 +-
 dlls/combase/combase_private.h |  34 +++++
 dlls/combase/rpc.c             | 238 +++++++++++++++++++++++++++++++++
 dlls/ole32/compobj.c           | 203 ----------------------------
 dlls/ole32/compobj_private.h   |   5 -
 dlls/ole32/ole32.spec          |   2 +-
 dlls/ole32/rpc.c               | 228 -------------------------------
 9 files changed, 481 insertions(+), 464 deletions(-)

diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c
index 2d1f7a75744..3df8b165c13 100644
--- a/dlls/combase/apartment.c
+++ b/dlls/combase/apartment.c
@@ -49,27 +49,6 @@ enum comclass_threadingmodel
     ThreadingModel_Neutral   = 5
 };
 
-enum class_reg_data_origin
-{
-    CLASS_REG_ACTCTX,
-    CLASS_REG_REGISTRY,
-};
-
-struct class_reg_data
-{
-    enum class_reg_data_origin origin;
-    union
-    {
-        struct
-        {
-            const WCHAR *module_name;
-            DWORD threading_model;
-            HANDLE hactctx;
-        } actctx;
-        HKEY hkey;
-    } u;
-};
-
 static struct apartment *mta;
 static struct apartment *main_sta; /* the first STA */
 static struct list apts = LIST_INIT(apts);
@@ -1048,7 +1027,7 @@ static enum comclass_threadingmodel get_threading_model(const struct class_reg_d
         return data->u.actctx.threading_model;
 }
 
-HRESULT WINAPI apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata,
+HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata,
         REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv)
 {
     WCHAR dllpath[MAX_PATH+1];
diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c
index 47e31ebad14..228260ba214 100644
--- a/dlls/combase/combase.c
+++ b/dlls/combase/combase.c
@@ -38,9 +38,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
 HINSTANCE hProxyDll;
 
-#define CHARS_IN_GUID 39
-
+/* Ole32 exports */
 extern void WINAPI DestroyRunningObjectTable(void);
+extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void **obj);
 
 /*
  * Number of times CoInitialize is called. It is decreased every time CoUninitialize is called. When it hits 0, the COM libraries are freed
@@ -257,7 +257,7 @@ static LSTATUS open_classes_key(HKEY hkey, const WCHAR *name, REGSAM access, HKE
     return RtlNtStatusToDosError(NtOpenKey((HANDLE *)retkey, access, &attr));
 }
 
-static HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
+HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey)
 {
     static const WCHAR clsidW[] = L"CLSID\\";
     WCHAR path[CHARS_IN_GUID + ARRAY_SIZE(clsidW) - 1];
@@ -288,6 +288,42 @@ static HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM a
     return S_OK;
 }
 
+/* open HKCR\\AppId\\{string form of appid clsid} key */
+HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey)
+{
+    static const WCHAR appidkeyW[] = L"AppId\\";
+    DWORD res;
+    WCHAR buf[CHARS_IN_GUID];
+    WCHAR keyname[ARRAY_SIZE(appidkeyW) + CHARS_IN_GUID];
+    DWORD size;
+    HKEY hkey;
+    DWORD type;
+    HRESULT hr;
+
+    /* read the AppID value under the class's key */
+    hr = open_key_for_clsid(clsid, NULL, KEY_READ, &hkey);
+    if (FAILED(hr))
+        return hr;
+
+    size = sizeof(buf);
+    res = RegQueryValueExW(hkey, L"AppId", NULL, &type, (LPBYTE)buf, &size);
+    RegCloseKey(hkey);
+    if (res == ERROR_FILE_NOT_FOUND)
+        return REGDB_E_KEYMISSING;
+    else if (res != ERROR_SUCCESS || type!=REG_SZ)
+        return REGDB_E_READREGDB;
+
+    lstrcpyW(keyname, appidkeyW);
+    lstrcatW(keyname, buf);
+    res = open_classes_key(HKEY_CLASSES_ROOT, keyname, access, subkey);
+    if (res == ERROR_FILE_NOT_FOUND)
+        return REGDB_E_KEYMISSING;
+    else if (res != ERROR_SUCCESS)
+        return REGDB_E_READREGDB;
+
+    return S_OK;
+}
+
 /***********************************************************************
  *           InternalTlsAllocData    (combase.@)
  */
@@ -1443,6 +1479,173 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstanceEx(REFCLSID rclsid, IUnknown *o
     return return_multi_qi(unk, count, results, TRUE);
 }
 
+/***********************************************************************
+ *           CoGetClassObject    (combase.@)
+ */
+HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscontext,
+        COSERVERINFO *server_info, REFIID riid, void **obj)
+{
+    struct class_reg_data clsreg = { 0 };
+    IUnknown *regClassObject;
+    HRESULT hr = E_UNEXPECTED;
+    struct apartment *apt;
+
+    TRACE("%s, %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
+
+    if (!obj)
+        return E_INVALIDARG;
+
+    *obj = NULL;
+
+    if (!(apt = apartment_get_current_or_mta()))
+    {
+        ERR("apartment not initialised\n");
+        return CO_E_NOTINITIALIZED;
+    }
+
+    if (server_info)
+        FIXME("server_info name %s, authinfo %p\n", debugstr_w(server_info->pwszName), server_info->pAuthInfo);
+
+    if (clscontext & CLSCTX_INPROC_SERVER)
+    {
+        if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
+                IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
+                IsEqualCLSID(rclsid, &CLSID_ManualResetEvent) ||
+                IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
+        {
+            apartment_release(apt);
+            return Ole32DllGetClassObject(rclsid, riid, obj);
+        }
+    }
+
+    if (clscontext & CLSCTX_INPROC)
+    {
+        ACTCTX_SECTION_KEYED_DATA data;
+
+        data.cbSize = sizeof(data);
+        /* search activation context first */
+        if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
+                ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, rclsid, &data))
+        {
+            struct comclassredirect_data *comclass = (struct comclassredirect_data *)data.lpData;
+
+            clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
+            clsreg.u.actctx.hactctx = data.hActCtx;
+            clsreg.u.actctx.threading_model = comclass->model;
+            clsreg.origin = CLASS_REG_ACTCTX;
+
+            hr = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, riid,
+                    !(clscontext & WINE_CLSCTX_DONT_HOST), obj);
+            ReleaseActCtx(data.hActCtx);
+            apartment_release(apt);
+            return hr;
+        }
+    }
+
+    /*
+     * First, try and see if we can't match the class ID with one of the
+     * registered classes.
+     */
+    if (InternalGetRegisteredClassObject(apt, rclsid, clscontext, &regClassObject) == S_OK)
+    {
+        hr = IUnknown_QueryInterface(regClassObject, riid, obj);
+        IUnknown_Release(regClassObject);
+        apartment_release(apt);
+        return hr;
+    }
+
+    /* First try in-process server */
+    if (clscontext & CLSCTX_INPROC_SERVER)
+    {
+        HKEY hkey;
+
+        hr = open_key_for_clsid(rclsid, L"InprocServer32", KEY_READ, &hkey);
+        if (FAILED(hr))
+        {
+            if (hr == REGDB_E_CLASSNOTREG)
+                ERR("class %s not registered\n", debugstr_guid(rclsid));
+            else if (hr == REGDB_E_KEYMISSING)
+            {
+                WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
+                hr = REGDB_E_CLASSNOTREG;
+            }
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            clsreg.u.hkey = hkey;
+            clsreg.origin = CLASS_REG_REGISTRY;
+
+            hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, !(clscontext & WINE_CLSCTX_DONT_HOST), obj);
+            RegCloseKey(hkey);
+        }
+
+        /* return if we got a class, otherwise fall through to one of the
+         * other types */
+        if (SUCCEEDED(hr))
+        {
+            apartment_release(apt);
+            return hr;
+        }
+    }
+
+    /* Next try in-process handler */
+    if (clscontext & CLSCTX_INPROC_HANDLER)
+    {
+        HKEY hkey;
+
+        hr = open_key_for_clsid(rclsid, L"InprocHandler32", KEY_READ, &hkey);
+        if (FAILED(hr))
+        {
+            if (hr == REGDB_E_CLASSNOTREG)
+                ERR("class %s not registered\n", debugstr_guid(rclsid));
+            else if (hr == REGDB_E_KEYMISSING)
+            {
+                WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
+                hr = REGDB_E_CLASSNOTREG;
+            }
+        }
+
+        if (SUCCEEDED(hr))
+        {
+            clsreg.u.hkey = hkey;
+            clsreg.origin = CLASS_REG_REGISTRY;
+
+            hr = apartment_get_inproc_class_object(apt, &clsreg, rclsid, riid, !(clscontext & WINE_CLSCTX_DONT_HOST), obj);
+            RegCloseKey(hkey);
+        }
+
+        /* return if we got a class, otherwise fall through to one of the
+         * other types */
+        if (SUCCEEDED(hr))
+        {
+            apartment_release(apt);
+            return hr;
+        }
+    }
+    apartment_release(apt);
+
+    /* Next try out of process */
+    if (clscontext & CLSCTX_LOCAL_SERVER)
+    {
+        hr = rpc_get_local_class_object(rclsid, riid, obj);
+        if (SUCCEEDED(hr))
+            return hr;
+    }
+
+    /* Finally try remote: this requires networked DCOM (a lot of work) */
+    if (clscontext & CLSCTX_REMOTE_SERVER)
+    {
+        FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
+        hr = REGDB_E_CLASSNOTREG;
+    }
+
+    if (FAILED(hr))
+        ERR("no class object %s could be created for context %#x\n", debugstr_guid(rclsid), clscontext);
+
+    return hr;
+}
+
 /***********************************************************************
  *           CoFreeUnusedLibraries    (combase.@)
  */
diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec
index 143de28d7d6..f2f4506ae50 100644
--- a/dlls/combase/combase.spec
+++ b/dlls/combase/combase.spec
@@ -101,7 +101,7 @@
 @ stdcall CoGetCallState(long ptr)
 @ stdcall CoGetCallerTID(ptr) ole32.CoGetCallerTID
 @ stub CoGetCancelObject
-@ stdcall CoGetClassObject(ptr long ptr ptr ptr) ole32.CoGetClassObject
+@ stdcall CoGetClassObject(ptr long ptr ptr ptr)
 @ stub CoGetClassVersion
 @ stdcall CoGetContextToken(ptr)
 @ stdcall CoGetCurrentLogicalThreadId(ptr)
@@ -355,7 +355,6 @@
 @ stdcall apartment_release(ptr)
 @ stdcall enter_apartment(ptr long)
 @ stdcall leave_apartment(ptr)
-@ stdcall apartment_get_inproc_class_object(ptr ptr ptr ptr long ptr)
 @ stdcall apartment_findfromoxid(int64)
 @ stdcall apartment_getwindow(ptr)
 @ stdcall apartment_global_cleanup()
diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h
index 1f80f1a12be..c6d090707a7 100644
--- a/dlls/combase/combase_private.h
+++ b/dlls/combase/combase_private.h
@@ -54,10 +54,19 @@ struct apartment
     struct list usage_cookies; /* Used for refcount control with CoIncrementMTAUsage()/CoDecrementMTAUsage(). */
 };
 
+extern HRESULT WINAPI InternalGetRegisteredClassObject(struct apartment *apt, REFGUID guid,
+        DWORD clscontext, IUnknown **obj);
+
+HRESULT open_key_for_clsid(REFCLSID clsid, const WCHAR *keyname, REGSAM access, HKEY *subkey) DECLSPEC_HIDDEN;
+HRESULT open_appidkey_from_clsid(REFCLSID clsid, REGSAM access, HKEY *subkey) DECLSPEC_HIDDEN;
+
 /* DCOM messages used by the apartment window (not compatible with native) */
 #define DM_EXECUTERPC   (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */
 #define DM_HOSTOBJECT   (WM_USER + 1) /* WPARAM = 0, LPARAM = (struct host_object_params *) */
 
+#define WINE_CLSCTX_DONT_HOST   0x80000000
+#define CHARS_IN_GUID 39
+
 /* this is what is stored in TEB->ReservedForOle */
 struct tlsdata
 {
@@ -102,6 +111,7 @@ void apartment_freeunusedlibraries(struct apartment *apt, DWORD unload_delay) DE
 
 /* RpcSs interface */
 HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN;
+HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj) DECLSPEC_HIDDEN;
 
 /* stub managers hold refs on the object and each interface stub */
 struct stub_manager
@@ -131,12 +141,36 @@ struct stub_manager
     BOOL              disconnected; /* CoDisconnectObject has been called (CS lock) */
 };
 
+enum class_reg_data_origin
+{
+    CLASS_REG_ACTCTX,
+    CLASS_REG_REGISTRY,
+};
+
+struct class_reg_data
+{
+    enum class_reg_data_origin origin;
+    union
+    {
+        struct
+        {
+            const WCHAR *module_name;
+            DWORD threading_model;
+            HANDLE hactctx;
+        } actctx;
+        HKEY hkey;
+    } u;
+};
+
 HRESULT WINAPI enter_apartment(struct tlsdata *data, DWORD model);
 void WINAPI leave_apartment(struct tlsdata *data);
 void WINAPI apartment_release(struct apartment *apt);
+struct apartment * WINAPI apartment_get_current_or_mta(void);
 HRESULT apartment_increment_mta_usage(CO_MTA_USAGE_COOKIE *cookie) DECLSPEC_HIDDEN;
 void apartment_decrement_mta_usage(CO_MTA_USAGE_COOKIE cookie) DECLSPEC_HIDDEN;
 struct apartment * apartment_get_mta(void) DECLSPEC_HIDDEN;
+HRESULT apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata,
+        REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) DECLSPEC_HIDDEN;
 
 /* Stub Manager */
 
diff --git a/dlls/combase/rpc.c b/dlls/combase/rpc.c
index 3b531661726..2b655da8bad 100644
--- a/dlls/combase/rpc.c
+++ b/dlls/combase/rpc.c
@@ -16,14 +16,19 @@
 
 #include <stdarg.h>
 
+#define COBJMACROS
+
 #include "windef.h"
 #include "winbase.h"
 #include "winsvc.h"
+#include "servprov.h"
 
 #include "wine/debug.h"
 #include "wine/exception.h"
 #include "wine/heap.h"
 
+#include "combase_private.h"
+
 #include "irpcss.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
@@ -221,3 +226,236 @@ HRESULT WINAPI InternalIrotRevoke(IrotCookie cookie, IrotContextHandle *ctxt_han
     hr = IrotRevoke(get_irot_handle(), cookie, ctxt_handle, object, moniker);
     RPCSS_CALL_END
 }
+
+static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
+{
+    static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
+    lstrcpyW(pipefn, wszPipeRef);
+    StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID);
+}
+
+static DWORD start_local_service(const WCHAR *name, DWORD num, LPCWSTR *params)
+{
+    SC_HANDLE handle, hsvc;
+    DWORD r = ERROR_FUNCTION_FAILED;
+
+    TRACE("Starting service %s %d params\n", debugstr_w(name), num);
+
+    handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
+    if (!handle)
+        return r;
+    hsvc = OpenServiceW(handle, name, SERVICE_START);
+    if (hsvc)
+    {
+        if(StartServiceW(hsvc, num, params))
+            r = ERROR_SUCCESS;
+        else
+            r = GetLastError();
+        if (r == ERROR_SERVICE_ALREADY_RUNNING)
+            r = ERROR_SUCCESS;
+        CloseServiceHandle(hsvc);
+    }
+    else
+        r = GetLastError();
+    CloseServiceHandle(handle);
+
+    TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
+
+    return r;
+}
+
+/*
+ * create_local_service()  - start a COM server in a service
+ *
+ *   To start a Local Service, we read the AppID value under
+ * the class's CLSID key, then open the HKCR\\AppId key specified
+ * there and check for a LocalService value.
+ *
+ * Note:  Local Services are not supported under Windows 9x
+ */
+static HRESULT create_local_service(REFCLSID rclsid)
+{
+    HRESULT hr;
+    WCHAR buf[CHARS_IN_GUID];
+    HKEY hkey;
+    LONG r;
+    DWORD type, sz;
+
+    TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
+
+    hr = open_appidkey_from_clsid(rclsid, KEY_READ, &hkey);
+    if (FAILED(hr))
+        return hr;
+
+    /* read the LocalService and ServiceParameters values from the AppID key */
+    sz = sizeof buf;
+    r = RegQueryValueExW(hkey, L"LocalService", NULL, &type, (LPBYTE)buf, &sz);
+    if (r == ERROR_SUCCESS && type == REG_SZ)
+    {
+        DWORD num_args = 0;
+        LPWSTR args[1] = { NULL };
+
+        /*
+         * FIXME: I'm not really sure how to deal with the service parameters.
+         *        I suspect that the string returned from RegQueryValueExW
+         *        should be split into a number of arguments by spaces.
+         *        It would make more sense if ServiceParams contained a
+         *        REG_MULTI_SZ here, but it's a REG_SZ for the services
+         *        that I'm interested in for the moment.
+         */
+        r = RegQueryValueExW(hkey, L"ServiceParams", NULL, &type, NULL, &sz);
+        if (r == ERROR_SUCCESS && type == REG_SZ && sz)
+        {
+            args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
+            num_args++;
+            RegQueryValueExW(hkey, L"ServiceParams", NULL, &type, (LPBYTE)args[0], &sz);
+        }
+        r = start_local_service(buf, num_args, (LPCWSTR *)args);
+        if (r != ERROR_SUCCESS)
+            hr = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
+        HeapFree(GetProcessHeap(),0,args[0]);
+    }
+    else
+    {
+        WARN("No LocalService value\n");
+        hr = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
+    }
+    RegCloseKey(hkey);
+
+    return hr;
+}
+
+static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
+{
+    static const WCHAR  embeddingW[] = L" -Embedding";
+    HKEY                key;
+    HRESULT             hr;
+    WCHAR               command[MAX_PATH + ARRAY_SIZE(embeddingW)];
+    DWORD               size = (MAX_PATH+1) * sizeof(WCHAR);
+    STARTUPINFOW        sinfo;
+    PROCESS_INFORMATION pinfo;
+    LONG ret;
+
+    hr = open_key_for_clsid(rclsid, L"LocalServer32", KEY_READ, &key);
+    if (FAILED(hr))
+    {
+        ERR("class %s not registered\n", debugstr_guid(rclsid));
+        return hr;
+    }
+
+    ret = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
+    RegCloseKey(key);
+    if (ret)
+    {
+        WARN("No default value for LocalServer32 key\n");
+        return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
+    }
+
+    memset(&sinfo, 0, sizeof(sinfo));
+    sinfo.cb = sizeof(sinfo);
+
+    /* EXE servers are started with the -Embedding switch. */
+
+    lstrcatW(command, embeddingW);
+
+    TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
+
+    /* FIXME: Win2003 supports a ServerExecutable value that is passed into
+     * CreateProcess */
+    if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &sinfo, &pinfo))
+    {
+        WARN("failed to run local server %s\n", debugstr_w(command));
+        return HRESULT_FROM_WIN32(GetLastError());
+    }
+    *process = pinfo.hProcess;
+    CloseHandle(pinfo.hThread);
+
+    return S_OK;
+}
+
+/* FIXME: should call to rpcss instead */
+HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj)
+{
+    HRESULT        hr;
+    HANDLE         hPipe;
+    WCHAR          pipefn[100];
+    DWORD          res, bufferlen;
+    char           marshalbuffer[200];
+    IStream       *pStm;
+    LARGE_INTEGER  seekto;
+    ULARGE_INTEGER newpos;
+    int            tries = 0;
+    IServiceProvider *local_server;
+
+    static const int MAXTRIES = 30; /* 30 seconds */
+
+    TRACE("rclsid %s, riid %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
+
+    get_localserver_pipe_name(pipefn, rclsid);
+
+    while (tries++ < MAXTRIES)
+    {
+        TRACE("waiting for %s\n", debugstr_w(pipefn));
+
+        WaitNamedPipeW(pipefn, NMPWAIT_WAIT_FOREVER);
+        hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
+        if (hPipe == INVALID_HANDLE_VALUE)
+        {
+            DWORD index;
+            DWORD start_ticks;
+            HANDLE process = 0;
+            if (tries == 1)
+            {
+                if ((hr = create_local_service(rclsid)) && (hr = create_server(rclsid, &process)))
+                    return hr;
+            }
+            else
+            {
+                WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError());
+            }
+            /* wait for one second, even if messages arrive */
+            start_ticks = GetTickCount();
+            do
+            {
+                if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0), &process, &index)) && process && !index)
+                {
+                    WARN("server for %s failed to start\n", debugstr_guid(rclsid));
+                    CloseHandle( hPipe );
+                    CloseHandle( process );
+                    return E_NOINTERFACE;
+                }
+            } while (GetTickCount() - start_ticks < 1000);
+            if (process) CloseHandle(process);
+            continue;
+        }
+        bufferlen = 0;
+        if (!ReadFile(hPipe, marshalbuffer, sizeof(marshalbuffer), &bufferlen, NULL))
+        {
+            FIXME("Failed to read marshal id from classfactory of %s.\n", debugstr_guid(rclsid));
+            CloseHandle(hPipe);
+            Sleep(1000);
+            continue;
+        }
+        TRACE("read marshal id from pipe\n");
+        CloseHandle(hPipe);
+        break;
+    }
+
+    if (tries >= MAXTRIES)
+        return E_NOINTERFACE;
+
+    hr = CreateStreamOnHGlobal(0, TRUE, &pStm);
+    if (hr != S_OK) return hr;
+    hr = IStream_Write(pStm, marshalbuffer, bufferlen, &res);
+    if (hr != S_OK) goto out;
+    seekto.u.LowPart = 0;seekto.u.HighPart = 0;
+    hr = IStream_Seek(pStm, seekto, STREAM_SEEK_SET, &newpos);
+    TRACE("unmarshalling local server\n");
+    hr = CoUnmarshalInterface(pStm, &IID_IServiceProvider, (void **)&local_server);
+    if(SUCCEEDED(hr))
+        hr = IServiceProvider_QueryService(local_server, rclsid, riid, obj);
+    IServiceProvider_Release(local_server);
+out:
+    IStream_Release(pStm);
+    return hr;
+}
diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 975af46f854..45187fc8113 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -985,209 +985,6 @@ HRESULT WINAPI CoRegisterClassObject(
   return S_OK;
 }
 
-/***********************************************************************
- *           CoGetClassObject [OLE32.@]
- *
- * Creates an object of the specified class.
- *
- * PARAMS
- *  rclsid       [I] Class ID to create an instance of.
- *  dwClsContext [I] Flags to restrict the location of the created instance.
- *  pServerInfo  [I] Optional. Details for connecting to a remote server.
- *  iid          [I] The ID of the interface of the instance to return.
- *  ppv          [O] On returns, contains a pointer to the specified interface of the object.
- *
- * RETURNS
- *  Success: S_OK
- *  Failure: HRESULT code.
- *
- * NOTES
- *  The dwClsContext parameter can be one or more of the following:
- *| CLSCTX_INPROC_SERVER - Use an in-process server, such as from a DLL.
- *| CLSCTX_INPROC_HANDLER - Use an in-process object which handles certain functions for an object running in another process.
- *| CLSCTX_LOCAL_SERVER - Connect to an object running in another process.
- *| CLSCTX_REMOTE_SERVER - Connect to an object running on another machine.
- *
- * SEE ALSO
- *  CoCreateInstance()
- */
-HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(
-    REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
-    REFIID iid, LPVOID *ppv)
-{
-    struct class_reg_data clsreg = { 0 };
-    IUnknown *regClassObject;
-    HRESULT	hres = E_UNEXPECTED;
-    struct apartment *apt;
-
-    TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(iid));
-
-    if (!ppv)
-        return E_INVALIDARG;
-
-    *ppv = NULL;
-
-    if (!(apt = apartment_get_current_or_mta()))
-    {
-        ERR("apartment not initialised\n");
-        return CO_E_NOTINITIALIZED;
-    }
-
-    if (pServerInfo) {
-	FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
-              debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
-    }
-
-    if (CLSCTX_INPROC_SERVER & dwClsContext)
-    {
-        if (IsEqualCLSID(rclsid, &CLSID_InProcFreeMarshaler) ||
-                IsEqualCLSID(rclsid, &CLSID_GlobalOptions) ||
-                IsEqualCLSID(rclsid, &CLSID_ManualResetEvent) ||
-                IsEqualCLSID(rclsid, &CLSID_StdGlobalInterfaceTable))
-        {
-            apartment_release(apt);
-            return Ole32DllGetClassObject(rclsid, iid, ppv);
-        }
-    }
-
-    if (CLSCTX_INPROC & dwClsContext)
-    {
-        ACTCTX_SECTION_KEYED_DATA data;
-
-        data.cbSize = sizeof(data);
-        /* search activation context first */
-        if (FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
-                                  ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
-                                  rclsid, &data))
-        {
-            struct comclassredirect_data *comclass = (struct comclassredirect_data*)data.lpData;
-
-            clsreg.u.actctx.module_name = (WCHAR *)((BYTE *)data.lpSectionBase + comclass->name_offset);
-            clsreg.u.actctx.hactctx = data.hActCtx;
-            clsreg.u.actctx.threading_model = comclass->model;
-            clsreg.origin = CLASS_REG_ACTCTX;
-
-            hres = apartment_get_inproc_class_object(apt, &clsreg, &comclass->clsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
-            ReleaseActCtx(data.hActCtx);
-            apartment_release(apt);
-            return hres;
-        }
-    }
-
-    /*
-     * First, try and see if we can't match the class ID with one of the
-     * registered classes.
-     */
-    if (S_OK == InternalGetRegisteredClassObject(apt, rclsid, dwClsContext,
-                                             &regClassObject))
-    {
-      /* Get the required interface from the retrieved pointer. */
-      hres = IUnknown_QueryInterface(regClassObject, iid, ppv);
-
-      /*
-       * Since QI got another reference on the pointer, we want to release the
-       * one we already have. If QI was unsuccessful, this will release the object. This
-       * is good since we are not returning it in the "out" parameter.
-       */
-      IUnknown_Release(regClassObject);
-      apartment_release(apt);
-      return hres;
-    }
-
-    /* First try in-process server */
-    if (CLSCTX_INPROC_SERVER & dwClsContext)
-    {
-        static const WCHAR wszInprocServer32[] = {'I','n','p','r','o','c','S','e','r','v','e','r','3','2',0};
-        HKEY hkey;
-
-        hres = COM_OpenKeyForCLSID(rclsid, wszInprocServer32, KEY_READ, &hkey);
-        if (FAILED(hres))
-        {
-            if (hres == REGDB_E_CLASSNOTREG)
-                ERR("class %s not registered\n", debugstr_guid(rclsid));
-            else if (hres == REGDB_E_KEYMISSING)
-            {
-                WARN("class %s not registered as in-proc server\n", debugstr_guid(rclsid));
-                hres = REGDB_E_CLASSNOTREG;
-            }
-        }
-
-        if (SUCCEEDED(hres))
-        {
-            clsreg.u.hkey = hkey;
-            clsreg.origin = CLASS_REG_REGISTRY;
-
-            hres = apartment_get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
-            RegCloseKey(hkey);
-        }
-
-        /* return if we got a class, otherwise fall through to one of the
-         * other types */
-        if (SUCCEEDED(hres))
-        {
-            apartment_release(apt);
-            return hres;
-        }
-    }
-
-    /* Next try in-process handler */
-    if (CLSCTX_INPROC_HANDLER & dwClsContext)
-    {
-        static const WCHAR wszInprocHandler32[] = {'I','n','p','r','o','c','H','a','n','d','l','e','r','3','2',0};
-        HKEY hkey;
-
-        hres = COM_OpenKeyForCLSID(rclsid, wszInprocHandler32, KEY_READ, &hkey);
-        if (FAILED(hres))
-        {
-            if (hres == REGDB_E_CLASSNOTREG)
-                ERR("class %s not registered\n", debugstr_guid(rclsid));
-            else if (hres == REGDB_E_KEYMISSING)
-            {
-                WARN("class %s not registered in-proc handler\n", debugstr_guid(rclsid));
-                hres = REGDB_E_CLASSNOTREG;
-            }
-        }
-
-        if (SUCCEEDED(hres))
-        {
-            clsreg.u.hkey = hkey;
-            clsreg.origin = CLASS_REG_REGISTRY;
-
-            hres = apartment_get_inproc_class_object(apt, &clsreg, rclsid, iid, !(dwClsContext & WINE_CLSCTX_DONT_HOST), ppv);
-            RegCloseKey(hkey);
-        }
-
-        /* return if we got a class, otherwise fall through to one of the
-         * other types */
-        if (SUCCEEDED(hres))
-        {
-            apartment_release(apt);
-            return hres;
-        }
-    }
-    apartment_release(apt);
-
-    /* Next try out of process */
-    if (CLSCTX_LOCAL_SERVER & dwClsContext)
-    {
-        hres = RPC_GetLocalClassObject(rclsid,iid,ppv);
-        if (SUCCEEDED(hres))
-            return hres;
-    }
-
-    /* Finally try remote: this requires networked DCOM (a lot of work) */
-    if (CLSCTX_REMOTE_SERVER & dwClsContext)
-    {
-        FIXME ("CLSCTX_REMOTE_SERVER not supported\n");
-        hres = REGDB_E_CLASSNOTREG;
-    }
-
-    if (FAILED(hres))
-        ERR("no class object %s could be created for context 0x%x\n",
-            debugstr_guid(rclsid), dwClsContext);
-    return hres;
-}
-
 /***********************************************************************
  *        CoResumeClassObjects (OLE32.@)
  *
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 9d6a1d1b794..5fc100e8163 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -252,11 +252,6 @@ extern HWND WINAPI apartment_getwindow(const struct apartment *apt) DECLSPEC_HID
 extern HRESULT WINAPI enter_apartment(struct oletls *info, DWORD model) DECLSPEC_HIDDEN;
 void WINAPI leave_apartment(struct oletls *info) DECLSPEC_HIDDEN;
 extern struct apartment * WINAPI apartment_get_current_or_mta(void) DECLSPEC_HIDDEN;
-
-struct class_reg_data;
-extern HRESULT WINAPI apartment_get_inproc_class_object(struct apartment *apt, const struct class_reg_data *regdata,
-        REFCLSID rclsid, REFIID riid, BOOL hostifnecessary, void **ppv) DECLSPEC_HIDDEN;
-
 extern HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN;
 extern void WINAPI apartment_global_cleanup(void) DECLSPEC_HIDDEN;
 
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec
index 0b38e74388a..9c6b9396e17 100644
--- a/dlls/ole32/ole32.spec
+++ b/dlls/ole32/ole32.spec
@@ -30,7 +30,7 @@
 @ stdcall CoGetCallContext(ptr ptr) combase.CoGetCallContext
 @ stdcall CoGetCallState(long ptr) combase.CoGetCallState
 @ stdcall CoGetCallerTID(ptr)
-@ stdcall CoGetClassObject(ptr long ptr ptr ptr)
+@ stdcall CoGetClassObject(ptr long ptr ptr ptr) combase.CoGetClassObject
 @ stdcall CoGetContextToken(ptr) combase.CoGetContextToken
 @ stdcall CoGetCurrentLogicalThreadId(ptr) combase.CoGetCurrentLogicalThreadId
 @ stdcall CoGetCurrentProcess() combase.CoGetCurrentProcess
diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c
index 1c88ae21543..eb76d9cb668 100644
--- a/dlls/ole32/rpc.c
+++ b/dlls/ole32/rpc.c
@@ -1649,150 +1649,6 @@ void RPC_StartRemoting(struct apartment *apt)
     start_apartment_remote_unknown(apt);
 }
 
-
-static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
-{
-    static const WCHAR  wszLocalServer32[] = { 'L','o','c','a','l','S','e','r','v','e','r','3','2',0 };
-    static const WCHAR  embedding[] = { ' ', '-','E','m','b','e','d','d','i','n','g',0 };
-    HKEY                key;
-    HRESULT             hres;
-    WCHAR               command[MAX_PATH+ARRAY_SIZE(embedding)];
-    DWORD               size = (MAX_PATH+1) * sizeof(WCHAR);
-    STARTUPINFOW        sinfo;
-    PROCESS_INFORMATION pinfo;
-    LONG ret;
-
-    hres = COM_OpenKeyForCLSID(rclsid, wszLocalServer32, KEY_READ, &key);
-    if (FAILED(hres)) {
-        ERR("class %s not registered\n", debugstr_guid(rclsid));
-        return hres;
-    }
-
-    ret = RegQueryValueExW(key, NULL, NULL, NULL, (LPBYTE)command, &size);
-    RegCloseKey(key);
-    if (ret) {
-        WARN("No default value for LocalServer32 key\n");
-        return REGDB_E_CLASSNOTREG; /* FIXME: check retval */
-    }
-
-    memset(&sinfo,0,sizeof(sinfo));
-    sinfo.cb = sizeof(sinfo);
-
-    /* EXE servers are started with the -Embedding switch. */
-
-    lstrcatW(command, embedding);
-
-    TRACE("activating local server %s for %s\n", debugstr_w(command), debugstr_guid(rclsid));
-
-    /* FIXME: Win2003 supports a ServerExecutable value that is passed into
-     * CreateProcess */
-    if (!CreateProcessW(NULL, command, NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &sinfo, &pinfo)) {
-        WARN("failed to run local server %s\n", debugstr_w(command));
-        return HRESULT_FROM_WIN32(GetLastError());
-    }
-    *process = pinfo.hProcess;
-    CloseHandle(pinfo.hThread);
-
-    return S_OK;
-}
-
-/*
- * start_local_service()  - start a service given its name and parameters
- */
-static DWORD start_local_service(LPCWSTR name, DWORD num, LPCWSTR *params)
-{
-    SC_HANDLE handle, hsvc;
-    DWORD     r = ERROR_FUNCTION_FAILED;
-
-    TRACE("Starting service %s %d params\n", debugstr_w(name), num);
-
-    handle = OpenSCManagerW(NULL, NULL, SC_MANAGER_CONNECT);
-    if (!handle)
-        return r;
-    hsvc = OpenServiceW(handle, name, SERVICE_START);
-    if (hsvc)
-    {
-        if(StartServiceW(hsvc, num, params))
-            r = ERROR_SUCCESS;
-        else
-            r = GetLastError();
-        if (r == ERROR_SERVICE_ALREADY_RUNNING)
-            r = ERROR_SUCCESS;
-        CloseServiceHandle(hsvc);
-    }
-    else
-        r = GetLastError();
-    CloseServiceHandle(handle);
-
-    TRACE("StartService returned error %u (%s)\n", r, (r == ERROR_SUCCESS) ? "ok":"failed");
-
-    return r;
-}
-
-/*
- * create_local_service()  - start a COM server in a service
- *
- *   To start a Local Service, we read the AppID value under
- * the class's CLSID key, then open the HKCR\\AppId key specified
- * there and check for a LocalService value.
- *
- * Note:  Local Services are not supported under Windows 9x
- */
-static HRESULT create_local_service(REFCLSID rclsid)
-{
-    HRESULT hres;
-    WCHAR buf[CHARS_IN_GUID];
-    static const WCHAR szLocalService[] = { 'L','o','c','a','l','S','e','r','v','i','c','e',0 };
-    static const WCHAR szServiceParams[] = {'S','e','r','v','i','c','e','P','a','r','a','m','s',0};
-    HKEY hkey;
-    LONG r;
-    DWORD type, sz;
-
-    TRACE("Attempting to start Local service for %s\n", debugstr_guid(rclsid));
-
-    hres = COM_OpenKeyForAppIdFromCLSID(rclsid, KEY_READ, &hkey);
-    if (FAILED(hres))
-        return hres;
-
-    /* read the LocalService and ServiceParameters values from the AppID key */
-    sz = sizeof buf;
-    r = RegQueryValueExW(hkey, szLocalService, NULL, &type, (LPBYTE)buf, &sz);
-    if (r==ERROR_SUCCESS && type==REG_SZ)
-    {
-        DWORD num_args = 0;
-        LPWSTR args[1] = { NULL };
-
-        /*
-         * FIXME: I'm not really sure how to deal with the service parameters.
-         *        I suspect that the string returned from RegQueryValueExW
-         *        should be split into a number of arguments by spaces.
-         *        It would make more sense if ServiceParams contained a
-         *        REG_MULTI_SZ here, but it's a REG_SZ for the services
-         *        that I'm interested in for the moment.
-         */
-        r = RegQueryValueExW(hkey, szServiceParams, NULL, &type, NULL, &sz);
-        if (r == ERROR_SUCCESS && type == REG_SZ && sz)
-        {
-            args[0] = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sz);
-            num_args++;
-            RegQueryValueExW(hkey, szServiceParams, NULL, &type, (LPBYTE)args[0], &sz);
-        }
-        r = start_local_service(buf, num_args, (LPCWSTR *)args);
-        if (r != ERROR_SUCCESS)
-            hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
-        HeapFree(GetProcessHeap(),0,args[0]);
-    }
-    else
-    {
-        WARN("No LocalService value\n");
-        hres = REGDB_E_CLASSNOTREG; /* FIXME: check retval */
-    }
-    RegCloseKey(hkey);
-
-    return hres;
-}
-
-
 static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
 {
     static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
@@ -1800,90 +1656,6 @@ static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
     StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID);
 }
 
-/* FIXME: should call to rpcss instead */
-HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv)
-{
-    HRESULT        hres;
-    HANDLE         hPipe;
-    WCHAR          pipefn[100];
-    DWORD          res, bufferlen;
-    char           marshalbuffer[200];
-    IStream       *pStm;
-    LARGE_INTEGER  seekto;
-    ULARGE_INTEGER newpos;
-    int            tries = 0;
-    IServiceProvider *local_server;
-
-    static const int MAXTRIES = 30; /* 30 seconds */
-
-    TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
-
-    get_localserver_pipe_name(pipefn, rclsid);
-
-    while (tries++ < MAXTRIES) {
-        TRACE("waiting for %s\n", debugstr_w(pipefn));
-
-        WaitNamedPipeW( pipefn, NMPWAIT_WAIT_FOREVER );
-        hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
-        if (hPipe == INVALID_HANDLE_VALUE) {
-            DWORD index;
-            DWORD start_ticks;
-            HANDLE process = 0;
-            if (tries == 1) {
-                if ( (hres = create_local_service(rclsid)) &&
-                     (hres = create_server(rclsid, &process)) )
-                    return hres;
-            } else {
-                WARN("Connecting to %s, no response yet, retrying: le is %u\n", debugstr_w(pipefn), GetLastError());
-            }
-            /* wait for one second, even if messages arrive */
-            start_ticks = GetTickCount();
-            do {
-                if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0),
-                                                       &process, &index)) && process && !index)
-                {
-                    WARN( "server for %s failed to start\n", debugstr_guid(rclsid) );
-                    CloseHandle( hPipe );
-                    CloseHandle( process );
-                    return E_NOINTERFACE;
-                }
-            } while (GetTickCount() - start_ticks < 1000);
-            if (process) CloseHandle( process );
-            continue;
-        }
-        bufferlen = 0;
-        if (!ReadFile(hPipe,marshalbuffer,sizeof(marshalbuffer),&bufferlen,NULL)) {
-            FIXME("Failed to read marshal id from classfactory of %s.\n",debugstr_guid(rclsid));
-            CloseHandle(hPipe);
-            Sleep(1000);
-            continue;
-        }
-        TRACE("read marshal id from pipe\n");
-        CloseHandle(hPipe);
-        break;
-    }
-    
-    if (tries >= MAXTRIES)
-        return E_NOINTERFACE;
-    
-    hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
-    if (hres != S_OK) return hres;
-    hres = IStream_Write(pStm,marshalbuffer,bufferlen,&res);
-    if (hres != S_OK) goto out;
-    seekto.u.LowPart = 0;seekto.u.HighPart = 0;
-    hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
-    
-    TRACE("unmarshalling local server\n");
-    hres = CoUnmarshalInterface(pStm, &IID_IServiceProvider, (void**)&local_server);
-    if(SUCCEEDED(hres))
-        hres = IServiceProvider_QueryService(local_server, rclsid, iid, ppv);
-    IServiceProvider_Release(local_server);
-out:
-    IStream_Release(pStm);
-    return hres;
-}
-
-
 struct local_server_params
 {
     CLSID clsid;
-- 
2.28.0




More information about the wine-devel mailing list