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