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