- Remove stub for ordinal 394 and replace with forward to
[wine] / dlls / ole32 / oleproxy.c
1 /*
2  *      OLE32 proxy/stub handler
3  *
4  *  Copyright 2002  Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /* Documentation on MSDN:
22  *
23  * (COM Proxy)
24  * http://msdn.microsoft.com/library/en-us/com/comext_1q0p.asp
25  *
26  * (COM Stub)
27  * http://msdn.microsoft.com/library/en-us/com/comext_1lia.asp
28  *
29  * (Marshal)
30  * http://msdn.microsoft.com/library/en-us/com/comext_1gfn.asp
31  *
32  */
33
34 #include "config.h"
35
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <string.h>
39
40 #include "windef.h"
41 #include "objbase.h"
42 #include "ole2.h"
43 #include "rpc.h"
44 #include "winerror.h"
45 #include "winreg.h"
46 #include "wtypes.h"
47 #include "wine/obj_base.h"
48 #include "wine/obj_marshal.h"
49 #include "wine/obj_channel.h"
50
51 #include "compobj_private.h"
52
53 #include "wine/debug.h"
54
55 WINE_DEFAULT_DEBUG_CHANNEL(ole);
56
57 /* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp
58  *
59  * The first time a client requests a pointer to an interface on a
60  * particular object, COM loads an IClassFactory stub in the server
61  * process and uses it to marshal the first pointer back to the
62  * client. In the client process, COM loads the generic proxy for the
63  * class factory object and calls its implementation of IMarshal to
64  * unmarshal that first pointer. COM then creates the first interface
65  * proxy and hands it a pointer to the RPC channel. Finally, COM returns
66  * the IClassFactory pointer to the client, which uses it to call
67  * IClassFactory::CreateInstance, passing it a reference to the interface.
68  *
69  * Back in the server process, COM now creates a new instance of the
70  * object, along with a stub for the requested interface. This stub marshals
71  * the interface pointer back to the client process, where another object
72  * proxy is created, this time for the object itself. Also created is a
73  * proxy for the requested interface, a pointer to which is returned to
74  * the client. With subsequent calls to other interfaces on the object,
75  * COM will load the appropriate interface stubs and proxies as needed.
76  */
77 typedef struct _CFStub {
78     ICOM_VTABLE(IRpcStubBuffer) *lpvtbl;
79     DWORD                       ref;
80
81     LPUNKNOWN                   pUnkServer;
82 } CFStub;
83
84 static HRESULT WINAPI
85 CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
86     if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {
87         *ppv = (LPVOID)iface;
88         IUnknown_AddRef(iface);
89         return S_OK;
90     }
91     FIXME("(%s), interface not supported.\n",debugstr_guid(riid));
92     return E_NOINTERFACE;
93 }
94
95 static ULONG WINAPI
96 CFStub_AddRef(LPRPCSTUBBUFFER iface) {
97     ICOM_THIS(CFStub,iface);
98
99     This->ref++;
100     return This->ref;
101 }
102
103 static ULONG WINAPI
104 CFStub_Release(LPRPCSTUBBUFFER iface) {
105     ICOM_THIS(CFStub,iface);
106
107     This->ref--;
108     if (This->ref)
109         return This->ref;
110     HeapFree(GetProcessHeap(),0,This);
111     return 0;
112 }
113
114 static HRESULT WINAPI
115 CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
116     ICOM_THIS(CFStub,iface);
117
118     This->pUnkServer = pUnkServer;
119     IUnknown_AddRef(pUnkServer);
120     return S_OK;
121 }
122
123 static void WINAPI
124 CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
125     ICOM_THIS(CFStub,iface);
126
127     IUnknown_Release(This->pUnkServer);
128     This->pUnkServer = NULL;
129 }
130 static HRESULT WINAPI
131 CFStub_Invoke(
132     LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
133 ) {
134     ICOM_THIS(CFStub,iface);
135     HRESULT hres;
136
137     if (msg->iMethod == 3) { /* CreateInstance */
138         IID iid;
139         IClassFactory   *classfac;
140         IUnknown        *ppv;
141         IStream         *pStm;
142         STATSTG         ststg;
143         ULARGE_INTEGER  newpos;
144         LARGE_INTEGER   seekto;
145         ULONG           res;
146
147         if (msg->cbBuffer < sizeof(IID)) {
148             FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
149             return E_FAIL;
150         }
151         memcpy(&iid,msg->Buffer,sizeof(iid));
152         TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));
153         hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);
154         if (hres) {
155             FIXME("Ole server does not provide a IClassFactory?\n");
156             return hres;
157         }
158         hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
159         IClassFactory_Release(classfac);
160         if (hres) {
161             msg->cbBuffer = 0;
162             FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
163             return hres;
164         }
165         hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
166         if (hres) {
167             FIXME("Failed to create stream on hglobal\n");
168             return hres;
169         }
170         hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
171         if (hres) {
172             FIXME("CoMarshalInterface failed, %lx!\n",hres);
173             msg->cbBuffer = 0;
174             return hres;
175         }
176         hres = IStream_Stat(pStm,&ststg,0);
177         if (hres) {
178             FIXME("Stat failed.\n");
179             return hres;
180         }
181
182         msg->cbBuffer = ststg.cbSize.s.LowPart;
183         msg->Buffer = HeapReAlloc(GetProcessHeap(),0,msg->Buffer,ststg.cbSize.s.LowPart);
184         seekto.s.LowPart = 0;seekto.s.HighPart = 0;
185         hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
186         if (hres) {
187             FIXME("IStream_Seek failed, %lx\n",hres);
188             return hres;
189         }
190         hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
191         if (hres) {
192             FIXME("Stream Read failed, %lx\n",hres);
193             return hres;
194         }
195         IStream_Release(pStm);
196         return S_OK;
197     }
198     FIXME("(%p,%p), stub!\n",msg,chanbuf);
199     FIXME("iMethod is %ld\n",msg->iMethod);
200     FIXME("cbBuffer is %ld\n",msg->cbBuffer);
201     return E_FAIL;
202 }
203
204 static LPRPCSTUBBUFFER WINAPI
205 CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
206     FIXME("(%s), stub!\n",debugstr_guid(riid));
207     return NULL;
208 }
209
210 static ULONG WINAPI
211 CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
212     FIXME("(), stub!\n");
213     return 1;
214 }
215
216 static HRESULT WINAPI
217 CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
218     FIXME("(%p), stub!\n",ppv);
219     return E_FAIL;
220 }
221 static void    WINAPI
222 CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
223     FIXME("(%p), stub!\n",pv);
224 }
225
226 static ICOM_VTABLE(IRpcStubBuffer) cfstubvt = {
227     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
228     CFStub_QueryInterface,
229     CFStub_AddRef,
230     CFStub_Release,
231     CFStub_Connect,
232     CFStub_Disconnect,
233     CFStub_Invoke,
234     CFStub_IsIIDSupported,
235     CFStub_CountRefs,
236     CFStub_DebugServerQueryInterface,
237     CFStub_DebugServerRelease
238 };
239
240 static HRESULT
241 CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
242     CFStub *cfstub;
243     cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
244     if (!cfstub)
245         return E_OUTOFMEMORY;
246     *ppv = (LPRPCSTUBBUFFER)cfstub;
247     cfstub->lpvtbl      = &cfstubvt;
248     cfstub->ref         = 1;
249     return S_OK;
250 }
251
252 /* Since we create proxy buffers and classfactory in a pair, there is
253  * no need for 2 seperate structs. Just put them in one, but remember
254  * the refcount.
255  */
256 typedef struct _CFProxy {
257     ICOM_VTABLE(IClassFactory)          *lpvtbl_cf;
258     ICOM_VTABLE(IRpcProxyBuffer)        *lpvtbl_proxy;
259     DWORD                               ref;
260
261     IRpcChannelBuffer                   *chanbuf;
262 } CFProxy;
263
264 static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
265     *ppv = NULL;
266     if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
267         IRpcProxyBuffer_AddRef(iface);
268         *ppv = (LPVOID)iface;
269         return S_OK;
270     }
271     FIXME("(%s), no interface.\n",debugstr_guid(riid));
272     return E_NOINTERFACE;
273 }
274
275 static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
276     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
277     return ++(This->ref);
278 }
279
280 static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
281     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
282
283     if (!--(This->ref)) {
284         IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;
285         HeapFree(GetProcessHeap(),0,This);
286         return 0;
287     }
288     return This->ref;
289 }
290
291 static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
292     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
293
294     This->chanbuf = pRpcChannelBuffer;
295     IRpcChannelBuffer_AddRef(This->chanbuf);
296     return S_OK;
297 }
298 static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
299     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
300     if (This->chanbuf) {
301         IRpcChannelBuffer_Release(This->chanbuf);
302         This->chanbuf = NULL;
303     }
304 }
305
306 static HRESULT WINAPI
307 CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
308     *ppv = NULL;
309     if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
310         *ppv = (LPVOID)iface;
311         IClassFactory_AddRef(iface);
312         return S_OK;
313     }
314     if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debugoutput */
315         return E_NOINTERFACE;
316     FIXME("Unhandled interface: %s\n",debugstr_guid(riid));
317     return E_NOINTERFACE;
318 }
319
320 static ULONG   WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
321     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
322     This->ref++;
323     return This->ref;
324 }
325
326 static ULONG   WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
327     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
328     This->ref--;
329     if (This->ref)
330         return This->ref;
331     HeapFree(GetProcessHeap(),0,This);
332     return 0;
333 }
334
335 static HRESULT WINAPI CFProxy_CreateInstance(
336     LPCLASSFACTORY iface,
337     LPUNKNOWN pUnkOuter,/* [in] */
338     REFIID riid,        /* [in] */
339     LPVOID *ppv         /* [out] */
340 ) {
341     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
342     HRESULT             hres;
343     LPSTREAM            pStream;
344     HGLOBAL             hGlobal;
345     ULONG               srstatus;
346     RPCOLEMESSAGE       msg;
347
348     TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
349
350     /* Send CreateInstance to the remote classfactory.
351      *
352      * Data: Only the 'IID'.
353      */
354     msg.iMethod  = 3;
355     msg.cbBuffer = sizeof(*riid);
356     msg.Buffer   = NULL;
357     hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
358     if (hres) {
359         FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
360         return hres;
361     }
362     memcpy(msg.Buffer,riid,sizeof(*riid));
363     hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
364     if (hres) {
365         FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
366         return hres;
367     }
368
369     if (!msg.cbBuffer) /* interface not found on remote */
370         return srstatus;
371
372     /* We got back: [Marshaled Interface data] */
373     TRACE("got %ld bytes data.\n",msg.cbBuffer);
374     hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);
375     memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);
376     hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
377     if (hres) {
378         FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
379         return hres;
380     }
381     hres = CoUnmarshalInterface(
382             pStream,
383             riid,
384             ppv
385     );
386     IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
387     if (hres) {
388         FIXME("CoMarshalInterface failed, %lx\n",hres);
389         return hres;
390     }
391     return S_OK;
392 }
393
394 static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {
395     /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/
396     FIXME("(%d), stub!\n",fLock);
397     /* basically: write BOOL, read empty */
398     return S_OK;
399 }
400
401 static ICOM_VTABLE(IRpcProxyBuffer) pspbvtbl = {
402     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
403     IRpcProxyBufferImpl_QueryInterface,
404     IRpcProxyBufferImpl_AddRef,
405     IRpcProxyBufferImpl_Release,
406     IRpcProxyBufferImpl_Connect,
407     IRpcProxyBufferImpl_Disconnect
408 };
409 static ICOM_VTABLE(IClassFactory) cfproxyvt = {
410     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
411     CFProxy_QueryInterface,
412     CFProxy_AddRef,
413     CFProxy_Release,
414     CFProxy_CreateInstance,
415     CFProxy_LockServer
416 };
417
418 static HRESULT
419 CFProxy_Construct(LPVOID *ppv,LPVOID *ppProxy) {
420     CFProxy *cf;
421
422     cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
423     if (!cf)
424         return E_OUTOFMEMORY;
425
426     cf->lpvtbl_cf       = &cfproxyvt;
427     cf->lpvtbl_proxy    = &pspbvtbl;
428     cf->ref             = 2; /* we return 2 references to the object! */
429     *ppv                = &(cf->lpvtbl_cf);
430     *ppProxy            = &(cf->lpvtbl_proxy);
431     return S_OK;
432 }
433
434
435 /********************* OLE Proxy/Stub Factory ********************************/
436 static HRESULT WINAPI
437 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
438     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
439         *ppv = (LPVOID)iface;
440         /* No ref counting, static class */
441         return S_OK;
442     }
443     FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
444     return E_NOINTERFACE;
445 }
446
447 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
448 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
449
450 static HRESULT WINAPI
451 PSFacBuf_CreateProxy(
452     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
453     IRpcProxyBuffer **ppProxy, LPVOID *ppv
454 ) {
455     if (IsEqualIID(&IID_IClassFactory,riid) ||
456         IsEqualIID(&IID_IUnknown,riid)
457     )
458         return CFProxy_Construct(ppv,(LPVOID*)ppProxy);
459     FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid));
460     return E_FAIL;
461 }
462
463 static HRESULT WINAPI
464 PSFacBuf_CreateStub(
465     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
466     IRpcStubBuffer** ppStub
467 ) {
468     HRESULT hres;
469
470     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
471
472     if (IsEqualIID(&IID_IClassFactory,riid) ||
473         IsEqualIID(&IID_IUnknown,riid)
474     ) {
475         hres = CFStub_Construct(ppStub);
476         if (!hres)
477             IRpcStubBuffer_Connect((*ppStub),pUnkServer);
478         return hres;
479     }
480     FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));
481     return E_FAIL;
482 }
483
484 static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
485     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
486     PSFacBuf_QueryInterface,
487     PSFacBuf_AddRef,
488     PSFacBuf_Release,
489     PSFacBuf_CreateProxy,
490     PSFacBuf_CreateStub
491 };
492
493 /* This is the whole PSFactoryBuffer object, just the vtableptr */
494 static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
495
496 /***********************************************************************
497  *           DllGetClassObject [OLE32.63]
498  */
499 HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
500 {
501     *ppv = NULL;
502     if (IsEqualIID(rclsid,&CLSID_PSFactoryBuffer)) {
503         *ppv = &lppsfac;
504         /* If we create a ps factory, we might need a stub manager later
505          * anyway
506          */
507         STUBMGR_Start();
508         return S_OK;
509     }
510     if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&(
511                 IsEqualIID(iid,&IID_IClassFactory) ||
512                 IsEqualIID(iid,&IID_IUnknown)
513         )
514     )
515         return MARSHAL_GetStandardMarshalCF(ppv);
516     FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
517     return CLASS_E_CLASSNOTAVAILABLE;
518 }