combase: Implement local server registration via SCM.
Main point of this change is to get rid of auxiliary thread that is causing issues when CoRevokeClassObject() has to wait on it, potentially deadlocking when called from DllMain. Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Huw Davies <huw@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
5d5329936e
commit
adfaa93877
|
@ -115,10 +115,6 @@ static CRITICAL_SECTION_DEBUG psclsid_cs_debug =
|
||||||
};
|
};
|
||||||
static CRITICAL_SECTION cs_registered_ps = { &psclsid_cs_debug, -1, 0, 0, 0, 0 };
|
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 registered_class
|
||||||
{
|
{
|
||||||
struct list entry;
|
struct list entry;
|
||||||
|
@ -127,8 +123,8 @@ struct registered_class
|
||||||
IUnknown *object;
|
IUnknown *object;
|
||||||
DWORD clscontext;
|
DWORD clscontext;
|
||||||
DWORD flags;
|
DWORD flags;
|
||||||
DWORD cookie;
|
unsigned int cookie;
|
||||||
void *RpcRegistration;
|
unsigned int rpcss_cookie;
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct list registered_classes = LIST_INIT(registered_classes);
|
static struct list registered_classes = LIST_INIT(registered_classes);
|
||||||
|
@ -2824,7 +2820,7 @@ HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD cl
|
||||||
return CO_E_OBJISREG;
|
return CO_E_OBJISREG;
|
||||||
}
|
}
|
||||||
|
|
||||||
newclass = heap_alloc(sizeof(*newclass));
|
newclass = heap_alloc_zero(sizeof(*newclass));
|
||||||
if (!newclass)
|
if (!newclass)
|
||||||
{
|
{
|
||||||
apartment_release(apt);
|
apartment_release(apt);
|
||||||
|
@ -2835,7 +2831,6 @@ HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD cl
|
||||||
newclass->apartment_id = apt->oxid;
|
newclass->apartment_id = apt->oxid;
|
||||||
newclass->clscontext = clscontext;
|
newclass->clscontext = clscontext;
|
||||||
newclass->flags = flags;
|
newclass->flags = flags;
|
||||||
newclass->RpcRegistration = NULL;
|
|
||||||
|
|
||||||
if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
|
if (!(newclass->cookie = InterlockedIncrement(&next_cookie)))
|
||||||
newclass->cookie = InterlockedIncrement(&next_cookie);
|
newclass->cookie = InterlockedIncrement(&next_cookie);
|
||||||
|
@ -2860,8 +2855,7 @@ HRESULT WINAPI CoRegisterClassObject(REFCLSID rclsid, IUnknown *object, DWORD cl
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
hr = rpc_start_local_server(&newclass->clsid, marshal_stream, flags & (REGCLS_MULTIPLEUSE|REGCLS_MULTI_SEPARATE),
|
hr = rpc_register_local_server(&newclass->clsid, marshal_stream, flags, &newclass->rpcss_cookie);
|
||||||
&newclass->RpcRegistration);
|
|
||||||
IStream_Release(marshal_stream);
|
IStream_Release(marshal_stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2874,12 +2868,28 @@ static void com_revoke_class_object(struct registered_class *entry)
|
||||||
list_remove(&entry->entry);
|
list_remove(&entry->entry);
|
||||||
|
|
||||||
if (entry->clscontext & CLSCTX_LOCAL_SERVER)
|
if (entry->clscontext & CLSCTX_LOCAL_SERVER)
|
||||||
rpc_stop_local_server(entry->RpcRegistration);
|
rpc_revoke_local_server(entry->rpcss_cookie);
|
||||||
|
|
||||||
IUnknown_Release(entry->object);
|
IUnknown_Release(entry->object);
|
||||||
heap_free(entry);
|
heap_free(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cleans up rpcss registry */
|
||||||
|
static void com_revoke_local_servers(void)
|
||||||
|
{
|
||||||
|
struct registered_class *cur, *cur2;
|
||||||
|
|
||||||
|
EnterCriticalSection(®istered_classes_cs);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY_SAFE(cur, cur2, ®istered_classes, struct registered_class, entry)
|
||||||
|
{
|
||||||
|
if (cur->clscontext & CLSCTX_LOCAL_SERVER)
|
||||||
|
com_revoke_class_object(cur);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(®istered_classes_cs);
|
||||||
|
}
|
||||||
|
|
||||||
void apartment_revoke_all_classes(const struct apartment *apt)
|
void apartment_revoke_all_classes(const struct apartment *apt)
|
||||||
{
|
{
|
||||||
struct registered_class *cur, *cur2;
|
struct registered_class *cur, *cur2;
|
||||||
|
@ -3164,6 +3174,7 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD reason, LPVOID reserved)
|
||||||
hProxyDll = hinstDLL;
|
hProxyDll = hinstDLL;
|
||||||
break;
|
break;
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
com_revoke_local_servers();
|
||||||
if (reserved) break;
|
if (reserved) break;
|
||||||
apartment_global_cleanup();
|
apartment_global_cleanup();
|
||||||
DeleteCriticalSection(®istered_classes_cs);
|
DeleteCriticalSection(®istered_classes_cs);
|
||||||
|
|
|
@ -112,8 +112,8 @@ HRESULT apartment_disconnectproxies(struct apartment *apt) DECLSPEC_HIDDEN;
|
||||||
/* RpcSs interface */
|
/* RpcSs interface */
|
||||||
HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN;
|
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_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;
|
HRESULT rpc_register_local_server(REFCLSID clsid, IStream *stream, DWORD flags, unsigned int *cookie) DECLSPEC_HIDDEN;
|
||||||
void rpc_stop_local_server(void *registration) DECLSPEC_HIDDEN;
|
HRESULT rpc_revoke_local_server(unsigned int cookie) DECLSPEC_HIDDEN;
|
||||||
HRESULT rpc_create_clientchannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, const IID *iid,
|
HRESULT rpc_create_clientchannel(const OXID *oxid, const IPID *ipid, const OXID_INFO *oxid_info, const IID *iid,
|
||||||
DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, struct apartment *apt) DECLSPEC_HIDDEN;
|
DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, struct apartment *apt) DECLSPEC_HIDDEN;
|
||||||
HRESULT rpc_create_serverchannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN;
|
HRESULT rpc_create_serverchannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -363,11 +363,25 @@ HRESULT WINAPI InternalIrotRevoke(IrotCookie cookie, IrotContextHandle *ctxt_han
|
||||||
RPCSS_CALL_END
|
RPCSS_CALL_END
|
||||||
}
|
}
|
||||||
|
|
||||||
static void get_localserver_pipe_name(WCHAR *pipefn, REFCLSID rclsid)
|
static HRESULT rpcss_server_register(REFCLSID clsid, DWORD flags, MInterfacePointer *obj, unsigned int *cookie)
|
||||||
{
|
{
|
||||||
static const WCHAR wszPipeRef[] = {'\\','\\','.','\\','p','i','p','e','\\',0};
|
RPCSS_CALL_START
|
||||||
lstrcpyW(pipefn, wszPipeRef);
|
hr = irpcss_server_register(get_irpcss_handle(), clsid, flags, obj, cookie);
|
||||||
StringFromGUID2(rclsid, pipefn + ARRAY_SIZE(wszPipeRef) - 1, CHARS_IN_GUID);
|
RPCSS_CALL_END
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT rpc_revoke_local_server(unsigned int cookie)
|
||||||
|
{
|
||||||
|
RPCSS_CALL_START
|
||||||
|
hr = irpcss_server_revoke(get_irpcss_handle(), cookie);
|
||||||
|
RPCSS_CALL_END
|
||||||
|
}
|
||||||
|
|
||||||
|
static HRESULT rpcss_get_class_object(REFCLSID rclsid, PMInterfacePointer *objref)
|
||||||
|
{
|
||||||
|
RPCSS_CALL_START
|
||||||
|
hr = irpcss_get_class_object(get_irpcss_handle(), rclsid, objref);
|
||||||
|
RPCSS_CALL_END
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD start_local_service(const WCHAR *name, DWORD num, LPCWSTR *params)
|
static DWORD start_local_service(const WCHAR *name, DWORD num, LPCWSTR *params)
|
||||||
|
@ -509,261 +523,103 @@ static HRESULT create_server(REFCLSID rclsid, HANDLE *process)
|
||||||
return S_OK;
|
return S_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* FIXME: should call to rpcss instead */
|
|
||||||
HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj)
|
HRESULT rpc_get_local_class_object(REFCLSID rclsid, REFIID riid, void **obj)
|
||||||
{
|
{
|
||||||
HRESULT hr;
|
PMInterfacePointer objref = NULL;
|
||||||
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;
|
IServiceProvider *local_server;
|
||||||
|
IStream *stream = NULL;
|
||||||
|
ULARGE_INTEGER newpos;
|
||||||
|
LARGE_INTEGER seekto;
|
||||||
|
int tries = 0;
|
||||||
|
ULONG length;
|
||||||
|
HRESULT hr;
|
||||||
static const int MAXTRIES = 30; /* 30 seconds */
|
static const int MAXTRIES = 30; /* 30 seconds */
|
||||||
|
|
||||||
TRACE("rclsid %s, riid %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
|
TRACE("clsid %s, riid %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
|
||||||
|
|
||||||
get_localserver_pipe_name(pipefn, rclsid);
|
|
||||||
|
|
||||||
while (tries++ < MAXTRIES)
|
while (tries++ < MAXTRIES)
|
||||||
{
|
{
|
||||||
TRACE("waiting for %s\n", debugstr_w(pipefn));
|
DWORD index, start_ticks;
|
||||||
|
HANDLE process = 0;
|
||||||
|
|
||||||
WaitNamedPipeW(pipefn, NMPWAIT_WAIT_FOREVER);
|
if (SUCCEEDED(hr = rpcss_get_class_object(rclsid, &objref)))
|
||||||
hPipe = CreateFileW(pipefn, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0);
|
break;
|
||||||
if (hPipe == INVALID_HANDLE_VALUE)
|
|
||||||
|
if (tries == 1)
|
||||||
{
|
{
|
||||||
DWORD index;
|
if ((hr = create_local_service(rclsid)) && (hr = create_server(rclsid, &process)) )
|
||||||
DWORD start_ticks;
|
return hr;
|
||||||
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))
|
/* Wait for one second, even if messages arrive. */
|
||||||
|
start_ticks = GetTickCount();
|
||||||
|
do
|
||||||
{
|
{
|
||||||
FIXME("Failed to read marshal id from classfactory of %s.\n", debugstr_guid(rclsid));
|
if (SUCCEEDED(CoWaitForMultipleHandles(0, 1000, (process != 0), &process, &index)) && process && !index)
|
||||||
CloseHandle(hPipe);
|
{
|
||||||
Sleep(1000);
|
WARN("Server for %s failed to start.\n", debugstr_guid(rclsid));
|
||||||
continue;
|
CloseHandle(process);
|
||||||
}
|
return E_NOINTERFACE;
|
||||||
TRACE("read marshal id from pipe\n");
|
}
|
||||||
CloseHandle(hPipe);
|
} while (GetTickCount() - start_ticks < 1000);
|
||||||
break;
|
|
||||||
|
if (process) CloseHandle(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tries >= MAXTRIES)
|
if (!objref || tries >= MAXTRIES)
|
||||||
return E_NOINTERFACE;
|
return E_NOINTERFACE;
|
||||||
|
|
||||||
hr = CreateStreamOnHGlobal(0, TRUE, &pStm);
|
if (SUCCEEDED(hr = CreateStreamOnHGlobal(0, TRUE, &stream)))
|
||||||
if (hr != S_OK) return hr;
|
hr = IStream_Write(stream, objref->abData, objref->ulCntData, &length);
|
||||||
hr = IStream_Write(pStm, marshalbuffer, bufferlen, &res);
|
|
||||||
if (hr != S_OK) goto out;
|
MIDL_user_free(objref);
|
||||||
seekto.u.LowPart = 0;seekto.u.HighPart = 0;
|
|
||||||
hr = IStream_Seek(pStm, seekto, STREAM_SEEK_SET, &newpos);
|
if (SUCCEEDED(hr))
|
||||||
TRACE("unmarshalling local server\n");
|
{
|
||||||
hr = CoUnmarshalInterface(pStm, &IID_IServiceProvider, (void **)&local_server);
|
seekto.QuadPart = 0;
|
||||||
if(SUCCEEDED(hr))
|
IStream_Seek(stream, seekto, STREAM_SEEK_SET, &newpos);
|
||||||
hr = IServiceProvider_QueryService(local_server, rclsid, riid, obj);
|
|
||||||
IServiceProvider_Release(local_server);
|
TRACE("Unmarshalling local server.\n");
|
||||||
out:
|
hr = CoUnmarshalInterface(stream, &IID_IServiceProvider, (void **)&local_server);
|
||||||
IStream_Release(pStm);
|
if (SUCCEEDED(hr))
|
||||||
|
{
|
||||||
|
hr = IServiceProvider_QueryService(local_server, rclsid, riid, obj);
|
||||||
|
IServiceProvider_Release(local_server);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stream)
|
||||||
|
IStream_Release(stream);
|
||||||
|
|
||||||
return hr;
|
return hr;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct local_server_params
|
HRESULT rpc_register_local_server(REFCLSID clsid, IStream *stream, DWORD flags, unsigned int *cookie)
|
||||||
{
|
{
|
||||||
CLSID clsid;
|
MInterfacePointer *obj;
|
||||||
IStream *stream;
|
const void *ptr;
|
||||||
HANDLE pipe;
|
HGLOBAL hmem;
|
||||||
HANDLE stop_event;
|
SIZE_T size;
|
||||||
HANDLE thread;
|
HRESULT hr;
|
||||||
BOOL multi_use;
|
|
||||||
};
|
|
||||||
|
|
||||||
/* FIXME: should call to rpcss instead */
|
TRACE("%s, %#x\n", debugstr_guid(clsid), flags);
|
||||||
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));
|
hr = GetHGlobalFromStream(stream, &hmem);
|
||||||
|
if (FAILED(hr)) return hr;
|
||||||
|
|
||||||
memset(&ovl, 0, sizeof(ovl));
|
size = GlobalSize(hmem);
|
||||||
get_localserver_pipe_name(pipefn, &lsp->clsid);
|
if (!(obj = heap_alloc(FIELD_OFFSET(MInterfacePointer, abData[size]))))
|
||||||
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;
|
return E_OUTOFMEMORY;
|
||||||
|
obj->ulCntData = size;
|
||||||
|
ptr = GlobalLock(hmem);
|
||||||
|
memcpy(obj->abData, ptr, size);
|
||||||
|
GlobalUnlock(hmem);
|
||||||
|
|
||||||
lsp->clsid = *clsid;
|
hr = rpcss_server_register(clsid, flags, obj, cookie);
|
||||||
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);
|
heap_free(obj);
|
||||||
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);
|
return hr;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, ORPC_EXTENT_ARRAY *orpc_ext_array,
|
static HRESULT unmarshal_ORPCTHAT(RPC_MESSAGE *msg, ORPCTHAT *orpcthat, ORPC_EXTENT_ARRAY *orpc_ext_array,
|
||||||
|
|
|
@ -29,8 +29,6 @@
|
||||||
*
|
*
|
||||||
* TODO list: (items bunched together depend on each other)
|
* TODO list: (items bunched together depend on each other)
|
||||||
*
|
*
|
||||||
* - Implement the service control manager (in rpcss) to keep track
|
|
||||||
* of registered class objects: ISCM::ServerRegisterClsid et al
|
|
||||||
* - Implement the OXID resolver so we don't need magic endpoint names for
|
* - Implement the OXID resolver so we don't need magic endpoint names for
|
||||||
* clients and servers to meet up
|
* clients and servers to meet up
|
||||||
*
|
*
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import "wtypes.idl";
|
import "wtypes.idl";
|
||||||
|
#include "wine/orpc.idl"
|
||||||
|
|
||||||
cpp_quote("#define IRPCSS_PROTSEQ {'n','c','a','l','r','p','c',0}")
|
cpp_quote("#define IRPCSS_PROTSEQ {'n','c','a','l','r','p','c',0}")
|
||||||
cpp_quote("#define IRPCSS_ENDPOINT {'i','r','p','c','s','s',0}")
|
cpp_quote("#define IRPCSS_ENDPOINT {'i','r','p','c','s','s',0}")
|
||||||
|
@ -27,6 +28,22 @@ cpp_quote("#define IRPCSS_ENDPOINT {'i','r','p','c','s','s',0}")
|
||||||
]
|
]
|
||||||
interface Irpcss
|
interface Irpcss
|
||||||
{
|
{
|
||||||
|
HRESULT irpcss_server_register(
|
||||||
|
[in] handle_t handle,
|
||||||
|
[in] const GUID *clsid,
|
||||||
|
[in] unsigned int flags,
|
||||||
|
[in] PMInterfacePointer object,
|
||||||
|
[out] unsigned int *cookie);
|
||||||
|
|
||||||
|
HRESULT irpcss_server_revoke(
|
||||||
|
[in] handle_t handle,
|
||||||
|
[in] unsigned int cookie);
|
||||||
|
|
||||||
|
HRESULT irpcss_get_class_object(
|
||||||
|
[in] handle_t handle,
|
||||||
|
[in] const GUID *clsid,
|
||||||
|
[out] PMInterfacePointer *object);
|
||||||
|
|
||||||
HRESULT irpcss_get_thread_seq_id(
|
HRESULT irpcss_get_thread_seq_id(
|
||||||
[in] handle_t handle,
|
[in] handle_t handle,
|
||||||
[out] DWORD *sequence_id);
|
[out] DWORD *sequence_id);
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
#include "irpcss.h"
|
#include "irpcss.h"
|
||||||
|
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "wine/heap.h"
|
||||||
|
#include "wine/list.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
WINE_DEFAULT_DEBUG_CHANNEL(ole);
|
||||||
|
|
||||||
|
@ -38,6 +40,104 @@ static WCHAR rpcssW[] = {'R','p','c','S','s',0};
|
||||||
static HANDLE exit_event;
|
static HANDLE exit_event;
|
||||||
static SERVICE_STATUS_HANDLE service_handle;
|
static SERVICE_STATUS_HANDLE service_handle;
|
||||||
|
|
||||||
|
struct registered_class
|
||||||
|
{
|
||||||
|
struct list entry;
|
||||||
|
GUID clsid;
|
||||||
|
unsigned int cookie;
|
||||||
|
PMInterfacePointer object;
|
||||||
|
unsigned int single_use : 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
static CRITICAL_SECTION registered_classes_cs = { NULL, -1, 0, 0, 0, 0 };
|
||||||
|
static struct list registered_classes = LIST_INIT(registered_classes);
|
||||||
|
|
||||||
|
HRESULT __cdecl irpcss_server_register(handle_t h, const GUID *clsid, DWORD flags,
|
||||||
|
PMInterfacePointer object, unsigned int *cookie)
|
||||||
|
{
|
||||||
|
struct registered_class *entry;
|
||||||
|
static int next_cookie;
|
||||||
|
|
||||||
|
if (!(entry = heap_alloc_zero(sizeof(*entry))))
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
|
||||||
|
entry->clsid = *clsid;
|
||||||
|
entry->single_use = !(flags & (REGCLS_MULTIPLEUSE | REGCLS_MULTI_SEPARATE));
|
||||||
|
if (!(entry->object = heap_alloc(FIELD_OFFSET(MInterfacePointer, abData[object->ulCntData]))))
|
||||||
|
{
|
||||||
|
heap_free(entry);
|
||||||
|
return E_OUTOFMEMORY;
|
||||||
|
}
|
||||||
|
entry->object->ulCntData = object->ulCntData;
|
||||||
|
memcpy(&entry->object->abData, object->abData, object->ulCntData);
|
||||||
|
*cookie = entry->cookie = InterlockedIncrement(&next_cookie);
|
||||||
|
|
||||||
|
EnterCriticalSection(®istered_classes_cs);
|
||||||
|
list_add_tail(®istered_classes, &entry->entry);
|
||||||
|
LeaveCriticalSection(®istered_classes_cs);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void scm_revoke_class(struct registered_class *_class)
|
||||||
|
{
|
||||||
|
list_remove(&_class->entry);
|
||||||
|
heap_free(_class->object);
|
||||||
|
heap_free(_class);
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __cdecl irpcss_server_revoke(handle_t h, unsigned int cookie)
|
||||||
|
{
|
||||||
|
struct registered_class *cur;
|
||||||
|
|
||||||
|
EnterCriticalSection(®istered_classes_cs);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry)
|
||||||
|
{
|
||||||
|
if (cur->cookie == cookie)
|
||||||
|
{
|
||||||
|
scm_revoke_class(cur);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(®istered_classes_cs);
|
||||||
|
|
||||||
|
return S_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
HRESULT __cdecl irpcss_get_class_object(handle_t h, const GUID *clsid,
|
||||||
|
PMInterfacePointer *object)
|
||||||
|
{
|
||||||
|
struct registered_class *cur;
|
||||||
|
|
||||||
|
*object = NULL;
|
||||||
|
|
||||||
|
EnterCriticalSection(®istered_classes_cs);
|
||||||
|
|
||||||
|
LIST_FOR_EACH_ENTRY(cur, ®istered_classes, struct registered_class, entry)
|
||||||
|
{
|
||||||
|
if (!memcmp(clsid, &cur->clsid, sizeof(*clsid)))
|
||||||
|
{
|
||||||
|
*object = MIDL_user_allocate(FIELD_OFFSET(MInterfacePointer, abData[cur->object->ulCntData]));
|
||||||
|
if (*object)
|
||||||
|
{
|
||||||
|
(*object)->ulCntData = cur->object->ulCntData;
|
||||||
|
memcpy((*object)->abData, cur->object->abData, cur->object->ulCntData);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cur->single_use)
|
||||||
|
scm_revoke_class(cur);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaveCriticalSection(®istered_classes_cs);
|
||||||
|
|
||||||
|
return *object ? S_OK : E_NOINTERFACE;
|
||||||
|
}
|
||||||
|
|
||||||
HRESULT __cdecl irpcss_get_thread_seq_id(handle_t h, DWORD *id)
|
HRESULT __cdecl irpcss_get_thread_seq_id(handle_t h, DWORD *id)
|
||||||
{
|
{
|
||||||
static LONG thread_seq_id;
|
static LONG thread_seq_id;
|
||||||
|
|
Loading…
Reference in New Issue