user32/tests: Accept DISP_CHANGE_RESTART also for tests expected to fail.
[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,0);
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 = (LPVOID)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\\win32",tlguid,ver);
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 = (LPVOID)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
610     TRACE("(tdesc.vt %s)\n",debugstr_vt(tdesc->vt));
611
612     switch (tdesc->vt) {
613     case VT_EMPTY: /* nothing. empty variant for instance */
614         return S_OK;
615     case VT_I8:
616     case VT_UI8:
617     case VT_R8:
618     case VT_CY:
619         hres = S_OK;
620         if (debugout) TRACE_(olerelay)("%x%x\n",arg[0],arg[1]);
621         if (writeit)
622             hres = xbuf_add(buf,(LPBYTE)arg,8);
623         return hres;
624     case VT_BOOL:
625     case VT_ERROR:
626     case VT_INT:
627     case VT_UINT:
628     case VT_I4:
629     case VT_R4:
630     case VT_UI4:
631         hres = S_OK;
632         if (debugout) TRACE_(olerelay)("%x\n",*arg);
633         if (writeit)
634             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
635         return hres;
636     case VT_I2:
637     case VT_UI2:
638         hres = S_OK;
639         if (debugout) TRACE_(olerelay)("%04x\n",*arg & 0xffff);
640         if (writeit)
641             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
642         return hres;
643     case VT_I1:
644     case VT_UI1:
645         hres = S_OK;
646         if (debugout) TRACE_(olerelay)("%02x\n",*arg & 0xff);
647         if (writeit)
648             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
649         return hres;
650     case VT_I4|VT_BYREF:
651         hres = S_OK;
652         if (debugout) TRACE_(olerelay)("&0x%x\n",*arg);
653         if (writeit)
654             hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD));
655         /* do not dealloc at this time */
656         return hres;
657     case VT_VARIANT: {
658         TYPEDESC        tdesc2;
659         VARIANT         *vt = (VARIANT*)arg;
660         DWORD           vttype = V_VT(vt);
661
662         if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(vttype),debugstr_vf(vttype));
663         tdesc2.vt = vttype;
664         if (writeit) {
665             hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
666             if (hres) return hres;
667         }
668         /* need to recurse since we need to free the stuff */
669         hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,(DWORD*)&(V_I4(vt)),buf);
670         if (debugout) TRACE_(olerelay)(")");
671         return hres;
672     }
673     case VT_BSTR|VT_BYREF: {
674         if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : "<bstr NULL>");
675         if (writeit) {
676             /* ptr to ptr to magic widestring, basically */
677             BSTR *bstr = (BSTR *) *arg;
678             DWORD len;
679             if (!*bstr) {
680                 /* -1 means "null string" which is equivalent to empty string */
681                 len = -1;     
682                 hres = xbuf_add(buf, (LPBYTE)&len,sizeof(DWORD));
683                 if (hres) return hres;
684             } else {
685                 len = *((DWORD*)*bstr-1)/sizeof(WCHAR);
686                 hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
687                 if (hres) return hres;
688                 hres = xbuf_add(buf,(LPBYTE)*bstr,len * sizeof(WCHAR));
689                 if (hres) return hres;
690             }
691         }
692
693         if (dealloc && arg) {
694             BSTR *str = *((BSTR **)arg);
695             SysFreeString(*str);
696         }
697         return S_OK;
698     }
699     
700     case VT_BSTR: {
701         if (debugout) {
702             if (*arg)
703                    TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
704             else
705                     TRACE_(olerelay)("<bstr NULL>");
706         }
707         if (writeit) {
708             BSTR bstr = (BSTR)*arg;
709             DWORD len;
710             if (!bstr) {
711                 len = -1;
712                 hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
713                 if (hres) return hres;
714             } else {
715                 len = *((DWORD*)bstr-1)/sizeof(WCHAR);
716                 hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
717                 if (hres) return hres;
718                 hres = xbuf_add(buf,(LPBYTE)bstr,len * sizeof(WCHAR));
719                 if (hres) return hres;
720             }
721         }
722
723         if (dealloc && arg)
724             SysFreeString((BSTR)*arg);
725         return S_OK;
726     }
727     case VT_PTR: {
728         DWORD cookie;
729         BOOL        derefhere = TRUE;
730
731         if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
732             ITypeInfo   *tinfo2;
733             TYPEATTR    *tattr;
734
735             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
736             if (hres) {
737                 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
738                 return hres;
739             }
740             ITypeInfo_GetTypeAttr(tinfo2,&tattr);
741             switch (tattr->typekind) {
742             case TKIND_ALIAS:
743                 if (tattr->tdescAlias.vt == VT_USERDEFINED)
744                 {
745                     DWORD href = tattr->tdescAlias.u.hreftype;
746                     ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
747                     ITypeInfo_Release(tinfo2);
748                     hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
749                     if (hres) {
750                         ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
751                         return hres;
752                     }
753                     ITypeInfo_GetTypeAttr(tinfo2,&tattr);
754                     derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
755                 }
756                 break;
757             case TKIND_ENUM:    /* confirmed */
758             case TKIND_RECORD:  /* FIXME: mostly untested */
759                 break;
760             case TKIND_DISPATCH:        /* will be done in VT_USERDEFINED case */
761             case TKIND_INTERFACE:       /* will be done in VT_USERDEFINED case */
762                 derefhere=FALSE;
763                 break;
764             default:
765                 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
766                 derefhere=FALSE;
767                 break;
768             }
769             ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
770             ITypeInfo_Release(tinfo2);
771         }
772
773         if (debugout) TRACE_(olerelay)("*");
774         /* Write always, so the other side knows when it gets a NULL pointer.
775          */
776         cookie = *arg ? 0x42424242 : 0;
777         hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
778         if (hres)
779             return hres;
780         if (!*arg) {
781             if (debugout) TRACE_(olerelay)("NULL");
782             return S_OK;
783         }
784         hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
785         if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
786         return hres;
787     }
788     case VT_UNKNOWN:
789         if (debugout) TRACE_(olerelay)("unk(0x%x)",*arg);
790         if (writeit)
791             hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
792         if (dealloc && *(IUnknown **)arg)
793             IUnknown_Release((LPUNKNOWN)*arg);
794         return hres;
795     case VT_DISPATCH:
796         if (debugout) TRACE_(olerelay)("idisp(0x%x)",*arg);
797         if (writeit)
798             hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
799         if (dealloc && *(IUnknown **)arg)
800             IUnknown_Release((LPUNKNOWN)*arg);
801         return hres;
802     case VT_VOID:
803         if (debugout) TRACE_(olerelay)("<void>");
804         return S_OK;
805     case VT_USERDEFINED: {
806         ITypeInfo       *tinfo2;
807         TYPEATTR        *tattr;
808
809         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
810         if (hres) {
811             ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
812             return hres;
813         }
814         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
815         switch (tattr->typekind) {
816         case TKIND_DISPATCH:
817         case TKIND_INTERFACE:
818             if (writeit)
819                hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
820             if (dealloc)
821                 IUnknown_Release((LPUNKNOWN)arg);
822             break;
823         case TKIND_RECORD: {
824             int i;
825             if (debugout) TRACE_(olerelay)("{");
826             for (i=0;i<tattr->cVars;i++) {
827                 VARDESC *vdesc;
828                 ELEMDESC *elem2;
829                 TYPEDESC *tdesc2;
830
831                 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
832                 if (hres) {
833                     ERR("Could not get vardesc of %d\n",i);
834                     return hres;
835                 }
836                 elem2 = &vdesc->elemdescVar;
837                 tdesc2 = &elem2->tdesc;
838                 hres = serialize_param(
839                     tinfo2,
840                     writeit,
841                     debugout,
842                     dealloc,
843                     tdesc2,
844                     (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
845                     buf
846                 );
847                 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
848                 if (hres!=S_OK)
849                     return hres;
850                 if (debugout && (i<(tattr->cVars-1)))
851                     TRACE_(olerelay)(",");
852             }
853             if (debugout) TRACE_(olerelay)("}");
854             break;
855         }
856         case TKIND_ALIAS:
857             hres = serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
858             break;
859         case TKIND_ENUM:
860             hres = S_OK;
861             if (debugout) TRACE_(olerelay)("%x",*arg);
862             if (writeit)
863                 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
864             break;
865         default:
866             FIXME("Unhandled typekind %d\n",tattr->typekind);
867             hres = E_FAIL;
868             break;
869         }
870         ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
871         ITypeInfo_Release(tinfo2);
872         return hres;
873     }
874     case VT_CARRAY: {
875         ARRAYDESC *adesc = tdesc->u.lpadesc;
876         int i, arrsize = 1;
877
878         if (debugout) TRACE_(olerelay)("carr");
879         for (i=0;i<adesc->cDims;i++) {
880             if (debugout) TRACE_(olerelay)("[%d]",adesc->rgbounds[i].cElements);
881             arrsize *= adesc->rgbounds[i].cElements;
882         }
883         if (debugout) TRACE_(olerelay)("(vt %s)",debugstr_vt(adesc->tdescElem.vt));
884         if (debugout) TRACE_(olerelay)("[");
885         for (i=0;i<arrsize;i++) {
886             hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem, tinfo)), buf);
887             if (hres)
888                 return hres;
889             if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
890         }
891         if (debugout) TRACE_(olerelay)("]");
892         return S_OK;
893     }
894     case VT_SAFEARRAY: {
895         if (writeit)
896         {
897             ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
898             ULONG size = LPSAFEARRAY_UserSize(&flags, buf->curoff, (LPSAFEARRAY *)arg);
899             xbuf_resize(buf, size);
900             LPSAFEARRAY_UserMarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
901             buf->curoff = size;
902         }
903         return S_OK;
904     }
905     default:
906         ERR("Unhandled marshal type %d.\n",tdesc->vt);
907         return S_OK;
908     }
909 }
910
911 static HRESULT
912 deserialize_param(
913     ITypeInfo           *tinfo,
914     BOOL                readit,
915     BOOL                debugout,
916     BOOL                alloc,
917     TYPEDESC            *tdesc,
918     DWORD               *arg,
919     marshal_state       *buf)
920 {
921     HRESULT hres = S_OK;
922
923     TRACE("vt %s at %p\n",debugstr_vt(tdesc->vt),arg);
924
925     while (1) {
926         switch (tdesc->vt) {
927         case VT_EMPTY:
928             if (debugout) TRACE_(olerelay)("<empty>\n");
929             return S_OK;
930         case VT_NULL:
931             if (debugout) TRACE_(olerelay)("<null>\n");
932             return S_OK;
933         case VT_VARIANT: {
934             VARIANT     *vt = (VARIANT*)arg;
935
936             if (readit) {
937                 DWORD   vttype;
938                 TYPEDESC        tdesc2;
939                 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
940                 if (hres) {
941                     FIXME("vt type not read?\n");
942                     return hres;
943                 }
944                 memset(&tdesc2,0,sizeof(tdesc2));
945                 tdesc2.vt = vttype;
946                 V_VT(vt)  = vttype;
947                 if (debugout) TRACE_(olerelay)("Vt(%s%s)(",debugstr_vt(vttype),debugstr_vf(vttype));
948                 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, (DWORD*)&(V_I4(vt)), buf);
949                 TRACE_(olerelay)(")");
950                 return hres;
951             } else {
952                 VariantInit(vt);
953                 return S_OK;
954             }
955         }
956         case VT_I8:
957         case VT_UI8:
958         case VT_R8:
959         case VT_CY:
960             if (readit) {
961                 hres = xbuf_get(buf,(LPBYTE)arg,8);
962                 if (hres) ERR("Failed to read integer 8 byte\n");
963             }
964             if (debugout) TRACE_(olerelay)("%x%x",arg[0],arg[1]);
965             return hres;
966         case VT_ERROR:
967         case VT_BOOL:
968         case VT_I4:
969         case VT_INT:
970         case VT_UINT:
971         case VT_R4:
972         case VT_UI4:
973             if (readit) {
974                 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
975                 if (hres) ERR("Failed to read integer 4 byte\n");
976             }
977             if (debugout) TRACE_(olerelay)("%x",*arg);
978             return hres;
979         case VT_I2:
980         case VT_UI2:
981             if (readit) {
982                 DWORD x;
983                 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
984                 if (hres) ERR("Failed to read integer 4 byte\n");
985                 memcpy(arg,&x,2);
986             }
987             if (debugout) TRACE_(olerelay)("%04x",*arg & 0xffff);
988             return hres;
989         case VT_I1:
990         case VT_UI1:
991             if (readit) {
992                 DWORD x;
993                 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
994                 if (hres) ERR("Failed to read integer 4 byte\n");
995                 memcpy(arg,&x,1);
996             }
997             if (debugout) TRACE_(olerelay)("%02x",*arg & 0xff);
998             return hres;
999         case VT_I4|VT_BYREF:
1000             hres = S_OK;
1001             if (alloc)
1002                 *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
1003             if (readit) {
1004                 hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD));
1005                 if (hres) ERR("Failed to read integer 4 byte\n");
1006             }
1007             if (debugout) TRACE_(olerelay)("&0x%x",*(DWORD*)*arg);
1008             return hres;
1009         case VT_BSTR|VT_BYREF: {
1010             BSTR **bstr = (BSTR **)arg;
1011             WCHAR       *str;
1012             DWORD       len;
1013
1014             if (readit) {
1015                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
1016                 if (hres) {
1017                     ERR("failed to read bstr klen\n");
1018                     return hres;
1019                 }
1020                 if (len == -1) {
1021                     *bstr = CoTaskMemAlloc(sizeof(BSTR *));
1022                     **bstr = NULL;
1023                     if (debugout) TRACE_(olerelay)("<bstr NULL>");
1024                 } else {
1025                     str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR));
1026                     hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR));
1027                     if (hres) {
1028                         ERR("Failed to read BSTR.\n");
1029                         HeapFree(GetProcessHeap(),0,str);
1030                         return hres;
1031                     }
1032                     *bstr = CoTaskMemAlloc(sizeof(BSTR *));
1033                     **bstr = SysAllocStringLen(str,len);
1034                     if (debugout) TRACE_(olerelay)("%s",relaystr(str));
1035                     HeapFree(GetProcessHeap(),0,str);
1036                 }
1037             } else {
1038                 *bstr = NULL;
1039             }
1040             return S_OK;
1041         }
1042         case VT_BSTR: {
1043             WCHAR       *str;
1044             DWORD       len;
1045
1046             if (readit) {
1047                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
1048                 if (hres) {
1049                     ERR("failed to read bstr klen\n");
1050                     return hres;
1051                 }
1052                 if (len == -1) {
1053                     *arg = 0;
1054                     if (debugout) TRACE_(olerelay)("<bstr NULL>");
1055                 } else {
1056                     str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR));
1057                     hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR));
1058                     if (hres) {
1059                         ERR("Failed to read BSTR.\n");
1060                         HeapFree(GetProcessHeap(),0,str);
1061                         return hres;
1062                     }
1063                     *arg = (DWORD)SysAllocStringLen(str,len);
1064                     if (debugout) TRACE_(olerelay)("%s",relaystr(str));
1065                     HeapFree(GetProcessHeap(),0,str);
1066                 }
1067             } else {
1068                 *arg = 0;
1069             }
1070             return S_OK;
1071         }
1072         case VT_PTR: {
1073             DWORD       cookie;
1074             BOOL        derefhere = TRUE;
1075
1076             if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
1077                 ITypeInfo       *tinfo2;
1078                 TYPEATTR        *tattr;
1079
1080                 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
1081                 if (hres) {
1082                     ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1083                     return hres;
1084                 }
1085                 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1086                 switch (tattr->typekind) {
1087                 case TKIND_ALIAS:
1088                     if (tattr->tdescAlias.vt == VT_USERDEFINED)
1089                     {
1090                         DWORD href = tattr->tdescAlias.u.hreftype;
1091                         ITypeInfo_ReleaseTypeAttr(tinfo, tattr);
1092                         ITypeInfo_Release(tinfo2);
1093                         hres = ITypeInfo_GetRefTypeInfo(tinfo,href,&tinfo2);
1094                         if (hres) {
1095                             ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
1096                             return hres;
1097                         }
1098                         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1099                         derefhere = (tattr->typekind != TKIND_DISPATCH && tattr->typekind != TKIND_INTERFACE);
1100                     }
1101                     break;
1102                 case TKIND_ENUM:        /* confirmed */
1103                 case TKIND_RECORD:      /* FIXME: mostly untested */
1104                     break;
1105                 case TKIND_DISPATCH:    /* will be done in VT_USERDEFINED case */
1106                 case TKIND_INTERFACE:   /* will be done in VT_USERDEFINED case */
1107                     derefhere=FALSE;
1108                     break;
1109                 default:
1110                     FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
1111                     derefhere=FALSE;
1112                     break;
1113                 }
1114                 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1115                 ITypeInfo_Release(tinfo2);
1116             }
1117             /* read it in all cases, we need to know if we have 
1118              * NULL pointer or not.
1119              */
1120             hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1121             if (hres) {
1122                 ERR("Failed to load pointer cookie.\n");
1123                 return hres;
1124             }
1125             if (cookie != 0x42424242) {
1126                 /* we read a NULL ptr from the remote side */
1127                 if (debugout) TRACE_(olerelay)("NULL");
1128                 *arg = 0;
1129                 return S_OK;
1130             }
1131             if (debugout) TRACE_(olerelay)("*");
1132             if (alloc) {
1133                 /* Allocate space for the referenced struct */
1134                 if (derefhere)
1135                     *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc, tinfo));
1136             }
1137             if (derefhere)
1138                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
1139             else
1140                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
1141         }
1142         case VT_UNKNOWN:
1143             /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
1144             if (alloc)
1145                 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
1146             hres = S_OK;
1147             if (readit)
1148                 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
1149             if (debugout)
1150                 TRACE_(olerelay)("unk(%p)",arg);
1151             return hres;
1152         case VT_DISPATCH:
1153             hres = S_OK;
1154             if (readit)
1155                 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
1156             if (debugout)
1157                 TRACE_(olerelay)("idisp(%p)",arg);
1158             return hres;
1159         case VT_VOID:
1160             if (debugout) TRACE_(olerelay)("<void>");
1161             return S_OK;
1162         case VT_USERDEFINED: {
1163             ITypeInfo   *tinfo2;
1164             TYPEATTR    *tattr;
1165
1166             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1167             if (hres) {
1168                 ERR("Could not get typeinfo of hreftype %x for VT_USERDEFINED.\n",tdesc->u.hreftype);
1169                 return hres;
1170             }
1171             hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1172             if (hres) {
1173                 ERR("Could not get typeattr in VT_USERDEFINED.\n");
1174             } else {
1175                 switch (tattr->typekind) {
1176                 case TKIND_DISPATCH:
1177                 case TKIND_INTERFACE:
1178                     if (readit)
1179                         hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
1180                     break;
1181                 case TKIND_RECORD: {
1182                     int i;
1183
1184                     if (debugout) TRACE_(olerelay)("{");
1185                     for (i=0;i<tattr->cVars;i++) {
1186                         VARDESC *vdesc;
1187
1188                         hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
1189                         if (hres) {
1190                             ERR("Could not get vardesc of %d\n",i);
1191                             ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1192                             ITypeInfo_Release(tinfo2);
1193                             return hres;
1194                         }
1195                         hres = deserialize_param(
1196                             tinfo2,
1197                             readit,
1198                             debugout,
1199                             alloc,
1200                             &vdesc->elemdescVar.tdesc,
1201                             (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
1202                             buf
1203                         );
1204                         ITypeInfo2_ReleaseVarDesc(tinfo2, vdesc);
1205                         if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1206                     }
1207                     if (debugout) TRACE_(olerelay)("}");
1208                     break;
1209                 }
1210                 case TKIND_ALIAS:
1211                     hres = deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
1212                     break;
1213                 case TKIND_ENUM:
1214                     if (readit) {
1215                         hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1216                         if (hres) ERR("Failed to read enum (4 byte)\n");
1217                     }
1218                     if (debugout) TRACE_(olerelay)("%x",*arg);
1219                     break;
1220                 default:
1221                     ERR("Unhandled typekind %d\n",tattr->typekind);
1222                     hres = E_FAIL;
1223                     break;
1224                 }
1225                 ITypeInfo_ReleaseTypeAttr(tinfo2, tattr);
1226             }
1227             if (hres)
1228                 ERR("failed to stuballoc in TKIND_RECORD.\n");
1229             ITypeInfo_Release(tinfo2);
1230             return hres;
1231         }
1232         case VT_CARRAY: {
1233             /* arg is pointing to the start of the array. */
1234             ARRAYDESC *adesc = tdesc->u.lpadesc;
1235             int         arrsize,i;
1236             arrsize = 1;
1237             if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1238             for (i=0;i<adesc->cDims;i++)
1239                 arrsize *= adesc->rgbounds[i].cElements;
1240             for (i=0;i<arrsize;i++)
1241                 deserialize_param(
1242                     tinfo,
1243                     readit,
1244                     debugout,
1245                     alloc,
1246                     &adesc->tdescElem,
1247                     (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem, tinfo)),
1248                     buf
1249                 );
1250             return S_OK;
1251         }
1252     case VT_SAFEARRAY: {
1253             if (readit)
1254             {
1255                 ULONG flags = MAKELONG(MSHCTX_DIFFERENTMACHINE, NDR_LOCAL_DATA_REPRESENTATION);
1256                 unsigned char *buffer;
1257                 buffer = LPSAFEARRAY_UserUnmarshal(&flags, buf->base + buf->curoff, (LPSAFEARRAY *)arg);
1258                 buf->curoff = buffer - buf->base;
1259             }
1260             return S_OK;
1261         }
1262         default:
1263             ERR("No handler for VT type %d!\n",tdesc->vt);
1264             return S_OK;
1265         }
1266     }
1267 }
1268
1269 /* Retrieves a function's funcdesc, searching back into inherited interfaces. */
1270 static HRESULT get_funcdesc(ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, const FUNCDESC **fdesc,
1271                             BSTR *iname, BSTR *fname, UINT *num)
1272 {
1273     HRESULT hr;
1274     UINT i, impl_types;
1275     UINT inherited_funcs = 0;
1276     TYPEATTR *attr;
1277
1278     if (fname) *fname = NULL;
1279     if (iname) *iname = NULL;
1280     if (num) *num = 0;
1281     *tactual = NULL;
1282
1283     hr = ITypeInfo_GetTypeAttr(tinfo, &attr);
1284     if (FAILED(hr))
1285     {
1286         ERR("GetTypeAttr failed with %x\n",hr);
1287         return hr;
1288     }
1289
1290     if(attr->typekind == TKIND_DISPATCH)
1291     {
1292         if(attr->wTypeFlags & TYPEFLAG_FDUAL)
1293         {
1294             HREFTYPE href;
1295             ITypeInfo *tinfo2;
1296
1297             hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
1298             if(FAILED(hr))
1299             {
1300                 ERR("Cannot get interface href from dual dispinterface\n");
1301                 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1302                 return hr;
1303             }
1304             hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1305             if(FAILED(hr))
1306             {
1307                 ERR("Cannot get interface from dual dispinterface\n");
1308                 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1309                 return hr;
1310             }
1311             hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
1312             ITypeInfo_Release(tinfo2);
1313             ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1314             return hr;
1315         }
1316         ERR("Shouldn't be called with a non-dual dispinterface\n");
1317         return E_FAIL;
1318     }
1319
1320     impl_types = attr->cImplTypes;
1321     ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1322
1323     for (i = 0; i < impl_types; i++)
1324     {
1325         HREFTYPE href;
1326         ITypeInfo *pSubTypeInfo;
1327         UINT sub_funcs;
1328
1329         hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
1330         if (FAILED(hr)) return hr;
1331         hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
1332         if (FAILED(hr)) return hr;
1333
1334         hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
1335         inherited_funcs += sub_funcs;
1336         ITypeInfo_Release(pSubTypeInfo);
1337         if(SUCCEEDED(hr)) return hr;
1338     }
1339     if(iMethod < inherited_funcs)
1340     {
1341         ERR("shouldn't be here\n");
1342         return E_INVALIDARG;
1343     }
1344
1345     for(i = inherited_funcs; i <= iMethod; i++)
1346     {
1347         hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
1348         if(FAILED(hr))
1349         {
1350             if(num) *num = i;
1351             return hr;
1352         }
1353     }
1354
1355     /* found it. We don't care about num so zero it */
1356     if(num) *num = 0;
1357     *tactual = tinfo;
1358     ITypeInfo_AddRef(*tactual);
1359     if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1360     if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1361     return S_OK;
1362 }
1363
1364 static inline BOOL is_in_elem(const ELEMDESC *elem)
1365 {
1366     return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
1367 }
1368
1369 static inline BOOL is_out_elem(const ELEMDESC *elem)
1370 {
1371     return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
1372 }
1373
1374 static DWORD
1375 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1376 {
1377     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
1378     const FUNCDESC      *fdesc;
1379     HRESULT             hres;
1380     int                 i, relaydeb = TRACE_ON(olerelay);
1381     marshal_state       buf;
1382     RPCOLEMESSAGE       msg;
1383     ULONG               status;
1384     BSTR                fname,iname;
1385     BSTR                names[10];
1386     UINT                nrofnames;
1387     DWORD               remoteresult = 0;
1388     ITypeInfo           *tinfo;
1389     IRpcChannelBuffer *chanbuf;
1390
1391     EnterCriticalSection(&tpinfo->crit);
1392
1393     hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1394     if (hres) {
1395         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1396         LeaveCriticalSection(&tpinfo->crit);
1397         return E_FAIL;
1398     }
1399
1400     if (!tpinfo->chanbuf)
1401     {
1402         WARN("Tried to use disconnected proxy\n");
1403         ITypeInfo_Release(tinfo);
1404         LeaveCriticalSection(&tpinfo->crit);
1405         return RPC_E_DISCONNECTED;
1406     }
1407     chanbuf = tpinfo->chanbuf;
1408     IRpcChannelBuffer_AddRef(chanbuf);
1409
1410     LeaveCriticalSection(&tpinfo->crit);
1411
1412     if (relaydeb) {
1413        TRACE_(olerelay)("->");
1414         if (iname)
1415             TRACE_(olerelay)("%s:",relaystr(iname));
1416         if (fname)
1417             TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1418         else
1419             TRACE_(olerelay)("%d",method);
1420         TRACE_(olerelay)("(");
1421     }
1422
1423     SysFreeString(iname);
1424     SysFreeString(fname);
1425
1426     memset(&buf,0,sizeof(buf));
1427
1428     /* normal typelib driven serializing */
1429
1430     /* Need them for hack below */
1431     memset(names,0,sizeof(names));
1432     if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1433         nrofnames = 0;
1434     if (nrofnames > sizeof(names)/sizeof(names[0]))
1435         ERR("Need more names!\n");
1436
1437     xargs = args;
1438     for (i=0;i<fdesc->cParams;i++) {
1439         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1440         if (relaydeb) {
1441             if (i) TRACE_(olerelay)(",");
1442             if (i+1<nrofnames && names[i+1])
1443                 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1444         }
1445         /* No need to marshal other data than FIN and any VT_PTR. */
1446         if (!is_in_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1447             xargs+=_argsize(&elem->tdesc, tinfo);
1448             if (relaydeb) TRACE_(olerelay)("[out]");
1449             continue;
1450         }
1451         hres = serialize_param(
1452             tinfo,
1453             is_in_elem(elem),
1454             relaydeb,
1455             FALSE,
1456             &elem->tdesc,
1457             xargs,
1458             &buf
1459         );
1460
1461         if (hres) {
1462             ERR("Failed to serialize param, hres %x\n",hres);
1463             break;
1464         }
1465         xargs+=_argsize(&elem->tdesc, tinfo);
1466     }
1467     if (relaydeb) TRACE_(olerelay)(")");
1468
1469     memset(&msg,0,sizeof(msg));
1470     msg.cbBuffer = buf.curoff;
1471     msg.iMethod  = method;
1472     hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1473     if (hres) {
1474         ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1475         goto exit;
1476     }
1477     memcpy(msg.Buffer,buf.base,buf.curoff);
1478     if (relaydeb) TRACE_(olerelay)("\n");
1479     hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1480     if (hres) {
1481         ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1482         goto exit;
1483     }
1484
1485     if (relaydeb) TRACE_(olerelay)(" status = %08x (",status);
1486     if (buf.base)
1487         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1488     else
1489         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1490     buf.size = msg.cbBuffer;
1491     memcpy(buf.base,msg.Buffer,buf.size);
1492     buf.curoff = 0;
1493
1494     /* generic deserializer using typelib description */
1495     xargs = args;
1496     status = S_OK;
1497     for (i=0;i<fdesc->cParams;i++) {
1498         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1499
1500         if (relaydeb) {
1501             if (i) TRACE_(olerelay)(",");
1502             if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1503         }
1504         /* No need to marshal other data than FOUT and any VT_PTR */
1505         if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1506             xargs += _argsize(&elem->tdesc, tinfo);
1507             if (relaydeb) TRACE_(olerelay)("[in]");
1508             continue;
1509         }
1510         hres = deserialize_param(
1511             tinfo,
1512             is_out_elem(elem),
1513             relaydeb,
1514             FALSE,
1515             &(elem->tdesc),
1516             xargs,
1517             &buf
1518         );
1519         if (hres) {
1520             ERR("Failed to unmarshall param, hres %x\n",hres);
1521             status = hres;
1522             break;
1523         }
1524         xargs += _argsize(&elem->tdesc, tinfo);
1525     }
1526
1527     hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1528     if (hres != S_OK)
1529         goto exit;
1530     if (relaydeb) TRACE_(olerelay)(") = %08x\n", remoteresult);
1531
1532     hres = remoteresult;
1533
1534 exit:
1535     IRpcChannelBuffer_FreeBuffer(chanbuf,&msg);
1536     for (i = 0; i < nrofnames; i++)
1537         SysFreeString(names[i]);
1538     HeapFree(GetProcessHeap(),0,buf.base);
1539     IRpcChannelBuffer_Release(chanbuf);
1540     ITypeInfo_Release(tinfo);
1541     TRACE("-- 0x%08x\n", hres);
1542     return hres;
1543 }
1544
1545 static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1546 {
1547     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1548
1549     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1550
1551     if (proxy->outerunknown)
1552         return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1553
1554     FIXME("No interface\n");
1555     return E_NOINTERFACE;
1556 }
1557
1558 static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1559 {
1560     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1561
1562     TRACE("\n");
1563
1564     if (proxy->outerunknown)
1565         return IUnknown_AddRef(proxy->outerunknown);
1566
1567     return 2; /* FIXME */
1568 }
1569
1570 static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1571 {
1572     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1573
1574     TRACE("\n");
1575
1576     if (proxy->outerunknown)
1577         return IUnknown_Release(proxy->outerunknown);
1578
1579     return 1; /* FIXME */
1580 }
1581
1582 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1583 {
1584     TMProxyImpl *This = (TMProxyImpl *)iface;
1585
1586     TRACE("(%p)\n", pctinfo);
1587
1588     return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1589 }
1590
1591 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1592 {
1593     TMProxyImpl *This = (TMProxyImpl *)iface;
1594
1595     TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1596
1597     return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1598 }
1599
1600 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1601 {
1602     TMProxyImpl *This = (TMProxyImpl *)iface;
1603
1604     TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1605
1606     return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1607                                    cNames, lcid, rgDispId);
1608 }
1609
1610 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1611                                             WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1612                                             EXCEPINFO * pExcepInfo, UINT * puArgErr)
1613 {
1614     TMProxyImpl *This = (TMProxyImpl *)iface;
1615
1616     TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1617           debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
1618           pExcepInfo, puArgErr);
1619
1620     return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1621                             wFlags, pDispParams, pVarResult, pExcepInfo,
1622                             puArgErr);
1623 }
1624
1625 typedef struct
1626 {
1627     const IRpcChannelBufferVtbl *lpVtbl;
1628     LONG                  refs;
1629     /* the IDispatch-derived interface we are handling */
1630         IID                   tmarshal_iid;
1631     IRpcChannelBuffer    *pDelegateChannel;
1632 } TMarshalDispatchChannel;
1633
1634 static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
1635 {
1636     *ppv = NULL;
1637     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
1638     {
1639         *ppv = (LPVOID)iface;
1640         IUnknown_AddRef(iface);
1641         return S_OK;
1642     }
1643     return E_NOINTERFACE;
1644 }
1645
1646 static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
1647 {
1648     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1649     return InterlockedIncrement(&This->refs);
1650 }
1651
1652 static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
1653 {
1654     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1655     ULONG ref;
1656
1657     ref = InterlockedDecrement(&This->refs);
1658     if (ref)
1659         return ref;
1660
1661         IRpcChannelBuffer_Release(This->pDelegateChannel);
1662     HeapFree(GetProcessHeap(), 0, This);
1663     return 0;
1664 }
1665
1666 static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1667 {
1668     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1669     TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
1670     /* Note: we are pretending to invoke a method on the interface identified
1671      * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
1672      * without the RPC runtime getting confused by not exporting an IDispatch interface */
1673     return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
1674 }
1675
1676 static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1677 {
1678     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1679     TRACE("(%p, %p)\n", olemsg, pstatus);
1680     return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
1681 }
1682
1683 static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1684 {
1685     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1686     TRACE("(%p)\n", olemsg);
1687     return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
1688 }
1689
1690 static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1691 {
1692     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1693     TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1694     return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
1695 }
1696
1697 static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
1698 {
1699     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1700     TRACE("()\n");
1701     return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
1702 }
1703
1704 static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
1705 {
1706     TMarshalDispatchChannel_QueryInterface,
1707     TMarshalDispatchChannel_AddRef,
1708     TMarshalDispatchChannel_Release,
1709     TMarshalDispatchChannel_GetBuffer,
1710     TMarshalDispatchChannel_SendReceive,
1711     TMarshalDispatchChannel_FreeBuffer,
1712     TMarshalDispatchChannel_GetDestCtx,
1713     TMarshalDispatchChannel_IsConnected
1714 };
1715
1716 static HRESULT TMarshalDispatchChannel_Create(
1717     IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
1718     IRpcChannelBuffer **ppChannel)
1719 {
1720     TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1721     if (!This)
1722         return E_OUTOFMEMORY;
1723
1724     This->lpVtbl = &TMarshalDispatchChannelVtbl;
1725     This->refs = 1;
1726     IRpcChannelBuffer_AddRef(pDelegateChannel);
1727     This->pDelegateChannel = pDelegateChannel;
1728     This->tmarshal_iid = *tmarshal_riid;
1729
1730     *ppChannel = (IRpcChannelBuffer *)&This->lpVtbl;
1731     return S_OK;
1732 }
1733
1734
1735 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
1736 {
1737     HRESULT       hr;
1738     CLSID         clsid;
1739
1740     if ((hr = CoGetPSClsid(riid, &clsid)))
1741         return hr;
1742     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
1743                              &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1744 }
1745
1746 static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
1747 {
1748     int j;
1749     /* nrofargs without This */
1750     int nrofargs;
1751     ITypeInfo *tinfo2;
1752     TMAsmProxy  *xasm = proxy->asmstubs + num;
1753     HRESULT hres;
1754     const FUNCDESC *fdesc;
1755
1756     hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
1757     if (hres) {
1758         ERR("GetFuncDesc %x should not fail here.\n",hres);
1759         return hres;
1760     }
1761     ITypeInfo_Release(tinfo2);
1762     /* some args take more than 4 byte on the stack */
1763     nrofargs = 0;
1764     for (j=0;j<fdesc->cParams;j++)
1765         nrofargs += _argsize(&fdesc->lprgelemdescParam[j].tdesc, proxy->tinfo);
1766
1767 #ifdef __i386__
1768     if (fdesc->callconv != CC_STDCALL) {
1769         ERR("calling convention is not stdcall????\n");
1770         return E_FAIL;
1771     }
1772 /* popl %eax    -       return ptr
1773  * pushl <nr>
1774  * pushl %eax
1775  * call xCall
1776  * lret <nr> (+4)
1777  *
1778  *
1779  * arg3 arg2 arg1 <method> <returnptr>
1780  */
1781     xasm->popleax       = 0x58;
1782     xasm->pushlval      = 0x68;
1783     xasm->nr            = num;
1784     xasm->pushleax      = 0x50;
1785     xasm->lcall         = 0xe8; /* relative jump */
1786     xasm->xcall         = (DWORD)xCall;
1787     xasm->xcall        -= (DWORD)&(xasm->lret);
1788     xasm->lret          = 0xc2;
1789     xasm->bytestopop    = (nrofargs+2)*4; /* pop args, This, iMethod */
1790     xasm->nop           = 0x90;
1791     proxy->lpvtbl[num]  = xasm;
1792 #else
1793     FIXME("not implemented on non i386\n");
1794     return E_FAIL;
1795 #endif
1796     return S_OK;
1797 }
1798
1799 static HRESULT WINAPI
1800 PSFacBuf_CreateProxy(
1801     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1802     IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1803 {
1804     HRESULT     hres;
1805     ITypeInfo   *tinfo;
1806     unsigned int i, nroffuncs;
1807     TMProxyImpl *proxy;
1808     TYPEATTR    *typeattr;
1809     BOOL        defer_to_dispatch = FALSE;
1810
1811     TRACE("(...%s...)\n",debugstr_guid(riid));
1812     hres = _get_typeinfo_for_iid(riid,&tinfo);
1813     if (hres) {
1814         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1815         return hres;
1816     }
1817
1818     hres = num_of_funcs(tinfo, &nroffuncs);
1819     if (FAILED(hres)) {
1820         ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
1821         ITypeInfo_Release(tinfo);
1822         return hres;
1823     }
1824
1825     proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1826     if (!proxy) return E_OUTOFMEMORY;
1827
1828     assert(sizeof(TMAsmProxy) == 16);
1829
1830     proxy->dispatch = NULL;
1831     proxy->dispatch_proxy = NULL;
1832     proxy->outerunknown = pUnkOuter;
1833     proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1834     if (!proxy->asmstubs) {
1835         ERR("Could not commit pages for proxy thunks\n");
1836         CoTaskMemFree(proxy);
1837         return E_OUTOFMEMORY;
1838     }
1839     proxy->lpvtbl2      = &tmproxyvtable;
1840     /* one reference for the proxy */
1841     proxy->ref          = 1;
1842     proxy->tinfo        = tinfo;
1843     proxy->iid          = *riid;
1844     proxy->chanbuf      = 0;
1845
1846     InitializeCriticalSection(&proxy->crit);
1847     proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
1848
1849     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1850
1851     /* if we derive from IDispatch then defer to its proxy for its methods */
1852     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
1853     if (hres == S_OK)
1854     {
1855         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
1856         {
1857             IPSFactoryBuffer *factory_buffer;
1858             hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1859             if (hres == S_OK)
1860             {
1861                 hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
1862                     &IID_IDispatch, &proxy->dispatch_proxy,
1863                     (void **)&proxy->dispatch);
1864                 IPSFactoryBuffer_Release(factory_buffer);
1865             }
1866             if ((hres == S_OK) && (nroffuncs < 7))
1867             {
1868                 ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
1869                 hres = E_UNEXPECTED;
1870             }
1871             if (hres == S_OK)
1872             {
1873                 defer_to_dispatch = TRUE;
1874             }
1875         }
1876         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
1877     }
1878
1879     for (i=0;i<nroffuncs;i++) {
1880         switch (i) {
1881         case 0:
1882                 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
1883                 break;
1884         case 1:
1885                 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
1886                 break;
1887         case 2:
1888                 proxy->lpvtbl[i] = ProxyIUnknown_Release;
1889                 break;
1890         case 3:
1891                 if(!defer_to_dispatch)
1892                 {
1893                     hres = init_proxy_entry_point(proxy, i);
1894                     if(FAILED(hres)) return hres;
1895                 }
1896                 else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
1897                 break;
1898         case 4:
1899                 if(!defer_to_dispatch)
1900                 {
1901                     hres = init_proxy_entry_point(proxy, i);
1902                     if(FAILED(hres)) return hres;
1903                 }
1904                 else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
1905                 break;
1906         case 5:
1907                 if(!defer_to_dispatch)
1908                 {
1909                     hres = init_proxy_entry_point(proxy, i);
1910                     if(FAILED(hres)) return hres;
1911                 }
1912                 else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
1913                 break;
1914         case 6:
1915                 if(!defer_to_dispatch)
1916                 {
1917                     hres = init_proxy_entry_point(proxy, i);
1918                     if(FAILED(hres)) return hres;
1919                 }
1920                 else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
1921                 break;
1922         default:
1923                 hres = init_proxy_entry_point(proxy, i);
1924                 if(FAILED(hres)) return hres;
1925         }
1926     }
1927
1928     if (hres == S_OK)
1929     {
1930         *ppv            = (LPVOID)proxy;
1931         *ppProxy                = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1932         IUnknown_AddRef((IUnknown *)*ppv);
1933         return S_OK;
1934     }
1935     else
1936         TMProxyImpl_Release((IRpcProxyBuffer *)&proxy->lpvtbl2);
1937     return hres;
1938 }
1939
1940 typedef struct _TMStubImpl {
1941     const IRpcStubBufferVtbl   *lpvtbl;
1942     LONG                        ref;
1943
1944     LPUNKNOWN                   pUnk;
1945     ITypeInfo                   *tinfo;
1946     IID                         iid;
1947     IRpcStubBuffer              *dispatch_stub;
1948     BOOL                        dispatch_derivative;
1949 } TMStubImpl;
1950
1951 static HRESULT WINAPI
1952 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1953 {
1954     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1955         *ppv = (LPVOID)iface;
1956         IRpcStubBuffer_AddRef(iface);
1957         return S_OK;
1958     }
1959     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1960     return E_NOINTERFACE;
1961 }
1962
1963 static ULONG WINAPI
1964 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1965 {
1966     TMStubImpl *This = (TMStubImpl *)iface;
1967     ULONG refCount = InterlockedIncrement(&This->ref);
1968         
1969     TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
1970
1971     return refCount;
1972 }
1973
1974 static ULONG WINAPI
1975 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1976 {
1977     TMStubImpl *This = (TMStubImpl *)iface;
1978     ULONG refCount = InterlockedDecrement(&This->ref);
1979
1980     TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
1981
1982     if (!refCount)
1983     {
1984         IRpcStubBuffer_Disconnect(iface);
1985         ITypeInfo_Release(This->tinfo);
1986         if (This->dispatch_stub)
1987             IRpcStubBuffer_Release(This->dispatch_stub);
1988         CoTaskMemFree(This);
1989     }
1990     return refCount;
1991 }
1992
1993 static HRESULT WINAPI
1994 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1995 {
1996     TMStubImpl *This = (TMStubImpl *)iface;
1997
1998     TRACE("(%p)->(%p)\n", This, pUnkServer);
1999
2000     IUnknown_AddRef(pUnkServer);
2001     This->pUnk = pUnkServer;
2002
2003     if (This->dispatch_stub)
2004         IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);
2005
2006     return S_OK;
2007 }
2008
2009 static void WINAPI
2010 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
2011 {
2012     TMStubImpl *This = (TMStubImpl *)iface;
2013
2014     TRACE("(%p)->()\n", This);
2015
2016     if (This->pUnk)
2017     {
2018         IUnknown_Release(This->pUnk);
2019         This->pUnk = NULL;
2020     }
2021
2022     if (This->dispatch_stub)
2023         IRpcStubBuffer_Disconnect(This->dispatch_stub);
2024 }
2025
2026 static HRESULT WINAPI
2027 TMStubImpl_Invoke(
2028     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
2029 {
2030     int         i;
2031     const FUNCDESC *fdesc;
2032     TMStubImpl *This = (TMStubImpl *)iface;
2033     HRESULT     hres;
2034     DWORD       *args = NULL, res, *xargs, nrofargs;
2035     marshal_state       buf;
2036     UINT        nrofnames = 0;
2037     BSTR        names[10];
2038     BSTR        iname = NULL;
2039     ITypeInfo   *tinfo = NULL;
2040
2041     TRACE("...\n");
2042
2043     if (xmsg->iMethod < 3) {
2044         ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
2045         return E_UNEXPECTED;
2046     }
2047
2048     if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
2049     {
2050         IPSFactoryBuffer *factory_buffer;
2051         hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
2052         if (hres == S_OK)
2053         {
2054             hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
2055                 This->pUnk, &This->dispatch_stub);
2056             IPSFactoryBuffer_Release(factory_buffer);
2057         }
2058         if (hres != S_OK)
2059             return hres;
2060         return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
2061     }
2062
2063     memset(&buf,0,sizeof(buf));
2064     buf.size    = xmsg->cbBuffer;
2065     buf.base    = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
2066     memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
2067     buf.curoff  = 0;
2068
2069     hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
2070     if (hres) {
2071         ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
2072         return hres;
2073     }
2074
2075     if (iname && !lstrcmpW(iname, IDispatchW))
2076     {
2077         ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
2078         hres = E_UNEXPECTED;
2079         SysFreeString (iname);
2080         goto exit;
2081     }
2082
2083     SysFreeString (iname);
2084
2085     /* Need them for hack below */
2086     memset(names,0,sizeof(names));
2087     ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
2088     if (nrofnames > sizeof(names)/sizeof(names[0])) {
2089         ERR("Need more names!\n");
2090     }
2091
2092     /*dump_FUNCDESC(fdesc);*/
2093     nrofargs = 0;
2094     for (i=0;i<fdesc->cParams;i++)
2095         nrofargs += _argsize(&fdesc->lprgelemdescParam[i].tdesc, tinfo);
2096     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
2097     if (!args)
2098     {
2099         hres = E_OUTOFMEMORY;
2100         goto exit;
2101     }
2102
2103     /* Allocate all stuff used by call. */
2104     xargs = args+1;
2105     for (i=0;i<fdesc->cParams;i++) {
2106         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
2107
2108         hres = deserialize_param(
2109            tinfo,
2110            is_in_elem(elem),
2111            FALSE,
2112            TRUE,
2113            &(elem->tdesc),
2114            xargs,
2115            &buf
2116         );
2117         xargs += _argsize(&elem->tdesc, tinfo);
2118         if (hres) {
2119             ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2120             break;
2121         }
2122     }
2123
2124     args[0] = (DWORD)This->pUnk;
2125
2126     __TRY
2127     {
2128         res = _invoke(
2129             (*((FARPROC**)args[0]))[fdesc->oVft/4],
2130             fdesc->callconv,
2131             (xargs-args),
2132             args
2133         );
2134     }
2135     __EXCEPT_ALL
2136     {
2137         DWORD dwExceptionCode = GetExceptionCode();
2138         ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2139         if (FAILED(dwExceptionCode))
2140             hres = dwExceptionCode;
2141         else
2142             hres = HRESULT_FROM_WIN32(dwExceptionCode);
2143     }
2144     __ENDTRY
2145
2146     if (hres != S_OK)
2147         goto exit;
2148
2149     buf.curoff = 0;
2150
2151     xargs = args+1;
2152     for (i=0;i<fdesc->cParams;i++) {
2153         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
2154         hres = serialize_param(
2155            tinfo,
2156            is_out_elem(elem),
2157            FALSE,
2158            TRUE,
2159            &elem->tdesc,
2160            xargs,
2161            &buf
2162         );
2163         xargs += _argsize(&elem->tdesc, tinfo);
2164         if (hres) {
2165             ERR("Failed to stuballoc param, hres %x\n",hres);
2166             break;
2167         }
2168     }
2169
2170     hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2171
2172     if (hres != S_OK)
2173         goto exit;
2174
2175     xmsg->cbBuffer      = buf.curoff;
2176     hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
2177     if (hres != S_OK)
2178         ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2179
2180     if (hres == S_OK)
2181         memcpy(xmsg->Buffer, buf.base, buf.curoff);
2182
2183 exit:
2184     for (i = 0; i < nrofnames; i++)
2185         SysFreeString(names[i]);
2186
2187     ITypeInfo_Release(tinfo);
2188     HeapFree(GetProcessHeap(), 0, args);
2189
2190     HeapFree(GetProcessHeap(), 0, buf.base);
2191
2192     TRACE("returning\n");
2193     return hres;
2194 }
2195
2196 static LPRPCSTUBBUFFER WINAPI
2197 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
2198     FIXME("Huh (%s)?\n",debugstr_guid(riid));
2199     return NULL;
2200 }
2201
2202 static ULONG WINAPI
2203 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
2204     TMStubImpl *This = (TMStubImpl *)iface;
2205
2206     FIXME("()\n");
2207     return This->ref; /*FIXME? */
2208 }
2209
2210 static HRESULT WINAPI
2211 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
2212     return E_NOTIMPL;
2213 }
2214
2215 static void WINAPI
2216 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
2217     return;
2218 }
2219
2220 static const IRpcStubBufferVtbl tmstubvtbl = {
2221     TMStubImpl_QueryInterface,
2222     TMStubImpl_AddRef,
2223     TMStubImpl_Release,
2224     TMStubImpl_Connect,
2225     TMStubImpl_Disconnect,
2226     TMStubImpl_Invoke,
2227     TMStubImpl_IsIIDSupported,
2228     TMStubImpl_CountRefs,
2229     TMStubImpl_DebugServerQueryInterface,
2230     TMStubImpl_DebugServerRelease
2231 };
2232
2233 static HRESULT WINAPI
2234 PSFacBuf_CreateStub(
2235     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
2236     IRpcStubBuffer** ppStub
2237 ) {
2238     HRESULT hres;
2239     ITypeInfo   *tinfo;
2240     TMStubImpl  *stub;
2241     TYPEATTR *typeattr;
2242
2243     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2244
2245     hres = _get_typeinfo_for_iid(riid,&tinfo);
2246     if (hres) {
2247         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2248         return hres;
2249     }
2250
2251     stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2252     if (!stub)
2253         return E_OUTOFMEMORY;
2254     stub->lpvtbl        = &tmstubvtbl;
2255     stub->ref           = 1;
2256     stub->tinfo         = tinfo;
2257     stub->dispatch_stub = NULL;
2258     stub->dispatch_derivative = FALSE;
2259     stub->iid           = *riid;
2260     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
2261     *ppStub             = (LPRPCSTUBBUFFER)stub;
2262     TRACE("IRpcStubBuffer: %p\n", stub);
2263     if (hres)
2264         ERR("Connect to pUnkServer failed?\n");
2265
2266     /* if we derive from IDispatch then defer to its stub for some of its methods */
2267     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2268     if (hres == S_OK)
2269     {
2270         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2271             stub->dispatch_derivative = TRUE;
2272         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2273     }
2274
2275     return hres;
2276 }
2277
2278 static const IPSFactoryBufferVtbl psfacbufvtbl = {
2279     PSFacBuf_QueryInterface,
2280     PSFacBuf_AddRef,
2281     PSFacBuf_Release,
2282     PSFacBuf_CreateProxy,
2283     PSFacBuf_CreateStub
2284 };
2285
2286 /* This is the whole PSFactoryBuffer object, just the vtableptr */
2287 static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
2288
2289 /***********************************************************************
2290  *           TMARSHAL_DllGetClassObject
2291  */
2292 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
2293 {
2294     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
2295         *ppv = &lppsfac;
2296         return S_OK;
2297     }
2298     return E_NOINTERFACE;
2299 }