Make COM use the RPC runtime as the backend for RPC calls. Based on a
authorRobert Shearman <rob@codeweavers.com>
Tue, 15 Feb 2005 15:02:49 +0000 (15:02 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Tue, 15 Feb 2005 15:02:49 +0000 (15:02 +0000)
patch by Ove Kåven.

dlls/ole32/compobj.c
dlls/ole32/compobj_private.h
dlls/ole32/marshal.c
dlls/ole32/rpc.c
dlls/ole32/stubmanager.c

index 3fbfc358d618fc7f1d69d297c588aeb1b3d2e879..bf75c1ec4f7c6f54c9430b6ee11094ffe75246a8 100644 (file)
@@ -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
index 1df27374121d1695b7cdb7e9cc75031a5a5bb712..870a1800a130f9954132e59e2a4caef78b65cd47 100644 (file)
@@ -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);
index 41bf1236edf2c17360b0d92cf77ee0931ed8c51e..bcc54d861de268d8c02842de5914af19ed88eced 100644 (file)
@@ -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);
index 4e0408e0ee1010ab47c59ab5518a16173b8c6e66..523f74230c1d4e77ea88986e8d1da017269fd9fb 100644 (file)
@@ -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
  *
 
 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 response_header
+struct registered_if
 {
-    DWORD              reqid;
-    DWORD              cbBuffer;
-    DWORD              retval;
+    struct list entry;
+    DWORD refs; /* ref count */
+    RPC_SERVER_INTERFACE If; /* interface registered with the RPC runtime */
 };
 
+/* get the pipe endpoint specified of the specified apartment */
+static inline void get_rpc_endpoint(LPWSTR endpoint, const OXID *oxid)
+{
+    /* 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);
+}
 
-#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
+typedef struct
+{
+    const IRpcChannelBufferVtbl *lpVtbl;
+    DWORD                  refs;
+} RpcChannelBuffer;
 
-struct rpc
+typedef struct
 {
-    int                                state;
-    HANDLE                     hPipe;  /* temp copy of handle */
-    struct request_header      reqh;
-    struct response_header     resph;
-    LPBYTE                     Buffer;
-};
+    RpcChannelBuffer       super; /* superclass */
 
-/* fixme: this should have a lock */
-static struct rpc **reqs = NULL;
-static int nrofreqs = 0;
+    RPC_BINDING_HANDLE     bind; /* handle to the remote server */
+} ClientRpcChannelBuffer;
 
-/* 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
+static HRESULT WINAPI RpcChannelBuffer_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
 {
-    wine_marshal_id    mid;    /* target mid */
-    DWORD              tid;    /* thread which owns this pipe */
-    HANDLE             hPipe;
+    *ppv = NULL;
+    if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
+    {
+        *ppv = (LPVOID)iface;
+        IUnknown_AddRef(iface);
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
 
-    int                        pending;
-    HANDLE             hThread;
-    CRITICAL_SECTION   crit;
+static ULONG WINAPI RpcChannelBuffer_AddRef(LPRPCCHANNELBUFFER iface)
+{
+    RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
+    return InterlockedIncrement(&This->refs);
+}
 
-    APARTMENT          *apt;    /* apartment of the marshalling thread for the stub dispatch case */
-};
+static ULONG WINAPI ServerRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
+{
+    RpcChannelBuffer *This = (RpcChannelBuffer *)iface;
+    ULONG ref;
 
-typedef struct _PipeBuf {
-    IRpcChannelBufferVtbl *lpVtbl;
-    DWORD                  ref;
+    ref = InterlockedDecrement(&This->refs);
+    if (ref)
+        return ref;
 
-    wine_marshal_id        mid;
-    HANDLE                 pipe;
-} PipeBuf;
+    HeapFree(GetProcessHeap(), 0, This);
+    return 0;
+}
 
+static ULONG WINAPI ClientRpcChannelBuffer_Release(LPRPCCHANNELBUFFER iface)
+{
+    ClientRpcChannelBuffer *This = (ClientRpcChannelBuffer *)iface;
+    ULONG ref;
 
+    ref = InterlockedDecrement(&This->super.refs);
+    if (ref)
+        return ref;
 
-/* some helper functions */
+    RpcBindingFree(&This->bind);
+    HeapFree(GetProcessHeap(), 0, This);
+    return 0;
+}
 
-static HRESULT WINAPI read_pipe(HANDLE hf, LPVOID ptr, DWORD size)
+static HRESULT WINAPI ServerRpcChannelBuffer_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
 {
-    DWORD res;
-    
-    if (!ReadFile(hf,ptr,size,&res,NULL))
-    {
-        ERR("Failed to read from %p, le is %ld\n",hf,GetLastError());
-        return E_FAIL;
-    }
+    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;
     
-    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;
+    status = I_RpcGetBuffer(msg);
+
+    TRACE("-- %ld\n", status);
+
+    return HRESULT_FROM_WIN32(status);
 }
 
-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 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 HANDLE dupe_handle(HANDLE h)
+static HRESULT WINAPI ServerRpcChannelBuffer_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
 {
-    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;
+    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);
 
-static DWORD WINAPI client_dispatch_thread(LPVOID);
+    HeapFree(GetProcessHeap(), 0, msg->RpcInterfaceInformation);
+    msg->RpcInterfaceInformation = NULL;
 
-/* FIXME: this all needs to be made thread safe */
-static HRESULT RPC_GetRequest(struct rpc **req)
+    TRACE("-- %ld\n", status);
+
+    return HRESULT_FROM_WIN32(status);
+}
+
+static HRESULT WINAPI RpcChannelBuffer_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
 {
-    static int reqid = 0;
-    int i;
+    FIXME("(%p,%p), stub!\n", pdwDestContext, ppvDestContext);
+    return E_FAIL;
+}
 
-    /* try to reuse */
-    for (i = 0; i < nrofreqs; i++)
+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)
     {
-        if (reqs[i]->state == REQSTATE_DONE)
+        status = RpcBindingFromStringBindingW(string_binding, &bind);
+
+        if (status == RPC_S_OK)
         {
-            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;
+            status = RpcBindingSetObject(bind, &mid->ipid);
+            if (status != RPC_S_OK)
+                RpcBindingFree(&bind);
         }
+
+        RpcStringFreeW(&string_binding);
     }
-    
-    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;
-}
 
-static HRESULT WINAPI
-PipeBuf_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 (status != RPC_S_OK)
+    {
+        ERR("Couldn't get binding for endpoint %s, status = %ld\n", debugstr_w(endpoint), status);
+        return HRESULT_FROM_WIN32(status);
     }
-    return E_NOINTERFACE;
-}
 
-static ULONG WINAPI
-PipeBuf_AddRef(LPRPCCHANNELBUFFER iface) {
-    PipeBuf *This = (PipeBuf *)iface;
-    return InterlockedIncrement(&This->ref);
-}
+    This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+    if (!This)
+    {
+        RpcBindingFree(&bind);
+        return E_OUTOFMEMORY;
+    }
 
-static ULONG WINAPI
-PipeBuf_Release(LPRPCCHANNELBUFFER iface) {
-    PipeBuf *This = (PipeBuf *)iface;
-    ULONG ref;
+    This->super.lpVtbl = &ClientRpcChannelBufferVtbl;
+    This->super.refs = 1;
+    This->bind = bind;
 
-    ref = InterlockedDecrement(&This->ref);
-    if (ref)
-       return ref;
+    *chan = (IRpcChannelBuffer*)This;
 
-    CloseHandle(This->pipe);
-    HeapFree(GetProcessHeap(),0,This);
-    return 0;
+    return S_OK;
 }
 
-static HRESULT WINAPI
-PipeBuf_GetBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,REFIID riid)
+HRESULT RPC_CreateServerChannel(IRpcChannelBuffer **chan)
 {
-    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);
+    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;
-
-    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;i<nrofreqs;i++) {
-           xreq = reqs[i];
-           if ((xreq->state==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;
-    }
+    struct registered_if *rif;
+    BOOL found = FALSE;
+    HRESULT hr = S_OK;
+    
+    TRACE("(%s)\n", debugstr_guid(riid));
 
-    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, &registered_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;
-}
+    if (!found)
+    {
+        TRACE("Creating new interface\n");
 
-static HRESULT WINAPI
-PipeBuf_IsConnected(LPRPCCHANNELBUFFER iface)
-{
-    FIXME("(), stub!\n");
-    return S_OK;
+        rif = HeapAlloc(GetProcessHeap(), 0, sizeof(*rif));
+        if (rif)
+        {
+            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(&registered_interfaces, &rif->entry);
+            else
+            {
+                ERR("RpcServerRegisterIfEx failed with error %ld\n", status);
+                HeapFree(GetProcessHeap(), 0, rif);
+                hr = HRESULT_FROM_WIN32(status);
+            }
+        }
+        else
+            hr = E_OUTOFMEMORY;
+    }
+    LeaveCriticalSection(&csRegIf);
+    return hr;
 }
 
-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)
+/* stub unregistration */
+void RPC_UnregisterInterface(REFIID riid)
 {
-    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)
+    struct registered_if *rif;
+    EnterCriticalSection(&csRegIf);
+    LIST_FOR_EACH_ENTRY(rif, &registered_interfaces, struct registered_if, entry)
     {
-        BOOL ret = WaitNamedPipeA(pipefn, NMPWAIT_USE_DEFAULT_WAIT);
-        if (!ret)
+        if (IsEqualGUID(&rif->If.InterfaceId.SyntaxGUID, riid))
         {
-            ERR("Could not open named pipe %s, error %ld\n", pipefn, GetLastError());
-            return RPC_E_SERVER_DIED;
+            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);
+}
 
-        handle = CreateFileA(pipefn, GENERIC_READ | GENERIC_WRITE,
-                             0, NULL, OPEN_EXISTING, 0, 0);
+/* FIXME: needs renaming */
+void start_apartment_listener_thread()
+{
+    APARTMENT *apt = COM_CurrentApt(); /* FIXME: pass as parameter */
 
-        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;
-        }
+    if (!apt->listenertid)
+    {
+        WCHAR endpoint[200];
+        RPC_STATUS status;
 
-        break;
-    }
-    
-    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;
+        get_rpc_endpoint(endpoint, &apt->oxid);
     
-    return S_OK;
+        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;
index c78294ed0570da3262c78ca691f8a5abe0140e9c..a120deb877d067e9e337329edb113073f24a48b1 100644 (file)
@@ -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);