2 * OLE32 proxy/stub handler
4 * Copyright 2002 Marcus Meissner
7 /* Documentation on MSDN:
10 * http://msdn.microsoft.com/library/en-us/com/comext_1q0p.asp
13 * http://msdn.microsoft.com/library/en-us/com/comext_1lia.asp
16 * http://msdn.microsoft.com/library/en-us/com/comext_1gfn.asp
33 #include "wine/obj_base.h"
34 #include "wine/obj_marshal.h"
35 #include "wine/obj_channel.h"
37 #include "compobj_private.h"
39 #include "debugtools.h"
41 DEFAULT_DEBUG_CHANNEL(ole);
43 /* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp
45 * The first time a client requests a pointer to an interface on a
46 * particular object, COM loads an IClassFactory stub in the server
47 * process and uses it to marshal the first pointer back to the
48 * client. In the client process, COM loads the generic proxy for the
49 * class factory object and calls its implementation of IMarshal to
50 * unmarshal that first pointer. COM then creates the first interface
51 * proxy and hands it a pointer to the RPC channel. Finally, COM returns
52 * the IClassFactory pointer to the client, which uses it to call
53 * IClassFactory::CreateInstance, passing it a reference to the interface.
55 * Back in the server process, COM now creates a new instance of the
56 * object, along with a stub for the requested interface. This stub marshals
57 * the interface pointer back to the client process, where another object
58 * proxy is created, this time for the object itself. Also created is a
59 * proxy for the requested interface, a pointer to which is returned to
60 * the client. With subsequent calls to other interfaces on the object,
61 * COM will load the appropriate interface stubs and proxies as needed.
63 typedef struct _CFStub {
64 ICOM_VTABLE(IRpcStubBuffer) *lpvtbl;
71 CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
72 if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {
74 IUnknown_AddRef(iface);
77 FIXME("(%s), interface not supported.\n",debugstr_guid(riid));
82 CFStub_AddRef(LPRPCSTUBBUFFER iface) {
83 ICOM_THIS(CFStub,iface);
90 CFStub_Release(LPRPCSTUBBUFFER iface) {
91 ICOM_THIS(CFStub,iface);
96 HeapFree(GetProcessHeap(),0,This);
100 static HRESULT WINAPI
101 CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
102 ICOM_THIS(CFStub,iface);
104 This->pUnkServer = pUnkServer;
105 IUnknown_AddRef(pUnkServer);
110 CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
111 ICOM_THIS(CFStub,iface);
113 IUnknown_Release(This->pUnkServer);
114 This->pUnkServer = NULL;
116 static HRESULT WINAPI
118 LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
120 ICOM_THIS(CFStub,iface);
123 if (msg->iMethod == 3) { /* CreateInstance */
125 IClassFactory *classfac;
129 ULARGE_INTEGER newpos;
130 LARGE_INTEGER seekto;
133 if (msg->cbBuffer < sizeof(IID)) {
134 FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
137 memcpy(&iid,msg->Buffer,sizeof(iid));
138 TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));
139 hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);
141 FIXME("Ole server does not provide a IClassFactory?\n");
144 hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
145 IClassFactory_Release(classfac);
148 FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
151 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
153 FIXME("Failed to create stream on hglobal\n");
156 hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
158 FIXME("CoMarshalInterface failed, %lx!\n",hres);
162 hres = IStream_Stat(pStm,&ststg,0);
164 FIXME("Stat failed.\n");
168 msg->cbBuffer = ststg.cbSize.s.LowPart;
169 msg->Buffer = HeapReAlloc(GetProcessHeap(),0,msg->Buffer,ststg.cbSize.s.LowPart);
170 seekto.s.LowPart = 0;seekto.s.HighPart = 0;
171 hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
173 FIXME("IStream_Seek failed, %lx\n",hres);
176 hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
178 FIXME("Stream Read failed, %lx\n",hres);
181 IStream_Release(pStm);
184 FIXME("(%p,%p), stub!\n",msg,chanbuf);
185 FIXME("iMethod is %ld\n",msg->iMethod);
186 FIXME("cbBuffer is %ld\n",msg->cbBuffer);
190 static LPRPCSTUBBUFFER WINAPI
191 CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
192 FIXME("(%s), stub!\n",debugstr_guid(riid));
197 CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
198 FIXME("(), stub!\n");
202 static HRESULT WINAPI
203 CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
204 FIXME("(%p), stub!\n",ppv);
208 CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
209 FIXME("(%p), stub!\n",pv);
212 static ICOM_VTABLE(IRpcStubBuffer) cfstubvt = {
213 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
214 CFStub_QueryInterface,
220 CFStub_IsIIDSupported,
222 CFStub_DebugServerQueryInterface,
223 CFStub_DebugServerRelease
227 CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
229 cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
231 return E_OUTOFMEMORY;
232 *ppv = (LPRPCSTUBBUFFER)cfstub;
233 cfstub->lpvtbl = &cfstubvt;
238 /* Since we create proxy buffers and classfactory in a pair, there is
239 * no need for 2 seperate structs. Just put them in one, but remember
242 typedef struct _CFProxy {
243 ICOM_VTABLE(IClassFactory) *lpvtbl_cf;
244 ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl_proxy;
247 IRpcChannelBuffer *chanbuf;
250 static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
252 if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
253 IRpcProxyBuffer_AddRef(iface);
254 *ppv = (LPVOID)iface;
257 FIXME("(%s), no interface.\n",debugstr_guid(riid));
258 return E_NOINTERFACE;
261 static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
262 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
263 return ++(This->ref);
266 static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
267 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
269 if (!--(This->ref)) {
270 IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;
271 HeapFree(GetProcessHeap(),0,This);
277 static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
278 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
280 This->chanbuf = pRpcChannelBuffer;
281 IRpcChannelBuffer_AddRef(This->chanbuf);
284 static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
285 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
287 IRpcChannelBuffer_Release(This->chanbuf);
288 This->chanbuf = NULL;
292 static HRESULT WINAPI
293 CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
295 if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
296 *ppv = (LPVOID)iface;
297 IClassFactory_AddRef(iface);
300 if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debugoutput */
301 return E_NOINTERFACE;
302 FIXME("Unhandled interface: %s\n",debugstr_guid(riid));
303 return E_NOINTERFACE;
306 static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
307 ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
312 static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
313 ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
317 HeapFree(GetProcessHeap(),0,This);
321 static HRESULT WINAPI CFProxy_CreateInstance(
322 LPCLASSFACTORY iface,
323 LPUNKNOWN pUnkOuter,/* [in] */
324 REFIID riid, /* [in] */
325 LPVOID *ppv /* [out] */
327 ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
334 TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
336 /* Send CreateInstance to the remote classfactory.
338 * Data: Only the 'IID'.
341 msg.cbBuffer = sizeof(*riid);
343 hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
345 FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
348 memcpy(msg.Buffer,riid,sizeof(*riid));
349 hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
351 FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
355 if (!msg.cbBuffer) /* interface not found on remote */
358 /* We got back: [Marshaled Interface data] */
359 TRACE("got %ld bytes data.\n",msg.cbBuffer);
360 hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);
361 memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);
362 hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
364 FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
367 hres = CoUnmarshalInterface(
372 IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
374 FIXME("CoMarshalInterface failed, %lx\n",hres);
380 static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {
381 /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/
382 FIXME("(%d), stub!\n",fLock);
383 /* basically: write BOOL, read empty */
387 static ICOM_VTABLE(IRpcProxyBuffer) pspbvtbl = {
388 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
389 IRpcProxyBufferImpl_QueryInterface,
390 IRpcProxyBufferImpl_AddRef,
391 IRpcProxyBufferImpl_Release,
392 IRpcProxyBufferImpl_Connect,
393 IRpcProxyBufferImpl_Disconnect
395 static ICOM_VTABLE(IClassFactory) cfproxyvt = {
396 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
397 CFProxy_QueryInterface,
400 CFProxy_CreateInstance,
405 CFProxy_Construct(LPVOID *ppv,LPVOID *ppProxy) {
408 cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
410 return E_OUTOFMEMORY;
412 cf->lpvtbl_cf = &cfproxyvt;
413 cf->lpvtbl_proxy = &pspbvtbl;
414 cf->ref = 2; /* we return 2 references to the object! */
415 *ppv = &(cf->lpvtbl_cf);
416 *ppProxy = &(cf->lpvtbl_proxy);
421 /********************* OLE Proxy/Stub Factory ********************************/
422 static HRESULT WINAPI
423 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
424 if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
425 *ppv = (LPVOID)iface;
426 /* No ref counting, static class */
429 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
430 return E_NOINTERFACE;
433 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
434 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
436 static HRESULT WINAPI
437 PSFacBuf_CreateProxy(
438 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
439 IRpcProxyBuffer **ppProxy, LPVOID *ppv
441 if (IsEqualIID(&IID_IClassFactory,riid))
442 return CFProxy_Construct(ppv,(LPVOID*)ppProxy);
443 FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid));
447 static HRESULT WINAPI
449 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
450 IRpcStubBuffer** ppStub
454 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
456 if (IsEqualIID(&IID_IClassFactory,riid)) {
457 hres = CFStub_Construct(ppStub);
459 IRpcStubBuffer_Connect((*ppStub),pUnkServer);
462 FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));
466 static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
467 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
468 PSFacBuf_QueryInterface,
471 PSFacBuf_CreateProxy,
475 /* This is the whole PSFactoryBuffer object, just the vtableptr */
476 static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
478 /***********************************************************************
479 * DllGetClassObject [OLE32.63]
481 HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
484 if (IsEqualIID(rclsid,&CLSID_PSFactoryBuffer)) {
486 /* If we create a ps factory, we might need a stub manager later
492 if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&IsEqualIID(iid,&IID_IClassFactory))
493 return MARSHAL_GetStandardMarshalCF(ppv);
494 FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
495 return CLASS_E_CLASSNOTAVAILABLE;