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