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