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