Commit fad7818e authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

combase: Move server class registration.

parent d1b67b22
......@@ -285,9 +285,6 @@ static ULONG WINAPI local_server_Release(IServiceProvider *iface)
return refcount;
}
extern HRESULT WINAPI InternalGetRegisteredClassObject(struct apartment *apt, REFGUID guid,
DWORD clscontext, IUnknown **obj);
static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID guid, REFIID riid, void **obj)
{
struct local_server *local_server = impl_from_IServiceProvider(iface);
......@@ -300,7 +297,7 @@ static HRESULT WINAPI local_server_QueryService(IServiceProvider *iface, REFGUID
if (!local_server->apt)
return E_UNEXPECTED;
if (SUCCEEDED(InternalGetRegisteredClassObject(apt, guid, CLSCTX_LOCAL_SERVER, &unk)))
if ((unk = com_get_registered_class_object(apt, guid, CLSCTX_LOCAL_SERVER)))
{
hr = IUnknown_QueryInterface(unk, riid, obj);
IUnknown_Release(unk);
......@@ -317,7 +314,7 @@ static const IServiceProviderVtbl local_server_vtbl =
local_server_QueryService
};
HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret)
HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret)
{
HRESULT hr = S_OK;
......@@ -446,7 +443,6 @@ void apartment_freeunusedlibraries(struct apartment *apt, DWORD delay)
LeaveCriticalSection(&apt->cs);
}
extern void WINAPI InternalRevokeAllClasses(struct apartment *apt);
extern HRESULT WINAPI Internal_apartment_disconnectproxies(struct apartment *apt);
extern ULONG WINAPI Internal_stub_manager_int_release(struct stub_manager *stubmgr);
......@@ -499,7 +495,7 @@ void WINAPI apartment_release(struct apartment *apt)
}
/* Release the references to the registered class objects */
InternalRevokeAllClasses(apt);
apartment_revoke_all_classes(apt);
/* no locking is needed for this apartment, because no other thread
* can access it at this point */
......
......@@ -47,6 +47,8 @@ extern HRESULT WINAPI Ole32DllGetClassObject(REFCLSID rclsid, REFIID riid, void
*/
static LONG com_lockcount;
static LONG com_server_process_refcount;
struct comclassredirect_data
{
ULONG size;
......@@ -113,6 +115,57 @@ static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
};
static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
/*
* TODO: Make this data structure aware of inter-process communication. This
* means that parts of this will be exported to rpcss.
*/
struct registered_class
{
struct list entry;
CLSID clsid;
OXID apartment_id;
IUnknown *object;
DWORD clscontext;
DWORD flags;
DWORD cookie;
void *RpcRegistration;
};
static struct list registered_classes = LIST_INIT(registered_classes);
static CRITICAL_SECTION registered_classes_cs;
static CRITICAL_SECTION_DEBUG registered_classes_cs_debug =
{
0, 0, &registered_classes_cs,
{ &registered_classes_cs_debug.ProcessLocksList, &registered_classes_cs_debug.ProcessLocksList },
0, 0, { (DWORD_PTR)(__FILE__ ": registered_classes_cs") }
};
static CRITICAL_SECTION registered_classes_cs = { &registered_classes_cs_debug, -1, 0, 0, 0, 0 };
IUnknown * com_get_registered_class_object(const struct apartment *apt, REFCLSID rclsid, DWORD clscontext)
{
struct registered_class *cur;
IUnknown *object = NULL;
EnterCriticalSection(&registered_classes_cs);
LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
{
if ((apt->oxid == cur->apartment_id) &&
(clscontext & cur->clscontext) &&
IsEqualGUID(&cur->clsid, rclsid))
{
object = cur->object;
IUnknown_AddRef(cur->object);
break;
}
}
LeaveCriticalSection(&registered_classes_cs);
return object;
}
static struct init_spy *get_spy_entry(struct tlsdata *tlsdata, unsigned int id)
{
struct init_spy *spy;
......@@ -1498,8 +1551,8 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscont
COSERVERINFO *server_info, REFIID riid, void **obj)
{
struct class_reg_data clsreg = { 0 };
IUnknown *regClassObject;
HRESULT hr = E_UNEXPECTED;
IUnknown *registered_obj;
struct apartment *apt;
TRACE("%s, %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
......@@ -1558,10 +1611,10 @@ HRESULT WINAPI DECLSPEC_HOTPATCH CoGetClassObject(REFCLSID rclsid, DWORD clscont
* 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)
if ((registered_obj = com_get_registered_class_object(apt, rclsid, clscontext)))
{
hr = IUnknown_QueryInterface(regClassObject, riid, obj);
IUnknown_Release(regClassObject);
hr = IUnknown_QueryInterface(registered_obj, riid, obj);
IUnknown_Release(registered_obj);
apartment_release(apt);
return hr;
}
......@@ -2676,6 +2729,215 @@ HRESULT WINAPI CoGetApartmentType(APTTYPE *type, APTTYPEQUALIFIER *qualifier)
return tlsdata->apt ? S_OK : CO_E_NOTINITIALIZED;
}
/******************************************************************************
* CoRegisterClassObject (combase.@)
* BUGS
* MSDN claims that multiple interface registrations are legal, but we
* can't do that with our current implementation.
*/
HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD clscontext,
DWORD flags, DWORD *cookie)
{
static LONG next_cookie;
struct registered_class *newclass;
IUnknown *found_object;
struct apartment *apt;
HRESULT hr = S_OK;
TRACE("%s, %p, %#x, %#x, %p\n", debugstr_guid(rclsid), object, clscontext, flags, cookie);
if (!cookie || !object)
return E_INVALIDARG;
if (!(apt = apartment_get_current_or_mta()))
{
ERR("COM was not initialized\n");
return CO_E_NOTINITIALIZED;
}
*cookie = 0;
/* REGCLS_MULTIPLEUSE implies registering as inproc server. This is what
* differentiates the flag from REGCLS_MULTI_SEPARATE. */
if (flags & REGCLS_MULTIPLEUSE)
clscontext |= CLSCTX_INPROC_SERVER;
/*
* First, check if the class is already registered.
* If it is, this should cause an error.
*/
if ((found_object = com_get_registered_class_object(apt, rclsid, clscontext)))
{
if (flags & REGCLS_MULTIPLEUSE)
{
if (clscontext & CLSCTX_LOCAL_SERVER)
hr = CoLockObjectExternal(found_object, TRUE, FALSE);
IUnknown_Release(found_object);
apartment_release(apt);
return hr;
}
IUnknown_Release(found_object);
ERR("object already registered for class %s\n", debugstr_guid(rclsid));
apartment_release(apt);
return CO_E_OBJISREG;
}
newclass = heap_alloc(sizeof(*newclass));
if (!newclass)
{
apartment_release(apt);
return E_OUTOFMEMORY;
}
newclass->clsid = *rclsid;
newclass->apartment_id = apt->oxid;
newclass->clscontext = clscontext;
newclass->flags = flags;
newclass->RpcRegistration = NULL;
if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
newclass->cookie = InterlockedIncrement(&next_cookie);
newclass->object = object;
IUnknown_AddRef(newclass->object);
EnterCriticalSection(&registered_classes_cs);
list_add_tail(&registered_classes, &newclass->entry);
LeaveCriticalSection(&registered_classes_cs);
*cookie = newclass->cookie;
if (clscontext & CLSCTX_LOCAL_SERVER)
{
IStream *marshal_stream;
hr = apartment_get_local_server_stream(apt, &marshal_stream);
if(FAILED(hr))
{
apartment_release(apt);
return hr;
}
hr = rpc_start_local_server(&newclass->clsid, marshal_stream, flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
&newclass->RpcRegistration);
IStream_Release(marshal_stream);
}
apartment_release(apt);
return S_OK;
}
static void com_revoke_class_object(struct registered_class *entry)
{
list_remove(&entry->entry);
if (entry->clscontext & CLSCTX_LOCAL_SERVER)
rpc_stop_local_server(entry->RpcRegistration);
IUnknown_Release(entry->object);
heap_free(entry);
}
void apartment_revoke_all_classes(const struct apartment *apt)
{
struct registered_class *cur, *cur2;
EnterCriticalSection(&registered_classes_cs);
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, &registered_classes, struct registered_class, entry)
{
if (cur->apartment_id == apt->oxid)
com_revoke_class_object(cur);
}
LeaveCriticalSection(&registered_classes_cs);
}
/***********************************************************************
* CoRevokeClassObject (combase.@)
*/
HRESULT WINAPI DECLSPEC_HOTPATCH CoRevokeClassObject(DWORD cookie)
{
HRESULT hr = E_INVALIDARG;
struct registered_class *cur;
struct apartment *apt;
TRACE("%#x\n", cookie);
if (!(apt = apartment_get_current_or_mta()))
{
ERR("COM was not initialized\n");
return CO_E_NOTINITIALIZED;
}
EnterCriticalSection(&registered_classes_cs);
LIST_FOR_EACH_ENTRY(cur, &registered_classes, struct registered_class, entry)
{
if (cur->cookie != cookie)
continue;
if (cur->apartment_id == apt->oxid)
{
com_revoke_class_object(cur);
hr = S_OK;
}
else
{
ERR("called from wrong apartment, should be called from %s\n", wine_dbgstr_longlong(cur->apartment_id));
hr = RPC_E_WRONG_THREAD;
}
break;
}
LeaveCriticalSection(&registered_classes_cs);
apartment_release(apt);
return hr;
}
/***********************************************************************
* CoAddRefServerProcess (combase.@)
*/
ULONG WINAPI CoAddRefServerProcess(void)
{
ULONG refs;
TRACE("\n");
EnterCriticalSection(&registered_classes_cs);
refs = ++com_server_process_refcount;
LeaveCriticalSection(&registered_classes_cs);
TRACE("refs before: %d\n", refs - 1);
return refs;
}
/***********************************************************************
* CoReleaseServerProcess [OLE32.@]
*/
ULONG WINAPI CoReleaseServerProcess(void)
{
ULONG refs;
TRACE("\n");
EnterCriticalSection(&registered_classes_cs);
refs = --com_server_process_refcount;
/* FIXME: suspend objects */
LeaveCriticalSection(&registered_classes_cs);
TRACE("refs after: %d\n", refs);
return refs;
}
/***********************************************************************
* DllMain (combase.@)
*/
......@@ -2688,6 +2950,10 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
case DLL_PROCESS_ATTACH:
hProxyDll = hinstDLL;
break;
case DLL_PROCESS_DETACH:
if (reserved) break;
DeleteCriticalSection(&registered_classes_cs);
break;
}
return TRUE;
......
......@@ -73,7 +73,7 @@
@ stub CleanupOleStateInAllTls
@ stdcall CleanupTlsOleState(ptr)
@ stub ClearCleanupFlag
@ stdcall CoAddRefServerProcess() ole32.CoAddRefServerProcess
@ stdcall CoAddRefServerProcess()
@ stub CoAllowUnmarshalerCLSID
@ stub CoCancelCall
@ stdcall CoCopyProxy(ptr ptr)
......@@ -139,7 +139,7 @@
@ stdcall CoQueryProxyBlanket(ptr ptr ptr ptr ptr ptr ptr ptr)
@ stub CoReactivateObject
@ stub CoRegisterActivationFilter
@ stdcall CoRegisterClassObject(ptr ptr long long ptr) ole32.CoRegisterClassObject
@ stdcall CoRegisterClassObject(ptr ptr long long ptr)
@ stdcall CoRegisterInitializeSpy(ptr ptr)
@ stdcall CoRegisterMallocSpy(ptr)
@ stdcall CoRegisterMessageFilter(ptr ptr)
......@@ -147,11 +147,11 @@
@ stdcall CoRegisterSurrogate(ptr) ole32.CoRegisterSurrogate
@ stdcall CoRegisterSurrogateEx(ptr ptr) ole32.CoRegisterSurrogateEx
@ stdcall CoReleaseMarshalData(ptr) ole32.CoReleaseMarshalData
@ stdcall CoReleaseServerProcess() ole32.CoReleaseServerProcess
@ stdcall CoReleaseServerProcess()
@ stdcall CoResumeClassObjects() ole32.CoResumeClassObjects
@ stub CoRetireServer
@ stdcall CoRevertToSelf()
@ stdcall CoRevokeClassObject(long) ole32.CoRevokeClassObject
@ stdcall CoRevokeClassObject(long)
@ stdcall CoRevokeInitializeSpy(int64)
@ stdcall CoRevokeMallocSpy()
@ stub CoSetCancelObject
......@@ -359,5 +359,4 @@
@ stdcall apartment_getwindow(ptr)
@ stdcall apartment_global_cleanup()
@ stdcall apartment_createwindowifneeded(ptr)
@ stdcall apartment_get_local_server_stream(ptr ptr)
@ stdcall apartment_findfromtid(long)
......@@ -54,9 +54,6 @@ 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;
......@@ -112,6 +109,8 @@ 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;
HRESULT rpc_start_local_server(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) DECLSPEC_HIDDEN;
void rpc_stop_local_server(void *registration) DECLSPEC_HIDDEN;
/* stub managers hold refs on the object and each interface stub */
struct stub_manager
......@@ -171,6 +170,10 @@ 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;
HRESULT apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN;
IUnknown *com_get_registered_class_object(const struct apartment *apartment, REFCLSID rclsid,
DWORD clscontext) DECLSPEC_HIDDEN;
void apartment_revoke_all_classes(const struct apartment *apt) DECLSPEC_HIDDEN;
/* Stub Manager */
......
......@@ -459,3 +459,173 @@ out:
IStream_Release(pStm);
return hr;
}
struct local_server_params
{
CLSID clsid;
IStream *stream;
HANDLE pipe;
HANDLE stop_event;
HANDLE thread;
BOOL multi_use;
};
/* FIXME: should call to rpcss instead */
static DWORD WINAPI local_server_thread(void *param)
{
struct local_server_params * lsp = param;
WCHAR pipefn[100];
HRESULT hres;
IStream *pStm = lsp->stream;
STATSTG ststg;
unsigned char *buffer;
int buflen;
LARGE_INTEGER seekto;
ULARGE_INTEGER newpos;
ULONG res;
BOOL multi_use = lsp->multi_use;
OVERLAPPED ovl;
HANDLE pipe_event, hPipe = lsp->pipe, new_pipe;
DWORD bytes;
TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
memset(&ovl, 0, sizeof(ovl));
get_localserver_pipe_name(pipefn, &lsp->clsid);
ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL);
while (1) {
if (!ConnectNamedPipe(hPipe, &ovl))
{
DWORD error = GetLastError();
if (error == ERROR_IO_PENDING)
{
HANDLE handles[2] = { pipe_event, lsp->stop_event };
DWORD ret;
ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (ret != WAIT_OBJECT_0)
break;
}
/* client already connected isn't an error */
else if (error != ERROR_PIPE_CONNECTED)
{
ERR("ConnectNamedPipe failed with error %d\n", GetLastError());
break;
}
}
TRACE("marshalling LocalServer to client\n");
hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
if (hres != S_OK)
break;
seekto.u.LowPart = 0;
seekto.u.HighPart = 0;
hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
if (hres != S_OK) {
FIXME("IStream_Seek failed, %x\n",hres);
break;
}
buflen = ststg.cbSize.u.LowPart;
buffer = HeapAlloc(GetProcessHeap(),0,buflen);
hres = IStream_Read(pStm,buffer,buflen,&res);
if (hres != S_OK) {
FIXME("Stream Read failed, %x\n",hres);
HeapFree(GetProcessHeap(),0,buffer);
break;
}
WriteFile(hPipe,buffer,buflen,&res,&ovl);
GetOverlappedResult(hPipe, &ovl, &bytes, TRUE);
HeapFree(GetProcessHeap(),0,buffer);
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
TRACE("done marshalling LocalServer\n");
if (!multi_use)
{
TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
break;
}
new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
4096, 4096, 500 /* 0.5 second timeout */, NULL );
if (new_pipe == INVALID_HANDLE_VALUE)
{
FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
break;
}
CloseHandle(hPipe);
hPipe = new_pipe;
}
CloseHandle(pipe_event);
CloseHandle(hPipe);
return 0;
}
HRESULT rpc_start_local_server(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
{
DWORD tid, err;
struct local_server_params *lsp;
WCHAR pipefn[100];
lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
if (!lsp)
return E_OUTOFMEMORY;
lsp->clsid = *clsid;
lsp->stream = stream;
IStream_AddRef(stream);
lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!lsp->stop_event)
{
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(GetLastError());
}
lsp->multi_use = multi_use;
get_localserver_pipe_name(pipefn, &lsp->clsid);
lsp->pipe = CreateNamedPipeW(pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
4096, 4096, 500 /* 0.5 second timeout */, NULL);
if (lsp->pipe == INVALID_HANDLE_VALUE)
{
err = GetLastError();
FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
CloseHandle(lsp->stop_event);
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(err);
}
lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
if (!lsp->thread)
{
CloseHandle(lsp->pipe);
CloseHandle(lsp->stop_event);
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(GetLastError());
}
*registration = lsp;
return S_OK;
}
void rpc_stop_local_server(void *registration)
{
struct local_server_params *lsp = registration;
/* signal local_server_thread to stop */
SetEvent(lsp->stop_event);
/* wait for it to exit */
WaitForSingleObject(lsp->thread, INFINITE);
IStream_Release(lsp->stream);
CloseHandle(lsp->stop_event);
CloseHandle(lsp->thread);
HeapFree(GetProcessHeap(), 0, lsp);
}
......@@ -223,12 +223,8 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
DWORD dest_context, void *dest_context_data,
IRpcChannelBuffer **chan, struct apartment *apt) DECLSPEC_HIDDEN;
HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN;
void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN;
HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN;
void RPC_UnregisterInterface(REFIID riid, BOOL wait) DECLSPEC_HIDDEN;
HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) DECLSPEC_HIDDEN;
void RPC_StopLocalServer(void *registration) DECLSPEC_HIDDEN;
HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) DECLSPEC_HIDDEN;
HRESULT RPC_RegisterChannelHook(REFGUID rguid, IChannelHook *hook) DECLSPEC_HIDDEN;
void RPC_UnregisterAllChannelHooks(void) DECLSPEC_HIDDEN;
HRESULT RPC_ResolveOxid(OXID oxid, OXID_INFO *oxid_info) DECLSPEC_HIDDEN;
......@@ -254,10 +250,6 @@ extern struct apartment * WINAPI apartment_get_current_or_mta(void) DECLSPEC_HID
extern HRESULT WINAPI apartment_get_local_server_stream(struct apartment *apt, IStream **ret) DECLSPEC_HIDDEN;
extern void WINAPI apartment_global_cleanup(void) DECLSPEC_HIDDEN;
HRESULT COM_GetRegisteredClassObject(const struct apartment *apt, REFCLSID rclsid,
DWORD dwClsContext, IUnknown **ppUnk) DECLSPEC_HIDDEN;
void COM_RevokeAllClasses(const struct apartment *apt) 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 *) */
......
......@@ -6,7 +6,7 @@
@ stdcall CLSIDFromProgID(wstr ptr) combase.CLSIDFromProgID
@ stdcall CLSIDFromProgIDEx(wstr ptr) combase.CLSIDFromProgIDEx
@ stdcall CLSIDFromString(wstr ptr) combase.CLSIDFromString
@ stdcall CoAddRefServerProcess()
@ stdcall CoAddRefServerProcess() combase.CoAddRefServerProcess
@ stdcall CoAllowSetForegroundWindow(ptr ptr)
@ stdcall CoBuildVersion()
@ stdcall CoCopyProxy(ptr ptr) combase.CoCopyProxy
......@@ -65,7 +65,7 @@
@ stdcall CoQueryProxyBlanket(ptr ptr ptr ptr ptr ptr ptr ptr) combase.CoQueryProxyBlanket
@ stub CoQueryReleaseObject
@ stdcall CoRegisterChannelHook(ptr ptr)
@ stdcall CoRegisterClassObject(ptr ptr long long ptr)
@ stdcall CoRegisterClassObject(ptr ptr long long ptr) combase.CoRegisterClassObject
@ stdcall CoRegisterInitializeSpy(ptr ptr) combase.CoRegisterInitializeSpy
@ stdcall CoRegisterMallocSpy(ptr) combase.CoRegisterMallocSpy
@ stdcall CoRegisterMessageFilter(ptr ptr) combase.CoRegisterMessageFilter
......@@ -73,10 +73,10 @@
@ stdcall CoRegisterSurrogate(ptr)
@ stdcall CoRegisterSurrogateEx(ptr ptr)
@ stdcall CoReleaseMarshalData(ptr)
@ stdcall CoReleaseServerProcess()
@ stdcall CoReleaseServerProcess() combase.CoReleaseServerProcess
@ stdcall CoResumeClassObjects()
@ stdcall CoRevertToSelf() combase.CoRevertToSelf
@ stdcall CoRevokeClassObject(long)
@ stdcall CoRevokeClassObject(long) combase.CoRevokeClassObject
@ stdcall CoRevokeInitializeSpy(int64) combase.CoRevokeInitializeSpy
@ stdcall CoRevokeMallocSpy() combase.CoRevokeMallocSpy
@ stdcall CoSetProxyBlanket(ptr long long ptr long long ptr long) combase.CoSetProxyBlanket
......@@ -298,8 +298,6 @@
@ stdcall WriteFmtUserTypeStg(ptr long ptr)
@ stub WriteOleStg
@ stub WriteStringStream
@ stdcall InternalGetRegisteredClassObject(ptr ptr long ptr)
@ stdcall InternalRevokeAllClasses(ptr)
@ stdcall Internal_apartment_disconnectproxies(ptr)
@ stdcall Internal_RPC_ExecuteCall(ptr)
@ stdcall Internal_stub_manager_int_release(ptr)
......@@ -1648,182 +1648,3 @@ void RPC_StartRemoting(struct apartment *apt)
}
start_apartment_remote_unknown(apt);
}
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);
}
struct local_server_params
{
CLSID clsid;
IStream *stream;
HANDLE pipe;
HANDLE stop_event;
HANDLE thread;
BOOL multi_use;
};
/* FIXME: should call to rpcss instead */
static DWORD WINAPI local_server_thread(LPVOID param)
{
struct local_server_params * lsp = param;
WCHAR pipefn[100];
HRESULT hres;
IStream *pStm = lsp->stream;
STATSTG ststg;
unsigned char *buffer;
int buflen;
LARGE_INTEGER seekto;
ULARGE_INTEGER newpos;
ULONG res;
BOOL multi_use = lsp->multi_use;
OVERLAPPED ovl;
HANDLE pipe_event, hPipe = lsp->pipe, new_pipe;
DWORD bytes;
TRACE("Starting threader for %s.\n",debugstr_guid(&lsp->clsid));
memset(&ovl, 0, sizeof(ovl));
get_localserver_pipe_name(pipefn, &lsp->clsid);
ovl.hEvent = pipe_event = CreateEventW(NULL, FALSE, FALSE, NULL);
while (1) {
if (!ConnectNamedPipe(hPipe, &ovl))
{
DWORD error = GetLastError();
if (error == ERROR_IO_PENDING)
{
HANDLE handles[2] = { pipe_event, lsp->stop_event };
DWORD ret;
ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
if (ret != WAIT_OBJECT_0)
break;
}
/* client already connected isn't an error */
else if (error != ERROR_PIPE_CONNECTED)
{
ERR("ConnectNamedPipe failed with error %d\n", GetLastError());
break;
}
}
TRACE("marshalling LocalServer to client\n");
hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
if (hres != S_OK)
break;
seekto.u.LowPart = 0;
seekto.u.HighPart = 0;
hres = IStream_Seek(pStm,seekto,STREAM_SEEK_SET,&newpos);
if (hres != S_OK) {
FIXME("IStream_Seek failed, %x\n",hres);
break;
}
buflen = ststg.cbSize.u.LowPart;
buffer = HeapAlloc(GetProcessHeap(),0,buflen);
hres = IStream_Read(pStm,buffer,buflen,&res);
if (hres != S_OK) {
FIXME("Stream Read failed, %x\n",hres);
HeapFree(GetProcessHeap(),0,buffer);
break;
}
WriteFile(hPipe,buffer,buflen,&res,&ovl);
GetOverlappedResult(hPipe, &ovl, &bytes, TRUE);
HeapFree(GetProcessHeap(),0,buffer);
FlushFileBuffers(hPipe);
DisconnectNamedPipe(hPipe);
TRACE("done marshalling LocalServer\n");
if (!multi_use)
{
TRACE("single use object, shutting down pipe %s\n", debugstr_w(pipefn));
break;
}
new_pipe = CreateNamedPipeW( pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
4096, 4096, 500 /* 0.5 second timeout */, NULL );
if (new_pipe == INVALID_HANDLE_VALUE)
{
FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
break;
}
CloseHandle(hPipe);
hPipe = new_pipe;
}
CloseHandle(pipe_event);
CloseHandle(hPipe);
return 0;
}
/* starts listening for a local server */
HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration)
{
DWORD tid, err;
struct local_server_params *lsp;
WCHAR pipefn[100];
lsp = HeapAlloc(GetProcessHeap(), 0, sizeof(*lsp));
if (!lsp)
return E_OUTOFMEMORY;
lsp->clsid = *clsid;
lsp->stream = stream;
IStream_AddRef(stream);
lsp->stop_event = CreateEventW(NULL, FALSE, FALSE, NULL);
if (!lsp->stop_event)
{
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(GetLastError());
}
lsp->multi_use = multi_use;
get_localserver_pipe_name(pipefn, &lsp->clsid);
lsp->pipe = CreateNamedPipeW(pipefn, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE|PIPE_WAIT, PIPE_UNLIMITED_INSTANCES,
4096, 4096, 500 /* 0.5 second timeout */, NULL);
if (lsp->pipe == INVALID_HANDLE_VALUE)
{
err = GetLastError();
FIXME("pipe creation failed for %s, le is %u\n", debugstr_w(pipefn), GetLastError());
CloseHandle(lsp->stop_event);
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(err);
}
lsp->thread = CreateThread(NULL, 0, local_server_thread, lsp, 0, &tid);
if (!lsp->thread)
{
CloseHandle(lsp->pipe);
CloseHandle(lsp->stop_event);
HeapFree(GetProcessHeap(), 0, lsp);
return HRESULT_FROM_WIN32(GetLastError());
}
*registration = lsp;
return S_OK;
}
/* stops listening for a local server */
void RPC_StopLocalServer(void *registration)
{
struct local_server_params *lsp = registration;
/* signal local_server_thread to stop */
SetEvent(lsp->stop_event);
/* wait for it to exit */
WaitForSingleObject(lsp->thread, INFINITE);
IStream_Release(lsp->stream);
CloseHandle(lsp->stop_event);
CloseHandle(lsp->thread);
HeapFree(GetProcessHeap(), 0, lsp);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment