Add support for more than 2 audio channels.
[wine] / dlls / ole32 / oleproxy.c
1 /*
2  *      OLE32 proxy/stub handler
3  *
4  *  Copyright 2002  Marcus Meissner
5  *  Copyright 2001  Ove Kåven, TransGaming Technologies
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 /* Documentation on MSDN:
23  *
24  * (Top level COM documentation)
25  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnanchor/html/componentdevelopmentank.asp
26  *
27  * (COM Proxy)
28  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1q0p.asp
29  *
30  * (COM Stub)
31  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1lia.asp
32  *
33  * (Marshal)
34  * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/com/htm/comext_1gfn.asp
35  *
36  */
37
38 #include "config.h"
39
40 #include <stdlib.h>
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44
45 #define COBJMACROS
46 #define NONAMELESSUNION
47 #define NONAMELESSSTRUCT
48
49 #include "windef.h"
50 #include "winbase.h"
51 #include "winuser.h"
52 #include "objbase.h"
53 #include "ole2.h"
54 #include "rpc.h"
55 #include "winerror.h"
56 #include "winreg.h"
57 #include "wtypes.h"
58
59 #include "compobj_private.h"
60 #include "moniker.h"
61
62 #include "wine/debug.h"
63
64 WINE_DEFAULT_DEBUG_CHANNEL(ole);
65
66 const CLSID CLSID_DfMarshal       = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
67 const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
68
69 /* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp
70  *
71  * The first time a client requests a pointer to an interface on a
72  * particular object, COM loads an IClassFactory stub in the server
73  * process and uses it to marshal the first pointer back to the
74  * client. In the client process, COM loads the generic proxy for the
75  * class factory object and calls its implementation of IMarshal to
76  * unmarshal that first pointer. COM then creates the first interface
77  * proxy and hands it a pointer to the RPC channel. Finally, COM returns
78  * the IClassFactory pointer to the client, which uses it to call
79  * IClassFactory::CreateInstance, passing it a reference to the interface.
80  *
81  * Back in the server process, COM now creates a new instance of the
82  * object, along with a stub for the requested interface. This stub marshals
83  * the interface pointer back to the client process, where another object
84  * proxy is created, this time for the object itself. Also created is a
85  * proxy for the requested interface, a pointer to which is returned to
86  * the client. With subsequent calls to other interfaces on the object,
87  * COM will load the appropriate interface stubs and proxies as needed.
88  */
89 typedef struct _CFStub {
90     IRpcStubBufferVtbl  *lpvtbl;
91     DWORD                       ref;
92
93     LPUNKNOWN                   pUnkServer;
94 } CFStub;
95
96 static HRESULT WINAPI
97 CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
98     if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {
99         *ppv = (LPVOID)iface;
100         IUnknown_AddRef(iface);
101         return S_OK;
102     }
103     FIXME("(%s), interface not supported.\n",debugstr_guid(riid));
104     return E_NOINTERFACE;
105 }
106
107 static ULONG WINAPI
108 CFStub_AddRef(LPRPCSTUBBUFFER iface) {
109     CFStub *This = (CFStub *)iface;
110     return InterlockedIncrement(&This->ref);
111 }
112
113 static ULONG WINAPI
114 CFStub_Release(LPRPCSTUBBUFFER iface) {
115     CFStub *This = (CFStub *)iface;
116     ULONG ref;
117
118     ref = InterlockedDecrement(&This->ref);
119     if (!ref) HeapFree(GetProcessHeap(),0,This);
120     return ref;
121 }
122
123 static HRESULT WINAPI
124 CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
125     CFStub *This = (CFStub *)iface;
126
127     This->pUnkServer = pUnkServer;
128     IUnknown_AddRef(pUnkServer);
129     return S_OK;
130 }
131
132 static void WINAPI
133 CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
134     CFStub *This = (CFStub *)iface;
135
136     IUnknown_Release(This->pUnkServer);
137     This->pUnkServer = NULL;
138 }
139 static HRESULT WINAPI
140 CFStub_Invoke(
141     LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
142 ) {
143     CFStub *This = (CFStub *)iface;
144     HRESULT hres;
145
146     if (msg->iMethod == 3) { /* CreateInstance */
147         IID iid;
148         IClassFactory   *classfac;
149         IUnknown        *ppv;
150         IStream         *pStm;
151         STATSTG         ststg;
152         ULARGE_INTEGER  newpos;
153         LARGE_INTEGER   seekto;
154         ULONG           res;
155
156         if (msg->cbBuffer < sizeof(IID)) {
157             FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
158             return E_FAIL;
159         }
160         memcpy(&iid,msg->Buffer,sizeof(iid));
161         TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));
162         hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);
163         if (hres) {
164             FIXME("Ole server does not provide an IClassFactory?\n");
165             return hres;
166         }
167         hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
168         IClassFactory_Release(classfac);
169         if (hres) {
170             msg->cbBuffer = 0;
171             FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
172             return hres;
173         }
174         hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
175         if (hres) {
176             FIXME("Failed to create stream on hglobal\n");
177             return hres;
178         }
179         hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
180         IUnknown_Release((IUnknown*)ppv);
181         if (hres) {
182             FIXME("CoMarshalInterface failed, %lx!\n",hres);
183             msg->cbBuffer = 0;
184             return hres;
185         }
186         hres = IStream_Stat(pStm,&ststg,0);
187         if (hres) {
188             FIXME("Stat failed.\n");
189             return hres;
190         }
191
192         msg->cbBuffer = ststg.cbSize.u.LowPart;
193
194         I_RpcGetBuffer((RPC_MESSAGE *)msg);
195         if (hres) return hres;
196
197         seekto.u.LowPart = 0;seekto.u.HighPart = 0;
198         hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
199         if (hres) {
200             FIXME("IStream_Seek failed, %lx\n",hres);
201             return hres;
202         }
203         hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
204         if (hres) {
205             FIXME("Stream Read failed, %lx\n",hres);
206             return hres;
207         }
208         IStream_Release(pStm);
209         return S_OK;
210     }
211     FIXME("(%p,%p), stub!\n",msg,chanbuf);
212     FIXME("iMethod is %ld\n",msg->iMethod);
213     FIXME("cbBuffer is %ld\n",msg->cbBuffer);
214     return E_FAIL;
215 }
216
217 static LPRPCSTUBBUFFER WINAPI
218 CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
219     FIXME("(%s), stub!\n",debugstr_guid(riid));
220     return NULL;
221 }
222
223 static ULONG WINAPI
224 CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
225     FIXME("(), stub!\n");
226     return 1;
227 }
228
229 static HRESULT WINAPI
230 CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
231     FIXME("(%p), stub!\n",ppv);
232     return E_FAIL;
233 }
234 static void    WINAPI
235 CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
236     FIXME("(%p), stub!\n",pv);
237 }
238
239 static IRpcStubBufferVtbl cfstubvt = {
240     CFStub_QueryInterface,
241     CFStub_AddRef,
242     CFStub_Release,
243     CFStub_Connect,
244     CFStub_Disconnect,
245     CFStub_Invoke,
246     CFStub_IsIIDSupported,
247     CFStub_CountRefs,
248     CFStub_DebugServerQueryInterface,
249     CFStub_DebugServerRelease
250 };
251
252 static HRESULT
253 CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
254     CFStub *cfstub;
255     cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
256     if (!cfstub)
257         return E_OUTOFMEMORY;
258     *ppv = (LPRPCSTUBBUFFER)cfstub;
259     cfstub->lpvtbl      = &cfstubvt;
260     cfstub->ref         = 1;
261     return S_OK;
262 }
263
264 /* Since we create proxy buffers and classfactory in a pair, there is
265  * no need for 2 separate structs. Just put them in one, but remember
266  * the refcount.
267  */
268 typedef struct _CFProxy {
269     const IClassFactoryVtbl             *lpvtbl_cf;
270     const IRpcProxyBufferVtbl   *lpvtbl_proxy;
271     DWORD                               ref;
272
273     IRpcChannelBuffer                   *chanbuf;
274     IUnknown *outer_unknown;
275 } CFProxy;
276
277 static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
278     *ppv = NULL;
279     if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
280         IRpcProxyBuffer_AddRef(iface);
281         *ppv = (LPVOID)iface;
282         return S_OK;
283     }
284     FIXME("(%s), no interface.\n",debugstr_guid(riid));
285     return E_NOINTERFACE;
286 }
287
288 static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
289     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
290     return InterlockedIncrement(&This->ref);
291 }
292
293 static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
294     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
295     ULONG ref = InterlockedDecrement(&This->ref);
296
297     if (!ref) {
298         IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;
299         HeapFree(GetProcessHeap(),0,This);
300     }
301     return ref;
302 }
303
304 static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
305     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
306
307     This->chanbuf = pRpcChannelBuffer;
308     IRpcChannelBuffer_AddRef(This->chanbuf);
309     return S_OK;
310 }
311 static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
312     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
313     if (This->chanbuf) {
314         IRpcChannelBuffer_Release(This->chanbuf);
315         This->chanbuf = NULL;
316     }
317 }
318
319 static HRESULT WINAPI
320 CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
321     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
322     if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
323     *ppv = NULL;
324     if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
325         *ppv = (LPVOID)iface;
326         IClassFactory_AddRef(iface);
327         return S_OK;
328     }
329     if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */
330         return E_NOINTERFACE;
331     FIXME("Unhandled interface: %s\n",debugstr_guid(riid));
332     return E_NOINTERFACE;
333 }
334
335 static ULONG   WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
336     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
337     if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown);
338     return InterlockedIncrement(&This->ref);
339 }
340
341 static ULONG   WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
342     ULONG ref;
343     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
344     if (This->outer_unknown)
345         ref = IUnknown_Release(This->outer_unknown);
346     else    
347         ref = InterlockedDecrement(&This->ref);
348
349     if (!ref) {
350         if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
351         HeapFree(GetProcessHeap(),0,This);
352     }
353     return ref;
354 }
355
356 static HRESULT WINAPI CFProxy_CreateInstance(
357     LPCLASSFACTORY iface,
358     LPUNKNOWN pUnkOuter,/* [in] */
359     REFIID riid,        /* [in] */
360     LPVOID *ppv         /* [out] */
361 ) {
362     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
363     HRESULT             hres;
364     LPSTREAM            pStream;
365     HGLOBAL             hGlobal;
366     ULONG               srstatus;
367     RPCOLEMESSAGE       msg;
368
369     TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
370
371     /* Send CreateInstance to the remote classfactory.
372      *
373      * Data: Only the 'IID'.
374      */
375     msg.iMethod  = 3;
376     msg.cbBuffer = sizeof(*riid);
377     msg.Buffer   = NULL;
378     hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
379     if (hres) {
380         FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
381         return hres;
382     }
383     memcpy(msg.Buffer,riid,sizeof(*riid));
384     hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
385     if (hres) {
386         FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
387         return hres;
388     }
389
390     if (!msg.cbBuffer) /* interface not found on remote */
391         return srstatus;
392
393     /* We got back: [Marshalled Interface data] */
394     TRACE("got %ld bytes data.\n",msg.cbBuffer);
395     hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);
396     memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);
397     hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
398     if (hres) {
399         FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
400         return hres;
401     }
402     hres = CoUnmarshalInterface(
403             pStream,
404             riid,
405             ppv
406     );
407     IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
408     if (hres) {
409         FIXME("CoMarshalInterface failed, %lx\n",hres);
410         return hres;
411     }
412     return S_OK;
413 }
414
415 static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {
416     /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/
417     FIXME("(%d), stub!\n",fLock);
418     /* basically: write BOOL, read empty */
419     return S_OK;
420 }
421
422 static IRpcProxyBufferVtbl pspbvtbl = {
423     IRpcProxyBufferImpl_QueryInterface,
424     IRpcProxyBufferImpl_AddRef,
425     IRpcProxyBufferImpl_Release,
426     IRpcProxyBufferImpl_Connect,
427     IRpcProxyBufferImpl_Disconnect
428 };
429 static IClassFactoryVtbl cfproxyvt = {
430     CFProxy_QueryInterface,
431     CFProxy_AddRef,
432     CFProxy_Release,
433     CFProxy_CreateInstance,
434     CFProxy_LockServer
435 };
436
437 static HRESULT
438 CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
439     CFProxy *cf;
440
441     cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
442     if (!cf)
443         return E_OUTOFMEMORY;
444
445     cf->lpvtbl_cf       = &cfproxyvt;
446     cf->lpvtbl_proxy    = &pspbvtbl;
447     /* only one reference for the proxy buffer */
448     cf->ref             = 1;
449     cf->outer_unknown = pUnkOuter;
450     *ppv                = &(cf->lpvtbl_cf);
451     *ppProxy            = &(cf->lpvtbl_proxy);
452     return S_OK;
453 }
454
455
456 /********************* IRemUnknown Proxy/Stub ********************************/
457
458 typedef struct
459 {
460     const IRpcStubBufferVtbl *lpVtbl;
461     ULONG refs;
462     IRemUnknown *iface;
463 } RemUnkStub;
464
465 static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface,
466                                              REFIID riid,
467                                              LPVOID *obj)
468 {
469   RemUnkStub *This = (RemUnkStub *)iface;
470   TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);
471   if (IsEqualGUID(&IID_IUnknown,riid) ||
472       IsEqualGUID(&IID_IRpcStubBuffer,riid)) {
473     *obj = This;
474     return S_OK;
475   }
476   return E_NOINTERFACE;
477 }
478
479 static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface)
480 {
481   RemUnkStub *This = (RemUnkStub *)iface;
482   TRACE("(%p)->AddRef()\n",This);
483   return InterlockedIncrement(&This->refs);
484 }
485
486 static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface)
487 {
488   RemUnkStub *This = (RemUnkStub *)iface;
489   ULONG refs;
490   TRACE("(%p)->Release()\n",This);
491   refs = InterlockedDecrement(&This->refs);
492   if (!refs)
493     HeapFree(GetProcessHeap(), 0, This);
494   return refs;
495 }
496
497 static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface,
498                                       LPUNKNOWN lpUnkServer)
499 {
500   RemUnkStub *This = (RemUnkStub *)iface;
501   TRACE("(%p)->Connect(%p)\n",This,lpUnkServer);
502   This->iface = (IRemUnknown*)lpUnkServer;
503   IRemUnknown_AddRef(This->iface);
504   return S_OK;
505 }
506
507 static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface)
508 {
509   RemUnkStub *This = (RemUnkStub *)iface;
510   TRACE("(%p)->Disconnect()\n",This);
511   IUnknown_Release(This->iface);
512   This->iface = NULL;
513 }
514
515 static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface,
516                                      PRPCOLEMESSAGE pMsg,
517                                      LPRPCCHANNELBUFFER pChannel)
518 {
519   RemUnkStub *This = (RemUnkStub *)iface;
520   ULONG iMethod = pMsg->iMethod;
521   LPBYTE buf = pMsg->Buffer;
522   HRESULT hr = RPC_E_INVALIDMETHOD;
523
524   TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod);
525   switch (iMethod)
526   {
527   case 3: /* RemQueryInterface */
528   {
529     IPID ipid;
530     ULONG cRefs;
531     USHORT cIids;
532     IID *iids;
533     REMQIRESULT *pQIResults = NULL;
534
535     /* in */
536     memcpy(&ipid, buf, sizeof(ipid));
537     buf += sizeof(ipid);
538     memcpy(&cRefs, buf, sizeof(cRefs));
539     buf += sizeof(cRefs);
540     memcpy(&cIids, buf, sizeof(cIids));
541     buf += sizeof(cIids);
542     iids = (IID *)buf;
543
544     hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults);
545
546     /* out */
547     pMsg->cbBuffer = cIids * sizeof(REMQIRESULT);
548
549     I_RpcGetBuffer((RPC_MESSAGE *)pMsg);
550     if (hr) return hr;
551
552     buf = pMsg->Buffer;
553     /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */
554     memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT));
555
556     break;
557   }
558   case 4: /* RemAddRef */
559   {
560     USHORT cIids;
561     REMINTERFACEREF *ir;
562     HRESULT *pResults;
563
564     /* in */
565     memcpy(&cIids, buf, sizeof(USHORT));
566     buf += sizeof(USHORT);
567     ir = (REMINTERFACEREF*)buf;
568     pResults = CoTaskMemAlloc(cIids * sizeof(HRESULT));
569     if (!pResults) return E_OUTOFMEMORY;
570
571     hr = IRemUnknown_RemAddRef(This->iface, cIids, ir, pResults);
572
573     /* out */
574     pMsg->cbBuffer = cIids * sizeof(HRESULT);
575
576     I_RpcGetBuffer((RPC_MESSAGE *)pMsg);
577     if (!hr)
578     {
579         buf = pMsg->Buffer;
580         memcpy(buf, pResults, cIids * sizeof(HRESULT));
581     }
582
583     CoTaskMemFree(pResults);
584
585     break;
586   }
587   case 5: /* RemRelease */
588   {
589     USHORT cIids;
590     REMINTERFACEREF *ir;
591
592     /* in */
593     memcpy(&cIids, buf, sizeof(USHORT));
594     buf += sizeof(USHORT);
595     ir = (REMINTERFACEREF*)buf;
596
597     hr = IRemUnknown_RemRelease(This->iface, cIids, ir);
598
599     /* out */
600     pMsg->cbBuffer = 0;
601     break;
602   }
603   }
604   return hr;
605 }
606
607 static LPRPCSTUBBUFFER WINAPI RemUnkStub_IsIIDSupported(LPRPCSTUBBUFFER iface,
608                                                      REFIID riid)
609 {
610   RemUnkStub *This = (RemUnkStub *)iface;
611   TRACE("(%p)->IsIIDSupported(%s)\n", This, debugstr_guid(riid));
612   return IsEqualGUID(&IID_IRemUnknown, riid) ? iface : NULL;
613 }
614
615 static ULONG WINAPI RemUnkStub_CountRefs(LPRPCSTUBBUFFER iface)
616 {
617   RemUnkStub *This = (RemUnkStub *)iface;
618   FIXME("(%p)->CountRefs()\n", This);
619   return 1;
620 }
621
622 static HRESULT WINAPI RemUnkStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,
623                                                         LPVOID *ppv)
624 {
625   RemUnkStub *This = (RemUnkStub *)iface;
626   FIXME("(%p)->DebugServerQueryInterface(%p)\n",This,ppv);
627   return E_NOINTERFACE;
628 }
629
630 static void WINAPI RemUnkStub_DebugServerRelease(LPRPCSTUBBUFFER iface,
631                                               LPVOID pv)
632 {
633   RemUnkStub *This = (RemUnkStub *)iface;
634   FIXME("(%p)->DebugServerRelease(%p)\n", This, pv);
635 }
636
637 static const IRpcStubBufferVtbl RemUnkStub_VTable =
638 {
639   RemUnkStub_QueryInterface,
640   RemUnkStub_AddRef,
641   RemUnkStub_Release,
642   RemUnkStub_Connect,
643   RemUnkStub_Disconnect,
644   RemUnkStub_Invoke,
645   RemUnkStub_IsIIDSupported,
646   RemUnkStub_CountRefs,
647   RemUnkStub_DebugServerQueryInterface,
648   RemUnkStub_DebugServerRelease
649 };
650
651 static HRESULT RemUnkStub_Construct(IRpcStubBuffer **ppStub)
652 {
653     RemUnkStub *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
654     if (!This) return E_OUTOFMEMORY;
655     This->lpVtbl = &RemUnkStub_VTable;
656     This->refs = 0;
657     This->iface = NULL;
658     *ppStub = (IRpcStubBuffer*)This;
659     return S_OK;
660 }
661
662
663 typedef struct _RemUnkProxy {
664     const IRemUnknownVtbl               *lpvtbl_remunk;
665     const IRpcProxyBufferVtbl   *lpvtbl_proxy;
666     DWORD                               refs;
667
668     IRpcChannelBuffer                   *chan;
669     IUnknown *outer_unknown;
670 } RemUnkProxy;
671
672 static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid, void **ppv)
673 {
674     RemUnkProxy *This = (RemUnkProxy *)iface;
675     if (This->outer_unknown)
676         return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
677     if (IsEqualIID(riid, &IID_IUnknown) ||
678         IsEqualIID(riid, &IID_IRemUnknown))
679     {
680         IRemUnknown_AddRef(iface);
681         *ppv = (LPVOID)iface;
682         return S_OK;
683     }
684     return E_NOINTERFACE;
685 }
686
687 static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface)
688 {
689   RemUnkProxy *This = (RemUnkProxy *)iface;
690
691   TRACE("(%p)->AddRef()\n",This);
692   return InterlockedIncrement(&This->refs);
693 }
694
695 static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface)
696 {
697   RemUnkProxy *This = (RemUnkProxy *)iface;
698   ULONG refs;
699
700   TRACE("(%p)->Release()\n",This);
701   if (This->outer_unknown)
702       refs = IUnknown_Release(This->outer_unknown);
703   else    
704       refs = InterlockedDecrement(&This->refs);
705
706   if (!refs) {
707       if (This->chan) IRpcChannelBuffer_Release(This->chan);
708       HeapFree(GetProcessHeap(),0,This);
709   }
710   return refs;
711 }
712
713 static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface,
714                                                  REFIPID ripid,
715                                                  ULONG cRefs,
716                                                  USHORT cIids,
717                                                  IID* iids,
718                                                  REMQIRESULT** ppQIResults)
719 {
720   RemUnkProxy *This = (RemUnkProxy *)iface;
721   RPCOLEMESSAGE msg;
722   HRESULT hr = S_OK;
723   ULONG status;
724
725   TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This,
726         debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults);
727
728   *ppQIResults = NULL;
729   memset(&msg, 0, sizeof(msg));
730   msg.iMethod = 3;
731   msg.cbBuffer = sizeof(IPID) + sizeof(ULONG) +
732     sizeof(USHORT) + cIids*sizeof(IID);
733   hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
734   if (SUCCEEDED(hr)) {
735     LPBYTE buf = msg.Buffer;
736     memcpy(buf, ripid, sizeof(IPID));
737     buf += sizeof(IPID);
738     memcpy(buf, &cRefs, sizeof(ULONG));
739     buf += sizeof(ULONG);
740     memcpy(buf, &cIids, sizeof(USHORT));
741     buf += sizeof(USHORT);
742     memcpy(buf, iids, cIids*sizeof(IID));
743
744     hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
745
746     if (SUCCEEDED(hr)) {
747       buf = msg.Buffer;
748       *ppQIResults = CoTaskMemAlloc(cIids*sizeof(REMQIRESULT));
749       memcpy(*ppQIResults, buf, cIids*sizeof(REMQIRESULT));
750     }
751
752     IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
753   }
754
755   return hr;
756 }
757
758 static HRESULT WINAPI RemUnkProxy_RemAddRef(LPREMUNKNOWN iface,
759                                          USHORT cInterfaceRefs,
760                                          REMINTERFACEREF* InterfaceRefs,
761                                          HRESULT* pResults)
762 {
763   RemUnkProxy *This = (RemUnkProxy *)iface;
764   RPCOLEMESSAGE msg;
765   HRESULT hr = S_OK;
766   ULONG status;
767
768   TRACE("(%p)->(%d,%p,%p)\n",This,
769         cInterfaceRefs,InterfaceRefs,pResults);
770
771   memset(&msg, 0, sizeof(msg));
772   msg.iMethod = 4;
773   msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);
774   hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
775   if (SUCCEEDED(hr)) {
776     LPBYTE buf = msg.Buffer;
777     memcpy(buf, &cInterfaceRefs, sizeof(USHORT));
778     buf += sizeof(USHORT);
779     memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));
780
781     hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
782
783     if (SUCCEEDED(hr)) {
784       buf = msg.Buffer;
785       memcpy(pResults, buf, cInterfaceRefs*sizeof(HRESULT));
786     }
787
788     IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
789   }
790
791   return hr;
792 }
793
794 static HRESULT WINAPI RemUnkProxy_RemRelease(LPREMUNKNOWN iface,
795                                           USHORT cInterfaceRefs,
796                                           REMINTERFACEREF* InterfaceRefs)
797 {
798   RemUnkProxy *This = (RemUnkProxy *)iface;
799   RPCOLEMESSAGE msg;
800   HRESULT hr = S_OK;
801   ULONG status;
802
803   TRACE("(%p)->(%d,%p)\n",This,
804         cInterfaceRefs,InterfaceRefs);
805
806   memset(&msg, 0, sizeof(msg));
807   msg.iMethod = 5;
808   msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);
809   hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
810   if (SUCCEEDED(hr)) {
811     LPBYTE buf = msg.Buffer;
812     memcpy(buf, &cInterfaceRefs, sizeof(USHORT));
813     buf += sizeof(USHORT);
814     memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));
815
816     hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
817
818     IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
819   }
820
821   return hr;
822 }
823
824 static const IRemUnknownVtbl RemUnkProxy_VTable =
825 {
826   RemUnkProxy_QueryInterface,
827   RemUnkProxy_AddRef,
828   RemUnkProxy_Release,
829   RemUnkProxy_RemQueryInterface,
830   RemUnkProxy_RemAddRef,
831   RemUnkProxy_RemRelease
832 };
833
834
835 static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
836     *ppv = NULL;
837     if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
838         IRpcProxyBuffer_AddRef(iface);
839         *ppv = (LPVOID)iface;
840         return S_OK;
841     }
842     FIXME("(%s), no interface.\n",debugstr_guid(riid));
843     return E_NOINTERFACE;
844 }
845
846 static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
847     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
848     return InterlockedIncrement(&This->refs);
849 }
850
851 static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
852     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
853     ULONG ref = InterlockedDecrement(&This->refs);
854
855     if (!ref) {
856         IRpcChannelBuffer_Release(This->chan);This->chan = NULL;
857         HeapFree(GetProcessHeap(),0,This);
858     }
859     return ref;
860 }
861
862 static HRESULT WINAPI RURpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
863     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
864
865     This->chan = pRpcChannelBuffer;
866     IRpcChannelBuffer_AddRef(This->chan);
867     return S_OK;
868 }
869 static void WINAPI RURpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
870     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
871     if (This->chan) {
872         IRpcChannelBuffer_Release(This->chan);
873         This->chan = NULL;
874     }
875 }
876
877
878 static const IRpcProxyBufferVtbl RURpcProxyBuffer_VTable = {
879     RURpcProxyBufferImpl_QueryInterface,
880     RURpcProxyBufferImpl_AddRef,
881     RURpcProxyBufferImpl_Release,
882     RURpcProxyBufferImpl_Connect,
883     RURpcProxyBufferImpl_Disconnect
884 };
885
886 static HRESULT
887 RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
888     RemUnkProxy *This;
889
890     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*This));
891     if (!This)
892         return E_OUTOFMEMORY;
893
894     This->lpvtbl_remunk = &RemUnkProxy_VTable;
895     This->lpvtbl_proxy  = &RURpcProxyBuffer_VTable;
896     /* only one reference for the proxy buffer */
897     This->refs          = 1;
898     This->outer_unknown = pUnkOuter;
899     *ppv                = &(This->lpvtbl_remunk);
900     *ppProxy            = &(This->lpvtbl_proxy);
901     return S_OK;
902 }
903
904
905 /********************* OLE Proxy/Stub Factory ********************************/
906 static HRESULT WINAPI
907 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
908     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
909         *ppv = (LPVOID)iface;
910         /* No ref counting, static class */
911         return S_OK;
912     }
913     FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
914     return E_NOINTERFACE;
915 }
916
917 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
918 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
919
920 static HRESULT WINAPI
921 PSFacBuf_CreateProxy(
922     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
923     IRpcProxyBuffer **ppProxy, LPVOID *ppv
924 ) {
925     if (IsEqualIID(&IID_IClassFactory,riid))
926         return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);
927     else if (IsEqualIID(&IID_IRemUnknown,riid))
928         return RemUnkProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);
929     FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid));
930     return E_FAIL;
931 }
932
933 static HRESULT WINAPI
934 PSFacBuf_CreateStub(
935     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
936     IRpcStubBuffer** ppStub
937 ) {
938     HRESULT hres;
939
940     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
941
942     if (IsEqualIID(&IID_IClassFactory, riid) ||
943         IsEqualIID(&IID_IUnknown, riid) /* FIXME: fixup stub manager and remove this*/) {
944         hres = CFStub_Construct(ppStub);
945         if (!hres)
946             IRpcStubBuffer_Connect((*ppStub),pUnkServer);
947         return hres;
948     } else if (IsEqualIID(&IID_IRemUnknown,riid)) {
949         hres = RemUnkStub_Construct(ppStub);
950         if (!hres)
951             IRpcStubBuffer_Connect((*ppStub),pUnkServer);
952         return hres;
953     }
954     FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));
955     return E_FAIL;
956 }
957
958 static IPSFactoryBufferVtbl psfacbufvtbl = {
959     PSFacBuf_QueryInterface,
960     PSFacBuf_AddRef,
961     PSFacBuf_Release,
962     PSFacBuf_CreateProxy,
963     PSFacBuf_CreateStub
964 };
965
966 /* This is the whole PSFactoryBuffer object, just the vtableptr */
967 static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
968
969 /***********************************************************************
970  *           DllGetClassObject [OLE32.@]
971  */
972 HRESULT WINAPI OLE32_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
973 {
974     *ppv = NULL;
975     if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer))
976         return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv);
977     if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&(
978                 IsEqualIID(iid,&IID_IClassFactory) ||
979                 IsEqualIID(iid,&IID_IUnknown)
980         )
981     )
982         return MARSHAL_GetStandardMarshalCF(ppv);
983     if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown)))
984         return StdGlobalInterfaceTable_GetFactory(ppv);
985     if (IsEqualCLSID(rclsid, &CLSID_FileMoniker))
986         return FileMonikerCF_Create(iid, ppv);
987     if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker))
988         return ItemMonikerCF_Create(iid, ppv);
989
990     FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
991     return CLASS_E_CLASSNOTAVAILABLE;
992 }