set svn:eol-style to native
[reactos.git] / reactos / lib / ole32 / oleproxy.c
index 014875e..e647a51 100644 (file)
-/*\r
- *     OLE32 proxy/stub handler\r
- *\r
- *  Copyright 2002  Marcus Meissner\r
- *  Copyright 2001  Ove Kåven, TransGaming Technologies\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
- */\r
-\r
-/* Documentation on MSDN:\r
- *\r
- * (Top level COM documentation)\r
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/componentdevelopmentank.asp\r
- *\r
- * (COM Proxy)\r
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1q0p.asp\r
- *\r
- * (COM Stub)\r
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1lia.asp\r
- *\r
- * (Marshal)\r
- * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1gfn.asp\r
- *\r
- */\r
-\r
-#include "config.h"\r
-\r
-#include <stdlib.h>\r
-#include <stdarg.h>\r
-#include <stddef.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-#define COBJMACROS\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "winuser.h"\r
-#include "objbase.h"\r
-#include "ole2.h"\r
-#include "rpc.h"\r
-#include "winerror.h"\r
-#include "winreg.h"\r
-#include "wtypes.h"\r
-\r
-#include "compobj_private.h"\r
-#include "moniker.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(ole);\r
-\r
-const CLSID CLSID_DfMarshal       = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };\r
-const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };\r
-\r
-/* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp\r
- *\r
- * The first time a client requests a pointer to an interface on a\r
- * particular object, COM loads an IClassFactory stub in the server\r
- * process and uses it to marshal the first pointer back to the\r
- * client. In the client process, COM loads the generic proxy for the\r
- * class factory object and calls its implementation of IMarshal to\r
- * unmarshal that first pointer. COM then creates the first interface\r
- * proxy and hands it a pointer to the RPC channel. Finally, COM returns\r
- * the IClassFactory pointer to the client, which uses it to call\r
- * IClassFactory::CreateInstance, passing it a reference to the interface.\r
- *\r
- * Back in the server process, COM now creates a new instance of the\r
- * object, along with a stub for the requested interface. This stub marshals\r
- * the interface pointer back to the client process, where another object\r
- * proxy is created, this time for the object itself. Also created is a\r
- * proxy for the requested interface, a pointer to which is returned to\r
- * the client. With subsequent calls to other interfaces on the object,\r
- * COM will load the appropriate interface stubs and proxies as needed.\r
- */\r
-typedef struct _CFStub {\r
-    IRpcStubBufferVtbl *lpvtbl;\r
-    DWORD                      ref;\r
-\r
-    LPUNKNOWN                  pUnkServer;\r
-} CFStub;\r
-\r
-static HRESULT WINAPI\r
-CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {\r
-    if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {\r
-       *ppv = (LPVOID)iface;\r
-       IUnknown_AddRef(iface);\r
-       return S_OK;\r
-    }\r
-    FIXME("(%s), interface not supported.\n",debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI\r
-CFStub_AddRef(LPRPCSTUBBUFFER iface) {\r
-    CFStub *This = (CFStub *)iface;\r
-    return InterlockedIncrement(&This->ref);\r
-}\r
-\r
-static ULONG WINAPI\r
-CFStub_Release(LPRPCSTUBBUFFER iface) {\r
-    CFStub *This = (CFStub *)iface;\r
-    ULONG ref;\r
-\r
-    ref = InterlockedDecrement(&This->ref);\r
-    if (!ref) HeapFree(GetProcessHeap(),0,This);\r
-    return ref;\r
-}\r
-\r
-static HRESULT WINAPI\r
-CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {\r
-    CFStub *This = (CFStub *)iface;\r
-\r
-    This->pUnkServer = pUnkServer;\r
-    IUnknown_AddRef(pUnkServer);\r
-    return S_OK;\r
-}\r
-\r
-static void WINAPI\r
-CFStub_Disconnect(LPRPCSTUBBUFFER iface) {\r
-    CFStub *This = (CFStub *)iface;\r
-\r
-    IUnknown_Release(This->pUnkServer);\r
-    This->pUnkServer = NULL;\r
-}\r
-static HRESULT WINAPI\r
-CFStub_Invoke(\r
-    LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf\r
-) {\r
-    CFStub *This = (CFStub *)iface;\r
-    HRESULT hres;\r
-\r
-    if (msg->iMethod == 3) { /* CreateInstance */\r
-       IID iid;\r
-       IClassFactory   *classfac;\r
-       IUnknown        *ppv;\r
-       IStream         *pStm;\r
-       STATSTG         ststg;\r
-       ULARGE_INTEGER  newpos;\r
-       LARGE_INTEGER   seekto;\r
-       ULONG           res;\r
-\r
-       if (msg->cbBuffer < sizeof(IID)) {\r
-           FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));\r
-           return E_FAIL;\r
-       }\r
-       memcpy(&iid,msg->Buffer,sizeof(iid));\r
-       TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));\r
-       hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);\r
-       if (hres) {\r
-           FIXME("Ole server does not provide an IClassFactory?\n");\r
-           return hres;\r
-       }\r
-       hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);\r
-       IClassFactory_Release(classfac);\r
-       if (hres) {\r
-           msg->cbBuffer = 0;\r
-           FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));\r
-           return hres;\r
-       }\r
-       hres = CreateStreamOnHGlobal(0,TRUE,&pStm);\r
-       if (hres) {\r
-           FIXME("Failed to create stream on hglobal\n");\r
-           return hres;\r
-       }\r
-       hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);\r
-       IUnknown_Release((IUnknown*)ppv);\r
-       if (hres) {\r
-           FIXME("CoMarshalInterface failed, %lx!\n",hres);\r
-           msg->cbBuffer = 0;\r
-           return hres;\r
-       }\r
-       hres = IStream_Stat(pStm,&ststg,0);\r
-       if (hres) {\r
-           FIXME("Stat failed.\n");\r
-           return hres;\r
-       }\r
-\r
-       msg->cbBuffer = ststg.cbSize.u.LowPart;\r
-\r
-        I_RpcGetBuffer((RPC_MESSAGE *)msg);\r
-        if (hres) return hres;\r
-\r
-       seekto.u.LowPart = 0;seekto.u.HighPart = 0;\r
-       hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);\r
-       if (hres) {\r
-           FIXME("IStream_Seek failed, %lx\n",hres);\r
-           return hres;\r
-       }\r
-       hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);\r
-       if (hres) {\r
-           FIXME("Stream Read failed, %lx\n",hres);\r
-           return hres;\r
-       }\r
-       IStream_Release(pStm);\r
-       return S_OK;\r
-    }\r
-    FIXME("(%p,%p), stub!\n",msg,chanbuf);\r
-    FIXME("iMethod is %ld\n",msg->iMethod);\r
-    FIXME("cbBuffer is %ld\n",msg->cbBuffer);\r
-    return E_FAIL;\r
-}\r
-\r
-static LPRPCSTUBBUFFER WINAPI\r
-CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {\r
-    FIXME("(%s), stub!\n",debugstr_guid(riid));\r
-    return NULL;\r
-}\r
-\r
-static ULONG WINAPI\r
-CFStub_CountRefs(LPRPCSTUBBUFFER iface) {\r
-    FIXME("(), stub!\n");\r
-    return 1;\r
-}\r
-\r
-static HRESULT WINAPI\r
-CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {\r
-    FIXME("(%p), stub!\n",ppv);\r
-    return E_FAIL;\r
-}\r
-static void    WINAPI\r
-CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {\r
-    FIXME("(%p), stub!\n",pv);\r
-}\r
-\r
-static IRpcStubBufferVtbl cfstubvt = {\r
-    CFStub_QueryInterface,\r
-    CFStub_AddRef,\r
-    CFStub_Release,\r
-    CFStub_Connect,\r
-    CFStub_Disconnect,\r
-    CFStub_Invoke,\r
-    CFStub_IsIIDSupported,\r
-    CFStub_CountRefs,\r
-    CFStub_DebugServerQueryInterface,\r
-    CFStub_DebugServerRelease\r
-};\r
-\r
-static HRESULT\r
-CFStub_Construct(LPRPCSTUBBUFFER *ppv) {\r
-    CFStub *cfstub;\r
-    cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));\r
-    if (!cfstub)\r
-       return E_OUTOFMEMORY;\r
-    *ppv = (LPRPCSTUBBUFFER)cfstub;\r
-    cfstub->lpvtbl     = &cfstubvt;\r
-    cfstub->ref                = 1;\r
-    return S_OK;\r
-}\r
-\r
-/* Since we create proxy buffers and classfactory in a pair, there is\r
- * no need for 2 separate structs. Just put them in one, but remember\r
- * the refcount.\r
- */\r
-typedef struct _CFProxy {\r
-    const IClassFactoryVtbl            *lpvtbl_cf;\r
-    const IRpcProxyBufferVtbl  *lpvtbl_proxy;\r
-    DWORD                              ref;\r
-\r
-    IRpcChannelBuffer                  *chanbuf;\r
-    IUnknown *outer_unknown;\r
-} CFProxy;\r
-\r
-static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {\r
-    *ppv = NULL;\r
-    if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {\r
-       IRpcProxyBuffer_AddRef(iface);\r
-       *ppv = (LPVOID)iface;\r
-       return S_OK;\r
-    }\r
-    FIXME("(%s), no interface.\n",debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);\r
-    return InterlockedIncrement(&This->ref);\r
-}\r
-\r
-static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);\r
-    ULONG ref = InterlockedDecrement(&This->ref);\r
-\r
-    if (!ref) {\r
-       IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;\r
-       HeapFree(GetProcessHeap(),0,This);\r
-    }\r
-    return ref;\r
-}\r
-\r
-static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);\r
-\r
-    This->chanbuf = pRpcChannelBuffer;\r
-    IRpcChannelBuffer_AddRef(This->chanbuf);\r
-    return S_OK;\r
-}\r
-static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);\r
-    if (This->chanbuf) {\r
-       IRpcChannelBuffer_Release(This->chanbuf);\r
-       This->chanbuf = NULL;\r
-    }\r
-}\r
-\r
-static HRESULT WINAPI\r
-CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);\r
-    if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);\r
-    *ppv = NULL;\r
-    if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {\r
-       *ppv = (LPVOID)iface;\r
-       IClassFactory_AddRef(iface);\r
-       return S_OK;\r
-    }\r
-    if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */\r
-       return E_NOINTERFACE;\r
-    FIXME("Unhandled interface: %s\n",debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG   WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);\r
-    if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown);\r
-    return InterlockedIncrement(&This->ref);\r
-}\r
-\r
-static ULONG   WINAPI CFProxy_Release(LPCLASSFACTORY iface) {\r
-    ULONG ref;\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);\r
-    if (This->outer_unknown)\r
-        ref = IUnknown_Release(This->outer_unknown);\r
-    else    \r
-        ref = InterlockedDecrement(&This->ref);\r
-\r
-    if (!ref) {\r
-       if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);\r
-        HeapFree(GetProcessHeap(),0,This);\r
-    }\r
-    return ref;\r
-}\r
-\r
-static HRESULT WINAPI CFProxy_CreateInstance(\r
-    LPCLASSFACTORY iface,\r
-    LPUNKNOWN pUnkOuter,/* [in] */\r
-    REFIID riid,       /* [in] */\r
-    LPVOID *ppv                /* [out] */\r
-) {\r
-    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);\r
-    HRESULT            hres;\r
-    LPSTREAM           pStream;\r
-    HGLOBAL            hGlobal;\r
-    ULONG              srstatus;\r
-    RPCOLEMESSAGE      msg;\r
-\r
-    TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);\r
-\r
-    /* Send CreateInstance to the remote classfactory.\r
-     *\r
-     * Data: Only the 'IID'.\r
-     */\r
-    msg.iMethod  = 3;\r
-    msg.cbBuffer = sizeof(*riid);\r
-    msg.Buffer  = NULL;\r
-    hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);\r
-    if (hres) {\r
-       FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);\r
-       return hres;\r
-    }\r
-    memcpy(msg.Buffer,riid,sizeof(*riid));\r
-    hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);\r
-    if (hres) {\r
-       FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);\r
-       return hres;\r
-    }\r
-\r
-    if (!msg.cbBuffer) /* interface not found on remote */\r
-       return srstatus;\r
-\r
-    /* We got back: [Marshalled Interface data] */\r
-    TRACE("got %ld bytes data.\n",msg.cbBuffer);\r
-    hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);\r
-    memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);\r
-    hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);\r
-    if (hres) {\r
-       FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);\r
-       return hres;\r
-    }\r
-    hres = CoUnmarshalInterface(\r
-           pStream,\r
-           riid,\r
-           ppv\r
-    );\r
-    IStream_Release(pStream); /* Does GlobalFree hGlobal too. */\r
-    if (hres) {\r
-       FIXME("CoMarshalInterface failed, %lx\n",hres);\r
-       return hres;\r
-    }\r
-    return S_OK;\r
-}\r
-\r
-static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {\r
-    /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/\r
-    FIXME("(%d), stub!\n",fLock);\r
-    /* basically: write BOOL, read empty */\r
-    return S_OK;\r
-}\r
-\r
-static IRpcProxyBufferVtbl pspbvtbl = {\r
-    IRpcProxyBufferImpl_QueryInterface,\r
-    IRpcProxyBufferImpl_AddRef,\r
-    IRpcProxyBufferImpl_Release,\r
-    IRpcProxyBufferImpl_Connect,\r
-    IRpcProxyBufferImpl_Disconnect\r
-};\r
-static IClassFactoryVtbl cfproxyvt = {\r
-    CFProxy_QueryInterface,\r
-    CFProxy_AddRef,\r
-    CFProxy_Release,\r
-    CFProxy_CreateInstance,\r
-    CFProxy_LockServer\r
-};\r
-\r
-static HRESULT\r
-CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {\r
-    CFProxy *cf;\r
-\r
-    cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));\r
-    if (!cf)\r
-       return E_OUTOFMEMORY;\r
-\r
-    cf->lpvtbl_cf      = &cfproxyvt;\r
-    cf->lpvtbl_proxy   = &pspbvtbl;\r
-    /* only one reference for the proxy buffer */\r
-    cf->ref            = 1;\r
-    cf->outer_unknown = pUnkOuter;\r
-    *ppv               = &(cf->lpvtbl_cf);\r
-    *ppProxy           = &(cf->lpvtbl_proxy);\r
-    return S_OK;\r
-}\r
-\r
-\r
-/********************* IRemUnknown Proxy/Stub ********************************/\r
-\r
-typedef struct\r
-{\r
-    const IRpcStubBufferVtbl *lpVtbl;\r
-    ULONG refs;\r
-    IRemUnknown *iface;\r
-} RemUnkStub;\r
-\r
-static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface,\r
-                                            REFIID riid,\r
-                                            LPVOID *obj)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);\r
-  if (IsEqualGUID(&IID_IUnknown,riid) ||\r
-      IsEqualGUID(&IID_IRpcStubBuffer,riid)) {\r
-    *obj = This;\r
-    return S_OK;\r
-  }\r
-  return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  TRACE("(%p)->AddRef()\n",This);\r
-  return InterlockedIncrement(&This->refs);\r
-}\r
-\r
-static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  ULONG refs;\r
-  TRACE("(%p)->Release()\n",This);\r
-  refs = InterlockedDecrement(&This->refs);\r
-  if (!refs)\r
-    HeapFree(GetProcessHeap(), 0, This);\r
-  return refs;\r
-}\r
-\r
-static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface,\r
-                                     LPUNKNOWN lpUnkServer)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  TRACE("(%p)->Connect(%p)\n",This,lpUnkServer);\r
-  This->iface = (IRemUnknown*)lpUnkServer;\r
-  IRemUnknown_AddRef(This->iface);\r
-  return S_OK;\r
-}\r
-\r
-static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  TRACE("(%p)->Disconnect()\n",This);\r
-  IUnknown_Release(This->iface);\r
-  This->iface = NULL;\r
-}\r
-\r
-static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface,\r
-                                    PRPCOLEMESSAGE pMsg,\r
-                                    LPRPCCHANNELBUFFER pChannel)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  ULONG iMethod = pMsg->iMethod;\r
-  LPBYTE buf = pMsg->Buffer;\r
-  HRESULT hr = RPC_E_INVALIDMETHOD;\r
-\r
-  TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod);\r
-  switch (iMethod)\r
-  {\r
-  case 3: /* RemQueryInterface */\r
-  {\r
-    IPID ipid;\r
-    ULONG cRefs;\r
-    USHORT cIids;\r
-    IID *iids;\r
-    REMQIRESULT *pQIResults = NULL;\r
-\r
-    /* in */\r
-    memcpy(&ipid, buf, sizeof(ipid));\r
-    buf += sizeof(ipid);\r
-    memcpy(&cRefs, buf, sizeof(cRefs));\r
-    buf += sizeof(cRefs);\r
-    memcpy(&cIids, buf, sizeof(cIids));\r
-    buf += sizeof(cIids);\r
-    iids = (IID *)buf;\r
-\r
-    hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults);\r
-\r
-    /* out */\r
-    pMsg->cbBuffer = cIids * sizeof(REMQIRESULT);\r
-\r
-    I_RpcGetBuffer((RPC_MESSAGE *)pMsg);\r
-    if (hr) return hr;\r
-\r
-    buf = pMsg->Buffer;\r
-    /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */\r
-    memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT));\r
-\r
-    break;\r
-  }\r
-  case 4: /* RemAddRef */\r
-  {\r
-    USHORT cIids;\r
-    REMINTERFACEREF *ir;\r
-    HRESULT *pResults;\r
-\r
-    /* in */\r
-    memcpy(&cIids, buf, sizeof(USHORT));\r
-    buf += sizeof(USHORT);\r
-    ir = (REMINTERFACEREF*)buf;\r
-    pResults = CoTaskMemAlloc(cIids * sizeof(HRESULT));\r
-    if (!pResults) return E_OUTOFMEMORY;\r
-\r
-    hr = IRemUnknown_RemAddRef(This->iface, cIids, ir, pResults);\r
-\r
-    /* out */\r
-    pMsg->cbBuffer = cIids * sizeof(HRESULT);\r
-\r
-    I_RpcGetBuffer((RPC_MESSAGE *)pMsg);\r
-    if (!hr)\r
-    {\r
-        buf = pMsg->Buffer;\r
-        memcpy(buf, pResults, cIids * sizeof(HRESULT));\r
-    }\r
-\r
-    CoTaskMemFree(pResults);\r
-\r
-    break;\r
-  }\r
-  case 5: /* RemRelease */\r
-  {\r
-    USHORT cIids;\r
-    REMINTERFACEREF *ir;\r
-\r
-    /* in */\r
-    memcpy(&cIids, buf, sizeof(USHORT));\r
-    buf += sizeof(USHORT);\r
-    ir = (REMINTERFACEREF*)buf;\r
-\r
-    hr = IRemUnknown_RemRelease(This->iface, cIids, ir);\r
-\r
-    /* out */\r
-    pMsg->cbBuffer = 0;\r
-    break;\r
-  }\r
-  }\r
-  return hr;\r
-}\r
-\r
-static LPRPCSTUBBUFFER WINAPI RemUnkStub_IsIIDSupported(LPRPCSTUBBUFFER iface,\r
-                                                    REFIID riid)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  TRACE("(%p)->IsIIDSupported(%s)\n", This, debugstr_guid(riid));\r
-  return IsEqualGUID(&IID_IRemUnknown, riid) ? iface : NULL;\r
-}\r
-\r
-static ULONG WINAPI RemUnkStub_CountRefs(LPRPCSTUBBUFFER iface)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  FIXME("(%p)->CountRefs()\n", This);\r
-  return 1;\r
-}\r
-\r
-static HRESULT WINAPI RemUnkStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,\r
-                                                       LPVOID *ppv)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  FIXME("(%p)->DebugServerQueryInterface(%p)\n",This,ppv);\r
-  return E_NOINTERFACE;\r
-}\r
-\r
-static void WINAPI RemUnkStub_DebugServerRelease(LPRPCSTUBBUFFER iface,\r
-                                             LPVOID pv)\r
-{\r
-  RemUnkStub *This = (RemUnkStub *)iface;\r
-  FIXME("(%p)->DebugServerRelease(%p)\n", This, pv);\r
-}\r
-\r
-static const IRpcStubBufferVtbl RemUnkStub_VTable =\r
-{\r
-  RemUnkStub_QueryInterface,\r
-  RemUnkStub_AddRef,\r
-  RemUnkStub_Release,\r
-  RemUnkStub_Connect,\r
-  RemUnkStub_Disconnect,\r
-  RemUnkStub_Invoke,\r
-  RemUnkStub_IsIIDSupported,\r
-  RemUnkStub_CountRefs,\r
-  RemUnkStub_DebugServerQueryInterface,\r
-  RemUnkStub_DebugServerRelease\r
-};\r
-\r
-static HRESULT RemUnkStub_Construct(IRpcStubBuffer **ppStub)\r
-{\r
-    RemUnkStub *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));\r
-    if (!This) return E_OUTOFMEMORY;\r
-    This->lpVtbl = &RemUnkStub_VTable;\r
-    This->refs = 0;\r
-    This->iface = NULL;\r
-    *ppStub = (IRpcStubBuffer*)This;\r
-    return S_OK;\r
-}\r
-\r
-\r
-typedef struct _RemUnkProxy {\r
-    const IRemUnknownVtbl              *lpvtbl_remunk;\r
-    const IRpcProxyBufferVtbl  *lpvtbl_proxy;\r
-    DWORD                              refs;\r
-\r
-    IRpcChannelBuffer                  *chan;\r
-    IUnknown *outer_unknown;\r
-} RemUnkProxy;\r
-\r
-static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid, void **ppv)\r
-{\r
-    RemUnkProxy *This = (RemUnkProxy *)iface;\r
-    if (This->outer_unknown)\r
-        return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);\r
-    if (IsEqualIID(riid, &IID_IUnknown) ||\r
-        IsEqualIID(riid, &IID_IRemUnknown))\r
-    {\r
-        IRemUnknown_AddRef(iface);\r
-        *ppv = (LPVOID)iface;\r
-        return S_OK;\r
-    }\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface)\r
-{\r
-  RemUnkProxy *This = (RemUnkProxy *)iface;\r
-\r
-  TRACE("(%p)->AddRef()\n",This);\r
-  return InterlockedIncrement(&This->refs);\r
-}\r
-\r
-static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface)\r
-{\r
-  RemUnkProxy *This = (RemUnkProxy *)iface;\r
-  ULONG refs;\r
-\r
-  TRACE("(%p)->Release()\n",This);\r
-  if (This->outer_unknown)\r
-      refs = IUnknown_Release(This->outer_unknown);\r
-  else    \r
-      refs = InterlockedDecrement(&This->refs);\r
-\r
-  if (!refs) {\r
-      if (This->chan) IRpcChannelBuffer_Release(This->chan);\r
-      HeapFree(GetProcessHeap(),0,This);\r
-  }\r
-  return refs;\r
-}\r
-\r
-static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface,\r
-                                                REFIPID ripid,\r
-                                                ULONG cRefs,\r
-                                                USHORT cIids,\r
-                                                IID* iids,\r
-                                                REMQIRESULT** ppQIResults)\r
-{\r
-  RemUnkProxy *This = (RemUnkProxy *)iface;\r
-  RPCOLEMESSAGE msg;\r
-  HRESULT hr = S_OK;\r
-  ULONG status;\r
-\r
-  TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This,\r
-       debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults);\r
-\r
-  *ppQIResults = NULL;\r
-  memset(&msg, 0, sizeof(msg));\r
-  msg.iMethod = 3;\r
-  msg.cbBuffer = sizeof(IPID) + sizeof(ULONG) +\r
-    sizeof(USHORT) + cIids*sizeof(IID);\r
-  hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);\r
-  if (SUCCEEDED(hr)) {\r
-    LPBYTE buf = msg.Buffer;\r
-    memcpy(buf, ripid, sizeof(IPID));\r
-    buf += sizeof(IPID);\r
-    memcpy(buf, &cRefs, sizeof(ULONG));\r
-    buf += sizeof(ULONG);\r
-    memcpy(buf, &cIids, sizeof(USHORT));\r
-    buf += sizeof(USHORT);\r
-    memcpy(buf, iids, cIids*sizeof(IID));\r
-\r
-    hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);\r
-\r
-    if (SUCCEEDED(hr)) {\r
-      buf = msg.Buffer;\r
-      *ppQIResults = CoTaskMemAlloc(cIids*sizeof(REMQIRESULT));\r
-      memcpy(*ppQIResults, buf, cIids*sizeof(REMQIRESULT));\r
-    }\r
-\r
-    IRpcChannelBuffer_FreeBuffer(This->chan, &msg);\r
-  }\r
-\r
-  return hr;\r
-}\r
-\r
-static HRESULT WINAPI RemUnkProxy_RemAddRef(LPREMUNKNOWN iface,\r
-                                        USHORT cInterfaceRefs,\r
-                                        REMINTERFACEREF* InterfaceRefs,\r
-                                        HRESULT* pResults)\r
-{\r
-  RemUnkProxy *This = (RemUnkProxy *)iface;\r
-  RPCOLEMESSAGE msg;\r
-  HRESULT hr = S_OK;\r
-  ULONG status;\r
-\r
-  TRACE("(%p)->(%d,%p,%p)\n",This,\r
-       cInterfaceRefs,InterfaceRefs,pResults);\r
-\r
-  memset(&msg, 0, sizeof(msg));\r
-  msg.iMethod = 4;\r
-  msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);\r
-  hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);\r
-  if (SUCCEEDED(hr)) {\r
-    LPBYTE buf = msg.Buffer;\r
-    memcpy(buf, &cInterfaceRefs, sizeof(USHORT));\r
-    buf += sizeof(USHORT);\r
-    memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));\r
-\r
-    hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);\r
-\r
-    if (SUCCEEDED(hr)) {\r
-      buf = msg.Buffer;\r
-      memcpy(pResults, buf, cInterfaceRefs*sizeof(HRESULT));\r
-    }\r
-\r
-    IRpcChannelBuffer_FreeBuffer(This->chan, &msg);\r
-  }\r
-\r
-  return hr;\r
-}\r
-\r
-static HRESULT WINAPI RemUnkProxy_RemRelease(LPREMUNKNOWN iface,\r
-                                         USHORT cInterfaceRefs,\r
-                                         REMINTERFACEREF* InterfaceRefs)\r
-{\r
-  RemUnkProxy *This = (RemUnkProxy *)iface;\r
-  RPCOLEMESSAGE msg;\r
-  HRESULT hr = S_OK;\r
-  ULONG status;\r
-\r
-  TRACE("(%p)->(%d,%p)\n",This,\r
-       cInterfaceRefs,InterfaceRefs);\r
-\r
-  memset(&msg, 0, sizeof(msg));\r
-  msg.iMethod = 5;\r
-  msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);\r
-  hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);\r
-  if (SUCCEEDED(hr)) {\r
-    LPBYTE buf = msg.Buffer;\r
-    memcpy(buf, &cInterfaceRefs, sizeof(USHORT));\r
-    buf += sizeof(USHORT);\r
-    memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));\r
-\r
-    hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);\r
-\r
-    IRpcChannelBuffer_FreeBuffer(This->chan, &msg);\r
-  }\r
-\r
-  return hr;\r
-}\r
-\r
-static const IRemUnknownVtbl RemUnkProxy_VTable =\r
-{\r
-  RemUnkProxy_QueryInterface,\r
-  RemUnkProxy_AddRef,\r
-  RemUnkProxy_Release,\r
-  RemUnkProxy_RemQueryInterface,\r
-  RemUnkProxy_RemAddRef,\r
-  RemUnkProxy_RemRelease\r
-};\r
-\r
-\r
-static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {\r
-    *ppv = NULL;\r
-    if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {\r
-       IRpcProxyBuffer_AddRef(iface);\r
-       *ppv = (LPVOID)iface;\r
-       return S_OK;\r
-    }\r
-    FIXME("(%s), no interface.\n",debugstr_guid(riid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {\r
-    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);\r
-    return InterlockedIncrement(&This->refs);\r
-}\r
-\r
-static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {\r
-    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);\r
-    ULONG ref = InterlockedDecrement(&This->refs);\r
-\r
-    if (!ref) {\r
-       IRpcChannelBuffer_Release(This->chan);This->chan = NULL;\r
-       HeapFree(GetProcessHeap(),0,This);\r
-    }\r
-    return ref;\r
-}\r
-\r
-static HRESULT WINAPI RURpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {\r
-    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);\r
-\r
-    This->chan = pRpcChannelBuffer;\r
-    IRpcChannelBuffer_AddRef(This->chan);\r
-    return S_OK;\r
-}\r
-static void WINAPI RURpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {\r
-    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);\r
-    if (This->chan) {\r
-       IRpcChannelBuffer_Release(This->chan);\r
-       This->chan = NULL;\r
-    }\r
-}\r
-\r
-\r
-static const IRpcProxyBufferVtbl RURpcProxyBuffer_VTable = {\r
-    RURpcProxyBufferImpl_QueryInterface,\r
-    RURpcProxyBufferImpl_AddRef,\r
-    RURpcProxyBufferImpl_Release,\r
-    RURpcProxyBufferImpl_Connect,\r
-    RURpcProxyBufferImpl_Disconnect\r
-};\r
-\r
-static HRESULT\r
-RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {\r
-    RemUnkProxy *This;\r
-\r
-    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*This));\r
-    if (!This)\r
-       return E_OUTOFMEMORY;\r
-\r
-    This->lpvtbl_remunk        = &RemUnkProxy_VTable;\r
-    This->lpvtbl_proxy = &RURpcProxyBuffer_VTable;\r
-    /* only one reference for the proxy buffer */\r
-    This->refs         = 1;\r
-    This->outer_unknown = pUnkOuter;\r
-    *ppv               = &(This->lpvtbl_remunk);\r
-    *ppProxy           = &(This->lpvtbl_proxy);\r
-    return S_OK;\r
-}\r
-\r
-\r
-/********************* OLE Proxy/Stub Factory ********************************/\r
-static HRESULT WINAPI\r
-PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {\r
-    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {\r
-       *ppv = (LPVOID)iface;\r
-       /* No ref counting, static class */\r
-       return S_OK;\r
-    }\r
-    FIXME("(%s) unknown IID?\n",debugstr_guid(iid));\r
-    return E_NOINTERFACE;\r
-}\r
-\r
-static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }\r
-static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }\r
-\r
-static HRESULT WINAPI\r
-PSFacBuf_CreateProxy(\r
-    LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,\r
-    IRpcProxyBuffer **ppProxy, LPVOID *ppv\r
-) {\r
-    if (IsEqualIID(&IID_IClassFactory,riid))\r
-       return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);\r
-    else if (IsEqualIID(&IID_IRemUnknown,riid))\r
-       return RemUnkProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);\r
-    FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid));\r
-    return E_FAIL;\r
-}\r
-\r
-static HRESULT WINAPI\r
-PSFacBuf_CreateStub(\r
-    LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,\r
-    IRpcStubBuffer** ppStub\r
-) {\r
-    HRESULT hres;\r
-\r
-    TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);\r
-\r
-    if (IsEqualIID(&IID_IClassFactory, riid) ||\r
-        IsEqualIID(&IID_IUnknown, riid) /* FIXME: fixup stub manager and remove this*/) {\r
-       hres = CFStub_Construct(ppStub);\r
-       if (!hres)\r
-           IRpcStubBuffer_Connect((*ppStub),pUnkServer);\r
-       return hres;\r
-    } else if (IsEqualIID(&IID_IRemUnknown,riid)) {\r
-       hres = RemUnkStub_Construct(ppStub);\r
-       if (!hres)\r
-           IRpcStubBuffer_Connect((*ppStub),pUnkServer);\r
-       return hres;\r
-    }\r
-    FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));\r
-    return E_FAIL;\r
-}\r
-\r
-static IPSFactoryBufferVtbl psfacbufvtbl = {\r
-    PSFacBuf_QueryInterface,\r
-    PSFacBuf_AddRef,\r
-    PSFacBuf_Release,\r
-    PSFacBuf_CreateProxy,\r
-    PSFacBuf_CreateStub\r
-};\r
-\r
-/* This is the whole PSFactoryBuffer object, just the vtableptr */\r
-static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;\r
-\r
-/***********************************************************************\r
- *           DllGetClassObject [OLE32.@]\r
- */\r
-HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)\r
-{\r
-    *ppv = NULL;\r
-    if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer))\r
-        return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv);\r
-    if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&(\r
-               IsEqualIID(iid,&IID_IClassFactory) ||\r
-               IsEqualIID(iid,&IID_IUnknown)\r
-       )\r
-    )\r
-       return MARSHAL_GetStandardMarshalCF(ppv);\r
-    if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown)))\r
-        return StdGlobalInterfaceTable_GetFactory(ppv);\r
-    if (IsEqualCLSID(rclsid, &CLSID_FileMoniker))\r
-        return FileMonikerCF_Create(iid, ppv);\r
-    if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker))\r
-        return ItemMonikerCF_Create(iid, ppv);\r
-\r
-    FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));\r
-    return CLASS_E_CLASSNOTAVAILABLE;\r
-}\r
+/*
+ *     OLE32 proxy/stub handler
+ *
+ *  Copyright 2002  Marcus Meissner
+ *  Copyright 2001  Ove Kåven, TransGaming Technologies
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+/* Documentation on MSDN:
+ *
+ * (Top level COM documentation)
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/componentdevelopmentank.asp
+ *
+ * (COM Proxy)
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1q0p.asp
+ *
+ * (COM Stub)
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1lia.asp
+ *
+ * (Marshal)
+ * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1gfn.asp
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+
+#define COBJMACROS
+#define NONAMELESSUNION
+#define NONAMELESSSTRUCT
+
+#include "windef.h"
+#include "winbase.h"
+#include "winuser.h"
+#include "objbase.h"
+#include "ole2.h"
+#include "rpc.h"
+#include "winerror.h"
+#include "winreg.h"
+#include "wtypes.h"
+
+#include "compobj_private.h"
+#include "moniker.h"
+
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(ole);
+
+const CLSID CLSID_DfMarshal       = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
+const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
+
+/* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp
+ *
+ * The first time a client requests a pointer to an interface on a
+ * particular object, COM loads an IClassFactory stub in the server
+ * process and uses it to marshal the first pointer back to the
+ * client. In the client process, COM loads the generic proxy for the
+ * class factory object and calls its implementation of IMarshal to
+ * unmarshal that first pointer. COM then creates the first interface
+ * proxy and hands it a pointer to the RPC channel. Finally, COM returns
+ * the IClassFactory pointer to the client, which uses it to call
+ * IClassFactory::CreateInstance, passing it a reference to the interface.
+ *
+ * Back in the server process, COM now creates a new instance of the
+ * object, along with a stub for the requested interface. This stub marshals
+ * the interface pointer back to the client process, where another object
+ * proxy is created, this time for the object itself. Also created is a
+ * proxy for the requested interface, a pointer to which is returned to
+ * the client. With subsequent calls to other interfaces on the object,
+ * COM will load the appropriate interface stubs and proxies as needed.
+ */
+typedef struct _CFStub {
+    IRpcStubBufferVtbl *lpvtbl;
+    DWORD                      ref;
+
+    LPUNKNOWN                  pUnkServer;
+} CFStub;
+
+static HRESULT WINAPI
+CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
+    if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {
+       *ppv = (LPVOID)iface;
+       IUnknown_AddRef(iface);
+       return S_OK;
+    }
+    FIXME("(%s), interface not supported.\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI
+CFStub_AddRef(LPRPCSTUBBUFFER iface) {
+    CFStub *This = (CFStub *)iface;
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI
+CFStub_Release(LPRPCSTUBBUFFER iface) {
+    CFStub *This = (CFStub *)iface;
+    ULONG ref;
+
+    ref = InterlockedDecrement(&This->ref);
+    if (!ref) HeapFree(GetProcessHeap(),0,This);
+    return ref;
+}
+
+static HRESULT WINAPI
+CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
+    CFStub *This = (CFStub *)iface;
+
+    This->pUnkServer = pUnkServer;
+    IUnknown_AddRef(pUnkServer);
+    return S_OK;
+}
+
+static void WINAPI
+CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
+    CFStub *This = (CFStub *)iface;
+
+    IUnknown_Release(This->pUnkServer);
+    This->pUnkServer = NULL;
+}
+static HRESULT WINAPI
+CFStub_Invoke(
+    LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
+) {
+    CFStub *This = (CFStub *)iface;
+    HRESULT hres;
+
+    if (msg->iMethod == 3) { /* CreateInstance */
+       IID iid;
+       IClassFactory   *classfac;
+       IUnknown        *ppv;
+       IStream         *pStm;
+       STATSTG         ststg;
+       ULARGE_INTEGER  newpos;
+       LARGE_INTEGER   seekto;
+       ULONG           res;
+
+       if (msg->cbBuffer < sizeof(IID)) {
+           FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
+           return E_FAIL;
+       }
+       memcpy(&iid,msg->Buffer,sizeof(iid));
+       TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));
+       hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);
+       if (hres) {
+           FIXME("Ole server does not provide an IClassFactory?\n");
+           return hres;
+       }
+       hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
+       IClassFactory_Release(classfac);
+       if (hres) {
+           msg->cbBuffer = 0;
+           FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
+           return hres;
+       }
+       hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
+       if (hres) {
+           FIXME("Failed to create stream on hglobal\n");
+           return hres;
+       }
+       hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
+       IUnknown_Release((IUnknown*)ppv);
+       if (hres) {
+           FIXME("CoMarshalInterface failed, %lx!\n",hres);
+           msg->cbBuffer = 0;
+           return hres;
+       }
+       hres = IStream_Stat(pStm,&ststg,0);
+       if (hres) {
+           FIXME("Stat failed.\n");
+           return hres;
+       }
+
+       msg->cbBuffer = ststg.cbSize.u.LowPart;
+
+        I_RpcGetBuffer((RPC_MESSAGE *)msg);
+        if (hres) return hres;
+
+       seekto.u.LowPart = 0;seekto.u.HighPart = 0;
+       hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
+       if (hres) {
+           FIXME("IStream_Seek failed, %lx\n",hres);
+           return hres;
+       }
+       hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
+       if (hres) {
+           FIXME("Stream Read failed, %lx\n",hres);
+           return hres;
+       }
+       IStream_Release(pStm);
+       return S_OK;
+    }
+    FIXME("(%p,%p), stub!\n",msg,chanbuf);
+    FIXME("iMethod is %ld\n",msg->iMethod);
+    FIXME("cbBuffer is %ld\n",msg->cbBuffer);
+    return E_FAIL;
+}
+
+static LPRPCSTUBBUFFER WINAPI
+CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
+    FIXME("(%s), stub!\n",debugstr_guid(riid));
+    return NULL;
+}
+
+static ULONG WINAPI
+CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
+    FIXME("(), stub!\n");
+    return 1;
+}
+
+static HRESULT WINAPI
+CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
+    FIXME("(%p), stub!\n",ppv);
+    return E_FAIL;
+}
+static void    WINAPI
+CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
+    FIXME("(%p), stub!\n",pv);
+}
+
+static IRpcStubBufferVtbl cfstubvt = {
+    CFStub_QueryInterface,
+    CFStub_AddRef,
+    CFStub_Release,
+    CFStub_Connect,
+    CFStub_Disconnect,
+    CFStub_Invoke,
+    CFStub_IsIIDSupported,
+    CFStub_CountRefs,
+    CFStub_DebugServerQueryInterface,
+    CFStub_DebugServerRelease
+};
+
+static HRESULT
+CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
+    CFStub *cfstub;
+    cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
+    if (!cfstub)
+       return E_OUTOFMEMORY;
+    *ppv = (LPRPCSTUBBUFFER)cfstub;
+    cfstub->lpvtbl     = &cfstubvt;
+    cfstub->ref                = 1;
+    return S_OK;
+}
+
+/* Since we create proxy buffers and classfactory in a pair, there is
+ * no need for 2 separate structs. Just put them in one, but remember
+ * the refcount.
+ */
+typedef struct _CFProxy {
+    const IClassFactoryVtbl            *lpvtbl_cf;
+    const IRpcProxyBufferVtbl  *lpvtbl_proxy;
+    DWORD                              ref;
+
+    IRpcChannelBuffer                  *chanbuf;
+    IUnknown *outer_unknown;
+} CFProxy;
+
+static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
+    *ppv = NULL;
+    if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
+       IRpcProxyBuffer_AddRef(iface);
+       *ppv = (LPVOID)iface;
+       return S_OK;
+    }
+    FIXME("(%s), no interface.\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
+    ULONG ref = InterlockedDecrement(&This->ref);
+
+    if (!ref) {
+       IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;
+       HeapFree(GetProcessHeap(),0,This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
+
+    This->chanbuf = pRpcChannelBuffer;
+    IRpcChannelBuffer_AddRef(This->chanbuf);
+    return S_OK;
+}
+static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
+    if (This->chanbuf) {
+       IRpcChannelBuffer_Release(This->chanbuf);
+       This->chanbuf = NULL;
+    }
+}
+
+static HRESULT WINAPI
+CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
+    if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
+    *ppv = NULL;
+    if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
+       *ppv = (LPVOID)iface;
+       IClassFactory_AddRef(iface);
+       return S_OK;
+    }
+    if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */
+       return E_NOINTERFACE;
+    FIXME("Unhandled interface: %s\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG   WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
+    if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown);
+    return InterlockedIncrement(&This->ref);
+}
+
+static ULONG   WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
+    ULONG ref;
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
+    if (This->outer_unknown)
+        ref = IUnknown_Release(This->outer_unknown);
+    else    
+        ref = InterlockedDecrement(&This->ref);
+
+    if (!ref) {
+       if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
+        HeapFree(GetProcessHeap(),0,This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI CFProxy_CreateInstance(
+    LPCLASSFACTORY iface,
+    LPUNKNOWN pUnkOuter,/* [in] */
+    REFIID riid,       /* [in] */
+    LPVOID *ppv                /* [out] */
+) {
+    ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
+    HRESULT            hres;
+    LPSTREAM           pStream;
+    HGLOBAL            hGlobal;
+    ULONG              srstatus;
+    RPCOLEMESSAGE      msg;
+
+    TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
+
+    /* Send CreateInstance to the remote classfactory.
+     *
+     * Data: Only the 'IID'.
+     */
+    msg.iMethod  = 3;
+    msg.cbBuffer = sizeof(*riid);
+    msg.Buffer  = NULL;
+    hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
+    if (hres) {
+       FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
+       return hres;
+    }
+    memcpy(msg.Buffer,riid,sizeof(*riid));
+    hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
+    if (hres) {
+       FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
+       return hres;
+    }
+
+    if (!msg.cbBuffer) /* interface not found on remote */
+       return srstatus;
+
+    /* We got back: [Marshalled Interface data] */
+    TRACE("got %ld bytes data.\n",msg.cbBuffer);
+    hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);
+    memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);
+    hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
+    if (hres) {
+       FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
+       return hres;
+    }
+    hres = CoUnmarshalInterface(
+           pStream,
+           riid,
+           ppv
+    );
+    IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
+    if (hres) {
+       FIXME("CoMarshalInterface failed, %lx\n",hres);
+       return hres;
+    }
+    return S_OK;
+}
+
+static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {
+    /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/
+    FIXME("(%d), stub!\n",fLock);
+    /* basically: write BOOL, read empty */
+    return S_OK;
+}
+
+static IRpcProxyBufferVtbl pspbvtbl = {
+    IRpcProxyBufferImpl_QueryInterface,
+    IRpcProxyBufferImpl_AddRef,
+    IRpcProxyBufferImpl_Release,
+    IRpcProxyBufferImpl_Connect,
+    IRpcProxyBufferImpl_Disconnect
+};
+static IClassFactoryVtbl cfproxyvt = {
+    CFProxy_QueryInterface,
+    CFProxy_AddRef,
+    CFProxy_Release,
+    CFProxy_CreateInstance,
+    CFProxy_LockServer
+};
+
+static HRESULT
+CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
+    CFProxy *cf;
+
+    cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
+    if (!cf)
+       return E_OUTOFMEMORY;
+
+    cf->lpvtbl_cf      = &cfproxyvt;
+    cf->lpvtbl_proxy   = &pspbvtbl;
+    /* only one reference for the proxy buffer */
+    cf->ref            = 1;
+    cf->outer_unknown = pUnkOuter;
+    *ppv               = &(cf->lpvtbl_cf);
+    *ppProxy           = &(cf->lpvtbl_proxy);
+    return S_OK;
+}
+
+
+/********************* IRemUnknown Proxy/Stub ********************************/
+
+typedef struct
+{
+    const IRpcStubBufferVtbl *lpVtbl;
+    ULONG refs;
+    IRemUnknown *iface;
+} RemUnkStub;
+
+static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface,
+                                            REFIID riid,
+                                            LPVOID *obj)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);
+  if (IsEqualGUID(&IID_IUnknown,riid) ||
+      IsEqualGUID(&IID_IRpcStubBuffer,riid)) {
+    *obj = This;
+    return S_OK;
+  }
+  return E_NOINTERFACE;
+}
+
+static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  TRACE("(%p)->AddRef()\n",This);
+  return InterlockedIncrement(&This->refs);
+}
+
+static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  ULONG refs;
+  TRACE("(%p)->Release()\n",This);
+  refs = InterlockedDecrement(&This->refs);
+  if (!refs)
+    HeapFree(GetProcessHeap(), 0, This);
+  return refs;
+}
+
+static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface,
+                                     LPUNKNOWN lpUnkServer)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  TRACE("(%p)->Connect(%p)\n",This,lpUnkServer);
+  This->iface = (IRemUnknown*)lpUnkServer;
+  IRemUnknown_AddRef(This->iface);
+  return S_OK;
+}
+
+static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  TRACE("(%p)->Disconnect()\n",This);
+  IUnknown_Release(This->iface);
+  This->iface = NULL;
+}
+
+static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface,
+                                    PRPCOLEMESSAGE pMsg,
+                                    LPRPCCHANNELBUFFER pChannel)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  ULONG iMethod = pMsg->iMethod;
+  LPBYTE buf = pMsg->Buffer;
+  HRESULT hr = RPC_E_INVALIDMETHOD;
+
+  TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod);
+  switch (iMethod)
+  {
+  case 3: /* RemQueryInterface */
+  {
+    IPID ipid;
+    ULONG cRefs;
+    USHORT cIids;
+    IID *iids;
+    REMQIRESULT *pQIResults = NULL;
+
+    /* in */
+    memcpy(&ipid, buf, sizeof(ipid));
+    buf += sizeof(ipid);
+    memcpy(&cRefs, buf, sizeof(cRefs));
+    buf += sizeof(cRefs);
+    memcpy(&cIids, buf, sizeof(cIids));
+    buf += sizeof(cIids);
+    iids = (IID *)buf;
+
+    hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults);
+
+    /* out */
+    pMsg->cbBuffer = cIids * sizeof(REMQIRESULT);
+
+    I_RpcGetBuffer((RPC_MESSAGE *)pMsg);
+    if (hr) return hr;
+
+    buf = pMsg->Buffer;
+    /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */
+    memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT));
+
+    break;
+  }
+  case 4: /* RemAddRef */
+  {
+    USHORT cIids;
+    REMINTERFACEREF *ir;
+    HRESULT *pResults;
+
+    /* in */
+    memcpy(&cIids, buf, sizeof(USHORT));
+    buf += sizeof(USHORT);
+    ir = (REMINTERFACEREF*)buf;
+    pResults = CoTaskMemAlloc(cIids * sizeof(HRESULT));
+    if (!pResults) return E_OUTOFMEMORY;
+
+    hr = IRemUnknown_RemAddRef(This->iface, cIids, ir, pResults);
+
+    /* out */
+    pMsg->cbBuffer = cIids * sizeof(HRESULT);
+
+    I_RpcGetBuffer((RPC_MESSAGE *)pMsg);
+    if (!hr)
+    {
+        buf = pMsg->Buffer;
+        memcpy(buf, pResults, cIids * sizeof(HRESULT));
+    }
+
+    CoTaskMemFree(pResults);
+
+    break;
+  }
+  case 5: /* RemRelease */
+  {
+    USHORT cIids;
+    REMINTERFACEREF *ir;
+
+    /* in */
+    memcpy(&cIids, buf, sizeof(USHORT));
+    buf += sizeof(USHORT);
+    ir = (REMINTERFACEREF*)buf;
+
+    hr = IRemUnknown_RemRelease(This->iface, cIids, ir);
+
+    /* out */
+    pMsg->cbBuffer = 0;
+    break;
+  }
+  }
+  return hr;
+}
+
+static LPRPCSTUBBUFFER WINAPI RemUnkStub_IsIIDSupported(LPRPCSTUBBUFFER iface,
+                                                    REFIID riid)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  TRACE("(%p)->IsIIDSupported(%s)\n", This, debugstr_guid(riid));
+  return IsEqualGUID(&IID_IRemUnknown, riid) ? iface : NULL;
+}
+
+static ULONG WINAPI RemUnkStub_CountRefs(LPRPCSTUBBUFFER iface)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  FIXME("(%p)->CountRefs()\n", This);
+  return 1;
+}
+
+static HRESULT WINAPI RemUnkStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,
+                                                       LPVOID *ppv)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  FIXME("(%p)->DebugServerQueryInterface(%p)\n",This,ppv);
+  return E_NOINTERFACE;
+}
+
+static void WINAPI RemUnkStub_DebugServerRelease(LPRPCSTUBBUFFER iface,
+                                             LPVOID pv)
+{
+  RemUnkStub *This = (RemUnkStub *)iface;
+  FIXME("(%p)->DebugServerRelease(%p)\n", This, pv);
+}
+
+static const IRpcStubBufferVtbl RemUnkStub_VTable =
+{
+  RemUnkStub_QueryInterface,
+  RemUnkStub_AddRef,
+  RemUnkStub_Release,
+  RemUnkStub_Connect,
+  RemUnkStub_Disconnect,
+  RemUnkStub_Invoke,
+  RemUnkStub_IsIIDSupported,
+  RemUnkStub_CountRefs,
+  RemUnkStub_DebugServerQueryInterface,
+  RemUnkStub_DebugServerRelease
+};
+
+static HRESULT RemUnkStub_Construct(IRpcStubBuffer **ppStub)
+{
+    RemUnkStub *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
+    if (!This) return E_OUTOFMEMORY;
+    This->lpVtbl = &RemUnkStub_VTable;
+    This->refs = 0;
+    This->iface = NULL;
+    *ppStub = (IRpcStubBuffer*)This;
+    return S_OK;
+}
+
+
+typedef struct _RemUnkProxy {
+    const IRemUnknownVtbl              *lpvtbl_remunk;
+    const IRpcProxyBufferVtbl  *lpvtbl_proxy;
+    DWORD                              refs;
+
+    IRpcChannelBuffer                  *chan;
+    IUnknown *outer_unknown;
+} RemUnkProxy;
+
+static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid, void **ppv)
+{
+    RemUnkProxy *This = (RemUnkProxy *)iface;
+    if (This->outer_unknown)
+        return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
+    if (IsEqualIID(riid, &IID_IUnknown) ||
+        IsEqualIID(riid, &IID_IRemUnknown))
+    {
+        IRemUnknown_AddRef(iface);
+        *ppv = (LPVOID)iface;
+        return S_OK;
+    }
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface)
+{
+  RemUnkProxy *This = (RemUnkProxy *)iface;
+
+  TRACE("(%p)->AddRef()\n",This);
+  return InterlockedIncrement(&This->refs);
+}
+
+static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface)
+{
+  RemUnkProxy *This = (RemUnkProxy *)iface;
+  ULONG refs;
+
+  TRACE("(%p)->Release()\n",This);
+  if (This->outer_unknown)
+      refs = IUnknown_Release(This->outer_unknown);
+  else    
+      refs = InterlockedDecrement(&This->refs);
+
+  if (!refs) {
+      if (This->chan) IRpcChannelBuffer_Release(This->chan);
+      HeapFree(GetProcessHeap(),0,This);
+  }
+  return refs;
+}
+
+static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface,
+                                                REFIPID ripid,
+                                                ULONG cRefs,
+                                                USHORT cIids,
+                                                IID* iids,
+                                                REMQIRESULT** ppQIResults)
+{
+  RemUnkProxy *This = (RemUnkProxy *)iface;
+  RPCOLEMESSAGE msg;
+  HRESULT hr = S_OK;
+  ULONG status;
+
+  TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This,
+       debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults);
+
+  *ppQIResults = NULL;
+  memset(&msg, 0, sizeof(msg));
+  msg.iMethod = 3;
+  msg.cbBuffer = sizeof(IPID) + sizeof(ULONG) +
+    sizeof(USHORT) + cIids*sizeof(IID);
+  hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
+  if (SUCCEEDED(hr)) {
+    LPBYTE buf = msg.Buffer;
+    memcpy(buf, ripid, sizeof(IPID));
+    buf += sizeof(IPID);
+    memcpy(buf, &cRefs, sizeof(ULONG));
+    buf += sizeof(ULONG);
+    memcpy(buf, &cIids, sizeof(USHORT));
+    buf += sizeof(USHORT);
+    memcpy(buf, iids, cIids*sizeof(IID));
+
+    hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
+
+    if (SUCCEEDED(hr)) {
+      buf = msg.Buffer;
+      *ppQIResults = CoTaskMemAlloc(cIids*sizeof(REMQIRESULT));
+      memcpy(*ppQIResults, buf, cIids*sizeof(REMQIRESULT));
+    }
+
+    IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
+  }
+
+  return hr;
+}
+
+static HRESULT WINAPI RemUnkProxy_RemAddRef(LPREMUNKNOWN iface,
+                                        USHORT cInterfaceRefs,
+                                        REMINTERFACEREF* InterfaceRefs,
+                                        HRESULT* pResults)
+{
+  RemUnkProxy *This = (RemUnkProxy *)iface;
+  RPCOLEMESSAGE msg;
+  HRESULT hr = S_OK;
+  ULONG status;
+
+  TRACE("(%p)->(%d,%p,%p)\n",This,
+       cInterfaceRefs,InterfaceRefs,pResults);
+
+  memset(&msg, 0, sizeof(msg));
+  msg.iMethod = 4;
+  msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);
+  hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
+  if (SUCCEEDED(hr)) {
+    LPBYTE buf = msg.Buffer;
+    memcpy(buf, &cInterfaceRefs, sizeof(USHORT));
+    buf += sizeof(USHORT);
+    memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));
+
+    hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
+
+    if (SUCCEEDED(hr)) {
+      buf = msg.Buffer;
+      memcpy(pResults, buf, cInterfaceRefs*sizeof(HRESULT));
+    }
+
+    IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
+  }
+
+  return hr;
+}
+
+static HRESULT WINAPI RemUnkProxy_RemRelease(LPREMUNKNOWN iface,
+                                         USHORT cInterfaceRefs,
+                                         REMINTERFACEREF* InterfaceRefs)
+{
+  RemUnkProxy *This = (RemUnkProxy *)iface;
+  RPCOLEMESSAGE msg;
+  HRESULT hr = S_OK;
+  ULONG status;
+
+  TRACE("(%p)->(%d,%p)\n",This,
+       cInterfaceRefs,InterfaceRefs);
+
+  memset(&msg, 0, sizeof(msg));
+  msg.iMethod = 5;
+  msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);
+  hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
+  if (SUCCEEDED(hr)) {
+    LPBYTE buf = msg.Buffer;
+    memcpy(buf, &cInterfaceRefs, sizeof(USHORT));
+    buf += sizeof(USHORT);
+    memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));
+
+    hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
+
+    IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
+  }
+
+  return hr;
+}
+
+static const IRemUnknownVtbl RemUnkProxy_VTable =
+{
+  RemUnkProxy_QueryInterface,
+  RemUnkProxy_AddRef,
+  RemUnkProxy_Release,
+  RemUnkProxy_RemQueryInterface,
+  RemUnkProxy_RemAddRef,
+  RemUnkProxy_RemRelease
+};
+
+
+static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
+    *ppv = NULL;
+    if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
+       IRpcProxyBuffer_AddRef(iface);
+       *ppv = (LPVOID)iface;
+       return S_OK;
+    }
+    FIXME("(%s), no interface.\n",debugstr_guid(riid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
+    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
+    return InterlockedIncrement(&This->refs);
+}
+
+static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
+    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
+    ULONG ref = InterlockedDecrement(&This->refs);
+
+    if (!ref) {
+       IRpcChannelBuffer_Release(This->chan);This->chan = NULL;
+       HeapFree(GetProcessHeap(),0,This);
+    }
+    return ref;
+}
+
+static HRESULT WINAPI RURpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
+    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
+
+    This->chan = pRpcChannelBuffer;
+    IRpcChannelBuffer_AddRef(This->chan);
+    return S_OK;
+}
+static void WINAPI RURpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
+    ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
+    if (This->chan) {
+       IRpcChannelBuffer_Release(This->chan);
+       This->chan = NULL;
+    }
+}
+
+
+static const IRpcProxyBufferVtbl RURpcProxyBuffer_VTable = {
+    RURpcProxyBufferImpl_QueryInterface,
+    RURpcProxyBufferImpl_AddRef,
+    RURpcProxyBufferImpl_Release,
+    RURpcProxyBufferImpl_Connect,
+    RURpcProxyBufferImpl_Disconnect
+};
+
+static HRESULT
+RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
+    RemUnkProxy *This;
+
+    This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*This));
+    if (!This)
+       return E_OUTOFMEMORY;
+
+    This->lpvtbl_remunk        = &RemUnkProxy_VTable;
+    This->lpvtbl_proxy = &RURpcProxyBuffer_VTable;
+    /* only one reference for the proxy buffer */
+    This->refs         = 1;
+    This->outer_unknown = pUnkOuter;
+    *ppv               = &(This->lpvtbl_remunk);
+    *ppProxy           = &(This->lpvtbl_proxy);
+    return S_OK;
+}
+
+
+/********************* OLE Proxy/Stub Factory ********************************/
+static HRESULT WINAPI
+PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
+    if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
+       *ppv = (LPVOID)iface;
+       /* No ref counting, static class */
+       return S_OK;
+    }
+    FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
+    return E_NOINTERFACE;
+}
+
+static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
+static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
+
+static HRESULT WINAPI
+PSFacBuf_CreateProxy(
+    LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
+    IRpcProxyBuffer **ppProxy, LPVOID *ppv
+) {
+    if (IsEqualIID(&IID_IClassFactory,riid))
+       return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);
+    else if (IsEqualIID(&IID_IRemUnknown,riid))
+       return RemUnkProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);
+    FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid));
+    return E_FAIL;
+}
+
+static HRESULT WINAPI
+PSFacBuf_CreateStub(
+    LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
+    IRpcStubBuffer** ppStub
+) {
+    HRESULT hres;
+
+    TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
+
+    if (IsEqualIID(&IID_IClassFactory, riid) ||
+        IsEqualIID(&IID_IUnknown, riid) /* FIXME: fixup stub manager and remove this*/) {
+       hres = CFStub_Construct(ppStub);
+       if (!hres)
+           IRpcStubBuffer_Connect((*ppStub),pUnkServer);
+       return hres;
+    } else if (IsEqualIID(&IID_IRemUnknown,riid)) {
+       hres = RemUnkStub_Construct(ppStub);
+       if (!hres)
+           IRpcStubBuffer_Connect((*ppStub),pUnkServer);
+       return hres;
+    }
+    FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));
+    return E_FAIL;
+}
+
+static IPSFactoryBufferVtbl psfacbufvtbl = {
+    PSFacBuf_QueryInterface,
+    PSFacBuf_AddRef,
+    PSFacBuf_Release,
+    PSFacBuf_CreateProxy,
+    PSFacBuf_CreateStub
+};
+
+/* This is the whole PSFactoryBuffer object, just the vtableptr */
+static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
+
+/***********************************************************************
+ *           DllGetClassObject [OLE32.@]
+ */
+HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
+{
+    *ppv = NULL;
+    if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer))
+        return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv);
+    if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&(
+               IsEqualIID(iid,&IID_IClassFactory) ||
+               IsEqualIID(iid,&IID_IUnknown)
+       )
+    )
+       return MARSHAL_GetStandardMarshalCF(ppv);
+    if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown)))
+        return StdGlobalInterfaceTable_GetFactory(ppv);
+    if (IsEqualCLSID(rclsid, &CLSID_FileMoniker))
+        return FileMonikerCF_Create(iid, ppv);
+    if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker))
+        return ItemMonikerCF_Create(iid, ppv);
+
+    FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
+    return CLASS_E_CLASSNOTAVAILABLE;
+}