Fix an error introduced when converting dialog lists to standard
[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     const IRpcStubBufferVtbl   *lpvtbl;
91     LONG                        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) {
120         IRpcStubBuffer_Disconnect(iface);
121         HeapFree(GetProcessHeap(),0,This);
122     }
123     return ref;
124 }
125
126 static HRESULT WINAPI
127 CFStub_Connect(LPRPCSTUBBUFFER iface, IUnknown *pUnkServer) {
128     CFStub *This = (CFStub *)iface;
129
130     This->pUnkServer = pUnkServer;
131     IUnknown_AddRef(pUnkServer);
132     return S_OK;
133 }
134
135 static void WINAPI
136 CFStub_Disconnect(LPRPCSTUBBUFFER iface) {
137     CFStub *This = (CFStub *)iface;
138
139     if (This->pUnkServer) {
140         IUnknown_Release(This->pUnkServer);
141         This->pUnkServer = NULL;
142     }
143 }
144
145 static HRESULT WINAPI
146 CFStub_Invoke(
147     LPRPCSTUBBUFFER iface,RPCOLEMESSAGE* msg,IRpcChannelBuffer* chanbuf
148 ) {
149     CFStub *This = (CFStub *)iface;
150     HRESULT hres;
151
152     if (msg->iMethod == 3) { /* CreateInstance */
153         IID iid;
154         IClassFactory   *classfac;
155         IUnknown        *ppv;
156         IStream         *pStm;
157         STATSTG         ststg;
158         ULARGE_INTEGER  newpos;
159         LARGE_INTEGER   seekto;
160         ULONG           res;
161
162         if (msg->cbBuffer < sizeof(IID)) {
163             FIXME("Not enough bytes in buffer (%ld instead of %d)?\n",msg->cbBuffer,sizeof(IID));
164             return E_FAIL;
165         }
166         memcpy(&iid,msg->Buffer,sizeof(iid));
167         TRACE("->CreateInstance(%s)\n",debugstr_guid(&iid));
168         hres = IUnknown_QueryInterface(This->pUnkServer,&IID_IClassFactory,(LPVOID*)&classfac);
169         if (hres) {
170             FIXME("Ole server does not provide an IClassFactory?\n");
171             return hres;
172         }
173         hres = IClassFactory_CreateInstance(classfac,NULL,&iid,(LPVOID*)&ppv);
174         IClassFactory_Release(classfac);
175         if (hres) {
176             msg->cbBuffer = 0;
177             FIXME("Failed to create an instance of %s\n",debugstr_guid(&iid));
178             return hres;
179         }
180         hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
181         if (hres) {
182             FIXME("Failed to create stream on hglobal\n");
183             return hres;
184         }
185         hres = CoMarshalInterface(pStm,&iid,ppv,0,NULL,0);
186         IUnknown_Release((IUnknown*)ppv);
187         if (hres) {
188             FIXME("CoMarshalInterface failed, %lx!\n",hres);
189             msg->cbBuffer = 0;
190             return hres;
191         }
192         hres = IStream_Stat(pStm,&ststg,0);
193         if (hres) {
194             FIXME("Stat failed.\n");
195             return hres;
196         }
197
198         msg->cbBuffer = ststg.cbSize.u.LowPart;
199
200         I_RpcGetBuffer((RPC_MESSAGE *)msg);
201         if (hres) return hres;
202
203         seekto.u.LowPart = 0;seekto.u.HighPart = 0;
204         hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
205         if (hres) {
206             FIXME("IStream_Seek failed, %lx\n",hres);
207             return hres;
208         }
209         hres = IStream_Read(pStm,msg->Buffer,msg->cbBuffer,&res);
210         if (hres) {
211             FIXME("Stream Read failed, %lx\n",hres);
212             return hres;
213         }
214         IStream_Release(pStm);
215         return S_OK;
216     }
217     FIXME("(%p,%p), stub!\n",msg,chanbuf);
218     FIXME("iMethod is %ld\n",msg->iMethod);
219     FIXME("cbBuffer is %ld\n",msg->cbBuffer);
220     return E_FAIL;
221 }
222
223 static LPRPCSTUBBUFFER WINAPI
224 CFStub_IsIIDSupported(LPRPCSTUBBUFFER iface,REFIID riid) {
225     FIXME("(%s), stub!\n",debugstr_guid(riid));
226     return NULL;
227 }
228
229 static ULONG WINAPI
230 CFStub_CountRefs(LPRPCSTUBBUFFER iface) {
231     FIXME("(), stub!\n");
232     return 1;
233 }
234
235 static HRESULT WINAPI
236 CFStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,void** ppv) {
237     FIXME("(%p), stub!\n",ppv);
238     return E_FAIL;
239 }
240 static void    WINAPI
241 CFStub_DebugServerRelease(LPRPCSTUBBUFFER iface,void *pv) {
242     FIXME("(%p), stub!\n",pv);
243 }
244
245 static const IRpcStubBufferVtbl cfstubvt = {
246     CFStub_QueryInterface,
247     CFStub_AddRef,
248     CFStub_Release,
249     CFStub_Connect,
250     CFStub_Disconnect,
251     CFStub_Invoke,
252     CFStub_IsIIDSupported,
253     CFStub_CountRefs,
254     CFStub_DebugServerQueryInterface,
255     CFStub_DebugServerRelease
256 };
257
258 static HRESULT
259 CFStub_Construct(LPRPCSTUBBUFFER *ppv) {
260     CFStub *cfstub;
261     cfstub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFStub));
262     if (!cfstub)
263         return E_OUTOFMEMORY;
264     *ppv = (LPRPCSTUBBUFFER)cfstub;
265     cfstub->lpvtbl      = &cfstubvt;
266     cfstub->ref         = 1;
267     return S_OK;
268 }
269
270 /* Since we create proxy buffers and classfactory in a pair, there is
271  * no need for 2 separate structs. Just put them in one, but remember
272  * the refcount.
273  */
274 typedef struct _CFProxy {
275     const IClassFactoryVtbl             *lpvtbl_cf;
276     const IRpcProxyBufferVtbl   *lpvtbl_proxy;
277     LONG                                ref;
278
279     IRpcChannelBuffer                   *chanbuf;
280     IUnknown *outer_unknown;
281 } CFProxy;
282
283 static HRESULT WINAPI IRpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
284     *ppv = NULL;
285     if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
286         IRpcProxyBuffer_AddRef(iface);
287         *ppv = (LPVOID)iface;
288         return S_OK;
289     }
290     FIXME("(%s), no interface.\n",debugstr_guid(riid));
291     return E_NOINTERFACE;
292 }
293
294 static ULONG WINAPI IRpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
295     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
296     return InterlockedIncrement(&This->ref);
297 }
298
299 static ULONG WINAPI IRpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
300     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
301     ULONG ref = InterlockedDecrement(&This->ref);
302
303     if (!ref) {
304         IRpcProxyBuffer_Disconnect(iface);
305         HeapFree(GetProcessHeap(),0,This);
306     }
307     return ref;
308 }
309
310 static HRESULT WINAPI IRpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
311     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
312
313     This->chanbuf = pRpcChannelBuffer;
314     IRpcChannelBuffer_AddRef(This->chanbuf);
315     return S_OK;
316 }
317 static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
318     ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface);
319     if (This->chanbuf) {
320         IRpcChannelBuffer_Release(This->chanbuf);
321         This->chanbuf = NULL;
322     }
323 }
324
325 static HRESULT WINAPI
326 CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) {
327     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
328     if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
329     *ppv = NULL;
330     if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) {
331         *ppv = (LPVOID)iface;
332         IClassFactory_AddRef(iface);
333         return S_OK;
334     }
335     if (IsEqualIID(riid,&IID_IMarshal)) /* just to avoid debug output */
336         return E_NOINTERFACE;
337     FIXME("Unhandled interface: %s\n",debugstr_guid(riid));
338     return E_NOINTERFACE;
339 }
340
341 static ULONG   WINAPI CFProxy_AddRef(LPCLASSFACTORY iface) {
342     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
343     if (This->outer_unknown) return IUnknown_AddRef(This->outer_unknown);
344     return InterlockedIncrement(&This->ref);
345 }
346
347 static ULONG   WINAPI CFProxy_Release(LPCLASSFACTORY iface) {
348     ULONG ref;
349     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
350     if (This->outer_unknown)
351         ref = IUnknown_Release(This->outer_unknown);
352     else    
353         ref = InterlockedDecrement(&This->ref);
354
355     if (!ref) {
356         if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
357         HeapFree(GetProcessHeap(),0,This);
358     }
359     return ref;
360 }
361
362 static HRESULT WINAPI CFProxy_CreateInstance(
363     LPCLASSFACTORY iface,
364     LPUNKNOWN pUnkOuter,/* [in] */
365     REFIID riid,        /* [in] */
366     LPVOID *ppv         /* [out] */
367 ) {
368     ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);
369     HRESULT             hres;
370     LPSTREAM            pStream;
371     HGLOBAL             hGlobal;
372     ULONG               srstatus;
373     RPCOLEMESSAGE       msg;
374
375     TRACE("(%p,%s,%p)\n",pUnkOuter,debugstr_guid(riid),ppv);
376
377     /* Send CreateInstance to the remote classfactory.
378      *
379      * Data: Only the 'IID'.
380      */
381     msg.iMethod  = 3;
382     msg.cbBuffer = sizeof(*riid);
383     msg.Buffer   = NULL;
384     hres = IRpcChannelBuffer_GetBuffer(This->chanbuf,&msg,&IID_IClassFactory);
385     if (hres) {
386         FIXME("IRpcChannelBuffer_GetBuffer failed with %lx?\n",hres);
387         return hres;
388     }
389     memcpy(msg.Buffer,riid,sizeof(*riid));
390     hres = IRpcChannelBuffer_SendReceive(This->chanbuf,&msg,&srstatus);
391     if (hres) {
392         FIXME("IRpcChannelBuffer_SendReceive failed with %lx?\n",hres);
393         return hres;
394     }
395
396     if (!msg.cbBuffer) /* interface not found on remote */
397         return srstatus;
398
399     /* We got back: [Marshalled Interface data] */
400     TRACE("got %ld bytes data.\n",msg.cbBuffer);
401     hGlobal = GlobalAlloc(GMEM_MOVEABLE|GMEM_NODISCARD|GMEM_SHARE,msg.cbBuffer);
402     memcpy(GlobalLock(hGlobal),msg.Buffer,msg.cbBuffer);
403     hres = CreateStreamOnHGlobal(hGlobal,TRUE,&pStream);
404     if (hres) {
405         FIXME("CreateStreamOnHGlobal failed with %lx\n",hres);
406         return hres;
407     }
408     hres = CoUnmarshalInterface(
409             pStream,
410             riid,
411             ppv
412     );
413     IStream_Release(pStream); /* Does GlobalFree hGlobal too. */
414     if (hres) {
415         FIXME("CoMarshalInterface failed, %lx\n",hres);
416         return hres;
417     }
418     return S_OK;
419 }
420
421 static HRESULT WINAPI CFProxy_LockServer(LPCLASSFACTORY iface,BOOL fLock) {
422     /*ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface);*/
423     FIXME("(%d), stub!\n",fLock);
424     /* basically: write BOOL, read empty */
425     return S_OK;
426 }
427
428 static const IRpcProxyBufferVtbl pspbvtbl = {
429     IRpcProxyBufferImpl_QueryInterface,
430     IRpcProxyBufferImpl_AddRef,
431     IRpcProxyBufferImpl_Release,
432     IRpcProxyBufferImpl_Connect,
433     IRpcProxyBufferImpl_Disconnect
434 };
435 static const IClassFactoryVtbl cfproxyvt = {
436     CFProxy_QueryInterface,
437     CFProxy_AddRef,
438     CFProxy_Release,
439     CFProxy_CreateInstance,
440     CFProxy_LockServer
441 };
442
443 static HRESULT
444 CFProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
445     CFProxy *cf;
446
447     cf = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(CFProxy));
448     if (!cf)
449         return E_OUTOFMEMORY;
450
451     cf->lpvtbl_cf       = &cfproxyvt;
452     cf->lpvtbl_proxy    = &pspbvtbl;
453     /* one reference for the proxy buffer */
454     cf->ref             = 1;
455     cf->outer_unknown = pUnkOuter;
456     *ppv                = &(cf->lpvtbl_cf);
457     *ppProxy            = &(cf->lpvtbl_proxy);
458     /* and one reference for the object */
459     IUnknown_AddRef((IUnknown *)*ppv);
460     return S_OK;
461 }
462
463
464 /********************* IRemUnknown Proxy/Stub ********************************/
465
466 typedef struct
467 {
468     const IRpcStubBufferVtbl *lpVtbl;
469     LONG refs;
470     IRemUnknown *iface;
471 } RemUnkStub;
472
473 static HRESULT WINAPI RemUnkStub_QueryInterface(LPRPCSTUBBUFFER iface,
474                                              REFIID riid,
475                                              LPVOID *obj)
476 {
477   RemUnkStub *This = (RemUnkStub *)iface;
478   TRACE("(%p)->QueryInterface(%s,%p)\n",This,debugstr_guid(riid),obj);
479   if (IsEqualGUID(&IID_IUnknown,riid) ||
480       IsEqualGUID(&IID_IRpcStubBuffer,riid)) {
481     *obj = This;
482     return S_OK;
483   }
484   return E_NOINTERFACE;
485 }
486
487 static ULONG WINAPI RemUnkStub_AddRef(LPRPCSTUBBUFFER iface)
488 {
489   RemUnkStub *This = (RemUnkStub *)iface;
490   TRACE("(%p)->AddRef()\n",This);
491   return InterlockedIncrement(&This->refs);
492 }
493
494 static ULONG WINAPI RemUnkStub_Release(LPRPCSTUBBUFFER iface)
495 {
496   RemUnkStub *This = (RemUnkStub *)iface;
497   ULONG refs;
498   TRACE("(%p)->Release()\n",This);
499   refs = InterlockedDecrement(&This->refs);
500   if (!refs)
501     HeapFree(GetProcessHeap(), 0, This);
502   return refs;
503 }
504
505 static HRESULT WINAPI RemUnkStub_Connect(LPRPCSTUBBUFFER iface,
506                                       LPUNKNOWN lpUnkServer)
507 {
508   RemUnkStub *This = (RemUnkStub *)iface;
509   TRACE("(%p)->Connect(%p)\n",This,lpUnkServer);
510   This->iface = (IRemUnknown*)lpUnkServer;
511   IRemUnknown_AddRef(This->iface);
512   return S_OK;
513 }
514
515 static void WINAPI RemUnkStub_Disconnect(LPRPCSTUBBUFFER iface)
516 {
517   RemUnkStub *This = (RemUnkStub *)iface;
518   TRACE("(%p)->Disconnect()\n",This);
519   IUnknown_Release(This->iface);
520   This->iface = NULL;
521 }
522
523 static HRESULT WINAPI RemUnkStub_Invoke(LPRPCSTUBBUFFER iface,
524                                      PRPCOLEMESSAGE pMsg,
525                                      LPRPCCHANNELBUFFER pChannel)
526 {
527   RemUnkStub *This = (RemUnkStub *)iface;
528   ULONG iMethod = pMsg->iMethod;
529   LPBYTE buf = pMsg->Buffer;
530   HRESULT hr = RPC_E_INVALIDMETHOD;
531
532   TRACE("(%p)->Invoke(%p,%p) method %ld\n", This, pMsg, pChannel, iMethod);
533   switch (iMethod)
534   {
535   case 3: /* RemQueryInterface */
536   {
537     IPID ipid;
538     ULONG cRefs;
539     USHORT cIids;
540     IID *iids;
541     REMQIRESULT *pQIResults = NULL;
542
543     /* in */
544     memcpy(&ipid, buf, sizeof(ipid));
545     buf += sizeof(ipid);
546     memcpy(&cRefs, buf, sizeof(cRefs));
547     buf += sizeof(cRefs);
548     memcpy(&cIids, buf, sizeof(cIids));
549     buf += sizeof(cIids);
550     iids = (IID *)buf;
551
552     hr = IRemUnknown_RemQueryInterface(This->iface, &ipid, cRefs, cIids, iids, &pQIResults);
553
554     /* out */
555     pMsg->cbBuffer = cIids * sizeof(REMQIRESULT) + sizeof(HRESULT);
556
557     I_RpcGetBuffer((RPC_MESSAGE *)pMsg);
558
559     buf = pMsg->Buffer;
560     *(HRESULT *)buf = hr;
561     buf += sizeof(HRESULT);
562     
563     if (hr) return hr;
564     /* FIXME: pQIResults is a unique pointer so pQIResults can be NULL! */
565     memcpy(buf, pQIResults, cIids * sizeof(REMQIRESULT));
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     I_RpcGetBuffer((RPC_MESSAGE *)pMsg);
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     break;
613   }
614   }
615   return hr;
616 }
617
618 static LPRPCSTUBBUFFER WINAPI RemUnkStub_IsIIDSupported(LPRPCSTUBBUFFER iface,
619                                                      REFIID riid)
620 {
621   RemUnkStub *This = (RemUnkStub *)iface;
622   TRACE("(%p)->IsIIDSupported(%s)\n", This, debugstr_guid(riid));
623   return IsEqualGUID(&IID_IRemUnknown, riid) ? iface : NULL;
624 }
625
626 static ULONG WINAPI RemUnkStub_CountRefs(LPRPCSTUBBUFFER iface)
627 {
628   RemUnkStub *This = (RemUnkStub *)iface;
629   FIXME("(%p)->CountRefs()\n", This);
630   return 1;
631 }
632
633 static HRESULT WINAPI RemUnkStub_DebugServerQueryInterface(LPRPCSTUBBUFFER iface,
634                                                         LPVOID *ppv)
635 {
636   RemUnkStub *This = (RemUnkStub *)iface;
637   FIXME("(%p)->DebugServerQueryInterface(%p)\n",This,ppv);
638   return E_NOINTERFACE;
639 }
640
641 static void WINAPI RemUnkStub_DebugServerRelease(LPRPCSTUBBUFFER iface,
642                                               LPVOID pv)
643 {
644   RemUnkStub *This = (RemUnkStub *)iface;
645   FIXME("(%p)->DebugServerRelease(%p)\n", This, pv);
646 }
647
648 static const IRpcStubBufferVtbl RemUnkStub_VTable =
649 {
650   RemUnkStub_QueryInterface,
651   RemUnkStub_AddRef,
652   RemUnkStub_Release,
653   RemUnkStub_Connect,
654   RemUnkStub_Disconnect,
655   RemUnkStub_Invoke,
656   RemUnkStub_IsIIDSupported,
657   RemUnkStub_CountRefs,
658   RemUnkStub_DebugServerQueryInterface,
659   RemUnkStub_DebugServerRelease
660 };
661
662 static HRESULT RemUnkStub_Construct(IRpcStubBuffer **ppStub)
663 {
664     RemUnkStub *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
665     if (!This) return E_OUTOFMEMORY;
666     This->lpVtbl = &RemUnkStub_VTable;
667     This->refs = 1;
668     This->iface = NULL;
669     *ppStub = (IRpcStubBuffer*)This;
670     return S_OK;
671 }
672
673
674 typedef struct _RemUnkProxy {
675     const IRemUnknownVtbl               *lpvtbl_remunk;
676     const IRpcProxyBufferVtbl   *lpvtbl_proxy;
677     LONG                                refs;
678
679     IRpcChannelBuffer                   *chan;
680     IUnknown *outer_unknown;
681 } RemUnkProxy;
682
683 static HRESULT WINAPI RemUnkProxy_QueryInterface(LPREMUNKNOWN iface, REFIID riid, void **ppv)
684 {
685     RemUnkProxy *This = (RemUnkProxy *)iface;
686     if (This->outer_unknown)
687         return IUnknown_QueryInterface(This->outer_unknown, riid, ppv);
688     if (IsEqualIID(riid, &IID_IUnknown) ||
689         IsEqualIID(riid, &IID_IRemUnknown))
690     {
691         IRemUnknown_AddRef(iface);
692         *ppv = (LPVOID)iface;
693         return S_OK;
694     }
695     return E_NOINTERFACE;
696 }
697
698 static ULONG WINAPI RemUnkProxy_AddRef(LPREMUNKNOWN iface)
699 {
700   RemUnkProxy *This = (RemUnkProxy *)iface;
701   ULONG refs;
702
703   TRACE("(%p)->AddRef()\n",This);
704
705   if (This->outer_unknown)
706       refs = IUnknown_AddRef(This->outer_unknown);
707   else
708       refs = InterlockedIncrement(&This->refs);
709   return refs;
710 }
711
712 static ULONG WINAPI RemUnkProxy_Release(LPREMUNKNOWN iface)
713 {
714   RemUnkProxy *This = (RemUnkProxy *)iface;
715   ULONG refs;
716
717   TRACE("(%p)->Release()\n",This);
718   if (This->outer_unknown)
719       refs = IUnknown_Release(This->outer_unknown);
720   else    
721       refs = InterlockedDecrement(&This->refs);
722
723   if (!refs) {
724       if (This->chan) IRpcChannelBuffer_Release(This->chan);
725       HeapFree(GetProcessHeap(),0,This);
726   }
727   return refs;
728 }
729
730 static HRESULT WINAPI RemUnkProxy_RemQueryInterface(LPREMUNKNOWN iface,
731                                                  REFIPID ripid,
732                                                  ULONG cRefs,
733                                                  USHORT cIids,
734                                                  IID* iids,
735                                                  REMQIRESULT** ppQIResults)
736 {
737   RemUnkProxy *This = (RemUnkProxy *)iface;
738   RPCOLEMESSAGE msg;
739   HRESULT hr = S_OK;
740   ULONG status;
741
742   TRACE("(%p)->(%s,%ld,%d,%p,%p)\n",This,
743         debugstr_guid(ripid),cRefs,cIids,iids,ppQIResults);
744
745   *ppQIResults = NULL;
746   memset(&msg, 0, sizeof(msg));
747   msg.iMethod = 3;
748   msg.cbBuffer = sizeof(IPID) + sizeof(ULONG) +
749     sizeof(USHORT) + cIids*sizeof(IID);
750   hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
751   if (SUCCEEDED(hr)) {
752     LPBYTE buf = msg.Buffer;
753     memcpy(buf, ripid, sizeof(IPID));
754     buf += sizeof(IPID);
755     memcpy(buf, &cRefs, sizeof(ULONG));
756     buf += sizeof(ULONG);
757     memcpy(buf, &cIids, sizeof(USHORT));
758     buf += sizeof(USHORT);
759     memcpy(buf, iids, cIids*sizeof(IID));
760
761     hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
762
763     buf = msg.Buffer;
764
765     if (SUCCEEDED(hr)) {
766         hr = *(HRESULT *)buf;
767         buf += sizeof(HRESULT);
768     }
769
770     if (SUCCEEDED(hr)) {
771       *ppQIResults = CoTaskMemAlloc(cIids*sizeof(REMQIRESULT));
772       memcpy(*ppQIResults, buf, cIids*sizeof(REMQIRESULT));
773     }
774
775     IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
776   }
777
778   return hr;
779 }
780
781 static HRESULT WINAPI RemUnkProxy_RemAddRef(LPREMUNKNOWN iface,
782                                          USHORT cInterfaceRefs,
783                                          REMINTERFACEREF* InterfaceRefs,
784                                          HRESULT* pResults)
785 {
786   RemUnkProxy *This = (RemUnkProxy *)iface;
787   RPCOLEMESSAGE msg;
788   HRESULT hr = S_OK;
789   ULONG status;
790
791   TRACE("(%p)->(%d,%p,%p)\n",This,
792         cInterfaceRefs,InterfaceRefs,pResults);
793
794   memset(&msg, 0, sizeof(msg));
795   msg.iMethod = 4;
796   msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);
797   hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
798   if (SUCCEEDED(hr)) {
799     LPBYTE buf = msg.Buffer;
800     memcpy(buf, &cInterfaceRefs, sizeof(USHORT));
801     buf += sizeof(USHORT);
802     memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));
803
804     hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
805
806     if (SUCCEEDED(hr)) {
807       buf = msg.Buffer;
808       memcpy(pResults, buf, cInterfaceRefs*sizeof(HRESULT));
809     }
810
811     IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
812   }
813
814   return hr;
815 }
816
817 static HRESULT WINAPI RemUnkProxy_RemRelease(LPREMUNKNOWN iface,
818                                           USHORT cInterfaceRefs,
819                                           REMINTERFACEREF* InterfaceRefs)
820 {
821   RemUnkProxy *This = (RemUnkProxy *)iface;
822   RPCOLEMESSAGE msg;
823   HRESULT hr = S_OK;
824   ULONG status;
825
826   TRACE("(%p)->(%d,%p)\n",This,
827         cInterfaceRefs,InterfaceRefs);
828
829   memset(&msg, 0, sizeof(msg));
830   msg.iMethod = 5;
831   msg.cbBuffer = sizeof(USHORT) + cInterfaceRefs*sizeof(REMINTERFACEREF);
832   hr = IRpcChannelBuffer_GetBuffer(This->chan, &msg, &IID_IRemUnknown);
833   if (SUCCEEDED(hr)) {
834     LPBYTE buf = msg.Buffer;
835     memcpy(buf, &cInterfaceRefs, sizeof(USHORT));
836     buf += sizeof(USHORT);
837     memcpy(buf, InterfaceRefs, cInterfaceRefs*sizeof(REMINTERFACEREF));
838
839     hr = IRpcChannelBuffer_SendReceive(This->chan, &msg, &status);
840
841     IRpcChannelBuffer_FreeBuffer(This->chan, &msg);
842   }
843
844   return hr;
845 }
846
847 static const IRemUnknownVtbl RemUnkProxy_VTable =
848 {
849   RemUnkProxy_QueryInterface,
850   RemUnkProxy_AddRef,
851   RemUnkProxy_Release,
852   RemUnkProxy_RemQueryInterface,
853   RemUnkProxy_RemAddRef,
854   RemUnkProxy_RemRelease
855 };
856
857
858 static HRESULT WINAPI RURpcProxyBufferImpl_QueryInterface(LPRPCPROXYBUFFER iface,REFIID riid,LPVOID *ppv) {
859     *ppv = NULL;
860     if (IsEqualIID(riid,&IID_IRpcProxyBuffer)||IsEqualIID(riid,&IID_IUnknown)) {
861         IRpcProxyBuffer_AddRef(iface);
862         *ppv = (LPVOID)iface;
863         return S_OK;
864     }
865     FIXME("(%s), no interface.\n",debugstr_guid(riid));
866     return E_NOINTERFACE;
867 }
868
869 static ULONG WINAPI RURpcProxyBufferImpl_AddRef(LPRPCPROXYBUFFER iface) {
870     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
871     TRACE("%p, %ld\n", iface, This->refs + 1);
872     return InterlockedIncrement(&This->refs);
873 }
874
875 static ULONG WINAPI RURpcProxyBufferImpl_Release(LPRPCPROXYBUFFER iface) {
876     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
877     ULONG ref = InterlockedDecrement(&This->refs);
878     TRACE("%p, %ld\n", iface, ref);
879     if (!ref) {
880         IRpcProxyBuffer_Disconnect(iface);
881         HeapFree(GetProcessHeap(),0,This);
882     }
883     return ref;
884 }
885
886 static HRESULT WINAPI RURpcProxyBufferImpl_Connect(LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer) {
887     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
888
889     TRACE("%p, %p\n", iface, pRpcChannelBuffer);
890     This->chan = pRpcChannelBuffer;
891     IRpcChannelBuffer_AddRef(This->chan);
892     return S_OK;
893 }
894 static void WINAPI RURpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) {
895     ICOM_THIS_MULTI(RemUnkProxy,lpvtbl_proxy,iface);
896     TRACE("%p, %p\n", iface, This->chan);
897     if (This->chan) {
898         IRpcChannelBuffer_Release(This->chan);
899         This->chan = NULL;
900     }
901 }
902
903
904 static const IRpcProxyBufferVtbl RURpcProxyBuffer_VTable = {
905     RURpcProxyBufferImpl_QueryInterface,
906     RURpcProxyBufferImpl_AddRef,
907     RURpcProxyBufferImpl_Release,
908     RURpcProxyBufferImpl_Connect,
909     RURpcProxyBufferImpl_Disconnect
910 };
911
912 static HRESULT
913 RemUnkProxy_Construct(IUnknown *pUnkOuter, LPVOID *ppv,LPVOID *ppProxy) {
914     RemUnkProxy *This;
915
916     This = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(*This));
917     if (!This)
918         return E_OUTOFMEMORY;
919
920     This->lpvtbl_remunk = &RemUnkProxy_VTable;
921     This->lpvtbl_proxy  = &RURpcProxyBuffer_VTable;
922     /* only one reference for the proxy buffer */
923     This->refs          = 1;
924     This->outer_unknown = pUnkOuter;
925     *ppv                = &(This->lpvtbl_remunk);
926     *ppProxy            = &(This->lpvtbl_proxy);
927     /* and one reference for the object */
928     IUnknown_AddRef((IUnknown *)*ppv);
929     return S_OK;
930 }
931
932
933 /********************* OLE Proxy/Stub Factory ********************************/
934 static HRESULT WINAPI
935 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
936     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
937         *ppv = (LPVOID)iface;
938         /* No ref counting, static class */
939         return S_OK;
940     }
941     FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
942     return E_NOINTERFACE;
943 }
944
945 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
946 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
947
948 static HRESULT WINAPI
949 PSFacBuf_CreateProxy(
950     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
951     IRpcProxyBuffer **ppProxy, LPVOID *ppv
952 ) {
953     if (IsEqualIID(&IID_IClassFactory,riid))
954         return CFProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);
955     else if (IsEqualIID(&IID_IRemUnknown,riid))
956         return RemUnkProxy_Construct(pUnkOuter, ppv,(LPVOID*)ppProxy);
957     FIXME("proxying not implemented for (%s) yet!\n",debugstr_guid(riid));
958     return E_FAIL;
959 }
960
961 static HRESULT WINAPI
962 PSFacBuf_CreateStub(
963     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
964     IRpcStubBuffer** ppStub
965 ) {
966     HRESULT hres;
967
968     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
969
970     if (IsEqualIID(&IID_IClassFactory, riid) ||
971         IsEqualIID(&IID_IUnknown, riid) /* FIXME: fixup stub manager and remove this*/) {
972         hres = CFStub_Construct(ppStub);
973         if (!hres)
974             IRpcStubBuffer_Connect((*ppStub),pUnkServer);
975         return hres;
976     } else if (IsEqualIID(&IID_IRemUnknown,riid)) {
977         hres = RemUnkStub_Construct(ppStub);
978         if (!hres)
979             IRpcStubBuffer_Connect((*ppStub),pUnkServer);
980         return hres;
981     }
982     FIXME("stubbing not implemented for (%s) yet!\n",debugstr_guid(riid));
983     return E_FAIL;
984 }
985
986 static const IPSFactoryBufferVtbl psfacbufvtbl = {
987     PSFacBuf_QueryInterface,
988     PSFacBuf_AddRef,
989     PSFacBuf_Release,
990     PSFacBuf_CreateProxy,
991     PSFacBuf_CreateStub
992 };
993
994 /* This is the whole PSFactoryBuffer object, just the vtableptr */
995 static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
996
997 /***********************************************************************
998  *           DllGetClassObject [OLE32.@]
999  */
1000 HRESULT WINAPI DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1001 {
1002     *ppv = NULL;
1003     if (IsEqualIID(rclsid, &CLSID_PSFactoryBuffer))
1004         return IPSFactoryBuffer_QueryInterface((IPSFactoryBuffer *)&lppsfac, iid, ppv);
1005     if (IsEqualIID(rclsid,&CLSID_DfMarshal)&&(
1006                 IsEqualIID(iid,&IID_IClassFactory) ||
1007                 IsEqualIID(iid,&IID_IUnknown)
1008         )
1009     )
1010         return MARSHAL_GetStandardMarshalCF(ppv);
1011     if (IsEqualIID(rclsid,&CLSID_StdGlobalInterfaceTable) && (IsEqualIID(iid,&IID_IClassFactory) || IsEqualIID(iid,&IID_IUnknown)))
1012         return StdGlobalInterfaceTable_GetFactory(ppv);
1013     if (IsEqualCLSID(rclsid, &CLSID_FileMoniker))
1014         return FileMonikerCF_Create(iid, ppv);
1015     if (IsEqualCLSID(rclsid, &CLSID_ItemMoniker))
1016         return ItemMonikerCF_Create(iid, ppv);
1017
1018     FIXME("\n\tCLSID:\t%s,\n\tIID:\t%s\n",debugstr_guid(rclsid),debugstr_guid(iid));
1019     return CLASS_E_CLASSNOTAVAILABLE;
1020 }