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