-/*\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;
+}