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