- Implement CoDisconnectObject.
[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
61 #include "wine/debug.h"
62
63 WINE_DEFAULT_DEBUG_CHANNEL(ole);
64
65 const CLSID CLSID_DfMarshal       = { 0x0000030b, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
66 const CLSID CLSID_PSFactoryBuffer = { 0x00000320, 0, 0, {0xc0, 0, 0, 0, 0, 0, 0, 0x46} };
67
68 /* From: http://msdn.microsoft.com/library/en-us/com/cmi_m_4lda.asp
69  *
70  * The first time a client requests a pointer to an interface on a
71  * particular object, COM loads an IClassFactory stub in the server
72  * process and uses it to marshal the first pointer back to the
73  * client. In the client process, COM loads the generic proxy for the
74  * class factory object and calls its implementation of IMarshal to
75  * unmarshal that first pointer. COM then creates the first interface
76  * proxy and hands it a pointer to the RPC channel. Finally, COM returns
77  * the IClassFactory pointer to the client, which uses it to call
78  * IClassFactory::CreateInstance, passing it a reference to the interface.
79  *
80  * Back in the server process, COM now creates a new instance of the
81  * object, along with a stub for the requested interface. This stub marshals
82  * the interface pointer back to the client process, where another object
83  * proxy is created, this time for the object itself. Also created is a
84  * proxy for the requested interface, a pointer to which is returned to
85  * the client. With subsequent calls to other interfaces on the object,
86  * COM will load the appropriate interface stubs and proxies as needed.
87  */
88 typedef struct _CFStub {
89     IRpcStubBufferVtbl  *lpvtbl;
90     DWORD                       ref;
91
92     LPUNKNOWN                   pUnkServer;
93 } CFStub;
94
95 static HRESULT WINAPI
96 CFStub_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
97     if (IsEqualIID(&IID_IUnknown,riid)||IsEqualIID(&IID_IRpcStubBuffer,riid)) {
98         *ppv = (LPVOID)iface;
99         IUnknown_AddRef(iface);
100         return S_OK;
101     }
102     FIXME("(%s), interface not supported.\n",debugstr_guid(riid));
103     return E_NOINTERFACE;
104 }
105
106 static ULONG WINAPI
107 CFStub_AddRef(LPRPCSTUBBUFFER iface) {
108     CFStub *This = (CFStub *)iface;
109     return InterlockedIncrement(&This->ref);
110 }
111
112 static ULONG WINAPI
113 CFStub_Release(LPRPCSTUBBUFFER iface) {
114     CFStub *This = (CFStub *)iface;
115     ULONG ref;
116
117     ref = InterlockedDecrement(&This->ref);
118     if (!ref) HeapFree(GetProcessHeap(),0,This);
119     return ref;
120 }
121
122 static HRESULT WINAPI
123 CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
124     CFStub *This = (CFStub *)iface;
125
126     This->pUnkServer = pUnkServer;
127     IUnknown_AddRef(pUnkServer);
128     return S_OK;
129 }
130
131 static void WINAPI
132 CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
133     CFStub *This = (CFStub *)iface;
134
135     IUnknown_Release(This->pUnkServer);
136     This->pUnkServer = NULL;
137 }
138 static HRESULT WINAPI
139 CFStub_Invoke(
140     LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
141 ) {
142     CFStub *This = (CFStub *)iface;
143     HRESULT hres;
144
145     if (msg->iMethod == 3) { /* CreateInstance */
146         IID iid;
147         IClassFactory   *classfac;
148         IUnknown        *ppv;
149         IStream         *pStm;
150         STATSTG         ststg;
151         ULARGE_INTEGER  newpos;
152         LARGE_INTEGER   seekto;
153         ULONG           res;
154
155         if (msg->cbBuffer < sizeof(IID)) {
156             FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
157             return E_FAIL;
158         }
159         memcpy(&iid,msg->Buffer,sizeof(iid));
160         TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));
161         hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);
162         if (hres) {
163             FIXME("Ole server does not provide a IClassFactory?\n");
164             return hres;
165         }
166         hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
167         IClassFactory_Release(classfac);
168         if (hres) {
169             msg->cbBuffer = 0;
170             FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
171             return hres;
172         }
173         hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
174         if (hres) {
175             FIXME("Failed to create stream on hglobal\n");
176             return hres;
177         }
178         hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
179         IUnknown_Release((IUnknown*)ppv);
180         if (hres) {
181             FIXME("CoMarshalInterface failed, %lx!\n",hres);
182             msg->cbBuffer = 0;
183             return hres;
184         }
185         hres = IStream_Stat(pStm,&ststg,0);
186         if (hres) {
187             FIXME("Stat failed.\n");
188             return hres;
189         }
190
191         msg->cbBuffer = ststg.cbSize.u.LowPart;
192
193         if (msg->Buffer)
194             msg->Buffer = HeapReAlloc(GetProcessHeap(),0,msg->Buffer,ststg.cbSize.u.LowPart);
195         else
196             msg->Buffer = HeapAlloc(GetProcessHeap(),0,ststg.cbSize.u.LowPart);
197
198         seekto.u.LowPart = 0;seekto.u.HighPart = 0;
199         hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
200         if (hres) {
201             FIXME("IStream_Seek failed, %lx\n",hres);
202             return hres;
203         }
204         hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
205         if (hres) {
206             FIXME("Stream Read failed, %lx\n",hres);
207             return hres;
208         }
209         IStream_Release(pStm);
210         return S_OK;
211     }
212     FIXME("(%p,%p), stub!\n",msg,chanbuf);
213     FIXME("iMethod is %ld\n",msg->iMethod);
214     FIXME("cbBuffer is %ld\n",msg->cbBuffer);
215     return E_FAIL;
216 }
217
218 static LPRPCSTUBBUFFER WINAPI
219 CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
220     FIXME("(%s), stub!\n",debugstr_guid(riid));
221     return NULL;
222 }
223
224 static ULONG WINAPI
225 CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
226     FIXME("(), stub!\n");
227     return 1;
228 }
229
230 static HRESULT WINAPI
231 CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
232     FIXME("(%p), stub!\n",ppv);
233     return E_FAIL;
234 }
235 static void    WINAPI
236 CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
237     FIXME("(%p), stub!\n",pv);
238 }
239
240 static IRpcStubBufferVtbl cfstubvt = {
241     CFStub_QueryInterface,
242     CFStub_AddRef,
243     CFStub_Release,
244     CFStub_Connect,
245     CFStub_Disconnect,
246     CFStub_Invoke,
247     CFStub_IsIIDSupported,
248     CFStub_CountRefs,
249     CFStub_DebugServerQueryInterface,
250     CFStub_DebugServerRelease
251 };
252
253 static HRESULT
254 CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
255     CFStub *cfstub;
256     cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
257     if (!cfstub)
258         return E_OUTOFMEMORY;
259     *ppv = (LPRPCSTUBBUFFER)cfstub;
260     cfstub->lpvtbl      = &cfstubvt;
261     cfstub->ref         = 1;
262     return S_OK;
263 }
264
265 /* Since we create proxy buffers and classfactory in a pair, there is
266  * no need for 2 separate structs. Just put them in one, but remember
267  * the refcount.
268  */
269 typedef struct _CFProxy {
270     const IClassFactoryVtbl             *lpvtbl_cf;
271     const IRpcProxyBufferVtbl   *lpvtbl_proxy;
272     DWORD                               ref;
273
274     IRpcChannelBuffer                   *chanbuf;
275     IUnknown *outer_unknown;
276 } CFProxy;
277
278 static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
279     *ppv = NULL;
280     if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
281         IRpcProxyBuffer_AddRef(iface);
282         *ppv = (LPVOID)iface;
283         return S_OK;
284     }
285     FIXME("(%s), no interface.\n",debugstr_guid(riid));
286     return E_NOINTERFACE;
287 }
288
289 static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
290     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
291     return InterlockedIncrement(&This->ref);
292 }
293
294 static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
295     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
296     ULONG ref = InterlockedDecrement(&This->ref);
297
298     if (!ref) {
299         IRpcChannelBuffer_Release(This->chanbuf);This->chanbuf = NULL;
300         HeapFree(GetProcessHeap(),0,This);
301     }
302     return ref;
303 }
304
305 static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
306     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
307
308     This->chanbuf = pRpcChannelBuffer;
309     IRpcChannelBuffer_AddRef(This->chanbuf);
310     return S_OK;
311 }
312 static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
313     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
314     if (This->chanbuf) {
315         IRpcChannelBuffer_Release(This->chanbuf);
316         This->chanbuf = NULL;
317     }
318 }
319
320 static HRESULT WINAPI
321 CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
322     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
323     if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
324     *ppv = NULL;
325     if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
326         *ppv = (LPVOID)iface;
327         IClassFactory_AddRef(iface);
328         return S_OK;
329     }
330     if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */
331         return E_NOINTERFACE;
332     FIXME("Unhandled interface: %s\n",debugstr_guid(riid));
333     return E_NOINTERFACE;
334 }
335
336 static ULONG   WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
337     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
338     if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown);
339     return InterlockedIncrement(&This->ref);
340 }
341
342 static ULONG   WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
343     ULONG ref;
344     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
345     if (This->outer_unknown)
346         ref = IUnknown_Release(This->outer_unknown);
347     else    
348         ref = InterlockedDecrement(&This->ref);
349
350     if (!ref) {
351         if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
352         HeapFree(GetProcessHeap(),0,This);
353     }
354     return ref;
355 }
356
357 static HRESULT WINAPI CFProxy_CreateInstance(
358     LPCLASSFACTORY iface,
359     LPUNKNOWN pUnkOuter,/* [in] */
360     REFIID riid,        /* [in] */
361     LPVOID *ppv         /* [out] */
362 ) {
363     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
364     HRESULT             hres;
365     LPSTREAM            pStream;
366     HGLOBAL             hGlobal;
367     ULONG               srstatus;
368     RPCOLEMESSAGE       msg;
369
370     TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
371
372     /* Send CreateInstance to the remote classfactory.
373      *
374      * Data: Only the 'IID'.
375      */
376     msg.iMethod  = 3;
377     msg.cbBuffer = sizeof(*riid);
378     msg.Buffer   = NULL;
379     hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
380     if (hres) {
381         FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
382         return hres;
383     }
384     memcpy(msg.Buffer,riid,sizeof(*riid));
385     hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
386     if (hres) {
387         FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
388         return hres;
389     }
390
391     if (!msg.cbBuffer) /* interface not found on remote */
392         return srstatus;
393
394     /* We got back: [Marshalled Interface data] */
395     TRACE("got %ld bytes data.\n",msg.cbBuffer);
396     hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);
397     memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);
398     hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
399     if (hres) {
400         FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
401         return hres;
402     }
403     hres = CoUnmarshalInterface(
404             pStream,
405             riid,
406             ppv
407     );
408     IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
409     if (hres) {
410         FIXME("CoMarshalInterface failed, %lx\n",hres);
411         return hres;
412     }
413     return S_OK;
414 }
415
416 static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {
417     /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/
418     FIXME("(%d), stub!\n",fLock);
419     /* basically: write BOOL, read empty */
420     return S_OK;
421 }
422
423 static IRpcProxyBufferVtbl pspbvtbl = {
424     IRpcProxyBufferImpl_QueryInterface,
425     IRpcProxyBufferImpl_AddRef,
426     IRpcProxyBufferImpl_Release,
427     IRpcProxyBufferImpl_Connect,
428     IRpcProxyBufferImpl_Disconnect
429 };
430 static IClassFactoryVtbl cfproxyvt = {
431     CFProxy_QueryInterface,
432     CFProxy_AddRef,
433     CFProxy_Release,
434     CFProxy_CreateInstance,
435     CFProxy_LockServer
436 };
437
438 static HRESULT
439 CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
440     CFProxy *cf;
441
442     cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
443     if (!cf)
444         return E_OUTOFMEMORY;
445
446     cf->lpvtbl_cf       = &cfproxyvt;
447     cf->lpvtbl_proxy    = &pspbvtbl;
448     /* only one reference for the proxy buffer */
449     cf->ref             = 1;
450     cf->outer_unknown = pUnkOuter;
451     *ppv                = &(cf->lpvtbl_cf);
452     *ppProxy            = &(cf->lpvtbl_proxy);
453     return S_OK;
454 }
455
456
457 /********************* IRemUnknown Proxy/Stub ********************************/
458
459 typedef struct
460 {
461     const IRpcStubBufferVtbl *lpVtbl;
462     ULONG refs;
463     IRemUnknown *iface;
464 } RemUnkStub;
465
466 static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface,
467                                              REFIID riid,
468                                              LPVOID *obj)
469 {
470   RemUnkStub *This = (RemUnkStub *)iface;
471   TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);
472   if (IsEqualGUID(&IID_IUnknown,riid) ||
473       IsEqualGUID(&IID_IRpcStubBuffer,riid)) {
474     *obj = This;
475     return S_OK;
476   }
477   return E_NOINTERFACE;
478 }
479
480 static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface)
481 {
482   RemUnkStub *This = (RemUnkStub *)iface;
483   TRACE("(%p)->AddRef()\n",This);
484   return InterlockedIncrement(&This->refs);
485 }
486
487 static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface)
488 {
489   RemUnkStub *This = (RemUnkStub *)iface;
490   ULONG refs;
491   TRACE("(%p)->Release()\n",This);
492   refs = InterlockedDecrement(&This->refs);
493   if (!refs)
494     HeapFree(GetProcessHeap(), 0, This);
495   return refs;
496 }
497
498 static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface,
499                                       LPUNKNOWN lpUnkServer)
500 {
501   RemUnkStub *This = (RemUnkStub *)iface;
502   TRACE("(%p)->Connect(%p)\n",This,lpUnkServer);
503   This->iface = (IRemUnknown*)lpUnkServer;
504   IRemUnknown_AddRef(This->iface);
505   return S_OK;
506 }
507
508 static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface)
509 {
510   RemUnkStub *This = (RemUnkStub *)iface;
511   TRACE("(%p)->Disconnect()\n",This);
512   IUnknown_Release(This->iface);
513   This->iface = NULL;
514 }
515
516 static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface,
517                                      PRPCOLEMESSAGE pMsg,
518                                      LPRPCCHANNELBUFFER pChannel)
519 {
520   RemUnkStub *This = (RemUnkStub *)iface;
521   ULONG iMethod = pMsg->iMethod;
522   LPBYTE buf = pMsg->Buffer;
523   HRESULT hr = RPC_E_INVALIDMETHOD;
524
525   TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod);
526   switch (iMethod)
527   {
528   case 3: /* RemQueryInterface */
529   {
530     IPID ipid;
531     ULONG cRefs;
532     USHORT cIids;
533     IID *iids;
534     REMQIRESULT *pQIResults = NULL;
535
536     /* in */
537     memcpy(&ipid, buf, sizeof(ipid));
538     buf += sizeof(ipid);
539     memcpy(&cRefs, buf, sizeof(cRefs));
540     buf += sizeof(cRefs);
541     memcpy(&cIids, buf, sizeof(cIids));
542     buf += sizeof(cIids);
543     iids = (IID *)buf;
544
545     hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults);
546
547     /* out */
548     pMsg->cbBuffer = cIids * sizeof(REMQIRESULT);
549     if (pMsg->Buffer)
550         pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->cbBuffer);
551         else
552         pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->cbBuffer);
553     buf = pMsg->Buffer;
554     /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */
555     memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT));
556
557     break;
558   }
559   case 4: /* RemAddRef */
560   {
561     USHORT cIids;
562     REMINTERFACEREF *ir;
563     HRESULT *pResults;
564
565     /* in */
566     memcpy(&cIids, buf, sizeof(USHORT));
567     buf += sizeof(USHORT);
568     ir = (REMINTERFACEREF*)buf;
569     pResults = CoTaskMemAlloc(cIids * sizeof(HRESULT));
570     if (!pResults) return E_OUTOFMEMORY;
571
572     hr = IRemUnknown_RemAddRef(This->iface, cIids, ir, pResults);
573
574     /* out */
575     pMsg->cbBuffer = cIids * sizeof(HRESULT);
576     if (pMsg->Buffer)
577         pMsg->Buffer = HeapReAlloc(GetProcessHeap(), 0, pMsg->Buffer, pMsg->cbBuffer);
578         else
579         pMsg->Buffer = HeapAlloc(GetProcessHeap(), 0, pMsg->cbBuffer);
580     buf = pMsg->Buffer;
581     memcpy(buf, pResults, cIids * sizeof(HRESULT));
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         *ppv = &lppsfac;
977         return S_OK;
978     }
979     if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&(
980                 IsEqualIID(iid,&IID_IClassFactory) ||
981                 IsEqualIID(iid,&IID_IUnknown)
982         )
983     )
984         return MARSHAL_GetStandardMarshalCF(ppv);
985     if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown)))
986         return StdGlobalInterfaceTable_GetFactory(ppv);
987
988     FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
989     return CLASS_E_CLASSNOTAVAILABLE;
990 }