oleaut32: Fix FormatString (valgrind).
[wine] / dlls / oleaut32 / tmarshal.c
1 /*
2  *      TYPELIB Marshaler
3  *
4  *      Copyright 2002,2005     Marcus Meissner
5  *
6  * The olerelay debug channel allows you to see calls marshalled by
7  * the typelib marshaller. It is not a generic COM relaying system.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wine/port.h"
26
27 #include <assert.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdarg.h>
31 #include <stdio.h>
32 #include <ctype.h>
33
34 #define COBJMACROS
35 #define NONAMELESSUNION
36 #define NONAMELESSSTRUCT
37
38 #include "winerror.h"
39 #include "windef.h"
40 #include "winbase.h"
41 #include "winnls.h"
42 #include "winreg.h"
43 #include "winuser.h"
44
45 #include "ole2.h"
46 #include "propidl.h" /* for LPSAFEARRAY_User* functions */
47 #include "typelib.h"
48 #include "variant.h"
49 #include "wine/debug.h"
50 #include "wine/exception.h"
51
52 static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
53
54 WINE_DEFAULT_DEBUG_CHANNEL(ole);
55 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
56
57 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
58
59 static HRESULT TMarshalDispatchChannel_Create(
60     IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
61     IRpcChannelBuffer **ppChannel);
62
63 typedef struct _marshal_state {
64     LPBYTE      base;
65     int         size;
66     int         curoff;
67 } marshal_state;
68
69 /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
70 static char *relaystr(WCHAR *in) {
71     char *tmp = (char *)debugstr_w(in);
72     tmp += 2;
73     tmp[strlen(tmp)-1] = '\0';
74     return tmp;
75 }
76
77 static HRESULT
78 xbuf_resize(marshal_state *buf, DWORD newsize)
79 {
80     if(buf->size >= newsize)
81         return S_FALSE;
82
83     if(buf->base)
84     {
85         buf->base = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf->base, newsize);
86         if(!buf->base)
87             return E_OUTOFMEMORY;
88     }
89     else
90     {
91         buf->base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
92         if(!buf->base)
93             return E_OUTOFMEMORY;
94     }
95     buf->size = newsize;
96     return S_OK;
97 }
98
99 static HRESULT
100 xbuf_add(marshal_state *buf, const BYTE *stuff, DWORD size)
101 {
102     HRESULT hr;
103
104     if(buf->size - buf->curoff < size)
105     {
106         hr = xbuf_resize(buf, buf->size + size + 100);
107         if(FAILED(hr)) return hr;
108     }
109     memcpy(buf->base+buf->curoff,stuff,size);
110     buf->curoff += size;
111     return S_OK;
112 }
113
114 static HRESULT
115 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
116     if (buf->size < buf->curoff+size) return E_FAIL;
117     memcpy(stuff,buf->base+buf->curoff,size);
118     buf->curoff += size;
119     return S_OK;
120 }
121
122 static HRESULT
123 xbuf_skip(marshal_state *buf, DWORD size) {
124     if (buf->size < buf->curoff+size) return E_FAIL;
125     buf->curoff += size;
126     return S_OK;
127 }
128
129 static HRESULT
130 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
131     IStream             *pStm;
132     ULARGE_INTEGER      newpos;
133     LARGE_INTEGER       seekto;
134     ULONG               res;
135     HRESULT             hres;
136     DWORD               xsize;
137
138     TRACE("...%s...\n",debugstr_guid(riid));
139     
140     *pUnk = NULL;
141     hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
142     if (hres) {
143         ERR("xbuf_get failed\n");
144         return hres;
145     }
146     
147     if (xsize == 0) return S_OK;
148     
149     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
150     if (hres) {
151         ERR("Stream create failed %x\n",hres);
152         return hres;
153     }
154     
155     hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
156     if (hres) {
157         ERR("stream write %x\n",hres);
158         return hres;
159     }
160     
161     memset(&seekto,0,sizeof(seekto));
162     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
163     if (hres) {
164         ERR("Failed Seek %x\n",hres);
165         return hres;
166     }
167     
168     hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
169     if (hres) {
170         ERR("Unmarshalling interface %s failed with %x\n",debugstr_guid(riid),hres);
171         return hres;
172     }
173     
174     IStream_Release(pStm);
175     return xbuf_skip(buf,xsize);
176 }
177
178 static HRESULT
179 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
180     LPBYTE              tempbuf = NULL;
181     IStream             *pStm = NULL;
182     STATSTG             ststg;
183     ULARGE_INTEGER      newpos;
184     LARGE_INTEGER       seekto;
185     ULONG               res;
186     DWORD               xsize;
187     HRESULT             hres;
188
189     if (!pUnk) {
190         /* this is valid, if for instance we serialize
191          * a VT_DISPATCH with NULL ptr which apparently
192          * can happen. S_OK to make sure we continue
193          * serializing.
194          */
195         WARN("pUnk is NULL\n");
196         xsize = 0;
197         return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
198     }
199
200     hres = E_FAIL;
201
202     TRACE("...%s...\n",debugstr_guid(riid));
203     
204     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
205     if (hres) {
206         ERR("Stream create failed %x\n",hres);
207         goto fail;
208     }
209     
210     hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
211     if (hres) {
212         ERR("Marshalling interface %s failed with %x\n", debugstr_guid(riid), hres);
213         goto fail;
214     }
215     
216     hres = IStream_Stat(pStm,&ststg,STATFLAG_NONAME);
217     if (hres) {
218         ERR("Stream stat failed\n");
219         goto fail;
220     }
221     
222     tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
223     memset(&seekto,0,sizeof(seekto));
224     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
225     if (hres) {
226         ERR("Failed Seek %x\n",hres);
227         goto fail;
228     }
229     
230     hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
231     if (hres) {
232         ERR("Failed Read %x\n",hres);
233         goto fail;
234     }
235     
236     xsize = ststg.cbSize.u.LowPart;
237     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
238     hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
239     
240     HeapFree(GetProcessHeap(),0,tempbuf);
241     IStream_Release(pStm);
242     
243     return hres;
244     
245 fail:
246     xsize = 0;
247     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
248     if (pStm) IUnknown_Release(pStm);
249     HeapFree(GetProcessHeap(), 0, tempbuf);
250     return hres;
251 }
252
253 /********************* OLE Proxy/Stub Factory ********************************/
254 static HRESULT WINAPI
255 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
256     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
257         *ppv = iface;
258         /* No ref counting, static class */
259         return S_OK;
260     }
261     FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
262     return E_NOINTERFACE;
263 }
264
265 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
266 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
267
268 static HRESULT
269 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
270     HRESULT     hres;
271     HKEY        ikey;
272     char        tlguid[200],typelibkey[300],interfacekey[300],ver[100];
273     char        tlfn[260];
274     OLECHAR     tlfnW[260];
275     DWORD       tlguidlen, verlen, type;
276     LONG        tlfnlen;
277     ITypeLib    *tl;
278
279     sprintf( interfacekey, "Interface\\{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
280         riid->Data1, riid->Data2, riid->Data3,
281         riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
282         riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
283     );
284
285     if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
286         ERR("No %s key found.\n",interfacekey);
287         return E_FAIL;
288     }
289     tlguidlen = sizeof(tlguid);
290     if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
291         ERR("Getting typelib guid failed.\n");
292         RegCloseKey(ikey);
293         return E_FAIL;
294     }
295     verlen = sizeof(ver);
296     if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
297         ERR("Could not get version value?\n");
298         RegCloseKey(ikey);
299         return E_FAIL;
300     }
301     RegCloseKey(ikey);
302     sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win%u",tlguid,ver,(sizeof(void*) == 8) ? 64 : 32);
303     tlfnlen = sizeof(tlfn);
304     if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
305         ERR("Could not get typelib fn?\n");
306         return E_FAIL;
307     }
308     MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, sizeof(tlfnW) / sizeof(tlfnW[0]));
309     hres = LoadTypeLib(tlfnW,&tl);
310     if (hres) {
311         ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
312         return hres;
313     }
314     hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
315     if (hres) {
316         ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
317         ITypeLib_Release(tl);
318         return hres;
319     }
320     ITypeLib_Release(tl);
321     return hres;
322 }
323
324 /*
325  * Determine the number of functions including all inherited functions.
326  * Note for non-dual dispinterfaces we simply return the size of IDispatch.
327  */
328 static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num)
329 {
330     HRESULT hres;
331     TYPEATTR *attr;
332     ITypeInfo *tinfo2;
333
334     *num = 0;
335     hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
336     if (hres) {
337         ERR("GetTypeAttr failed with %x\n",hres);
338         return hres;
339     }
340
341     if(attr->typekind == TKIND_DISPATCH && (attr->wTypeFlags & TYPEFLAG_FDUAL))
342     {
343         HREFTYPE href;
344         hres = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
345         if(FAILED(hres))
346         {
347             ERR("Unable to get interface href from dual dispinterface\n");
348             goto end;
349         }
350         hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
351         if(FAILED(hres))
352         {
353             ERR("Unable to get interface from dual dispinterface\n");
354             goto end;
355         }
356         hres = num_of_funcs(tinfo2, num);
357         ITypeInfo_Release(tinfo2);
358     }
359     else
360     {
361         *num = attr->cbSizeVft / 4;
362     }
363
364  end:
365     ITypeInfo_ReleaseTypeAttr(tinfo, attr);
366     return hres;
367 }
368
369 #ifdef __i386__
370
371 #include "pshpack1.h"
372
373 typedef struct _TMAsmProxy {
374     BYTE        popleax;
375     BYTE        pushlval;
376     DWORD       nr;
377     BYTE        pushleax;
378     BYTE        lcall;
379     DWORD       xcall;
380     BYTE        lret;
381     WORD        bytestopop;
382     BYTE        nop;
383 } TMAsmProxy;
384
385 #include "poppack.h"
386
387 #else /* __i386__ */
388 # warning You need to implement stubless proxies for your architecture
389 typedef struct _TMAsmProxy {
390 } TMAsmProxy;
391 #endif
392
393 typedef struct _TMProxyImpl {
394     LPVOID                             *lpvtbl;
395     const IRpcProxyBufferVtbl          *lpvtbl2;
396     LONG                                ref;
397
398     TMAsmProxy                          *asmstubs;
399     ITypeInfo*                          tinfo;
400     IRpcChannelBuffer*                  chanbuf;
401     IID                                 iid;
402     CRITICAL_SECTION    crit;
403     IUnknown                            *outerunknown;
404     IDispatch                           *dispatch;
405     IRpcProxyBuffer                     *dispatch_proxy;
406 } TMProxyImpl;
407
408 static HRESULT WINAPI
409 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
410 {
411     TRACE("()\n");
412     if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
413         *ppv = iface;
414         IRpcProxyBuffer_AddRef(iface);
415         return S_OK;
416     }
417     FIXME("no interface for %s\n",debugstr_guid(riid));
418     return E_NOINTERFACE;
419 }
420
421 static ULONG WINAPI
422 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
423 {
424     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
425     ULONG refCount = InterlockedIncrement(&This->ref);
426
427     TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
428
429     return refCount;
430 }
431
432 static ULONG WINAPI
433 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
434 {
435     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
436     ULONG refCount = InterlockedDecrement(&This->ref);
437
438     TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
439
440     if (!refCount)
441     {
442         if (This->dispatch_proxy) IRpcProxyBuffer_Release(This->dispatch_proxy);
443         This->crit.DebugInfo->Spare[0] = 0;
444         DeleteCriticalSection(&This->crit);
445         if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
446         VirtualFree(This->asmstubs, 0, MEM_RELEASE);
447         HeapFree(GetProcessHeap(), 0, This->lpvtbl);
448         ITypeInfo_Release(This->tinfo);
449         CoTaskMemFree(This);
450     }
451     return refCount;
452 }
453
454 static HRESULT WINAPI
455 TMProxyImpl_Connect(
456     LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
457 {
458     ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
459
460     TRACE("(%p)\n", pRpcChannelBuffer);
461
462     EnterCriticalSection(&This->crit);
463
464     IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
465     This->chanbuf = pRpcChannelBuffer;
466
467     LeaveCriticalSection(&This->crit);
468
469     if (This->dispatch_proxy)
470     {
471         IRpcChannelBuffer *pDelegateChannel;
472         HRESULT hr = TMarshalDispatchChannel_Create(pRpcChannelBuffer, &This->iid, &pDelegateChannel);
473         if (FAILED(hr))
474             return hr;
475         hr = IRpcProxyBuffer_Connect(This->dispatch_proxy, pDelegateChannel);
476         IRpcChannelBuffer_Release(pDelegateChannel);
477         return hr;
478     }
479
480     return S_OK;
481 }
482
483 static void WINAPI
484 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
485 {
486     ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
487
488     TRACE("()\n");
489
490     EnterCriticalSection(&This->crit);
491
492     IRpcChannelBuffer_Release(This->chanbuf);
493     This->chanbuf = NULL;
494
495     LeaveCriticalSection(&This->crit);
496
497     if (This->dispatch_proxy)
498         IRpcProxyBuffer_Disconnect(This->dispatch_proxy);
499 }
500
501
502 static const IRpcProxyBufferVtbl tmproxyvtable = {
503     TMProxyImpl_QueryInterface,
504     TMProxyImpl_AddRef,
505     TMProxyImpl_Release,
506     TMProxyImpl_Connect,
507     TMProxyImpl_Disconnect
508 };
509
510 /* how much space do we use on stack in DWORD steps. */
511 static int
512 _argsize(TYPEDESC *tdesc, ITypeInfo *tinfo) {
513     switch (tdesc->vt) {
514     case VT_I8:
515     case VT_UI8:
516         return 8/sizeof(DWORD);
517     case VT_R8:
518         return sizeof(double)/sizeof(DWORD);
519     case VT_CY:
520         return sizeof(CY)/sizeof(DWORD);
521     case VT_DATE:
522         return sizeof(DATE)/sizeof(DWORD);
523     case VT_DECIMAL:
524         return (sizeof(DECIMAL)+3)/sizeof(DWORD);
525     case VT_VARIANT:
526         return (sizeof(VARIANT)+3)/sizeof(DWORD);
527     case VT_USERDEFINED:
528     {
529         ITypeInfo *tinfo2;
530         TYPEATTR *tattr;
531         HRESULT hres;
532         DWORD ret;
533
534         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
535         if (FAILED(hres))
536             return 0; /* should fail critically in serialize_param */
537         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
538         ret = (tattr->cbSizeInstance+3)/sizeof(DWORD);
539         ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
540         ITypeInfo_Release(tinfo2);
541         return ret;
542     }
543     default:
544         return 1;
545     }
546 }
547
548 /* how much space do we use on the heap (in bytes) */
549 static int
550 _xsize(const TYPEDESC *td, ITypeInfo *tinfo) {
551     switch (td->vt) {
552     case VT_DATE:
553         return sizeof(DATE);
554     case VT_CY:
555         return sizeof(CY);
556     /* FIXME: VT_BOOL should return 2? */
557     case VT_VARIANT:
558         return sizeof(VARIANT)+3; /* FIXME: why the +3? */
559     case VT_CARRAY: {
560         int i, arrsize = 1;
561         const ARRAYDESC *adesc = td->u.lpadesc;
562
563         for (i=0;i<adesc->cDims;i++)
564             arrsize *= adesc->rgbounds[i].cElements;
565         return arrsize*_xsize(&adesc->tdescElem, tinfo);
566     }
567     case VT_UI8:
568     case VT_I8:
569     case VT_R8:
570         return 8;
571     case VT_UI2:
572     case VT_I2:
573         return 2;
574     case VT_UI1:
575     case VT_I1:
576         return 1;
577     case VT_USERDEFINED:
578     {
579         ITypeInfo *tinfo2;
580         TYPEATTR *tattr;
581         HRESULT hres;
582         DWORD ret;
583
584         hres = ITypeInfo_GetRefTypeInfo(tinfo,td->u.hreftype,&tinfo2);
585         if (FAILED(hres))
586             return 0;
587         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
588         ret = tattr->cbSizeInstance;
589         ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
590         ITypeInfo_Release(tinfo2);
591         return ret;
592     }
593     default:
594         return 4;
595     }
596 }
597
598 static HRESULT
599 serialize_param(
600     ITypeInfo           *tinfo,
601     BOOL                writeit,
602     BOOL                debugout,
603     BOOL                dealloc,
604     TYPEDESC            *tdesc,
605     DWORD               *arg,
606     marshal_state       *buf)
607 {
608     HRESULT hres = S_OK;
609     VARTYPE vartype;
610
611     TRACE("(tdesc.vt %s)\n",debugstr_vt(tdesc->vt));
612
613     vartype = tdesc->vt;
614     if ((vartype & 0xf000) == VT_ARRAY)
615         vartype = VT_SAFEARRAY;
616
617     switch (vartype) {
618     case VT_I8:
619     case VT_UI8:
620     case VT_R8:
621     case VT_CY:
622         hres = S_OK;
623         if (debugout) TRACE_(olerelay)("%x%x\n",arg[0],arg[1]);
624         if (writeit)
625             hres = xbuf_add(buf,(LPBYTE)arg,8);
626         return hres;
627     case VT_BOOL:
628     case VT_ERROR:
629     case VT_INT:
630     case VT_UINT:
631     case VT_I4:
632     case VT_R4:
633     case VT_UI4:
634         hres = S_OK;
635         if (debugout) TRACE_(olerelay)("%x\n",*arg);
636         if (writeit)
637             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
638         return hres;
639     case VT_I2:
640     case VT_UI2:
641         hres = S_OK;
642         if (debugout) TRACE_(olerelay)("%04x\n",*arg & 0xffff);
643         if (writeit)
644             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
645         return hres;
646     case VT_I1:
647     case VT_UI1:
648         hres = S_OK;
649         if (debugout) TRACE_(olerelay)("%02x\n",*arg & 0xff);
650         if (writeit)
651             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
652         return hres;
653     case VT_VARIANT: {
654         if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(V_VT((VARIANT *)arg)),debugstr_vf(V_VT((VARIANT *)arg)));
655         if (writeit)
656         {
657             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
658             ULONG size = VARIANT_UserSize(&flags, buf->curoff, (VARIANT *)arg);
659             xbuf_resize(buf, size);
660             VARIANT_UserMarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
661             buf->curoff = size;
662         }
663         if (dealloc)
664         {
665             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
666             VARIANT_UserFree(&flags, (VARIANT *)arg);
667         }
668         return S_OK;
669     }
670     case VT_BSTR: {
671         if (debugout) {
672             if (*arg)
673                    TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
674             else
675                     TRACE_(olerelay)("<bstr NULL>");
676         }
677         if (writeit)
678         {
679             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
680             ULONG size = BSTR_UserSize(&flags, buf->curoff, (BSTR *)arg);
681             xbuf_resize(buf, size);
682             BSTR_UserMarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
683             buf->curoff = size;
684         }
685         if (dealloc)
686         {
687             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
688             BSTR_UserFree(&flags, (BSTR *)arg);
689         }
690         return S_OK;
691     }
692     case VT_PTR: {
693         DWORD cookie;
694         BOOL        derefhere = TRUE;
695
696         if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
697             ITypeInfo   *tinfo2;
698             TYPEATTR    *tattr;
699
700             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
701             if (hres) {
702                 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
703                 return hres;
704             }
705             ITypeInfo_GetTypeAttr(tinfo2,&tattr);
706             switch (tattr->typekind) {
707             case TKIND_ALIAS:
708                 if (tattr->tdescAlias.vt == VT_USERDEFINED)
709                 {
710                     DWORD href = tattr->tdescAlias.u.hreftype;
711                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
712                     ITypeInfo_Release(tinfo2);
713                     hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
714                     if (hres) {
715                         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
716                         return hres;
717                     }
718                     ITypeInfo_GetTypeAttr(tinfo2,&tattr);
719                     derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
720                 }
721                 break;
722             case TKIND_ENUM:    /* confirmed */
723             case TKIND_RECORD:  /* FIXME: mostly untested */
724                 break;
725             case TKIND_DISPATCH:        /* will be done in VT_USERDEFINED case */
726             case TKIND_INTERFACE:       /* will be done in VT_USERDEFINED case */
727                 derefhere=FALSE;
728                 break;
729             default:
730                 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
731                 derefhere=FALSE;
732                 break;
733             }
734             ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
735             ITypeInfo_Release(tinfo2);
736         }
737
738         if (debugout) TRACE_(olerelay)("*");
739         /* Write always, so the other side knows when it gets a NULL pointer.
740          */
741         cookie = *arg ? 0x42424242 : 0;
742         hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
743         if (hres)
744             return hres;
745         if (!*arg) {
746             if (debugout) TRACE_(olerelay)("NULL");
747             return S_OK;
748         }
749         hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
750         if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
751         return hres;
752     }
753     case VT_UNKNOWN:
754         if (debugout) TRACE_(olerelay)("unk(0x%x)",*arg);
755         if (writeit)
756             hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
757         if (dealloc && *(IUnknown **)arg)
758             IUnknown_Release((LPUNKNOWN)*arg);
759         return hres;
760     case VT_DISPATCH:
761         if (debugout) TRACE_(olerelay)("idisp(0x%x)",*arg);
762         if (writeit)
763             hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
764         if (dealloc && *(IUnknown **)arg)
765             IUnknown_Release((LPUNKNOWN)*arg);
766         return hres;
767     case VT_VOID:
768         if (debugout) TRACE_(olerelay)("<void>");
769         return S_OK;
770     case VT_USERDEFINED: {
771         ITypeInfo       *tinfo2;
772         TYPEATTR        *tattr;
773
774         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
775         if (hres) {
776             ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
777             return hres;
778         }
779         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
780         switch (tattr->typekind) {
781         case TKIND_DISPATCH:
782         case TKIND_INTERFACE:
783             if (writeit)
784                hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
785             if (dealloc)
786                 IUnknown_Release((LPUNKNOWN)arg);
787             break;
788         case TKIND_RECORD: {
789             int i;
790             if (debugout) TRACE_(olerelay)("{");
791             for (i=0;i<tattr->cVars;i++) {
792                 VARDESC *vdesc;
793                 ELEMDESC *elem2;
794                 TYPEDESC *tdesc2;
795
796                 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
797                 if (hres) {
798                     ERR("Could not get vardesc of %d\n",i);
799                     return hres;
800                 }
801                 elem2 = &vdesc->elemdescVar;
802                 tdesc2 = &elem2->tdesc;
803                 hres = serialize_param(
804                     tinfo2,
805                     writeit,
806                     debugout,
807                     dealloc,
808                     tdesc2,
809                     (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
810                     buf
811                 );
812                 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
813                 if (hres!=S_OK)
814                     return hres;
815                 if (debugout && (i<(tattr->cVars-1)))
816                     TRACE_(olerelay)(",");
817             }
818             if (debugout) TRACE_(olerelay)("}");
819             break;
820         }
821         case TKIND_ALIAS:
822             hres = serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
823             break;
824         case TKIND_ENUM:
825             hres = S_OK;
826             if (debugout) TRACE_(olerelay)("%x",*arg);
827             if (writeit)
828                 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
829             break;
830         default:
831             FIXME("Unhandled typekind %d\n",tattr->typekind);
832             hres = E_FAIL;
833             break;
834         }
835         ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
836         ITypeInfo_Release(tinfo2);
837         return hres;
838     }
839     case VT_CARRAY: {
840         ARRAYDESC *adesc = tdesc->u.lpadesc;
841         int i, arrsize = 1;
842
843         if (debugout) TRACE_(olerelay)("carr");
844         for (i=0;i<adesc->cDims;i++) {
845             if (debugout) TRACE_(olerelay)("[%d]",adesc->rgbounds[i].cElements);
846             arrsize *= adesc->rgbounds[i].cElements;
847         }
848         if (debugout) TRACE_(olerelay)("(vt %s)",debugstr_vt(adesc->tdescElem.vt));
849         if (debugout) TRACE_(olerelay)("[");
850         for (i=0;i<arrsize;i++) {
851             hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)(*arg)+i*_xsize(&adesc->tdescElem, tinfo)), buf);
852             if (hres)
853                 return hres;
854             if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
855         }
856         if (debugout) TRACE_(olerelay)("]");
857         if (dealloc)
858             HeapFree(GetProcessHeap(), 0, *(void **)arg);
859         return S_OK;
860     }
861     case VT_SAFEARRAY: {
862         if (writeit)
863         {
864             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
865             ULONG size = LPSAFEARRAY_UserSize(&flags, buf->curoff, (LPSAFEARRAY *)arg);
866             xbuf_resize(buf, size);
867             LPSAFEARRAY_UserMarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
868             buf->curoff = size;
869         }
870         if (dealloc)
871         {
872             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
873             LPSAFEARRAY_UserFree(&flags, (LPSAFEARRAY *)arg);
874         }
875         return S_OK;
876     }
877     default:
878         ERR("Unhandled marshal type %d.\n",tdesc->vt);
879         return S_OK;
880     }
881 }
882
883 static HRESULT
884 deserialize_param(
885     ITypeInfo           *tinfo,
886     BOOL                readit,
887     BOOL                debugout,
888     BOOL                alloc,
889     TYPEDESC            *tdesc,
890     DWORD               *arg,
891     marshal_state       *buf)
892 {
893     HRESULT hres = S_OK;
894     VARTYPE vartype;
895
896     TRACE("vt %s at %p\n",debugstr_vt(tdesc->vt),arg);
897
898     vartype = tdesc->vt;
899     if ((vartype & 0xf000) == VT_ARRAY)
900         vartype = VT_SAFEARRAY;
901
902     while (1) {
903         switch (vartype) {
904         case VT_VARIANT: {
905             if (readit)
906             {
907                 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
908                 unsigned char *buffer;
909                 buffer = VARIANT_UserUnmarshal(&flags, buf->base + buf->curoff, (VARIANT *)arg);
910                 buf->curoff = buffer - buf->base;
911             }
912             return S_OK;
913         }
914         case VT_I8:
915         case VT_UI8:
916         case VT_R8:
917         case VT_CY:
918             if (readit) {
919                 hres = xbuf_get(buf,(LPBYTE)arg,8);
920                 if (hres) ERR("Failed to read integer 8 byte\n");
921             }
922             if (debugout) TRACE_(olerelay)("%x%x",arg[0],arg[1]);
923             return hres;
924         case VT_ERROR:
925         case VT_BOOL:
926         case VT_I4:
927         case VT_INT:
928         case VT_UINT:
929         case VT_R4:
930         case VT_UI4:
931             if (readit) {
932                 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
933                 if (hres) ERR("Failed to read integer 4 byte\n");
934             }
935             if (debugout) TRACE_(olerelay)("%x",*arg);
936             return hres;
937         case VT_I2:
938         case VT_UI2:
939             if (readit) {
940                 DWORD x;
941                 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
942                 if (hres) ERR("Failed to read integer 4 byte\n");
943                 memcpy(arg,&x,2);
944             }
945             if (debugout) TRACE_(olerelay)("%04x",*arg & 0xffff);
946             return hres;
947         case VT_I1:
948         case VT_UI1:
949             if (readit) {
950                 DWORD x;
951                 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
952                 if (hres) ERR("Failed to read integer 4 byte\n");
953                 memcpy(arg,&x,1);
954             }
955             if (debugout) TRACE_(olerelay)("%02x",*arg & 0xff);
956             return hres;
957         case VT_BSTR: {
958             if (readit)
959             {
960                 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
961                 unsigned char *buffer;
962                 buffer = BSTR_UserUnmarshal(&flags, buf->base + buf->curoff, (BSTR *)arg);
963                 buf->curoff = buffer - buf->base;
964                 if (debugout) TRACE_(olerelay)("%s",debugstr_w(*(BSTR *)arg));
965             }
966             return S_OK;
967         }
968         case VT_PTR: {
969             DWORD       cookie;
970             BOOL        derefhere = TRUE;
971
972             if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
973                 ITypeInfo       *tinfo2;
974                 TYPEATTR        *tattr;
975
976                 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
977                 if (hres) {
978                     ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
979                     return hres;
980                 }
981                 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
982                 switch (tattr->typekind) {
983                 case TKIND_ALIAS:
984                     if (tattr->tdescAlias.vt == VT_USERDEFINED)
985                     {
986                         DWORD href = tattr->tdescAlias.u.hreftype;
987                         ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
988                         ITypeInfo_Release(tinfo2);
989                         hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
990                         if (hres) {
991                             ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
992                             return hres;
993                         }
994                         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
995                         derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
996                     }
997                     break;
998                 case TKIND_ENUM:        /* confirmed */
999                 case TKIND_RECORD:      /* FIXME: mostly untested */
1000                     break;
1001                 case TKIND_DISPATCH:    /* will be done in VT_USERDEFINED case */
1002                 case TKIND_INTERFACE:   /* will be done in VT_USERDEFINED case */
1003                     derefhere=FALSE;
1004                     break;
1005                 default:
1006                     FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
1007                     derefhere=FALSE;
1008                     break;
1009                 }
1010                 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1011                 ITypeInfo_Release(tinfo2);
1012             }
1013             /* read it in all cases, we need to know if we have 
1014              * NULL pointer or not.
1015              */
1016             hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1017             if (hres) {
1018                 ERR("Failed to load pointer cookie.\n");
1019                 return hres;
1020             }
1021             if (cookie != 0x42424242) {
1022                 /* we read a NULL ptr from the remote side */
1023                 if (debugout) TRACE_(olerelay)("NULL");
1024                 *arg = 0;
1025                 return S_OK;
1026             }
1027             if (debugout) TRACE_(olerelay)("*");
1028             if (alloc) {
1029                 /* Allocate space for the referenced struct */
1030                 if (derefhere)
1031                     *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo));
1032             }
1033             if (derefhere)
1034                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
1035             else
1036                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
1037         }
1038         case VT_UNKNOWN:
1039             /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
1040             if (alloc)
1041                 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
1042             hres = S_OK;
1043             if (readit)
1044                 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
1045             if (debugout)
1046                 TRACE_(olerelay)("unk(%p)",arg);
1047             return hres;
1048         case VT_DISPATCH:
1049             hres = S_OK;
1050             if (readit)
1051                 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
1052             if (debugout)
1053                 TRACE_(olerelay)("idisp(%p)",arg);
1054             return hres;
1055         case VT_VOID:
1056             if (debugout) TRACE_(olerelay)("<void>");
1057             return S_OK;
1058         case VT_USERDEFINED: {
1059             ITypeInfo   *tinfo2;
1060             TYPEATTR    *tattr;
1061
1062             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1063             if (hres) {
1064                 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
1065                 return hres;
1066             }
1067             hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1068             if (hres) {
1069                 ERR("Could not get typeattr in VT_USERDEFINED.\n");
1070             } else {
1071                 switch (tattr->typekind) {
1072                 case TKIND_DISPATCH:
1073                 case TKIND_INTERFACE:
1074                     if (readit)
1075                         hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
1076                     break;
1077                 case TKIND_RECORD: {
1078                     int i;
1079
1080                     if (debugout) TRACE_(olerelay)("{");
1081                     for (i=0;i<tattr->cVars;i++) {
1082                         VARDESC *vdesc;
1083
1084                         hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
1085                         if (hres) {
1086                             ERR("Could not get vardesc of %d\n",i);
1087                             ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1088                             ITypeInfo_Release(tinfo2);
1089                             return hres;
1090                         }
1091                         hres = deserialize_param(
1092                             tinfo2,
1093                             readit,
1094                             debugout,
1095                             alloc,
1096                             &vdesc->elemdescVar.tdesc,
1097                             (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
1098                             buf
1099                         );
1100                         ITypeInfo2_ReleaseVarDesc(tinfo2, vdesc);
1101                         if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1102                     }
1103                     if (debugout) TRACE_(olerelay)("}");
1104                     break;
1105                 }
1106                 case TKIND_ALIAS:
1107                     hres = deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
1108                     break;
1109                 case TKIND_ENUM:
1110                     if (readit) {
1111                         hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1112                         if (hres) ERR("Failed to read enum (4 byte)\n");
1113                     }
1114                     if (debugout) TRACE_(olerelay)("%x",*arg);
1115                     break;
1116                 default:
1117                     ERR("Unhandled typekind %d\n",tattr->typekind);
1118                     hres = E_FAIL;
1119                     break;
1120                 }
1121                 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1122             }
1123             if (hres)
1124                 ERR("failed to stuballoc in TKIND_RECORD.\n");
1125             ITypeInfo_Release(tinfo2);
1126             return hres;
1127         }
1128         case VT_CARRAY: {
1129             /* arg is pointing to the start of the array. */
1130             ARRAYDESC *adesc = tdesc->u.lpadesc;
1131             int         arrsize,i;
1132             arrsize = 1;
1133             if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1134             for (i=0;i<adesc->cDims;i++)
1135                 arrsize *= adesc->rgbounds[i].cElements;
1136             *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo) * arrsize);
1137             for (i=0;i<arrsize;i++)
1138                 deserialize_param(
1139                     tinfo,
1140                     readit,
1141                     debugout,
1142                     alloc,
1143                     &adesc->tdescElem,
1144                     (DWORD*)((LPBYTE)(*arg)+i*_xsize(&adesc->tdescElem, tinfo)),
1145                     buf
1146                 );
1147             return S_OK;
1148         }
1149     case VT_SAFEARRAY: {
1150             if (readit)
1151             {
1152                 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1153                 unsigned char *buffer;
1154                 buffer = LPSAFEARRAY_UserUnmarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1155                 buf->curoff = buffer - buf->base;
1156             }
1157             return S_OK;
1158         }
1159         default:
1160             ERR("No handler for VT type %d!\n",tdesc->vt);
1161             return S_OK;
1162         }
1163     }
1164 }
1165
1166 /* Retrieves a function's funcdesc, searching back into inherited interfaces. */
1167 static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, const FUNCDESC **fdesc,
1168                             BSTR *iname, BSTR *fname, UINT *num)
1169 {
1170     HRESULT hr;
1171     UINT i, impl_types;
1172     UINT inherited_funcs = 0;
1173     TYPEATTR *attr;
1174
1175     if (fname) *fname = NULL;
1176     if (iname) *iname = NULL;
1177     if (num) *num = 0;
1178     *tactual = NULL;
1179
1180     hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
1181     if (FAILED(hr))
1182     {
1183         ERR("GetTypeAttr failed with %x\n",hr);
1184         return hr;
1185     }
1186
1187     if(attr->typekind == TKIND_DISPATCH)
1188     {
1189         if(attr->wTypeFlags & TYPEFLAG_FDUAL)
1190         {
1191             HREFTYPE href;
1192             ITypeInfo *tinfo2;
1193
1194             hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
1195             if(FAILED(hr))
1196             {
1197                 ERR("Cannot get interface href from dual dispinterface\n");
1198                 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1199                 return hr;
1200             }
1201             hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1202             if(FAILED(hr))
1203             {
1204                 ERR("Cannot get interface from dual dispinterface\n");
1205                 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1206                 return hr;
1207             }
1208             hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
1209             ITypeInfo_Release(tinfo2);
1210             ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1211             return hr;
1212         }
1213         ERR("Shouldn't be called with a non-dual dispinterface\n");
1214         return E_FAIL;
1215     }
1216
1217     impl_types = attr->cImplTypes;
1218     ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1219
1220     for (i = 0; i < impl_types; i++)
1221     {
1222         HREFTYPE href;
1223         ITypeInfo *pSubTypeInfo;
1224         UINT sub_funcs;
1225
1226         hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
1227         if (FAILED(hr)) return hr;
1228         hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
1229         if (FAILED(hr)) return hr;
1230
1231         hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
1232         inherited_funcs += sub_funcs;
1233         ITypeInfo_Release(pSubTypeInfo);
1234         if(SUCCEEDED(hr)) return hr;
1235     }
1236     if(iMethod < inherited_funcs)
1237     {
1238         ERR("shouldn't be here\n");
1239         return E_INVALIDARG;
1240     }
1241
1242     for(i = inherited_funcs; i <= iMethod; i++)
1243     {
1244         hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
1245         if(FAILED(hr))
1246         {
1247             if(num) *num = i;
1248             return hr;
1249         }
1250     }
1251
1252     /* found it. We don't care about num so zero it */
1253     if(num) *num = 0;
1254     *tactual = tinfo;
1255     ITypeInfo_AddRef(*tactual);
1256     if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1257     if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1258     return S_OK;
1259 }
1260
1261 static inline BOOL is_in_elem(const ELEMDESC *elem)
1262 {
1263     return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
1264 }
1265
1266 static inline BOOL is_out_elem(const ELEMDESC *elem)
1267 {
1268     return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
1269 }
1270
1271 static DWORD
1272 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1273 {
1274     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
1275     const FUNCDESC      *fdesc;
1276     HRESULT             hres;
1277     int                 i, relaydeb = TRACE_ON(olerelay);
1278     marshal_state       buf;
1279     RPCOLEMESSAGE       msg;
1280     ULONG               status;
1281     BSTR                fname,iname;
1282     BSTR                names[10];
1283     UINT                nrofnames;
1284     DWORD               remoteresult = 0;
1285     ITypeInfo           *tinfo;
1286     IRpcChannelBuffer *chanbuf;
1287
1288     EnterCriticalSection(&tpinfo->crit);
1289
1290     hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1291     if (hres) {
1292         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1293         LeaveCriticalSection(&tpinfo->crit);
1294         return E_FAIL;
1295     }
1296
1297     if (!tpinfo->chanbuf)
1298     {
1299         WARN("Tried to use disconnected proxy\n");
1300         ITypeInfo_Release(tinfo);
1301         LeaveCriticalSection(&tpinfo->crit);
1302         return RPC_E_DISCONNECTED;
1303     }
1304     chanbuf = tpinfo->chanbuf;
1305     IRpcChannelBuffer_AddRef(chanbuf);
1306
1307     LeaveCriticalSection(&tpinfo->crit);
1308
1309     if (relaydeb) {
1310        TRACE_(olerelay)("->");
1311         if (iname)
1312             TRACE_(olerelay)("%s:",relaystr(iname));
1313         if (fname)
1314             TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1315         else
1316             TRACE_(olerelay)("%d",method);
1317         TRACE_(olerelay)("(");
1318     }
1319
1320     SysFreeString(iname);
1321     SysFreeString(fname);
1322
1323     memset(&buf,0,sizeof(buf));
1324
1325     /* normal typelib driven serializing */
1326
1327     /* Need them for hack below */
1328     memset(names,0,sizeof(names));
1329     if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1330         nrofnames = 0;
1331     if (nrofnames > sizeof(names)/sizeof(names[0]))
1332         ERR("Need more names!\n");
1333
1334     xargs = args;
1335     for (i=0;i<fdesc->cParams;i++) {
1336         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1337         if (relaydeb) {
1338             if (i) TRACE_(olerelay)(",");
1339             if (i+1<nrofnames && names[i+1])
1340                 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1341         }
1342         /* No need to marshal other data than FIN and any VT_PTR. */
1343         if (!is_in_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1344             xargs+=_argsize(&elem->tdesc, tinfo);
1345             if (relaydeb) TRACE_(olerelay)("[out]");
1346             continue;
1347         }
1348         hres = serialize_param(
1349             tinfo,
1350             is_in_elem(elem),
1351             relaydeb,
1352             FALSE,
1353             &elem->tdesc,
1354             xargs,
1355             &buf
1356         );
1357
1358         if (hres) {
1359             ERR("Failed to serialize param, hres %x\n",hres);
1360             break;
1361         }
1362         xargs+=_argsize(&elem->tdesc, tinfo);
1363     }
1364     if (relaydeb) TRACE_(olerelay)(")");
1365
1366     memset(&msg,0,sizeof(msg));
1367     msg.cbBuffer = buf.curoff;
1368     msg.iMethod  = method;
1369     hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1370     if (hres) {
1371         ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1372         goto exit;
1373     }
1374     memcpy(msg.Buffer,buf.base,buf.curoff);
1375     if (relaydeb) TRACE_(olerelay)("\n");
1376     hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1377     if (hres) {
1378         ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1379         goto exit;
1380     }
1381
1382     if (relaydeb) TRACE_(olerelay)(" status = %08x (",status);
1383     if (buf.base)
1384         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1385     else
1386         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1387     buf.size = msg.cbBuffer;
1388     memcpy(buf.base,msg.Buffer,buf.size);
1389     buf.curoff = 0;
1390
1391     /* generic deserializer using typelib description */
1392     xargs = args;
1393     status = S_OK;
1394     for (i=0;i<fdesc->cParams;i++) {
1395         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1396
1397         if (relaydeb) {
1398             if (i) TRACE_(olerelay)(",");
1399             if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1400         }
1401         /* No need to marshal other data than FOUT and any VT_PTR */
1402         if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1403             xargs += _argsize(&elem->tdesc, tinfo);
1404             if (relaydeb) TRACE_(olerelay)("[in]");
1405             continue;
1406         }
1407         hres = deserialize_param(
1408             tinfo,
1409             is_out_elem(elem),
1410             relaydeb,
1411             FALSE,
1412             &(elem->tdesc),
1413             xargs,
1414             &buf
1415         );
1416         if (hres) {
1417             ERR("Failed to unmarshall param, hres %x\n",hres);
1418             status = hres;
1419             break;
1420         }
1421         xargs += _argsize(&elem->tdesc, tinfo);
1422     }
1423
1424     hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1425     if (hres != S_OK)
1426         goto exit;
1427     if (relaydeb) TRACE_(olerelay)(") = %08x\n", remoteresult);
1428
1429     hres = remoteresult;
1430
1431 exit:
1432     IRpcChannelBuffer_FreeBuffer(chanbuf,&msg);
1433     for (i = 0; i < nrofnames; i++)
1434         SysFreeString(names[i]);
1435     HeapFree(GetProcessHeap(),0,buf.base);
1436     IRpcChannelBuffer_Release(chanbuf);
1437     ITypeInfo_Release(tinfo);
1438     TRACE("-- 0x%08x\n", hres);
1439     return hres;
1440 }
1441
1442 static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1443 {
1444     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1445
1446     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1447
1448     if (proxy->outerunknown)
1449         return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1450
1451     FIXME("No interface\n");
1452     return E_NOINTERFACE;
1453 }
1454
1455 static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1456 {
1457     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1458
1459     TRACE("\n");
1460
1461     if (proxy->outerunknown)
1462         return IUnknown_AddRef(proxy->outerunknown);
1463
1464     return 2; /* FIXME */
1465 }
1466
1467 static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1468 {
1469     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1470
1471     TRACE("\n");
1472
1473     if (proxy->outerunknown)
1474         return IUnknown_Release(proxy->outerunknown);
1475
1476     return 1; /* FIXME */
1477 }
1478
1479 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1480 {
1481     TMProxyImpl *This = (TMProxyImpl *)iface;
1482
1483     TRACE("(%p)\n", pctinfo);
1484
1485     return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1486 }
1487
1488 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1489 {
1490     TMProxyImpl *This = (TMProxyImpl *)iface;
1491
1492     TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1493
1494     return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1495 }
1496
1497 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1498 {
1499     TMProxyImpl *This = (TMProxyImpl *)iface;
1500
1501     TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1502
1503     return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1504                                    cNames, lcid, rgDispId);
1505 }
1506
1507 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1508                                             WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1509                                             EXCEPINFO * pExcepInfo, UINT * puArgErr)
1510 {
1511     TMProxyImpl *This = (TMProxyImpl *)iface;
1512
1513     TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1514           debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
1515           pExcepInfo, puArgErr);
1516
1517     return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1518                             wFlags, pDispParams, pVarResult, pExcepInfo,
1519                             puArgErr);
1520 }
1521
1522 typedef struct
1523 {
1524     const IRpcChannelBufferVtbl *lpVtbl;
1525     LONG                  refs;
1526     /* the IDispatch-derived interface we are handling */
1527         IID                   tmarshal_iid;
1528     IRpcChannelBuffer    *pDelegateChannel;
1529 } TMarshalDispatchChannel;
1530
1531 static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
1532 {
1533     *ppv = NULL;
1534     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
1535     {
1536         *ppv = iface;
1537         IUnknown_AddRef(iface);
1538         return S_OK;
1539     }
1540     return E_NOINTERFACE;
1541 }
1542
1543 static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
1544 {
1545     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1546     return InterlockedIncrement(&This->refs);
1547 }
1548
1549 static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
1550 {
1551     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1552     ULONG ref;
1553
1554     ref = InterlockedDecrement(&This->refs);
1555     if (ref)
1556         return ref;
1557
1558         IRpcChannelBuffer_Release(This->pDelegateChannel);
1559     HeapFree(GetProcessHeap(), 0, This);
1560     return 0;
1561 }
1562
1563 static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1564 {
1565     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1566     TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
1567     /* Note: we are pretending to invoke a method on the interface identified
1568      * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
1569      * without the RPC runtime getting confused by not exporting an IDispatch interface */
1570     return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
1571 }
1572
1573 static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1574 {
1575     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1576     TRACE("(%p, %p)\n", olemsg, pstatus);
1577     return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
1578 }
1579
1580 static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1581 {
1582     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1583     TRACE("(%p)\n", olemsg);
1584     return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
1585 }
1586
1587 static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1588 {
1589     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1590     TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1591     return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
1592 }
1593
1594 static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
1595 {
1596     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1597     TRACE("()\n");
1598     return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
1599 }
1600
1601 static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
1602 {
1603     TMarshalDispatchChannel_QueryInterface,
1604     TMarshalDispatchChannel_AddRef,
1605     TMarshalDispatchChannel_Release,
1606     TMarshalDispatchChannel_GetBuffer,
1607     TMarshalDispatchChannel_SendReceive,
1608     TMarshalDispatchChannel_FreeBuffer,
1609     TMarshalDispatchChannel_GetDestCtx,
1610     TMarshalDispatchChannel_IsConnected
1611 };
1612
1613 static HRESULT TMarshalDispatchChannel_Create(
1614     IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
1615     IRpcChannelBuffer **ppChannel)
1616 {
1617     TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1618     if (!This)
1619         return E_OUTOFMEMORY;
1620
1621     This->lpVtbl = &TMarshalDispatchChannelVtbl;
1622     This->refs = 1;
1623     IRpcChannelBuffer_AddRef(pDelegateChannel);
1624     This->pDelegateChannel = pDelegateChannel;
1625     This->tmarshal_iid = *tmarshal_riid;
1626
1627     *ppChannel = (IRpcChannelBuffer *)&This->lpVtbl;
1628     return S_OK;
1629 }
1630
1631
1632 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
1633 {
1634     HRESULT       hr;
1635     CLSID         clsid;
1636
1637     if ((hr = CoGetPSClsid(riid, &clsid)))
1638         return hr;
1639     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
1640                              &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1641 }
1642
1643 static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
1644 {
1645     int j;
1646     /* nrofargs without This */
1647     int nrofargs;
1648     ITypeInfo *tinfo2;
1649     TMAsmProxy  *xasm = proxy->asmstubs + num;
1650     HRESULT hres;
1651     const FUNCDESC *fdesc;
1652
1653     hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
1654     if (hres) {
1655         ERR("GetFuncDesc %x should not fail here.\n",hres);
1656         return hres;
1657     }
1658     ITypeInfo_Release(tinfo2);
1659     /* some args take more than 4 byte on the stack */
1660     nrofargs = 0;
1661     for (j=0;j<fdesc->cParams;j++)
1662         nrofargs += _argsize(&fdesc->lprgelemdescParam[j].tdesc, proxy->tinfo);
1663
1664 #ifdef __i386__
1665     if (fdesc->callconv != CC_STDCALL) {
1666         ERR("calling convention is not stdcall????\n");
1667         return E_FAIL;
1668     }
1669 /* popl %eax    -       return ptr
1670  * pushl <nr>
1671  * pushl %eax
1672  * call xCall
1673  * lret <nr> (+4)
1674  *
1675  *
1676  * arg3 arg2 arg1 <method> <returnptr>
1677  */
1678     xasm->popleax       = 0x58;
1679     xasm->pushlval      = 0x68;
1680     xasm->nr            = num;
1681     xasm->pushleax      = 0x50;
1682     xasm->lcall         = 0xe8; /* relative jump */
1683     xasm->xcall         = (DWORD)xCall;
1684     xasm->xcall        -= (DWORD)&(xasm->lret);
1685     xasm->lret          = 0xc2;
1686     xasm->bytestopop    = (nrofargs+2)*4; /* pop args, This, iMethod */
1687     xasm->nop           = 0x90;
1688     proxy->lpvtbl[num]  = xasm;
1689 #else
1690     FIXME("not implemented on non i386\n");
1691     return E_FAIL;
1692 #endif
1693     return S_OK;
1694 }
1695
1696 static HRESULT WINAPI
1697 PSFacBuf_CreateProxy(
1698     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1699     IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1700 {
1701     HRESULT     hres;
1702     ITypeInfo   *tinfo;
1703     unsigned int i, nroffuncs;
1704     TMProxyImpl *proxy;
1705     TYPEATTR    *typeattr;
1706     BOOL        defer_to_dispatch = FALSE;
1707
1708     TRACE("(...%s...)\n",debugstr_guid(riid));
1709     hres = _get_typeinfo_for_iid(riid,&tinfo);
1710     if (hres) {
1711         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1712         return hres;
1713     }
1714
1715     hres = num_of_funcs(tinfo, &nroffuncs);
1716     if (FAILED(hres)) {
1717         ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
1718         ITypeInfo_Release(tinfo);
1719         return hres;
1720     }
1721
1722     proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1723     if (!proxy) return E_OUTOFMEMORY;
1724
1725     assert(sizeof(TMAsmProxy) == 16);
1726
1727     proxy->dispatch = NULL;
1728     proxy->dispatch_proxy = NULL;
1729     proxy->outerunknown = pUnkOuter;
1730     proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1731     if (!proxy->asmstubs) {
1732         ERR("Could not commit pages for proxy thunks\n");
1733         CoTaskMemFree(proxy);
1734         return E_OUTOFMEMORY;
1735     }
1736     proxy->lpvtbl2      = &tmproxyvtable;
1737     /* one reference for the proxy */
1738     proxy->ref          = 1;
1739     proxy->tinfo        = tinfo;
1740     proxy->iid          = *riid;
1741     proxy->chanbuf      = 0;
1742
1743     InitializeCriticalSection(&proxy->crit);
1744     proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
1745
1746     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1747
1748     /* if we derive from IDispatch then defer to its proxy for its methods */
1749     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
1750     if (hres == S_OK)
1751     {
1752         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
1753         {
1754             IPSFactoryBuffer *factory_buffer;
1755             hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1756             if (hres == S_OK)
1757             {
1758                 hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
1759                     &IID_IDispatch, &proxy->dispatch_proxy,
1760                     (void **)&proxy->dispatch);
1761                 IPSFactoryBuffer_Release(factory_buffer);
1762             }
1763             if ((hres == S_OK) && (nroffuncs < 7))
1764             {
1765                 ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
1766                 hres = E_UNEXPECTED;
1767             }
1768             if (hres == S_OK)
1769             {
1770                 defer_to_dispatch = TRUE;
1771             }
1772         }
1773         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
1774     }
1775
1776     for (i=0;i<nroffuncs;i++) {
1777         switch (i) {
1778         case 0:
1779                 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
1780                 break;
1781         case 1:
1782                 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
1783                 break;
1784         case 2:
1785                 proxy->lpvtbl[i] = ProxyIUnknown_Release;
1786                 break;
1787         case 3:
1788                 if(!defer_to_dispatch)
1789                 {
1790                     hres = init_proxy_entry_point(proxy, i);
1791                     if(FAILED(hres)) return hres;
1792                 }
1793                 else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
1794                 break;
1795         case 4:
1796                 if(!defer_to_dispatch)
1797                 {
1798                     hres = init_proxy_entry_point(proxy, i);
1799                     if(FAILED(hres)) return hres;
1800                 }
1801                 else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
1802                 break;
1803         case 5:
1804                 if(!defer_to_dispatch)
1805                 {
1806                     hres = init_proxy_entry_point(proxy, i);
1807                     if(FAILED(hres)) return hres;
1808                 }
1809                 else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
1810                 break;
1811         case 6:
1812                 if(!defer_to_dispatch)
1813                 {
1814                     hres = init_proxy_entry_point(proxy, i);
1815                     if(FAILED(hres)) return hres;
1816                 }
1817                 else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
1818                 break;
1819         default:
1820                 hres = init_proxy_entry_point(proxy, i);
1821                 if(FAILED(hres)) return hres;
1822         }
1823     }
1824
1825     if (hres == S_OK)
1826     {
1827         *ppv = proxy;
1828         *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1829         IUnknown_AddRef((IUnknown *)*ppv);
1830         return S_OK;
1831     }
1832     else
1833         TMProxyImpl_Release((IRpcProxyBuffer *)&proxy->lpvtbl2);
1834     return hres;
1835 }
1836
1837 typedef struct _TMStubImpl {
1838     const IRpcStubBufferVtbl   *lpvtbl;
1839     LONG                        ref;
1840
1841     LPUNKNOWN                   pUnk;
1842     ITypeInfo                   *tinfo;
1843     IID                         iid;
1844     IRpcStubBuffer              *dispatch_stub;
1845     BOOL                        dispatch_derivative;
1846 } TMStubImpl;
1847
1848 static HRESULT WINAPI
1849 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1850 {
1851     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1852         *ppv = iface;
1853         IRpcStubBuffer_AddRef(iface);
1854         return S_OK;
1855     }
1856     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1857     return E_NOINTERFACE;
1858 }
1859
1860 static ULONG WINAPI
1861 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1862 {
1863     TMStubImpl *This = (TMStubImpl *)iface;
1864     ULONG refCount = InterlockedIncrement(&This->ref);
1865         
1866     TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
1867
1868     return refCount;
1869 }
1870
1871 static ULONG WINAPI
1872 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1873 {
1874     TMStubImpl *This = (TMStubImpl *)iface;
1875     ULONG refCount = InterlockedDecrement(&This->ref);
1876
1877     TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
1878
1879     if (!refCount)
1880     {
1881         IRpcStubBuffer_Disconnect(iface);
1882         ITypeInfo_Release(This->tinfo);
1883         if (This->dispatch_stub)
1884             IRpcStubBuffer_Release(This->dispatch_stub);
1885         CoTaskMemFree(This);
1886     }
1887     return refCount;
1888 }
1889
1890 static HRESULT WINAPI
1891 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1892 {
1893     TMStubImpl *This = (TMStubImpl *)iface;
1894
1895     TRACE("(%p)->(%p)\n", This, pUnkServer);
1896
1897     IUnknown_AddRef(pUnkServer);
1898     This->pUnk = pUnkServer;
1899
1900     if (This->dispatch_stub)
1901         IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);
1902
1903     return S_OK;
1904 }
1905
1906 static void WINAPI
1907 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1908 {
1909     TMStubImpl *This = (TMStubImpl *)iface;
1910
1911     TRACE("(%p)->()\n", This);
1912
1913     if (This->pUnk)
1914     {
1915         IUnknown_Release(This->pUnk);
1916         This->pUnk = NULL;
1917     }
1918
1919     if (This->dispatch_stub)
1920         IRpcStubBuffer_Disconnect(This->dispatch_stub);
1921 }
1922
1923 static HRESULT WINAPI
1924 TMStubImpl_Invoke(
1925     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1926 {
1927 #ifdef __i386__
1928     int         i;
1929     const FUNCDESC *fdesc;
1930     TMStubImpl *This = (TMStubImpl *)iface;
1931     HRESULT     hres;
1932     DWORD       *args = NULL, res, *xargs, nrofargs;
1933     marshal_state       buf;
1934     UINT        nrofnames = 0;
1935     BSTR        names[10];
1936     BSTR        iname = NULL;
1937     ITypeInfo   *tinfo = NULL;
1938
1939     TRACE("...\n");
1940
1941     if (xmsg->iMethod < 3) {
1942         ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
1943         return E_UNEXPECTED;
1944     }
1945
1946     if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
1947     {
1948         IPSFactoryBuffer *factory_buffer;
1949         hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1950         if (hres == S_OK)
1951         {
1952             hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
1953                 This->pUnk, &This->dispatch_stub);
1954             IPSFactoryBuffer_Release(factory_buffer);
1955         }
1956         if (hres != S_OK)
1957             return hres;
1958         return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
1959     }
1960
1961     memset(&buf,0,sizeof(buf));
1962     buf.size    = xmsg->cbBuffer;
1963     buf.base    = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
1964     memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
1965     buf.curoff  = 0;
1966
1967     hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
1968     if (hres) {
1969         ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
1970         return hres;
1971     }
1972
1973     if (iname && !lstrcmpW(iname, IDispatchW))
1974     {
1975         ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
1976         hres = E_UNEXPECTED;
1977         SysFreeString (iname);
1978         goto exit;
1979     }
1980
1981     SysFreeString (iname);
1982
1983     /* Need them for hack below */
1984     memset(names,0,sizeof(names));
1985     ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1986     if (nrofnames > sizeof(names)/sizeof(names[0])) {
1987         ERR("Need more names!\n");
1988     }
1989
1990     /*dump_FUNCDESC(fdesc);*/
1991     nrofargs = 0;
1992     for (i=0;i<fdesc->cParams;i++)
1993         nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo);
1994     args = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(nrofargs+1)*sizeof(DWORD));
1995     if (!args)
1996     {
1997         hres = E_OUTOFMEMORY;
1998         goto exit;
1999     }
2000
2001     /* Allocate all stuff used by call. */
2002     xargs = args+1;
2003     for (i=0;i<fdesc->cParams;i++) {
2004         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
2005
2006         hres = deserialize_param(
2007            tinfo,
2008            is_in_elem(elem),
2009            FALSE,
2010            TRUE,
2011            &(elem->tdesc),
2012            xargs,
2013            &buf
2014         );
2015         xargs += _argsize(&elem->tdesc, tinfo);
2016         if (hres) {
2017             ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2018             break;
2019         }
2020     }
2021
2022     args[0] = (DWORD)This->pUnk;
2023
2024     __TRY
2025     {
2026         res = _invoke(
2027             (*((FARPROC**)args[0]))[fdesc->oVft/4],
2028             fdesc->callconv,
2029             (xargs-args),
2030             args
2031         );
2032     }
2033     __EXCEPT_ALL
2034     {
2035         DWORD dwExceptionCode = GetExceptionCode();
2036         ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2037         if (FAILED(dwExceptionCode))
2038             hres = dwExceptionCode;
2039         else
2040             hres = HRESULT_FROM_WIN32(dwExceptionCode);
2041     }
2042     __ENDTRY
2043
2044     if (hres != S_OK)
2045         goto exit;
2046
2047     buf.curoff = 0;
2048
2049     xargs = args+1;
2050     for (i=0;i<fdesc->cParams;i++) {
2051         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
2052         hres = serialize_param(
2053            tinfo,
2054            is_out_elem(elem),
2055            FALSE,
2056            TRUE,
2057            &elem->tdesc,
2058            xargs,
2059            &buf
2060         );
2061         xargs += _argsize(&elem->tdesc, tinfo);
2062         if (hres) {
2063             ERR("Failed to stuballoc param, hres %x\n",hres);
2064             break;
2065         }
2066     }
2067
2068     hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2069
2070     if (hres != S_OK)
2071         goto exit;
2072
2073     xmsg->cbBuffer      = buf.curoff;
2074     hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
2075     if (hres != S_OK)
2076         ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2077
2078     if (hres == S_OK)
2079         memcpy(xmsg->Buffer, buf.base, buf.curoff);
2080
2081 exit:
2082     for (i = 0; i < nrofnames; i++)
2083         SysFreeString(names[i]);
2084
2085     ITypeInfo_Release(tinfo);
2086     HeapFree(GetProcessHeap(), 0, args);
2087
2088     HeapFree(GetProcessHeap(), 0, buf.base);
2089
2090     TRACE("returning\n");
2091     return hres;
2092 #else
2093     FIXME( "not implemented on non-i386\n" );
2094     return E_FAIL;
2095 #endif
2096 }
2097
2098 static LPRPCSTUBBUFFER WINAPI
2099 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
2100     FIXME("Huh (%s)?\n",debugstr_guid(riid));
2101     return NULL;
2102 }
2103
2104 static ULONG WINAPI
2105 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
2106     TMStubImpl *This = (TMStubImpl *)iface;
2107
2108     FIXME("()\n");
2109     return This->ref; /*FIXME? */
2110 }
2111
2112 static HRESULT WINAPI
2113 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
2114     return E_NOTIMPL;
2115 }
2116
2117 static void WINAPI
2118 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
2119     return;
2120 }
2121
2122 static const IRpcStubBufferVtbl tmstubvtbl = {
2123     TMStubImpl_QueryInterface,
2124     TMStubImpl_AddRef,
2125     TMStubImpl_Release,
2126     TMStubImpl_Connect,
2127     TMStubImpl_Disconnect,
2128     TMStubImpl_Invoke,
2129     TMStubImpl_IsIIDSupported,
2130     TMStubImpl_CountRefs,
2131     TMStubImpl_DebugServerQueryInterface,
2132     TMStubImpl_DebugServerRelease
2133 };
2134
2135 static HRESULT WINAPI
2136 PSFacBuf_CreateStub(
2137     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
2138     IRpcStubBuffer** ppStub
2139 ) {
2140     HRESULT hres;
2141     ITypeInfo   *tinfo;
2142     TMStubImpl  *stub;
2143     TYPEATTR *typeattr;
2144
2145     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2146
2147     hres = _get_typeinfo_for_iid(riid,&tinfo);
2148     if (hres) {
2149         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2150         return hres;
2151     }
2152
2153     stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2154     if (!stub)
2155         return E_OUTOFMEMORY;
2156     stub->lpvtbl        = &tmstubvtbl;
2157     stub->ref           = 1;
2158     stub->tinfo         = tinfo;
2159     stub->dispatch_stub = NULL;
2160     stub->dispatch_derivative = FALSE;
2161     stub->iid           = *riid;
2162     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
2163     *ppStub             = (LPRPCSTUBBUFFER)stub;
2164     TRACE("IRpcStubBuffer: %p\n", stub);
2165     if (hres)
2166         ERR("Connect to pUnkServer failed?\n");
2167
2168     /* if we derive from IDispatch then defer to its stub for some of its methods */
2169     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2170     if (hres == S_OK)
2171     {
2172         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2173             stub->dispatch_derivative = TRUE;
2174         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2175     }
2176
2177     return hres;
2178 }
2179
2180 static const IPSFactoryBufferVtbl psfacbufvtbl = {
2181     PSFacBuf_QueryInterface,
2182     PSFacBuf_AddRef,
2183     PSFacBuf_Release,
2184     PSFacBuf_CreateProxy,
2185     PSFacBuf_CreateStub
2186 };
2187
2188 /* This is the whole PSFactoryBuffer object, just the vtableptr */
2189 static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
2190
2191 /***********************************************************************
2192  *           TMARSHAL_DllGetClassObject
2193  */
2194 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
2195 {
2196     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
2197         *ppv = &lppsfac;
2198         return S_OK;
2199     }
2200     return E_NOINTERFACE;
2201 }