diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 3fbfc358d61..bf75c1ec4f7 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -32,8 +32,6 @@ * of registered class objects: ISCM::ServerRegisterClsid et al * - Implement the OXID resolver so we don't need magic pipe names for * clients and servers to meet up - * - Flip our marshalling on top of the RPC runtime transport API, - * so we no longer use named pipes to communicate * * - Make all ole interface marshaling use NDR to be wire compatible with * native DCOM diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 1df27374121..870a1800a13 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -197,9 +197,11 @@ IRpcStubBuffer *mid_to_stubbuffer(wine_marshal_id *mid); void start_apartment_listener_thread(void); -extern HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf); -void RPC_StartLocalServer(REFCLSID clsid, IStream *stream); +HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf); HRESULT RPC_ExecuteCall(RPCOLEMESSAGE *msg, IRpcStubBuffer *stub); +HRESULT RPC_RegisterInterface(REFIID riid); +void RPC_UnregisterInterface(REFIID riid); +void RPC_StartLocalServer(REFCLSID clsid, IStream *stream); /* This function initialize the Running Object Table */ HRESULT WINAPI RunningObjectTableImpl_Initialize(void); diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index 41bf1236edf..bcc54d861de 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -153,6 +153,9 @@ HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkn stub_manager_ext_addref(manager, 1); } + /* FIXME: check return value */ + RPC_RegisterInterface(riid); + stdobjref->ipid = ifstub->ipid; stub_manager_int_release(manager); diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 4e0408e0ee1..523f74230c1 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -1,6 +1,7 @@ /* * (Local) RPC Stuff * + * Copyright 2001 Ove Kåven, TransGaming Technologies * Copyright 2002 Marcus Meissner * Copyright 2005 Mike Hearn, Rob Shearman for CodeWeavers * @@ -49,446 +50,449 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole); -#define PIPEPREF "\\\\.\\pipe\\" -#define OLESTUBMGR PIPEPREF"WINE_OLE_StubMgr" +static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg); -#define REQTYPE_REQUEST 0 -#define REQTYPE_RESPONSE 1 +/* we only use one function to dispatch calls for all methods - we use the + * RPC_IF_OLE flag to tell the RPC runtime that this is the case */ +static RPC_DISPATCH_FUNCTION rpc_dispatch_table[1] = { dispatch_rpc }; /* (RO) */ +static RPC_DISPATCH_TABLE rpc_dispatch = { 1, rpc_dispatch_table }; /* (RO) */ -struct request_header +static struct list registered_interfaces = LIST_INIT(registered_interfaces); /* (CS csRegIf) */ +static CRITICAL_SECTION csRegIf; +static CRITICAL_SECTION_DEBUG csRegIf_debug = { - DWORD reqid; - IPID ipid; - DWORD iMethod; - DWORD cbBuffer; + 0, 0, &csRegIf, + { &csRegIf_debug.ProcessLocksList, &csRegIf_debug.ProcessLocksList }, + 0, 0, { 0, (DWORD)(__FILE__ ": dcom registered server interfaces") } +}; +static CRITICAL_SECTION csRegIf = { &csRegIf_debug, -1, 0, 0, 0, 0 }; + +static WCHAR wszPipeTransport[] = {'n','c','a','c','n','_','n','p',0}; + + +struct registered_if +{ + struct list entry; + DWORD refs; /* ref count */ + RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */ }; -struct response_header +/* get the pipe endpoint specified of the specified apartment */ +static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid) { - DWORD reqid; - DWORD cbBuffer; - DWORD retval; -}; - - -#define REQSTATE_START 0 -#define REQSTATE_REQ_QUEUED 1 -#define REQSTATE_REQ_WAITING_FOR_REPLY 2 -#define REQSTATE_REQ_GOT 3 -#define REQSTATE_INVOKING 4 -#define REQSTATE_RESP_QUEUED 5 -#define REQSTATE_RESP_GOT 6 -#define REQSTATE_DONE 6 - -struct rpc -{ - int state; - HANDLE hPipe; /* temp copy of handle */ - struct request_header reqh; - struct response_header resph; - LPBYTE Buffer; -}; - -/* fixme: this should have a lock */ -static struct rpc **reqs = NULL; -static int nrofreqs = 0; - -/* This pipe is _thread_ based, each thread which talks to a remote - * apartment (oxid) has its own pipe. The same structure is used both - * for outgoing and incoming RPCs. - */ -struct pipe -{ - wine_marshal_id mid; /* target mid */ - DWORD tid; /* thread which owns this pipe */ - HANDLE hPipe; - - int pending; - HANDLE hThread; - CRITICAL_SECTION crit; - - APARTMENT *apt; /* apartment of the marshalling thread for the stub dispatch case */ -}; - -typedef struct _PipeBuf { - IRpcChannelBufferVtbl *lpVtbl; - DWORD ref; - - wine_marshal_id mid; - HANDLE pipe; -} PipeBuf; - - - -/* some helper functions */ - -static HRESULT WINAPI read_pipe(HANDLE hf, LPVOID ptr, DWORD size) -{ - DWORD res; - - if (!ReadFile(hf,ptr,size,&res,NULL)) - { - ERR("Failed to read from %p, le is %ld\n",hf,GetLastError()); - return E_FAIL; - } - - if (res != size) - { - if (!res) - { - WARN("%p disconnected\n", hf); - return RPC_E_DISCONNECTED; - } - ERR("Read only %ld of %ld bytes from %p.\n",res,size,hf); - return E_FAIL; - } - return S_OK; + /* FIXME: should get endpoint from rpcss */ + static const WCHAR wszEndpointFormat[] = {'\\','p','i','p','e','\\','O','L','E','_','%','0','8','l','x','%','0','8','l','x',0}; + wsprintfW(endpoint, wszEndpointFormat, (DWORD)(*oxid >> 32),(DWORD)*oxid); } -static HRESULT WINAPI -write_pipe(HANDLE hf, LPVOID ptr, DWORD size) { - DWORD res; - if (!WriteFile(hf,ptr,size,&res,NULL)) { - FIXME("Failed to write to %p, le is %ld\n",hf,GetLastError()); - return E_FAIL; - } - if (res!=size) { - FIXME("Wrote only %ld of %ld bytes to %p.\n",res,size,hf); - return E_FAIL; - } - return S_OK; -} - -static HANDLE dupe_handle(HANDLE h) +typedef struct { - HANDLE h2; - - if (!DuplicateHandle(GetCurrentProcess(), h, GetCurrentProcess(), - &h2, 0, FALSE, DUPLICATE_SAME_ACCESS)) - { - ERR("could not duplicate handle: %ld\n", GetLastError()); - return INVALID_HANDLE_VALUE; - } - - return h2; -} + const IRpcChannelBufferVtbl *lpVtbl; + DWORD refs; +} RpcChannelBuffer; - - - -static DWORD WINAPI client_dispatch_thread(LPVOID); - -/* FIXME: this all needs to be made thread safe */ -static HRESULT RPC_GetRequest(struct rpc **req) +typedef struct { - static int reqid = 0; - int i; + RpcChannelBuffer super; /* superclass */ - /* try to reuse */ - for (i = 0; i < nrofreqs; i++) - { - if (reqs[i]->state == REQSTATE_DONE) - { - TRACE("reusing reqs[%d]\n", i); - - reqs[i]->reqh.reqid = reqid++; - reqs[i]->resph.reqid = reqs[i]->reqh.reqid; - reqs[i]->hPipe = INVALID_HANDLE_VALUE; - reqs[i]->state = REQSTATE_START; - *req = reqs[i]; - return S_OK; - } - } - - TRACE("creating new struct rpc (request)\n"); - - if (reqs) - reqs = (struct rpc**)HeapReAlloc( - GetProcessHeap(), - HEAP_ZERO_MEMORY, - reqs, - sizeof(struct rpc*)*(nrofreqs+1) - ); - else - reqs = (struct rpc**)HeapAlloc( - GetProcessHeap(), - HEAP_ZERO_MEMORY, - sizeof(struct rpc*) - ); - - if (!reqs) return E_OUTOFMEMORY; - - reqs[nrofreqs] = (struct rpc*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(struct rpc)); - reqs[nrofreqs]->reqh.reqid = reqid++; - reqs[nrofreqs]->resph.reqid = reqs[nrofreqs]->reqh.reqid; - reqs[nrofreqs]->hPipe = INVALID_HANDLE_VALUE; - reqs[nrofreqs]->state = REQSTATE_START; - *req = reqs[nrofreqs]; - - nrofreqs++; - - return S_OK; -} + RPC_BINDING_HANDLE bind; /* handle to the remote server */ +} ClientRpcChannelBuffer; -static HRESULT WINAPI -PipeBuf_QueryInterface( - LPRPCCHANNELBUFFER iface,REFIID riid,LPVOID *ppv -) { +static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv) +{ *ppv = NULL; - if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) { - *ppv = (LPVOID)iface; - IUnknown_AddRef(iface); - return S_OK; + if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown)) + { + *ppv = (LPVOID)iface; + IUnknown_AddRef(iface); + return S_OK; } return E_NOINTERFACE; } -static ULONG WINAPI -PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) { - PipeBuf *This = (PipeBuf *)iface; - return InterlockedIncrement(&This->ref); +static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface) +{ + RpcChannelBuffer *This = (RpcChannelBuffer *)iface; + return InterlockedIncrement(&This->refs); } -static ULONG WINAPI -PipeBuf_Release(LPRPCCHANNELBUFFER iface) { - PipeBuf *This = (PipeBuf *)iface; +static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) +{ + RpcChannelBuffer *This = (RpcChannelBuffer *)iface; ULONG ref; - ref = InterlockedDecrement(&This->ref); + ref = InterlockedDecrement(&This->refs); if (ref) - return ref; + return ref; - CloseHandle(This->pipe); - HeapFree(GetProcessHeap(),0,This); + HeapFree(GetProcessHeap(), 0, This); return 0; } -static HRESULT WINAPI -PipeBuf_GetBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid) +static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface) { - TRACE("(%p,%s)\n",msg,debugstr_guid(riid)); - /* probably reuses IID in real. */ - if (msg->cbBuffer && (msg->Buffer == NULL)) - msg->Buffer = HeapAlloc(GetProcessHeap(),0,msg->cbBuffer); + ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; + ULONG ref; + + ref = InterlockedDecrement(&This->super.refs); + if (ref) + return ref; + + RpcBindingFree(&This->bind); + HeapFree(GetProcessHeap(), 0, This); + return 0; +} + +static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) +{ + RpcChannelBuffer *This = (RpcChannelBuffer *)iface; + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + + TRACE("(%p)->(%p,%p)\n", This, olemsg, riid); + + status = I_RpcGetBuffer(msg); + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI ClientRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid) +{ + ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface; + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_CLIENT_INTERFACE *cif; + RPC_STATUS status; + + TRACE("(%p)->(%p,%p)\n", This, olemsg, riid); + + cif = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RPC_CLIENT_INTERFACE)); + if (!cif) + return E_OUTOFMEMORY; + + cif->Length = sizeof(RPC_CLIENT_INTERFACE); + /* RPC interface ID = COM interface ID */ + cif->InterfaceId.SyntaxGUID = *riid; + /* COM objects always have a version of 0.0 */ + cif->InterfaceId.SyntaxVersion.MajorVersion = 0; + cif->InterfaceId.SyntaxVersion.MinorVersion = 0; + msg->RpcInterfaceInformation = cif; + msg->Handle = This->bind; + + status = I_RpcGetBuffer(msg); + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI RpcChannelBuffer_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus) +{ + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + HRESULT hr; + + TRACE("(%p)\n", msg); + + status = I_RpcSendReceive(msg); + + if (pstatus) *pstatus = status; + + if (status == RPC_S_OK) + hr = S_OK; + else if (status == RPC_S_CALL_FAILED) + hr = *(HRESULT *)msg->Buffer; + else + hr = HRESULT_FROM_WIN32(status); + + TRACE("-- 0x%08lx\n", hr); + + return hr; +} + +static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) +{ + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + + TRACE("(%p)\n", msg); + + status = I_RpcFreeBuffer(msg); + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI ClientRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg) +{ + RPC_MESSAGE *msg = (RPC_MESSAGE *)olemsg; + RPC_STATUS status; + + TRACE("(%p)\n", msg); + + status = I_RpcFreeBuffer(msg); + + HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation); + msg->RpcInterfaceInformation = NULL; + + TRACE("-- %ld\n", status); + + return HRESULT_FROM_WIN32(status); +} + +static HRESULT WINAPI RpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext) +{ + FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext); + return E_FAIL; +} + +static HRESULT WINAPI RpcChannelBuffer_IsConnected(LPRPCCHANNELBUFFER iface) +{ + TRACE("()\n"); + /* native does nothing too */ return S_OK; } +static const IRpcChannelBufferVtbl ClientRpcChannelBufferVtbl = +{ + RpcChannelBuffer_QueryInterface, + RpcChannelBuffer_AddRef, + ClientRpcChannelBuffer_Release, + ClientRpcChannelBuffer_GetBuffer, + RpcChannelBuffer_SendReceive, + ClientRpcChannelBuffer_FreeBuffer, + RpcChannelBuffer_GetDestCtx, + RpcChannelBuffer_IsConnected +}; + +static const IRpcChannelBufferVtbl ServerRpcChannelBufferVtbl = +{ + RpcChannelBuffer_QueryInterface, + RpcChannelBuffer_AddRef, + ServerRpcChannelBuffer_Release, + ServerRpcChannelBuffer_GetBuffer, + RpcChannelBuffer_SendReceive, + ServerRpcChannelBuffer_FreeBuffer, + RpcChannelBuffer_GetDestCtx, + RpcChannelBuffer_IsConnected +}; + +/* returns a channel buffer for proxies */ +/* FIXME: needs renaming and mid removing */ +HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **chan) +{ + ClientRpcChannelBuffer *This; + WCHAR endpoint[200]; + RPC_BINDING_HANDLE bind; + RPC_STATUS status; + LPWSTR string_binding; + + /* connect to the apartment listener thread */ + get_rpc_endpoint(endpoint, &mid->oxid); + + TRACE("proxy pipe: connecting to endpoint: %s\n", debugstr_w(endpoint)); + + status = RpcStringBindingComposeW( + NULL, + wszPipeTransport, + NULL, + endpoint, + NULL, + &string_binding); + + if (status == RPC_S_OK) + { + status = RpcBindingFromStringBindingW(string_binding, &bind); + + if (status == RPC_S_OK) + { + status = RpcBindingSetObject(bind, &mid->ipid); + if (status != RPC_S_OK) + RpcBindingFree(&bind); + } + + RpcStringFreeW(&string_binding); + } + + if (status != RPC_S_OK) + { + ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status); + return HRESULT_FROM_WIN32(status); + } + + This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + { + RpcBindingFree(&bind); + return E_OUTOFMEMORY; + } + + This->super.lpVtbl = &ClientRpcChannelBufferVtbl; + This->super.refs = 1; + This->bind = bind; + + *chan = (IRpcChannelBuffer*)This; + + return S_OK; +} + +HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan) +{ + RpcChannelBuffer *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This)); + if (!This) + return E_OUTOFMEMORY; + + This->lpVtbl = &ServerRpcChannelBufferVtbl; + This->refs = 1; + + *chan = (IRpcChannelBuffer*)This; + + return S_OK; +} + + HRESULT RPC_ExecuteCall(RPCOLEMESSAGE *msg, IRpcStubBuffer *stub) { + /* FIXME: pass server channel buffer, but don't create it every time */ return IRpcStubBuffer_Invoke(stub, msg, NULL); } -static HRESULT -COM_InvokeAndRpcSend(struct rpc *req) { +static void __RPC_STUB dispatch_rpc(RPC_MESSAGE *msg) +{ IRpcStubBuffer *stub; APARTMENT *apt; - RPCOLEMESSAGE msg; - HRESULT hres; - DWORD reqtype; + IPID ipid; - memset(&msg, 0, sizeof(msg)); - msg.Buffer = req->Buffer; - msg.iMethod = req->reqh.iMethod; - msg.cbBuffer = req->reqh.cbBuffer; - msg.dataRepresentation = NDR_LOCAL_DATA_REPRESENTATION; - req->state = REQSTATE_INVOKING; + RpcBindingInqObject(msg->Handle, &ipid); - stub = ipid_to_apt_and_stubbuffer(&req->reqh.ipid, &apt); - if (!apt) - /* ipid_to_apt_and_stubbuffer will already have logged the error */ - return RPC_E_DISCONNECTED; - if (!stub) + stub = ipid_to_apt_and_stubbuffer(&ipid, &apt); + if (!apt || !stub) { + if (apt) COM_ApartmentRelease(apt); /* ipid_to_apt_and_stubbuffer will already have logged the error */ - COM_ApartmentRelease(apt); - return RPC_E_DISCONNECTED; + return RpcRaiseException(RPC_E_DISCONNECTED); } /* Note: this is the important difference between STAs and MTAs - we * always execute RPCs to STAs in the thread that originally created the * apartment (i.e. the one that pumps messages to the window) */ if (apt->model & COINIT_APARTMENTTHREADED) - req->resph.retval = SendMessageW(apt->win, DM_EXECUTERPC, (WPARAM)&msg, (LPARAM)stub); + SendMessageW(apt->win, DM_EXECUTERPC, (WPARAM)msg, (LPARAM)stub); else - req->resph.retval = RPC_ExecuteCall(&msg, stub); + RPC_ExecuteCall((RPCOLEMESSAGE *)msg, stub); COM_ApartmentRelease(apt); IRpcStubBuffer_Release(stub); - - req->Buffer = msg.Buffer; - req->resph.cbBuffer = msg.cbBuffer; - reqtype = REQTYPE_RESPONSE; - hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype)); - if (hres) return hres; - hres = write_pipe(req->hPipe,&(req->resph),sizeof(req->resph)); - if (hres) return hres; - hres = write_pipe(req->hPipe,req->Buffer,req->resph.cbBuffer); - if (hres) return hres; - req->state = REQSTATE_DONE; - return S_OK; } -static HRESULT process_incoming_rpc(HANDLE pipe); - -static HRESULT RPC_QueueRequestAndWait(struct rpc *req, HANDLE pipe) +/* stub registration */ +HRESULT RPC_RegisterInterface(REFIID riid) { - int i; - struct rpc *xreq; - HRESULT hres; - DWORD reqtype; + struct registered_if *rif; + BOOL found = FALSE; + HRESULT hr = S_OK; + + TRACE("(%s)\n", debugstr_guid(riid)); - req->hPipe = pipe; - req->state = REQSTATE_REQ_WAITING_FOR_REPLY; - reqtype = REQTYPE_REQUEST; - hres = write_pipe(req->hPipe,&reqtype,sizeof(reqtype)); - if (hres) return hres; - hres = write_pipe(req->hPipe,&(req->reqh),sizeof(req->reqh)); - if (hres) return hres; - hres = write_pipe(req->hPipe,req->Buffer,req->reqh.cbBuffer); - if (hres) return hres; - - /* This loop is about allowing re-entrancy. While waiting for the - * response to one RPC we may receive a request starting another. */ - while (!hres) { - hres = process_incoming_rpc(pipe); - if (hres) break; - - for (i=0;istate==REQSTATE_REQ_GOT) && (xreq->hPipe==req->hPipe)) { - hres = COM_InvokeAndRpcSend(xreq); - if (hres) break; - } - } - if (req->state == REQSTATE_RESP_GOT) - return S_OK; - } - if (FAILED(hres)) - WARN("-- 0x%08lx\n", hres); - return hres; -} - -static HRESULT WINAPI -PipeBuf_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *msg, ULONG *status) -{ - PipeBuf *This = (PipeBuf *)iface; - struct rpc *req; - HRESULT hres; - - if (This->mid.oxid == COM_CurrentApt()->oxid) { - ERR("Need to call directly!\n"); - return E_FAIL; - } - - hres = RPC_GetRequest(&req); - if (hres) return hres; - req->reqh.iMethod = msg->iMethod; - req->reqh.cbBuffer = msg->cbBuffer; - req->reqh.ipid = This->mid.ipid; - req->Buffer = msg->Buffer; - TRACE(" -> rpc ->\n"); - hres = RPC_QueueRequestAndWait(req, This->pipe); - TRACE(" <- response <-\n"); - if (hres) + EnterCriticalSection(&csRegIf); + LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) { - req->state = REQSTATE_DONE; - return hres; + if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) + { + rif->refs++; + found = TRUE; + break; + } } - - msg->cbBuffer = req->resph.cbBuffer; - msg->Buffer = req->Buffer; - *status = req->resph.retval; - req->state = REQSTATE_DONE; - - return S_OK; -} - - -static HRESULT WINAPI -PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) -{ - TRACE("(%p)\n",msg); - HeapFree(GetProcessHeap(), 0, msg->Buffer); - return S_OK; -} - -static HRESULT WINAPI -PipeBuf_GetDestCtx(LPRPCCHANNELBUFFER iface,DWORD* pdwDestContext,void** ppvDestContext) -{ - FIXME("(%p,%p), stub!\n",pdwDestContext,ppvDestContext); - return E_FAIL; -} - -static HRESULT WINAPI -PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface) -{ - FIXME("(), stub!\n"); - return S_OK; -} - -static IRpcChannelBufferVtbl pipebufvt = { - PipeBuf_QueryInterface, - PipeBuf_AddRef, - PipeBuf_Release, - PipeBuf_GetBuffer, - PipeBuf_SendReceive, - PipeBuf_FreeBuffer, - PipeBuf_GetDestCtx, - PipeBuf_IsConnected -}; - -/* returns a pipebuf for proxies */ -HRESULT PIPE_GetNewPipeBuf(wine_marshal_id *mid, IRpcChannelBuffer **pipebuf) -{ - wine_marshal_id ourid; - HANDLE handle; - PipeBuf *pbuf; - char pipefn[200]; - - /* connect to the apartment listener thread */ - sprintf(pipefn,OLESTUBMGR"_%08lx%08lx",(DWORD)(mid->oxid >> 32),(DWORD)mid->oxid); - - TRACE("proxy pipe: connecting to apartment listener thread: %s\n", pipefn); - - while (TRUE) + if (!found) { - BOOL ret = WaitNamedPipeA(pipefn, NMPWAIT_USE_DEFAULT_WAIT); - if (!ret) + TRACE("Creating new interface\n"); + + rif = HeapAlloc(GetProcessHeap(), 0, sizeof(*rif)); + if (rif) { - ERR("Could not open named pipe %s, error %ld\n", pipefn, GetLastError()); - return RPC_E_SERVER_DIED; + RPC_STATUS status; + + rif->refs = 1; + rif->If.Length = sizeof(RPC_SERVER_INTERFACE); + /* RPC interface ID = COM interface ID */ + rif->If.InterfaceId.SyntaxGUID = *riid; + /* COM objects always have a version of 0.0 */ + rif->If.InterfaceId.SyntaxVersion.MajorVersion = 0; + rif->If.InterfaceId.SyntaxVersion.MinorVersion = 0; + rif->If.DispatchTable = &rpc_dispatch; + status = RpcServerRegisterIfEx( + (RPC_IF_HANDLE)&rif->If, + NULL, NULL, + RPC_IF_OLE | RPC_IF_AUTOLISTEN, + RPC_C_LISTEN_MAX_CALLS_DEFAULT, + NULL); + if (status == RPC_S_OK) + list_add_tail(®istered_interfaces, &rif->entry); + else + { + ERR("RpcServerRegisterIfEx failed with error %ld\n", status); + HeapFree(GetProcessHeap(), 0, rif); + hr = HRESULT_FROM_WIN32(status); + } } - - handle = CreateFileA(pipefn, GENERIC_READ | GENERIC_WRITE, - 0, NULL, OPEN_EXISTING, 0, 0); - - if (handle == INVALID_HANDLE_VALUE) - { - if (GetLastError() == ERROR_PIPE_BUSY) continue; - - ERR("Could not open named pipe %s, error %ld\n", pipefn, GetLastError()); - return RPC_E_SERVER_DIED; - } - - break; + else + hr = E_OUTOFMEMORY; } - - memset(&ourid,0,sizeof(ourid)); - ourid.oxid = COM_CurrentApt()->oxid; - - TRACE("constructing new pipebuf for proxy\n"); - - pbuf = (PipeBuf*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(PipeBuf)); - pbuf->lpVtbl = &pipebufvt; - pbuf->ref = 1; - memcpy(&(pbuf->mid),mid,sizeof(*mid)); - pbuf->pipe = dupe_handle(handle); - - *pipebuf = (IRpcChannelBuffer*)pbuf; - - return S_OK; + LeaveCriticalSection(&csRegIf); + return hr; } +/* stub unregistration */ +void RPC_UnregisterInterface(REFIID riid) +{ + struct registered_if *rif; + EnterCriticalSection(&csRegIf); + LIST_FOR_EACH_ENTRY(rif, ®istered_interfaces, struct registered_if, entry) + { + if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid)) + { + if (!--rif->refs) + { +#if 0 /* this is a stub in builtin and spams the console with FIXME's */ + IID iid = *riid; /* RpcServerUnregisterIf doesn't take const IID */ + RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, &iid, 0); +#endif + list_remove(&rif->entry); + HeapFree(GetProcessHeap(), 0, rif); + } + break; + } + } + LeaveCriticalSection(&csRegIf); +} + +/* FIXME: needs renaming */ +void start_apartment_listener_thread() +{ + APARTMENT *apt = COM_CurrentApt(); /* FIXME: pass as parameter */ + + if (!apt->listenertid) + { + WCHAR endpoint[200]; + RPC_STATUS status; + + get_rpc_endpoint(endpoint, &apt->oxid); + + status = RpcServerUseProtseqEpW( + wszPipeTransport, + RPC_C_PROTSEQ_MAX_REQS_DEFAULT, + endpoint, + NULL); + if (status != RPC_S_OK) + ERR("Couldn't register endpoint %s\n", debugstr_w(endpoint)); + apt->listenertid = TRUE; /* FIXME: don't abuse this field and use remunk_exported, by moving remunk exporting into this function */ + } +} + + static HRESULT create_server(REFCLSID rclsid) { @@ -648,7 +652,9 @@ create_local_service(REFCLSID rclsid) return hres; } -/* http://msdn.microsoft.com/library/en-us/dnmsj99/html/com0199.asp, Figure 4 */ +#define PIPEPREF "\\\\.\\pipe\\" + +/* FIXME: should call to rpcss instead */ HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) { HRESULT hres; @@ -660,7 +666,7 @@ HRESULT create_marshalled_proxy(REFCLSID rclsid, REFIID iid, LPVOID *ppv) LARGE_INTEGER seekto; ULARGE_INTEGER newpos; int tries = 0; - + static const int MAXTRIES = 10000; TRACE("rclsid=%s, iid=%s\n", debugstr_guid(rclsid), debugstr_guid(iid)); @@ -714,302 +720,13 @@ out: } -/* this reads an RPC from the given pipe and places it in the global reqs array */ -static HRESULT process_incoming_rpc(HANDLE pipe) -{ - DWORD reqtype; - HRESULT hres = S_OK; - - hres = read_pipe(pipe,&reqtype,sizeof(reqtype)); - if (hres) return hres; - - /* only received by servers */ - if (reqtype == REQTYPE_REQUEST) - { - struct rpc *xreq; - - RPC_GetRequest(&xreq); - - xreq->hPipe = pipe; - hres = read_pipe(pipe,&(xreq->reqh),sizeof(xreq->reqh)); - if (hres) - { - xreq->state = REQSTATE_DONE; - return hres; - } - - xreq->resph.reqid = xreq->reqh.reqid; - xreq->Buffer = HeapAlloc(GetProcessHeap(),0, xreq->reqh.cbBuffer); - hres = read_pipe(pipe,xreq->Buffer,xreq->reqh.cbBuffer); - if (hres) goto end; - - TRACE("received RPC for IPID %s\n", debugstr_guid(&xreq->reqh.ipid)); - - xreq->state = REQSTATE_REQ_GOT; - goto end; - } - else if (reqtype == REQTYPE_RESPONSE) - { - struct response_header resph; - int i; - - hres = read_pipe(pipe,&resph,sizeof(resph)); - if (hres) goto end; - - TRACE("read RPC response\n"); - - for (i = nrofreqs; i--;) - { - struct rpc *xreq = reqs[i]; - - if (xreq->state != REQSTATE_REQ_WAITING_FOR_REPLY) - continue; - - if (xreq->reqh.reqid == resph.reqid) - { - memcpy(&(xreq->resph),&resph,sizeof(resph)); - - if (xreq->Buffer) - xreq->Buffer = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->Buffer,xreq->resph.cbBuffer); - else - xreq->Buffer = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,xreq->resph.cbBuffer); - - hres = read_pipe(pipe,xreq->Buffer,xreq->resph.cbBuffer); - if (hres) goto end; - - TRACE("received response for reqid 0x%lx\n", xreq->reqh.reqid); - - xreq->state = REQSTATE_RESP_GOT; - goto end; - } - } - - ERR("protocol error: did not find request for id %lx\n",resph.reqid); - hres = E_FAIL; - goto end; - } - - ERR("protocol error: unknown reqtype %ld\n",reqtype); - hres = E_FAIL; -end: - return hres; -} - -struct stub_dispatch_params -{ - struct apartment *apt; - HANDLE pipe; -}; - -/* This thread listens on the given pipe for requests to any stub manager */ -static DWORD WINAPI client_dispatch_thread(LPVOID param) -{ - HANDLE pipe = ((struct stub_dispatch_params *)param)->pipe; - struct apartment *apt = ((struct stub_dispatch_params *)param)->apt; - HRESULT hres = S_OK; - HANDLE shutdown_event = dupe_handle(apt->shutdown_event); - - HeapFree(GetProcessHeap(), 0, param); - - /* join marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */ - COM_CurrentInfo()->apt = apt; - - while (TRUE) - { - int i; - - TRACE("waiting for RPC on OXID: %08lx%08lx\n", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid)); - - /* read a new request into the global array, block if no requests have been sent */ - hres = process_incoming_rpc(pipe); - if (hres) break; - - /* do you expect me to talk? */ - if (WaitForSingleObject(shutdown_event, 0) == WAIT_OBJECT_0) - { - /* no mr bond, i expect you to die! bwahaha */ - CloseHandle(shutdown_event); - break; - } - - TRACE("received RPC on OXID: %08lx%08lx\n", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid)); - - /* now scan the array looking for the RPC just loaded */ - for (i=nrofreqs;i--;) - { - struct rpc *req = reqs[i]; - - if ((req->state == REQSTATE_REQ_GOT) && (req->hPipe == pipe)) - { - hres = COM_InvokeAndRpcSend(req); - if (!hres) break; - } - } - } - - TRACE("exiting with hres %lx\n",hres); - - /* leave marshalling apartment. fixme: this stuff is all very wrong, threading needs to work like native */ - COM_CurrentInfo()->apt = NULL; - - DisconnectNamedPipe(pipe); - CloseHandle(pipe); - return 0; -} - -struct apartment_listener_params -{ - APARTMENT *apt; - HANDLE event; -}; - -/* This thread listens on a named pipe for each apartment that exports - * objects. It deals with incoming connection requests. Each time a - * client connects a separate thread is spawned for that particular - * connection. - * - * This architecture is different in native DCOM. - */ -static DWORD WINAPI apartment_listener_thread(LPVOID p) -{ - char pipefn[200]; - HANDLE listenPipe, thread_handle; - OVERLAPPED overlapped; - HANDLE wait[2]; - - struct apartment_listener_params * params = (struct apartment_listener_params *)p; - struct apartment *apt = params->apt; - HANDLE event = params->event; - HANDLE apt_shutdown_event = dupe_handle(apt->shutdown_event); - OXID this_oxid = apt->oxid; /* copy here so we can print it when we shut down */ - - HeapFree(GetProcessHeap(), 0, params); - - overlapped.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); - - /* we must join the marshalling threads apartment. we already have a ref here */ - COM_CurrentInfo()->apt = apt; - - sprintf(pipefn,OLESTUBMGR"_%08lx%08lx", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid)); - TRACE("Apartment listener thread starting on (%s)\n",pipefn); - - while (TRUE) - { - struct stub_dispatch_params *params; - DWORD res; - - listenPipe = CreateNamedPipeA( - pipefn, - PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, - PIPE_TYPE_BYTE|PIPE_WAIT, - PIPE_UNLIMITED_INSTANCES, - 4096, - 4096, - 500 /* 0.5 seconds */, - NULL - ); - - /* tell function that started this thread that we have attempted to created the - * named pipe. */ - if (event) { - SetEvent(event); - event = NULL; - } - - if (listenPipe == INVALID_HANDLE_VALUE) { - FIXME("pipe creation failed for %s, error %ld\n",pipefn,GetLastError()); - break; /* permanent failure, so quit stubmgr thread */ - } - - TRACE("waiting for a client ...\n"); - - /* an already connected pipe is not an error */ - if (!ConnectNamedPipe(listenPipe, &overlapped)) - { - DWORD le = GetLastError(); - - if ((le != ERROR_IO_PENDING) && (le != ERROR_PIPE_CONNECTED)) - { - ERR("Failure during ConnectNamedPipe %ld!\n",GetLastError()); - CloseHandle(listenPipe); - continue; - } - } - - /* wait for action */ - wait[0] = apt_shutdown_event; - wait[1] = overlapped.hEvent; - res = WaitForMultipleObjectsEx(2, wait, FALSE, INFINITE, FALSE); - if (res == WAIT_OBJECT_0) break; - - ResetEvent(overlapped.hEvent); - - /* start the stub dispatch thread for this connection */ - TRACE("starting stub dispatch thread for OXID %08lx%08lx\n", (DWORD)(apt->oxid >> 32), (DWORD)(apt->oxid)); - params = HeapAlloc(GetProcessHeap(), 0, sizeof(struct stub_dispatch_params)); - if (!params) - { - ERR("out of memory, dropping this client\n"); - CloseHandle(listenPipe); - continue; - } - params->apt = apt; - params->pipe = listenPipe; - thread_handle = CreateThread(NULL, 0, &client_dispatch_thread, params, 0, NULL); - CloseHandle(thread_handle); - } - - TRACE("shutting down: %s\n", wine_dbgstr_longlong(this_oxid)); - - /* we must leave the marshalling threads apartment. we don't have a ref here */ - COM_CurrentInfo()->apt = NULL; - - DisconnectNamedPipe(listenPipe); - CloseHandle(listenPipe); - CloseHandle(overlapped.hEvent); - CloseHandle(apt_shutdown_event); - return 0; -} - -void start_apartment_listener_thread() -{ - APARTMENT *apt = COM_CurrentApt(); - - assert( apt ); - - TRACE("apt->listenertid=%ld\n", apt->listenertid); - - /* apt->listenertid is a hack which needs to die at some point, as - * it leaks information into the apartment structure. in fact, - * this thread isn't quite correct anyway as native RPC doesn't - * use a thread per apartment at all, instead the dispatch thread - * either enters the apartment to perform the RPC (for MTAs, RTAs) - * or does a context switch into it for STAs. - */ - - if (!apt->listenertid) - { - HANDLE thread; - HANDLE event = CreateEventW(NULL, TRUE, FALSE, NULL); - struct apartment_listener_params * params = HeapAlloc(GetProcessHeap(), 0, sizeof(*params)); - - params->apt = apt; - params->event = event; - thread = CreateThread(NULL, 0, apartment_listener_thread, params, 0, &apt->listenertid); - CloseHandle(thread); - /* wait for pipe to be created before returning, otherwise we - * might try to use it and fail */ - WaitForSingleObject(event, INFINITE); - CloseHandle(event); - } -} - struct local_server_params { CLSID clsid; IStream *stream; }; +/* FIXME: should call to rpcss instead */ static DWORD WINAPI local_server_thread(LPVOID param) { struct local_server_params * lsp = (struct local_server_params *)param; diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index c78294ed057..a120deb877d 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -418,8 +418,10 @@ struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *s static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *ifstub) { TRACE("m=%p, m->oid=%s, ipid=%s\n", m, wine_dbgstr_longlong(m->oid), debugstr_guid(&ifstub->ipid)); - + list_remove(&ifstub->entry); + + RPC_UnregisterInterface(&ifstub->iid); IUnknown_Release(ifstub->stubbuffer); IUnknown_Release(ifstub->iface);