[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, ®ClassObject) == 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,
- ®ClassObject))
- {
- /* 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