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