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