source: trunk/src/ole32/oleproxy.c@ 7926

Last change on this file since 7926 was 7926, checked in by sandervl, 24 years ago

Wine 20020215 resync

File size: 13.6 KB
Line 
1/*
2 * OLE32 proxy/stub handler
3 *
4 * Copyright 2002 Marcus Meissner
5 */
6
7/* Documentation on MSDN:
8 *
9 * (COM Proxy)
10 * http://msdn.microsoft.com/library/en-us/com/comext_1q0p.asp
11 *
12 * (COM Stub)
13 * http://msdn.microsoft.com/library/en-us/com/comext_1lia.asp
14 *
15 * (Marshal)
16 * http://msdn.microsoft.com/library/en-us/com/comext_1gfn.asp
17 *
18 */
19
20#include "config.h"
21
22#include <stdlib.h>
23#include <stdio.h>
24#include <string.h>
25
26#include "windef.h"
27#include "objbase.h"
28#include "ole2.h"
29#include "rpc.h"
30#include "winerror.h"
31#include "winreg.h"
32#include "wtypes.h"
33#include "wine/obj_base.h"
34#include "wine/obj_marshal.h"
35#include "wine/obj_channel.h"
36
37#include "compobj_private.h"
38
39#include "debugtools.h"
40
41DEFAULT_DEBUG_CHANNEL(ole);
42
43/* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp
44 *
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.
54 *
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.
62 */
63typedef struct _CFStub {
64 ICOM_VTABLE(IRpcStubBuffer) *lpvtbl;
65 DWORD ref;
66
67 LPUNKNOWN pUnkServer;
68} CFStub;
69
70static HRESULT WINAPI
71CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
72 if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {
73 *ppv = (LPVOID)iface;
74 IUnknown_AddRef(iface);
75 return S_OK;
76 }
77 FIXME("(%s), interface not supported.\n",debugstr_guid(riid));
78 return E_NOINTERFACE;
79}
80
81static ULONG WINAPI
82CFStub_AddRef(LPRPCSTUBBUFFER iface) {
83 ICOM_THIS(CFStub,iface);
84
85 This->ref++;
86 return This->ref;
87}
88
89static ULONG WINAPI
90CFStub_Release(LPRPCSTUBBUFFER iface) {
91 ICOM_THIS(CFStub,iface);
92
93 This->ref--;
94 if (This->ref)
95 return This->ref;
96 HeapFree(GetProcessHeap(),0,This);
97 return 0;
98}
99
100static HRESULT WINAPI
101CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
102 ICOM_THIS(CFStub,iface);
103
104 This->pUnkServer = pUnkServer;
105 IUnknown_AddRef(pUnkServer);
106 return S_OK;
107}
108
109static void WINAPI
110CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
111 ICOM_THIS(CFStub,iface);
112
113 IUnknown_Release(This->pUnkServer);
114 This->pUnkServer = NULL;
115}
116static HRESULT WINAPI
117CFStub_Invoke(
118 LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
119) {
120 ICOM_THIS(CFStub,iface);
121 HRESULT hres;
122
123 if (msg->iMethod == 3) { /* CreateInstance */
124 IID iid;
125 IClassFactory *classfac;
126 IUnknown *ppv;
127 IStream *pStm;
128 STATSTG ststg;
129 ULARGE_INTEGER newpos;
130 LARGE_INTEGER seekto;
131 ULONG res;
132
133 if (msg->cbBuffer < sizeof(IID)) {
134 FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
135 return E_FAIL;
136 }
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);
140 if (hres) {
141 FIXME("Ole server does not provide a IClassFactory?\n");
142 return hres;
143 }
144 hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
145 IClassFactory_Release(classfac);
146 if (hres) {
147 msg->cbBuffer = 0;
148 FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
149 return hres;
150 }
151 hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
152 if (hres) {
153 FIXME("Failed to create stream on hglobal\n");
154 return hres;
155 }
156 hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
157 if (hres) {
158 FIXME("CoMarshalInterface failed, %lx!\n",hres);
159 msg->cbBuffer = 0;
160 return hres;
161 }
162 hres = IStream_Stat(pStm,&ststg,0);
163 if (hres) {
164 FIXME("Stat failed.\n");
165 return hres;
166 }
167
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);
172 if (hres) {
173 FIXME("IStream_Seek failed, %lx\n",hres);
174 return hres;
175 }
176 hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
177 if (hres) {
178 FIXME("Stream Read failed, %lx\n",hres);
179 return hres;
180 }
181 IStream_Release(pStm);
182 return S_OK;
183 }
184 FIXME("(%p,%p), stub!\n",msg,chanbuf);
185 FIXME("iMethod is %ld\n",msg->iMethod);
186 FIXME("cbBuffer is %ld\n",msg->cbBuffer);
187 return E_FAIL;
188}
189
190static LPRPCSTUBBUFFER WINAPI
191CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
192 FIXME("(%s), stub!\n",debugstr_guid(riid));
193 return NULL;
194}
195
196static ULONG WINAPI
197CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
198 FIXME("(), stub!\n");
199 return 1;
200}
201
202static HRESULT WINAPI
203CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
204 FIXME("(%p), stub!\n",ppv);
205 return E_FAIL;
206}
207static void WINAPI
208CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
209 FIXME("(%p), stub!\n",pv);
210}
211
212static ICOM_VTABLE(IRpcStubBuffer) cfstubvt = {
213 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
214 CFStub_QueryInterface,
215 CFStub_AddRef,
216 CFStub_Release,
217 CFStub_Connect,
218 CFStub_Disconnect,
219 CFStub_Invoke,
220 CFStub_IsIIDSupported,
221 CFStub_CountRefs,
222 CFStub_DebugServerQueryInterface,
223 CFStub_DebugServerRelease
224};
225
226static HRESULT
227CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
228 CFStub *cfstub;
229 cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
230 if (!cfstub)
231 return E_OUTOFMEMORY;
232 *ppv = (LPRPCSTUBBUFFER)cfstub;
233 cfstub->lpvtbl = &cfstubvt;
234 cfstub->ref = 1;
235 return S_OK;
236}
237
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
240 * the refcount.
241 */
242typedef struct _CFProxy {
243 ICOM_VTABLE(IClassFactory) *lpvtbl_cf;
244 ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl_proxy;
245 DWORD ref;
246
247 IRpcChannelBuffer *chanbuf;
248} CFProxy;
249
250static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
251 *ppv = NULL;
252 if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
253 IRpcProxyBuffer_AddRef(iface);
254 *ppv = (LPVOID)iface;
255 return S_OK;
256 }
257 FIXME("(%s), no interface.\n",debugstr_guid(riid));
258 return E_NOINTERFACE;
259}
260
261static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
262 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
263 return ++(This->ref);
264}
265
266static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
267 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
268
269 if (!--(This->ref)) {
270 IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;
271 HeapFree(GetProcessHeap(),0,This);
272 return 0;
273 }
274 return This->ref;
275}
276
277static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
278 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
279
280 This->chanbuf = pRpcChannelBuffer;
281 IRpcChannelBuffer_AddRef(This->chanbuf);
282 return S_OK;
283}
284static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
285 ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
286 if (This->chanbuf) {
287 IRpcChannelBuffer_Release(This->chanbuf);
288 This->chanbuf = NULL;
289 }
290}
291
292static HRESULT WINAPI
293CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
294 *ppv = NULL;
295 if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
296 *ppv = (LPVOID)iface;
297 IClassFactory_AddRef(iface);
298 return S_OK;
299 }
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;
304}
305
306static ULONG WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
307 ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
308 This->ref++;
309 return This->ref;
310}
311
312static ULONG WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
313 ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
314 This->ref--;
315 if (This->ref)
316 return This->ref;
317 HeapFree(GetProcessHeap(),0,This);
318 return 0;
319}
320
321static HRESULT WINAPI CFProxy_CreateInstance(
322 LPCLASSFACTORY iface,
323 LPUNKNOWN pUnkOuter,/* [in] */
324 REFIID riid, /* [in] */
325 LPVOID *ppv /* [out] */
326) {
327 ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
328 HRESULT hres;
329 LPSTREAM pStream;
330 HGLOBAL hGlobal;
331 ULONG srstatus;
332 RPCOLEMESSAGE msg;
333
334 TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
335
336 /* Send CreateInstance to the remote classfactory.
337 *
338 * Data: Only the 'IID'.
339 */
340 msg.iMethod = 3;
341 msg.cbBuffer = sizeof(*riid);
342 msg.Buffer = NULL;
343 hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
344 if (hres) {
345 FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
346 return hres;
347 }
348 memcpy(msg.Buffer,riid,sizeof(*riid));
349 hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
350 if (hres) {
351 FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
352 return hres;
353 }
354
355 if (!msg.cbBuffer) /* interface not found on remote */
356 return srstatus;
357
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);
363 if (hres) {
364 FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
365 return hres;
366 }
367 hres = CoUnmarshalInterface(
368 pStream,
369 riid,
370 ppv
371 );
372 IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
373 if (hres) {
374 FIXME("CoMarshalInterface failed, %lx\n",hres);
375 return hres;
376 }
377 return S_OK;
378}
379
380static 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 */
384 return S_OK;
385}
386
387static ICOM_VTABLE(IRpcProxyBuffer) pspbvtbl = {
388 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
389 IRpcProxyBufferImpl_QueryInterface,
390 IRpcProxyBufferImpl_AddRef,
391 IRpcProxyBufferImpl_Release,
392 IRpcProxyBufferImpl_Connect,
393 IRpcProxyBufferImpl_Disconnect
394};
395static ICOM_VTABLE(IClassFactory) cfproxyvt = {
396 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
397 CFProxy_QueryInterface,
398 CFProxy_AddRef,
399 CFProxy_Release,
400 CFProxy_CreateInstance,
401 CFProxy_LockServer
402};
403
404static HRESULT
405CFProxy_Construct(LPVOID *ppv,LPVOID *ppProxy) {
406 CFProxy *cf;
407
408 cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
409 if (!cf)
410 return E_OUTOFMEMORY;
411
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);
417 return S_OK;
418}
419
420
421/********************* OLE Proxy/Stub Factory ********************************/
422static HRESULT WINAPI
423PSFacBuf_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 */
427 return S_OK;
428 }
429 FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
430 return E_NOINTERFACE;
431}
432
433static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
434static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
435
436static HRESULT WINAPI
437PSFacBuf_CreateProxy(
438 LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
439 IRpcProxyBuffer **ppProxy, LPVOID *ppv
440) {
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));
444 return E_FAIL;
445}
446
447static HRESULT WINAPI
448PSFacBuf_CreateStub(
449 LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
450 IRpcStubBuffer** ppStub
451) {
452 HRESULT hres;
453
454 TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
455
456 if (IsEqualIID(&IID_IClassFactory,riid)) {
457 hres = CFStub_Construct(ppStub);
458 if (!hres)
459 IRpcStubBuffer_Connect((*ppStub),pUnkServer);
460 return hres;
461 }
462 FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));
463 return E_FAIL;
464}
465
466static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
467 ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
468 PSFacBuf_QueryInterface,
469 PSFacBuf_AddRef,
470 PSFacBuf_Release,
471 PSFacBuf_CreateProxy,
472 PSFacBuf_CreateStub
473};
474
475/* This is the whole PSFactoryBuffer object, just the vtableptr */
476static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
477
478/***********************************************************************
479 * DllGetClassObject [OLE32.63]
480 */
481HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
482{
483 *ppv = NULL;
484 if (IsEqualIID(rclsid,&CLSID_PSFactoryBuffer)) {
485 *ppv = &lppsfac;
486 /* If we create a ps factory, we might need a stub manager later
487 * anyway
488 */
489 STUBMGR_Start();
490 return S_OK;
491 }
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;
496}
Note: See TracBrowser for help on using the repository browser.