Load advpack.dll at runtime to avoid link problems with the platform
[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
52 WINE_DEFAULT_DEBUG_CHANNEL(ole);
53 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
54
55 #define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
56
57 typedef struct _marshal_state {
58     LPBYTE      base;
59     int         size;
60     int         curoff;
61
62     BOOL        thisisiid;
63     IID         iid;    /* HACK: for VT_VOID */
64 } marshal_state;
65
66 /* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
67 static char *relaystr(WCHAR *in) {
68     char *tmp = (char *)debugstr_w(in);
69     tmp += 2;
70     tmp[strlen(tmp)-1] = '\0';
71     return tmp;
72 }
73
74 static HRESULT
75 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
76     while (buf->size - buf->curoff < size) {
77         if (buf->base) {
78             buf->size += 100;
79             buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
80             if (!buf->base)
81                 return E_OUTOFMEMORY;
82         } else {
83             buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
84             buf->size = 32;
85             if (!buf->base)
86                 return E_OUTOFMEMORY;
87         }
88     }
89     memcpy(buf->base+buf->curoff,stuff,size);
90     buf->curoff += size;
91     return S_OK;
92 }
93
94 static HRESULT
95 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
96     if (buf->size < buf->curoff+size) return E_FAIL;
97     memcpy(stuff,buf->base+buf->curoff,size);
98     buf->curoff += size;
99     return S_OK;
100 }
101
102 static HRESULT
103 xbuf_skip(marshal_state *buf, DWORD size) {
104     if (buf->size < buf->curoff+size) return E_FAIL;
105     buf->curoff += size;
106     return S_OK;
107 }
108
109 static HRESULT
110 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
111     IStream             *pStm;
112     ULARGE_INTEGER      newpos;
113     LARGE_INTEGER       seekto;
114     ULONG               res;
115     HRESULT             hres;
116     DWORD               xsize;
117
118     TRACE("...%s...\n",debugstr_guid(riid));
119     
120     *pUnk = NULL;
121     hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
122     if (hres) {
123         ERR("xbuf_get failed\n");
124         return hres;
125     }
126     
127     if (xsize == 0) return S_OK;
128     
129     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
130     if (hres) {
131         ERR("Stream create failed %lx\n",hres);
132         return hres;
133     }
134     
135     hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
136     if (hres) {
137         ERR("stream write %lx\n",hres);
138         return hres;
139     }
140     
141     memset(&seekto,0,sizeof(seekto));
142     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
143     if (hres) {
144         ERR("Failed Seek %lx\n",hres);
145         return hres;
146     }
147     
148     hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
149     if (hres) {
150         ERR("Unmarshalling interface %s failed with %lx\n",debugstr_guid(riid),hres);
151         return hres;
152     }
153     
154     IStream_Release(pStm);
155     return xbuf_skip(buf,xsize);
156 }
157
158 static HRESULT
159 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
160     LPUNKNOWN           newiface = NULL;
161     LPBYTE              tempbuf = NULL;
162     IStream             *pStm = NULL;
163     STATSTG             ststg;
164     ULARGE_INTEGER      newpos;
165     LARGE_INTEGER       seekto;
166     ULONG               res;
167     DWORD               xsize;
168     HRESULT             hres;
169
170     hres = E_FAIL;
171     if (!pUnk) {
172         ERR("pUnk is NULL?\n");
173         goto fail;
174     }
175
176     TRACE("...%s...\n",debugstr_guid(riid));
177     hres = IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
178     if (hres) {
179         WARN("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
180         goto fail;
181     }
182     
183     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
184     if (hres) {
185         ERR("Stream create failed %lx\n",hres);
186         goto fail;
187     }
188     
189     hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
190     if (hres) {
191         ERR("Marshalling interface %s failed with %lx\n", debugstr_guid(riid), hres);
192         goto fail;
193     }
194     
195     hres = IStream_Stat(pStm,&ststg,0);
196     if (hres) {
197         ERR("Stream stat failed\n");
198         goto fail;
199     }
200     
201     tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
202     memset(&seekto,0,sizeof(seekto));
203     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
204     if (hres) {
205         ERR("Failed Seek %lx\n",hres);
206         goto fail;
207     }
208     
209     hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
210     if (hres) {
211         ERR("Failed Read %lx\n",hres);
212         goto fail;
213     }
214     
215     xsize = ststg.cbSize.u.LowPart;
216     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
217     hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
218     
219     HeapFree(GetProcessHeap(),0,tempbuf);
220     IUnknown_Release(newiface);
221     IStream_Release(pStm);
222     
223     return hres;
224     
225 fail:
226     xsize = 0;
227     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
228     if (pStm) IUnknown_Release(pStm);
229     if (newiface) IUnknown_Release(newiface);
230     HeapFree(GetProcessHeap(), 0, tempbuf);
231     return hres;
232 }
233
234 /********************* OLE Proxy/Stub Factory ********************************/
235 static HRESULT WINAPI
236 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
237     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
238         *ppv = (LPVOID)iface;
239         /* No ref counting, static class */
240         return S_OK;
241     }
242     FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
243     return E_NOINTERFACE;
244 }
245
246 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
247 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
248
249 static HRESULT
250 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
251     HRESULT     hres;
252     HKEY        ikey;
253     char        tlguid[200],typelibkey[300],interfacekey[300],ver[100];
254     char        tlfn[260];
255     OLECHAR     tlfnW[260];
256     DWORD       tlguidlen, verlen, type, tlfnlen;
257     ITypeLib    *tl;
258
259     sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
260         riid->Data1, riid->Data2, riid->Data3,
261         riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
262         riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
263     );
264
265     if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
266         ERR("No %s key found.\n",interfacekey);
267         return E_FAIL;
268     }
269     type = (1<<REG_SZ);
270     tlguidlen = sizeof(tlguid);
271     if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
272         ERR("Getting typelib guid failed.\n");
273         RegCloseKey(ikey);
274         return E_FAIL;
275     }
276     type = (1<<REG_SZ);
277     verlen = sizeof(ver);
278     if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
279         ERR("Could not get version value?\n");
280         RegCloseKey(ikey);
281         return E_FAIL;
282     }
283     RegCloseKey(ikey);
284     sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
285     tlfnlen = sizeof(tlfn);
286     if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
287         ERR("Could not get typelib fn?\n");
288         return E_FAIL;
289     }
290     MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
291     hres = LoadTypeLib(tlfnW,&tl);
292     if (hres) {
293         ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
294         return hres;
295     }
296     hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
297     if (hres) {
298         ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
299         ITypeLib_Release(tl);
300         return hres;
301     }
302     /* FIXME: do this?  ITypeLib_Release(tl); */
303     return hres;
304 }
305
306 /* Determine nr of functions. Since we use the toplevel interface and all
307  * inherited ones have lower numbers, we are ok to not to descent into
308  * the inheritance tree I think.
309  */
310 static int _nroffuncs(ITypeInfo *tinfo) {
311     int         n, max = 0;
312     FUNCDESC    *fdesc;
313     HRESULT     hres;
314
315     n=0;
316     while (1) {
317         hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
318         if (hres)
319             return max+1;
320         if (fdesc->oVft/4 > max)
321             max = fdesc->oVft/4;
322         n++;
323     }
324     /*NOTREACHED*/
325 }
326
327 #ifdef __i386__
328
329 #include "pshpack1.h"
330
331 typedef struct _TMAsmProxy {
332     BYTE        popleax;
333     BYTE        pushlval;
334     BYTE        nr;
335     BYTE        pushleax;
336     BYTE        lcall;
337     DWORD       xcall;
338     BYTE        lret;
339     WORD        bytestopop;
340 } TMAsmProxy;
341
342 #include "poppack.h"
343
344 #else /* __i386__ */
345 # error You need to implement stubless proxies for your architecture
346 #endif
347
348 typedef struct _TMProxyImpl {
349     LPVOID                              *lpvtbl;
350     IRpcProxyBufferVtbl *lpvtbl2;
351     ULONG                               ref;
352
353     TMAsmProxy                          *asmstubs;
354     ITypeInfo*                          tinfo;
355     IRpcChannelBuffer*                  chanbuf;
356     IID                                 iid;
357     CRITICAL_SECTION    crit;
358 } TMProxyImpl;
359
360 static HRESULT WINAPI
361 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv)
362 {
363     TRACE("()\n");
364     if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
365         *ppv = (LPVOID)iface;
366         IRpcProxyBuffer_AddRef(iface);
367         return S_OK;
368     }
369     FIXME("no interface for %s\n",debugstr_guid(riid));
370     return E_NOINTERFACE;
371 }
372
373 static ULONG WINAPI
374 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface)
375 {
376     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
377     ULONG refCount = InterlockedIncrement(&This->ref);
378
379     TRACE("(%p)->(ref before=%lu)\n",This, refCount - 1);
380
381     return refCount;
382 }
383
384 static ULONG WINAPI
385 TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
386 {
387     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
388     ULONG refCount = InterlockedDecrement(&This->ref);
389
390     TRACE("(%p)->(ref before=%lu)\n",This, refCount + 1);
391
392     if (!refCount)
393     {
394         DeleteCriticalSection(&This->crit);
395         if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
396         VirtualFree(This->asmstubs, 0, MEM_RELEASE);
397         CoTaskMemFree(This);
398     }
399     return refCount;
400 }
401
402 static HRESULT WINAPI
403 TMProxyImpl_Connect(
404     LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer)
405 {
406     ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
407
408     TRACE("(%p)\n", pRpcChannelBuffer);
409
410     EnterCriticalSection(&This->crit);
411
412     IRpcChannelBuffer_AddRef(pRpcChannelBuffer);
413     This->chanbuf = pRpcChannelBuffer;
414
415     LeaveCriticalSection(&This->crit);
416
417     return S_OK;
418 }
419
420 static void WINAPI
421 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface)
422 {
423     ICOM_THIS_MULTI(TMProxyImpl, lpvtbl2, iface);
424
425     TRACE("()\n");
426
427     EnterCriticalSection(&This->crit);
428
429     IRpcChannelBuffer_Release(This->chanbuf);
430     This->chanbuf = NULL;
431
432     LeaveCriticalSection(&This->crit);
433 }
434
435
436 static IRpcProxyBufferVtbl tmproxyvtable = {
437     TMProxyImpl_QueryInterface,
438     TMProxyImpl_AddRef,
439     TMProxyImpl_Release,
440     TMProxyImpl_Connect,
441     TMProxyImpl_Disconnect
442 };
443
444 /* how much space do we use on stack in DWORD steps. */
445 int
446 _argsize(DWORD vt) {
447     switch (vt) {
448     case VT_DATE:
449         return sizeof(DATE)/sizeof(DWORD);
450     case VT_VARIANT:
451         return (sizeof(VARIANT)+3)/sizeof(DWORD);
452     default:
453         return 1;
454     }
455 }
456
457 static int
458 _xsize(TYPEDESC *td) {
459     switch (td->vt) {
460     case VT_DATE:
461         return sizeof(DATE);
462     case VT_VARIANT:
463         return sizeof(VARIANT)+3;
464     case VT_CARRAY: {
465         int i, arrsize = 1;
466         ARRAYDESC *adesc = td->u.lpadesc;
467
468         for (i=0;i<adesc->cDims;i++)
469             arrsize *= adesc->rgbounds[i].cElements;
470         return arrsize*_xsize(&adesc->tdescElem);
471     }
472     case VT_UI2:
473     case VT_I2:
474         return 2;
475     case VT_UI1:
476     case VT_I1:
477         return 1;
478     default:
479         return 4;
480     }
481 }
482
483 static HRESULT
484 serialize_param(
485     ITypeInfo           *tinfo,
486     BOOL                writeit,
487     BOOL                debugout,
488     BOOL                dealloc,
489     TYPEDESC            *tdesc,
490     DWORD               *arg,
491     marshal_state       *buf)
492 {
493     HRESULT hres = S_OK;
494
495     TRACE("(tdesc.vt %d)\n",tdesc->vt);
496
497     switch (tdesc->vt) {
498     case VT_EMPTY: /* nothing. empty variant for instance */
499         return S_OK;
500     case VT_BOOL:
501     case VT_ERROR:
502     case VT_UI4:
503     case VT_UINT:
504     case VT_I4:
505     case VT_R4:
506     case VT_UI2:
507     case VT_UI1:
508         hres = S_OK;
509         if (debugout) TRACE_(olerelay)("%lx",*arg);
510         if (writeit)
511             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
512         return hres;
513     case VT_VARIANT: {
514         TYPEDESC        tdesc2;
515         VARIANT         *vt = (VARIANT*)arg;
516         DWORD           vttype = V_VT(vt);
517
518         if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
519         tdesc2.vt = vttype;
520         if (writeit) {
521             hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
522             if (hres) return hres;
523         }
524         /* need to recurse since we need to free the stuff */
525         hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,&(V_I4(vt)),buf);
526         if (debugout) TRACE_(olerelay)(")");
527         return hres;
528     }
529     case VT_BSTR: {
530         if (debugout) {
531             if (arg)
532                     TRACE_(olerelay)("%s",relaystr((BSTR)*arg));
533             else
534                     TRACE_(olerelay)("<bstr NULL>");
535         }
536         if (writeit) {
537             if (!*arg) {
538                 DWORD fakelen = -1;
539                 hres = xbuf_add(buf,(LPBYTE)&fakelen,4);
540                 if (hres)
541                     return hres;
542             } else {
543                 DWORD *bstr = ((DWORD*)(*arg))-1;
544
545                 hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
546                 if (hres)
547                     return hres;
548             }
549         }
550
551         if (dealloc && arg)
552             SysFreeString((BSTR)*arg);
553         return S_OK;
554     }
555     case VT_PTR: {
556         DWORD cookie;
557
558         if (debugout) TRACE_(olerelay)("*");
559         if (writeit) {
560             cookie = *arg ? 0x42424242 : 0;
561             hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
562             if (hres)
563                 return hres;
564         }
565         if (!*arg) {
566             if (debugout) TRACE_(olerelay)("NULL");
567             return S_OK;
568         }
569         hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
570         if (dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)arg);
571         return hres;
572     }
573     case VT_UNKNOWN:
574         if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg);
575         if (writeit)
576             hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
577         return hres;
578     case VT_DISPATCH:
579         if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg);
580         if (writeit)
581             hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
582         return hres;
583     case VT_VOID:
584         if (debugout) TRACE_(olerelay)("<void>");
585         return S_OK;
586     case VT_USERDEFINED: {
587         ITypeInfo       *tinfo2;
588         TYPEATTR        *tattr;
589
590         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
591         if (hres) {
592             ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
593             return hres;
594         }
595         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
596         switch (tattr->typekind) {
597         case TKIND_DISPATCH:
598         case TKIND_INTERFACE:
599             if (writeit)
600                hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
601             break;
602         case TKIND_RECORD: {
603             int i;
604             if (debugout) TRACE_(olerelay)("{");
605             for (i=0;i<tattr->cVars;i++) {
606                 VARDESC *vdesc;
607                 ELEMDESC *elem2;
608                 TYPEDESC *tdesc2;
609
610                 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
611                 if (hres) {
612                     ERR("Could not get vardesc of %d\n",i);
613                     return hres;
614                 }
615                 /* Need them for hack below */
616                 /*
617                 memset(names,0,sizeof(names));
618                 hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
619                 if (nrofnames > sizeof(names)/sizeof(names[0])) {
620                     ERR("Need more names!\n");
621                 }
622                 if (!hres && debugout)
623                     TRACE_(olerelay)("%s=",relaystr(names[0]));
624                 */
625                 elem2 = &vdesc->elemdescVar;
626                 tdesc2 = &elem2->tdesc;
627                 hres = serialize_param(
628                     tinfo2,
629                     writeit,
630                     debugout,
631                     dealloc,
632                     tdesc2,
633                     (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
634                     buf
635                 );
636                 if (hres!=S_OK)
637                     return hres;
638                 if (debugout && (i<(tattr->cVars-1)))
639                     TRACE_(olerelay)(",");
640             }
641             if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
642                 memcpy(&(buf->iid),arg,sizeof(buf->iid));
643             if (debugout) TRACE_(olerelay)("}");
644             break;
645         }
646         default:
647             FIXME("Unhandled typekind %d\n",tattr->typekind);
648             hres = E_FAIL;
649             break;
650         }
651         ITypeInfo_Release(tinfo2);
652         return hres;
653     }
654     case VT_CARRAY: {
655         ARRAYDESC *adesc = tdesc->u.lpadesc;
656         int i, arrsize = 1;
657
658         if (debugout) TRACE_(olerelay)("carr");
659         for (i=0;i<adesc->cDims;i++) {
660             if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);
661             arrsize *= adesc->rgbounds[i].cElements;
662         }
663         if (debugout) TRACE_(olerelay)("[");
664         for (i=0;i<arrsize;i++) {
665             hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
666             if (hres)
667                 return hres;
668             if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
669         }
670         if (debugout) TRACE_(olerelay)("]");
671         return S_OK;
672     }
673     default:
674         ERR("Unhandled marshal type %d.\n",tdesc->vt);
675         return S_OK;
676     }
677 }
678
679 static HRESULT
680 serialize_LPVOID_ptr(
681     ITypeInfo           *tinfo,
682     BOOL                writeit,
683     BOOL                debugout,
684     BOOL                dealloc,
685     TYPEDESC            *tdesc,
686     DWORD               *arg,
687     marshal_state       *buf)
688 {
689     HRESULT     hres;
690     DWORD       cookie;
691
692     if ((tdesc->vt != VT_PTR)                   ||
693         (tdesc->u.lptdesc->vt != VT_PTR)        ||
694         (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
695     ) {
696         FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
697         return E_FAIL;
698     }
699     cookie = (*arg) ? 0x42424242: 0x0;
700     if (writeit) {
701         hres = xbuf_add(buf, (LPVOID)&cookie, sizeof(cookie));
702         if (hres)
703             return hres;
704     }
705     if (!*arg) {
706         if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
707         return S_OK;
708     }
709     if (debugout)
710         TRACE_(olerelay)("ppv(%p)",*(LPUNKNOWN*)*arg);
711     if (writeit) {
712         hres = _marshal_interface(buf,&(buf->iid),*(LPUNKNOWN*)*arg);
713         if (hres)
714             return hres;
715     }
716     if (dealloc)
717         HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
718     return S_OK;
719 }
720
721 static HRESULT
722 serialize_DISPPARAM_ptr(
723     ITypeInfo           *tinfo,
724     BOOL                writeit,
725     BOOL                debugout,
726     BOOL                dealloc,
727     TYPEDESC            *tdesc,
728     DWORD               *arg,
729     marshal_state       *buf)
730 {
731     DWORD       cookie;
732     HRESULT     hres;
733     DISPPARAMS  *disp;
734     int         i;
735
736     if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
737         FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
738         return E_FAIL;
739     }
740
741     cookie = *arg ? 0x42424242 : 0x0;
742     if (writeit) {
743         hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
744         if (hres)
745             return hres;
746     }
747     if (!*arg) {
748         if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
749         return S_OK;
750     }
751     disp = (DISPPARAMS*)*arg;
752     if (writeit) {
753         hres = xbuf_add(buf,(LPBYTE)&disp->cArgs,sizeof(disp->cArgs));
754         if (hres)
755             return hres;
756     }
757     if (debugout) TRACE_(olerelay)("D{");
758     for (i=0;i<disp->cArgs;i++) {
759         TYPEDESC        vtdesc;
760
761         vtdesc.vt = VT_VARIANT;
762         serialize_param(
763             tinfo,
764             writeit,
765             debugout,
766             dealloc,
767             &vtdesc,
768             (DWORD*)(disp->rgvarg+i),
769             buf
770         );
771         if (debugout && (i<disp->cArgs-1))
772             TRACE_(olerelay)(",");
773     }
774     if (dealloc)
775         HeapFree(GetProcessHeap(),0,disp->rgvarg);
776     if (writeit) {
777         hres = xbuf_add(buf,(LPBYTE)&disp->cNamedArgs,sizeof(disp->cNamedArgs));
778         if (hres)
779             return hres;
780     }
781     if (debugout) TRACE_(olerelay)("}{");
782     for (i=0;i<disp->cNamedArgs;i++) {
783         TYPEDESC        vtdesc;
784
785         vtdesc.vt = VT_UINT;
786         serialize_param(
787             tinfo,
788             writeit,
789             debugout,
790             dealloc,
791             &vtdesc,
792             (DWORD*)(disp->rgdispidNamedArgs+i),
793             buf
794         );
795         if (debugout && (i<disp->cNamedArgs-1))
796             TRACE_(olerelay)(",");
797     }
798     if (debugout) TRACE_(olerelay)("}");
799     if (dealloc) {
800         HeapFree(GetProcessHeap(),0,disp->rgdispidNamedArgs);
801         HeapFree(GetProcessHeap(),0,disp);
802     }
803     return S_OK;
804 }
805
806 static HRESULT
807 deserialize_param(
808     ITypeInfo           *tinfo,
809     BOOL                readit,
810     BOOL                debugout,
811     BOOL                alloc,
812     TYPEDESC            *tdesc,
813     DWORD               *arg,
814     marshal_state       *buf)
815 {
816     HRESULT hres = S_OK;
817
818     TRACE("vt %d at %p\n",tdesc->vt,arg);
819
820     while (1) {
821         switch (tdesc->vt) {
822         case VT_EMPTY:
823             if (debugout) TRACE_(olerelay)("<empty>");
824             return S_OK;
825         case VT_NULL:
826             if (debugout) TRACE_(olerelay)("<null>");
827             return S_OK;
828         case VT_VARIANT: {
829             VARIANT     *vt = (VARIANT*)arg;
830
831             if (readit) {
832                 DWORD   vttype;
833                 TYPEDESC        tdesc2;
834                 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
835                 if (hres) {
836                     FIXME("vt type not read?\n");
837                     return hres;
838                 }
839                 memset(&tdesc2,0,sizeof(tdesc2));
840                 tdesc2.vt = vttype;
841                 V_VT(vt)  = vttype;
842                 if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
843                 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, &(V_I4(vt)), buf);
844                 TRACE_(olerelay)(")");
845                 return hres;
846             } else {
847                 VariantInit(vt);
848                 return S_OK;
849             }
850         }
851         case VT_ERROR:
852         case VT_BOOL: case VT_I4: case VT_UI4: case VT_UINT: case VT_R4:
853         case VT_UI2:
854         case VT_UI1:
855             if (readit) {
856                 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
857                 if (hres) ERR("Failed to read integer 4 byte\n");
858             }
859             if (debugout) TRACE_(olerelay)("%lx",*arg);
860             return hres;
861         case VT_BSTR: {
862             WCHAR       *str;
863             DWORD       len;
864
865             if (readit) {
866                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
867                 if (hres) {
868                     ERR("failed to read bstr klen\n");
869                     return hres;
870                 }
871                 if (len == -1) {
872                     *arg = 0;
873                     if (debugout) TRACE_(olerelay)("<bstr NULL>");
874                 } else {
875                     str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
876                     hres = xbuf_get(buf,(LPBYTE)str,len);
877                     if (hres) {
878                         ERR("Failed to read BSTR.\n");
879                         return hres;
880                     }
881                     *arg = (DWORD)SysAllocStringLen(str,len);
882                     if (debugout) TRACE_(olerelay)("%s",relaystr(str));
883                     HeapFree(GetProcessHeap(),0,str);
884                 }
885             } else {
886                 *arg = 0;
887             }
888             return S_OK;
889         }
890         case VT_PTR: {
891             DWORD       cookie;
892             BOOL        derefhere = 0;
893
894             derefhere = (tdesc->u.lptdesc->vt != VT_USERDEFINED);
895
896             if (readit) {
897                 hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
898                 if (hres) {
899                     ERR("Failed to load pointer cookie.\n");
900                     return hres;
901                 }
902                 if (cookie != 0x42424242) {
903                     if (debugout) TRACE_(olerelay)("NULL");
904                     *arg = 0;
905                     return S_OK;
906                 }
907                 if (debugout) TRACE_(olerelay)("*");
908             }
909             if (alloc) {
910                 if (derefhere)
911                     *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
912             }
913             if (derefhere)
914                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
915             else
916                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
917         }
918         case VT_UNKNOWN:
919             /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
920             if (alloc)
921                 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
922             hres = S_OK;
923             if (readit)
924                 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
925             if (debugout)
926                 TRACE_(olerelay)("unk(%p)",arg);
927             return hres;
928         case VT_DISPATCH:
929             hres = S_OK;
930             if (readit)
931                 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
932             if (debugout)
933                 TRACE_(olerelay)("idisp(%p)",arg);
934             return hres;
935         case VT_VOID:
936             if (debugout) TRACE_(olerelay)("<void>");
937             return S_OK;
938         case VT_USERDEFINED: {
939             ITypeInfo   *tinfo2;
940             TYPEATTR    *tattr;
941
942             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
943             if (hres) {
944                 ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
945                 return hres;
946             }
947             hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
948             if (hres) {
949                 ERR("Could not get typeattr in VT_USERDEFINED.\n");
950             } else {
951                 if (alloc)
952                     *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
953                 switch (tattr->typekind) {
954                 case TKIND_DISPATCH:
955                 case TKIND_INTERFACE:
956                     if (readit)
957                         hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
958                     break;
959                 case TKIND_RECORD: {
960                     int i;
961
962                     if (debugout) TRACE_(olerelay)("{");
963                     for (i=0;i<tattr->cVars;i++) {
964                         VARDESC *vdesc;
965
966                         hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
967                         if (hres) {
968                             ERR("Could not get vardesc of %d\n",i);
969                             return hres;
970                         }
971                         hres = deserialize_param(
972                             tinfo2,
973                             readit,
974                             debugout,
975                             alloc,
976                             &vdesc->elemdescVar.tdesc,
977                             (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
978                             buf
979                         );
980                         if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
981                     }
982                     if (buf->thisisiid && (tattr->cbSizeInstance==sizeof(GUID)))
983                         memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
984                     if (debugout) TRACE_(olerelay)("}");
985                     break;
986                 }
987                 default:
988                     ERR("Unhandled typekind %d\n",tattr->typekind);
989                     hres = E_FAIL;
990                     break;
991                 }
992             }
993             if (hres)
994                 ERR("failed to stuballoc in TKIND_RECORD.\n");
995             ITypeInfo_Release(tinfo2);
996             return hres;
997         }
998         case VT_CARRAY: {
999             /* arg is pointing to the start of the array. */
1000             ARRAYDESC *adesc = tdesc->u.lpadesc;
1001             int         arrsize,i;
1002             arrsize = 1;
1003             if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1004             for (i=0;i<adesc->cDims;i++)
1005                 arrsize *= adesc->rgbounds[i].cElements;
1006             for (i=0;i<arrsize;i++)
1007                 deserialize_param(
1008                     tinfo,
1009                     readit,
1010                     debugout,
1011                     alloc,
1012                     &adesc->tdescElem,
1013                     (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),
1014                     buf
1015                 );
1016             return S_OK;
1017         }
1018         default:
1019             ERR("No handler for VT type %d!\n",tdesc->vt);
1020             return S_OK;
1021         }
1022     }
1023 }
1024
1025 static HRESULT
1026 deserialize_LPVOID_ptr(
1027     ITypeInfo           *tinfo,
1028     BOOL                readit,
1029     BOOL                debugout,
1030     BOOL                alloc,
1031     TYPEDESC            *tdesc,
1032     DWORD               *arg,
1033     marshal_state       *buf
1034 ) {
1035     HRESULT     hres;
1036     DWORD       cookie;
1037
1038     if ((tdesc->vt != VT_PTR)                   ||
1039         (tdesc->u.lptdesc->vt != VT_PTR)        ||
1040         (tdesc->u.lptdesc->u.lptdesc->vt != VT_VOID)
1041     ) {
1042         FIXME("ppvObject not expressed as VT_PTR -> VT_PTR -> VT_VOID?\n");
1043         return E_FAIL;
1044     }
1045     if (alloc)
1046         *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
1047     if (readit) {
1048         hres = xbuf_get(buf, (LPVOID)&cookie, sizeof(cookie));
1049         if (hres)
1050             return hres;
1051         if (cookie != 0x42424242) {
1052             *(DWORD*)*arg = 0;
1053             if (debugout) TRACE_(olerelay)("<lpvoid NULL>");
1054             return S_OK;
1055         }
1056     }
1057     if (readit) {
1058         hres = _unmarshal_interface(buf,&buf->iid,(LPUNKNOWN*)*arg);
1059         if (hres)
1060             return hres;
1061     }
1062     if (debugout) TRACE_(olerelay)("ppv(%p)",(LPVOID)*arg);
1063     return S_OK;
1064 }
1065
1066 static HRESULT
1067 deserialize_DISPPARAM_ptr(
1068     ITypeInfo           *tinfo,
1069     BOOL                readit,
1070     BOOL                debugout,
1071     BOOL                alloc,
1072     TYPEDESC            *tdesc,
1073     DWORD               *arg,
1074     marshal_state       *buf)
1075 {
1076     DWORD       cookie;
1077     DISPPARAMS  *disps;
1078     HRESULT     hres;
1079     int         i;
1080
1081     if ((tdesc->vt != VT_PTR) || (tdesc->u.lptdesc->vt != VT_USERDEFINED)) {
1082         FIXME("DISPPARAMS not expressed as VT_PTR -> VT_USERDEFINED?\n");
1083         return E_FAIL;
1084     }
1085     if (readit) {
1086         hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
1087         if (hres)
1088             return hres;
1089         if (cookie == 0) {
1090             *arg = 0;
1091             if (debugout) TRACE_(olerelay)("<DISPPARAMS NULL>");
1092             return S_OK;
1093         }
1094     }
1095     if (alloc)
1096         *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPPARAMS));
1097     disps = (DISPPARAMS*)*arg;
1098     if (!readit)
1099         return S_OK;
1100     hres = xbuf_get(buf, (LPBYTE)&disps->cArgs, sizeof(disps->cArgs));
1101     if (hres)
1102         return hres;
1103     if (alloc)
1104         disps->rgvarg = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(VARIANT)*disps->cArgs);
1105     if (debugout) TRACE_(olerelay)("D{");
1106     for (i=0; i< disps->cArgs; i++) {
1107         TYPEDESC vdesc;
1108
1109         vdesc.vt = VT_VARIANT;
1110         hres = deserialize_param(
1111             tinfo,
1112             readit,
1113             debugout,
1114             alloc,
1115             &vdesc,
1116             (DWORD*)(disps->rgvarg+i),
1117             buf
1118         );
1119     }
1120     if (debugout) TRACE_(olerelay)("}{");
1121     hres = xbuf_get(buf, (LPBYTE)&disps->cNamedArgs, sizeof(disps->cNamedArgs));
1122     if (hres)
1123         return hres;
1124     if (disps->cNamedArgs) {
1125         if (alloc)
1126             disps->rgdispidNamedArgs = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DISPID)*disps->cNamedArgs);
1127         for (i=0; i< disps->cNamedArgs; i++) {
1128             TYPEDESC vdesc;
1129
1130             vdesc.vt = VT_UINT;
1131             hres = deserialize_param(
1132                 tinfo,
1133                 readit,
1134                 debugout,
1135                 alloc,
1136                 &vdesc,
1137                 (DWORD*)(disps->rgdispidNamedArgs+i),
1138                 buf
1139             );
1140             if (debugout && i<(disps->cNamedArgs-1)) TRACE_(olerelay)(",");
1141         }
1142     }
1143     if (debugout) TRACE_(olerelay)("}");
1144     return S_OK;
1145 }
1146
1147 /* Searches function, also in inherited interfaces */
1148 static HRESULT
1149 _get_funcdesc(
1150     ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, BSTR *iname, BSTR *fname)
1151 {
1152     int i = 0, j = 0;
1153     HRESULT hres;
1154
1155     if (fname) *fname = NULL;
1156     if (iname) *iname = NULL;
1157
1158     while (1) {
1159         hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
1160         if (hres) {
1161             ITypeInfo   *tinfo2;
1162             HREFTYPE    href;
1163             TYPEATTR    *attr;
1164
1165             hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
1166             if (hres) {
1167                 ERR("GetTypeAttr failed with %lx\n",hres);
1168                 return hres;
1169             }
1170             /* Not found, so look in inherited ifaces. */
1171             for (j=0;j<attr->cImplTypes;j++) {
1172                 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
1173                 if (hres) {
1174                     ERR("Did not find a reftype for interface offset %d?\n",j);
1175                     break;
1176                 }
1177                 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1178                 if (hres) {
1179                     ERR("Did not find a typeinfo for reftype %ld?\n",href);
1180                     continue;
1181                 }
1182                 hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
1183                 ITypeInfo_Release(tinfo2);
1184                 if (!hres) return S_OK;
1185             }
1186             return hres;
1187         }
1188         if (((*fdesc)->oVft/4) == iMethod) {
1189             if (fname)
1190                 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1191             if (iname)
1192                 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1193             return S_OK;
1194         }
1195         i++;
1196     }
1197 }
1198
1199 static DWORD
1200 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1201 {
1202     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
1203     FUNCDESC            *fdesc;
1204     HRESULT             hres;
1205     int                 i, relaydeb = TRACE_ON(olerelay);
1206     marshal_state       buf;
1207     RPCOLEMESSAGE       msg;
1208     ULONG               status;
1209     BSTR                fname,iname;
1210     BSTR                names[10];
1211     int                 nrofnames;
1212
1213     EnterCriticalSection(&tpinfo->crit);
1214
1215     hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
1216     if (hres) {
1217         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1218         LeaveCriticalSection(&tpinfo->crit);
1219         return E_FAIL;
1220     }
1221
1222     if (!tpinfo->chanbuf)
1223     {
1224         WARN("Tried to use disconnected proxy\n");
1225         LeaveCriticalSection(&tpinfo->crit);
1226         return RPC_E_DISCONNECTED;
1227     }
1228
1229     if (relaydeb) {
1230        TRACE_(olerelay)("->");
1231         if (iname)
1232             TRACE_(olerelay)("%s:",relaystr(iname));
1233         if (fname)
1234             TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1235         else
1236             TRACE_(olerelay)("%d",method);
1237         TRACE_(olerelay)("(");
1238         if (iname) SysFreeString(iname);
1239         if (fname) SysFreeString(fname);
1240     }
1241     /* Need them for hack below */
1242     memset(names,0,sizeof(names));
1243     if (ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1244         nrofnames = 0;
1245     if (nrofnames > sizeof(names)/sizeof(names[0]))
1246         ERR("Need more names!\n");
1247
1248     memset(&buf,0,sizeof(buf));
1249     buf.iid = IID_IUnknown;
1250     if (method == 0) {
1251         xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
1252         if (relaydeb) TRACE_(olerelay)("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
1253     } else {
1254         xargs = args;
1255         for (i=0;i<fdesc->cParams;i++) {
1256             ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
1257             BOOL        isserialized = FALSE;
1258             if (relaydeb) {
1259                 if (i) TRACE_(olerelay)(",");
1260                 if (i+1<nrofnames && names[i+1])
1261                     TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1262             }
1263             /* No need to marshal other data than FIN */
1264             if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
1265                 xargs+=_argsize(elem->tdesc.vt);
1266                 if (relaydeb) TRACE_(olerelay)("[out]");
1267                 continue;
1268             }
1269             if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1270                 /* If the parameter is 'riid', we use it as interface IID
1271                  * for a later ppvObject serialization.
1272                  */
1273                 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1274
1275                 /* DISPPARAMS* needs special serializer */
1276                 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1277                     hres = serialize_DISPPARAM_ptr(
1278                         tpinfo->tinfo,
1279                         elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1280                         relaydeb,
1281                         FALSE,
1282                         &elem->tdesc,
1283                         xargs,
1284                         &buf
1285                     );
1286                     isserialized = TRUE;
1287                 }
1288                 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1289                     hres = serialize_LPVOID_ptr(
1290                         tpinfo->tinfo,
1291                         elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1292                         relaydeb,
1293                         FALSE,
1294                         &elem->tdesc,
1295                         xargs,
1296                         &buf
1297                     );
1298                     if (hres == S_OK)
1299                         isserialized = TRUE;
1300                 }
1301             }
1302             if (!isserialized)
1303                 hres = serialize_param(
1304                     tpinfo->tinfo,
1305                     elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1306                     relaydeb,
1307                     FALSE,
1308                     &elem->tdesc,
1309                     xargs,
1310                     &buf
1311                 );
1312
1313             if (hres) {
1314                 ERR("Failed to serialize param, hres %lx\n",hres);
1315                 break;
1316             }
1317             xargs+=_argsize(elem->tdesc.vt);
1318         }
1319     }
1320     if (relaydeb) TRACE_(olerelay)(")");
1321     memset(&msg,0,sizeof(msg));
1322     msg.cbBuffer = buf.curoff;
1323     msg.iMethod  = method;
1324     hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
1325     if (hres) {
1326         ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
1327         LeaveCriticalSection(&tpinfo->crit);
1328         return hres;
1329     }
1330     memcpy(msg.Buffer,buf.base,buf.curoff);
1331     if (relaydeb) TRACE_(olerelay)("\n");
1332     hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
1333     if (hres) {
1334         ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);
1335         LeaveCriticalSection(&tpinfo->crit);
1336         return hres;
1337     }
1338
1339     if (relaydeb) TRACE_(olerelay)(" = %08lx (",status);
1340     if (buf.base)
1341         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1342     else
1343         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1344     buf.size = msg.cbBuffer;
1345     memcpy(buf.base,msg.Buffer,buf.size);
1346     buf.curoff = 0;
1347     if (method == 0) {
1348         _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
1349         if (relaydeb) TRACE_(olerelay)("[in],%p",*((DWORD**)args[1]));
1350     } else {
1351         xargs = args;
1352         for (i=0;i<fdesc->cParams;i++) {
1353             ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
1354             BOOL        isdeserialized = FALSE;
1355
1356             if (relaydeb) {
1357                 if (i) TRACE_(olerelay)(",");
1358                 if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1359             }
1360             /* No need to marshal other data than FOUT I think */
1361             if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
1362                 xargs += _argsize(elem->tdesc.vt);
1363                 if (relaydeb) TRACE_(olerelay)("[in]");
1364                 continue;
1365             }
1366             if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1367                 /* If the parameter is 'riid', we use it as interface IID
1368                  * for a later ppvObject serialization.
1369                  */
1370                 buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1371
1372                 /* deserialize DISPPARAM */
1373                 if (!lstrcmpW(names[i+1],pdispparamsW)) {
1374                     hres = deserialize_DISPPARAM_ptr(
1375                         tpinfo->tinfo,
1376                         elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1377                         relaydeb,
1378                         FALSE,
1379                         &(elem->tdesc),
1380                         xargs,
1381                         &buf
1382                     );
1383                     if (hres) {
1384                         ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1385                         break;
1386                     }
1387                     isdeserialized = TRUE;
1388                 }
1389                 if (!lstrcmpW(names[i+1],ppvObjectW)) {
1390                     hres = deserialize_LPVOID_ptr(
1391                         tpinfo->tinfo,
1392                         elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1393                         relaydeb,
1394                         FALSE,
1395                         &elem->tdesc,
1396                         xargs,
1397                         &buf
1398                     );
1399                     if (hres == S_OK)
1400                         isdeserialized = TRUE;
1401                 }
1402             }
1403             if (!isdeserialized)
1404                 hres = deserialize_param(
1405                     tpinfo->tinfo,
1406                     elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1407                     relaydeb,
1408                     FALSE,
1409                     &(elem->tdesc),
1410                     xargs,
1411                     &buf
1412                 );
1413             if (hres) {
1414                 ERR("Failed to unmarshall param, hres %lx\n",hres);
1415                 status = hres;
1416                 break;
1417             }
1418             xargs += _argsize(elem->tdesc.vt);
1419         }
1420     }
1421     if (relaydeb) TRACE_(olerelay)(")\n");
1422     HeapFree(GetProcessHeap(),0,buf.base);
1423
1424     LeaveCriticalSection(&tpinfo->crit);
1425
1426     return status;
1427 }
1428
1429 static HRESULT WINAPI
1430 PSFacBuf_CreateProxy(
1431     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1432     IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1433 {
1434     HRESULT     hres;
1435     ITypeInfo   *tinfo;
1436     int         i, nroffuncs;
1437     FUNCDESC    *fdesc;
1438     TMProxyImpl *proxy;
1439
1440     TRACE("(...%s...)\n",debugstr_guid(riid));
1441     hres = _get_typeinfo_for_iid(riid,&tinfo);
1442     if (hres) {
1443         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1444         return hres;
1445     }
1446     nroffuncs = _nroffuncs(tinfo);
1447     proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1448     if (!proxy) return E_OUTOFMEMORY;
1449
1450     assert(sizeof(TMAsmProxy) == 12);
1451
1452     proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1453     if (!proxy->asmstubs) {
1454         ERR("Could not commit pages for proxy thunks\n");
1455         CoTaskMemFree(proxy);
1456         return E_OUTOFMEMORY;
1457     }
1458
1459     InitializeCriticalSection(&proxy->crit);
1460
1461     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1462     for (i=0;i<nroffuncs;i++) {
1463         int             nrofargs;
1464         TMAsmProxy      *xasm = proxy->asmstubs+i;
1465
1466         /* nrofargs without This */
1467         switch (i) {
1468         case 0: nrofargs = 2;
1469                 break;
1470         case 1: case 2: nrofargs = 0;
1471                 break;
1472         default: {
1473                 int j;
1474                 hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
1475                 if (hres) {
1476                     ERR("GetFuncDesc %lx should not fail here.\n",hres);
1477                     return hres;
1478                 }
1479                 /* some args take more than 4 byte on the stack */
1480                 nrofargs = 0;
1481                 for (j=0;j<fdesc->cParams;j++)
1482                     nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
1483
1484                 if (fdesc->callconv != CC_STDCALL) {
1485                     ERR("calling convention is not stdcall????\n");
1486                     return E_FAIL;
1487                 }
1488                 break;
1489             }
1490         }
1491 /* popl %eax    -       return ptr
1492  * pushl <nr>
1493  * pushl %eax
1494  * call xCall
1495  * lret <nr> (+4)
1496  *
1497  *
1498  * arg3 arg2 arg1 <method> <returnptr>
1499  */
1500         xasm->popleax   = 0x58;
1501         xasm->pushlval  = 0x6a;
1502         xasm->nr        = i;
1503         xasm->pushleax  = 0x50;
1504         xasm->lcall     = 0xe8; /* relative jump */
1505         xasm->xcall     = (DWORD)xCall;
1506         xasm->xcall     -= (DWORD)&(xasm->lret);
1507         xasm->lret      = 0xc2;
1508         xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
1509         proxy->lpvtbl[i] = xasm;
1510     }
1511     proxy->lpvtbl2      = &tmproxyvtable;
1512     /* 1 reference for the proxy and 1 for the object */
1513     proxy->ref          = 2;
1514     proxy->tinfo        = tinfo;
1515     memcpy(&proxy->iid,riid,sizeof(*riid));
1516     proxy->chanbuf      = 0;
1517     *ppv                = (LPVOID)proxy;
1518     *ppProxy            = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1519     return S_OK;
1520 }
1521
1522 typedef struct _TMStubImpl {
1523     IRpcStubBufferVtbl  *lpvtbl;
1524     ULONG                       ref;
1525
1526     LPUNKNOWN                   pUnk;
1527     ITypeInfo                   *tinfo;
1528     IID                         iid;
1529 } TMStubImpl;
1530
1531 static HRESULT WINAPI
1532 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1533 {
1534     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1535         *ppv = (LPVOID)iface;
1536         IRpcStubBuffer_AddRef(iface);
1537         return S_OK;
1538     }
1539     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1540     return E_NOINTERFACE;
1541 }
1542
1543 static ULONG WINAPI
1544 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1545 {
1546     TMStubImpl *This = (TMStubImpl *)iface;
1547     ULONG refCount = InterlockedIncrement(&This->ref);
1548         
1549     TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
1550
1551     return refCount;
1552 }
1553
1554 static ULONG WINAPI
1555 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1556 {
1557     TMStubImpl *This = (TMStubImpl *)iface;
1558     ULONG refCount = InterlockedDecrement(&This->ref);
1559
1560     TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
1561
1562     if (!refCount)
1563     {
1564         IRpcStubBuffer_Disconnect(iface);
1565         CoTaskMemFree(This);
1566     }
1567     return refCount;
1568 }
1569
1570 static HRESULT WINAPI
1571 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1572 {
1573     TMStubImpl *This = (TMStubImpl *)iface;
1574
1575     TRACE("(%p)->(%p)\n", This, pUnkServer);
1576
1577     IUnknown_AddRef(pUnkServer);
1578     This->pUnk = pUnkServer;
1579     return S_OK;
1580 }
1581
1582 static void WINAPI
1583 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1584 {
1585     TMStubImpl *This = (TMStubImpl *)iface;
1586
1587     TRACE("(%p)->()\n", This);
1588
1589     IUnknown_Release(This->pUnk);
1590     This->pUnk = NULL;
1591     return;
1592 }
1593
1594 static HRESULT WINAPI
1595 TMStubImpl_Invoke(
1596     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1597 {
1598     int         i;
1599     FUNCDESC    *fdesc;
1600     TMStubImpl *This = (TMStubImpl *)iface;
1601     HRESULT     hres;
1602     DWORD       *args, res, *xargs, nrofargs;
1603     marshal_state       buf;
1604     int         nrofnames;
1605     BSTR        names[10];
1606
1607     memset(&buf,0,sizeof(buf));
1608     buf.size    = xmsg->cbBuffer;
1609     buf.base    = xmsg->Buffer;
1610     buf.curoff  = 0;
1611     buf.iid     = IID_IUnknown;
1612
1613     TRACE("...\n");
1614     if (xmsg->iMethod == 0) { /* QI */
1615         IID             xiid;
1616         /* in: IID, out: <iface> */
1617
1618         xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
1619         buf.curoff = 0;
1620         hres = _marshal_interface(&buf,&xiid,This->pUnk);
1621         xmsg->Buffer    = buf.base; /* Might have been reallocated */
1622         xmsg->cbBuffer  = buf.size;
1623         return hres;
1624     }
1625     hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
1626     if (hres) {
1627         ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1628         return hres;
1629     }
1630     /* Need them for hack below */
1631     memset(names,0,sizeof(names));
1632     ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1633     if (nrofnames > sizeof(names)/sizeof(names[0])) {
1634         ERR("Need more names!\n");
1635     }
1636
1637     /*dump_FUNCDESC(fdesc);*/
1638     nrofargs = 0;
1639     for (i=0;i<fdesc->cParams;i++)
1640         nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1641     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1642     if (!args) return E_OUTOFMEMORY;
1643
1644     /* Allocate all stuff used by call. */
1645     xargs = args+1;
1646     for (i=0;i<fdesc->cParams;i++) {
1647         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1648         BOOL            isdeserialized = FALSE;
1649
1650         if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1651             /* If the parameter is 'riid', we use it as interface IID
1652              * for a later ppvObject serialization.
1653              */
1654             buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1655
1656             /* deserialize DISPPARAM */
1657             if (!lstrcmpW(names[i+1],pdispparamsW)) {
1658                 hres = deserialize_DISPPARAM_ptr(
1659                     This->tinfo,
1660                     elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1661                     FALSE,
1662                     TRUE,
1663                     &(elem->tdesc),
1664                     xargs,
1665                     &buf
1666                 );
1667                 if (hres) {
1668                     ERR("Failed to deserialize DISPPARAM*, hres %lx\n",hres);
1669                     break;
1670                 }
1671                 isdeserialized = TRUE;
1672             }
1673             if (!lstrcmpW(names[i+1],ppvObjectW)) {
1674                 hres = deserialize_LPVOID_ptr(
1675                     This->tinfo,
1676                     elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1677                     FALSE,
1678                     TRUE,
1679                     &elem->tdesc,
1680                     xargs,
1681                     &buf
1682                 );
1683                 if (hres == S_OK)
1684                     isdeserialized = TRUE;
1685             }
1686         }
1687         if (!isdeserialized)
1688             hres = deserialize_param(
1689                 This->tinfo,
1690                 elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN,
1691                 FALSE,
1692                 TRUE,
1693                 &(elem->tdesc),
1694                 xargs,
1695                 &buf
1696             );
1697         xargs += _argsize(elem->tdesc.vt);
1698         if (hres) {
1699             ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
1700             break;
1701         }
1702     }
1703     hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1704     if (hres) {
1705         ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
1706         return hres;
1707     }
1708     res = _invoke(
1709             (*((FARPROC**)args[0]))[fdesc->oVft/4],
1710             fdesc->callconv,
1711             (xargs-args),
1712             args
1713     );
1714     IUnknown_Release((LPUNKNOWN)args[0]);
1715     buf.curoff = 0;
1716     xargs = args+1;
1717     for (i=0;i<fdesc->cParams;i++) {
1718         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1719         BOOL            isserialized = FALSE;
1720
1721         if (((i+1)<nrofnames) && !IsBadStringPtrW(names[i+1],1)) {
1722             /* If the parameter is 'riid', we use it as interface IID
1723              * for a later ppvObject serialization.
1724              */
1725             buf.thisisiid = !lstrcmpW(names[i+1],riidW);
1726
1727             /* DISPPARAMS* needs special serializer */
1728             if (!lstrcmpW(names[i+1],pdispparamsW)) {
1729                 hres = serialize_DISPPARAM_ptr(
1730                     This->tinfo,
1731                     elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1732                     FALSE,
1733                     TRUE,
1734                     &elem->tdesc,
1735                     xargs,
1736                     &buf
1737                 );
1738                 isserialized = TRUE;
1739             }
1740             if (!lstrcmpW(names[i+1],ppvObjectW)) {
1741                 hres = serialize_LPVOID_ptr(
1742                     This->tinfo,
1743                     elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1744                     FALSE,
1745                     TRUE,
1746                     &elem->tdesc,
1747                     xargs,
1748                     &buf
1749                 );
1750                 if (hres == S_OK)
1751                     isserialized = TRUE;
1752             }
1753         }
1754         if (!isserialized)
1755             hres = serialize_param(
1756                This->tinfo,
1757                elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1758                FALSE,
1759                TRUE,
1760                &elem->tdesc,
1761                xargs,
1762                &buf
1763             );
1764         xargs += _argsize(elem->tdesc.vt);
1765         if (hres) {
1766             ERR("Failed to stuballoc param, hres %lx\n",hres);
1767             break;
1768         }
1769     }
1770     /* might need to use IRpcChannelBuffer_GetBuffer ? */
1771     xmsg->cbBuffer      = buf.curoff;
1772     xmsg->Buffer        = buf.base;
1773     HeapFree(GetProcessHeap(),0,args);
1774     return res;
1775 }
1776
1777 static LPRPCSTUBBUFFER WINAPI
1778 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1779     FIXME("Huh (%s)?\n",debugstr_guid(riid));
1780     return NULL;
1781 }
1782
1783 static ULONG WINAPI
1784 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1785     TMStubImpl *This = (TMStubImpl *)iface;
1786
1787     return This->ref; /*FIXME? */
1788 }
1789
1790 static HRESULT WINAPI
1791 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1792     return E_NOTIMPL;
1793 }
1794
1795 static void WINAPI
1796 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1797     return;
1798 }
1799
1800 IRpcStubBufferVtbl tmstubvtbl = {
1801     TMStubImpl_QueryInterface,
1802     TMStubImpl_AddRef,
1803     TMStubImpl_Release,
1804     TMStubImpl_Connect,
1805     TMStubImpl_Disconnect,
1806     TMStubImpl_Invoke,
1807     TMStubImpl_IsIIDSupported,
1808     TMStubImpl_CountRefs,
1809     TMStubImpl_DebugServerQueryInterface,
1810     TMStubImpl_DebugServerRelease
1811 };
1812
1813 static HRESULT WINAPI
1814 PSFacBuf_CreateStub(
1815     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1816     IRpcStubBuffer** ppStub
1817 ) {
1818     HRESULT hres;
1819     ITypeInfo   *tinfo;
1820     TMStubImpl  *stub;
1821
1822     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1823     hres = _get_typeinfo_for_iid(riid,&tinfo);
1824     if (hres) {
1825         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1826         return hres;
1827     }
1828     stub = CoTaskMemAlloc(sizeof(TMStubImpl));
1829     if (!stub)
1830         return E_OUTOFMEMORY;
1831     stub->lpvtbl        = &tmstubvtbl;
1832     stub->ref           = 1;
1833     stub->tinfo         = tinfo;
1834     memcpy(&(stub->iid),riid,sizeof(*riid));
1835     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1836     *ppStub             = (LPRPCSTUBBUFFER)stub;
1837     TRACE("IRpcStubBuffer: %p\n", stub);
1838     if (hres)
1839         ERR("Connect to pUnkServer failed?\n");
1840     return hres;
1841 }
1842
1843 static IPSFactoryBufferVtbl psfacbufvtbl = {
1844     PSFacBuf_QueryInterface,
1845     PSFacBuf_AddRef,
1846     PSFacBuf_Release,
1847     PSFacBuf_CreateProxy,
1848     PSFacBuf_CreateStub
1849 };
1850
1851 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1852 static IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
1853
1854 /***********************************************************************
1855  *           DllGetClassObject [OLE32.63]
1856  */
1857 HRESULT WINAPI
1858 TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1859 {
1860     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1861         *ppv = &lppsfac;
1862         return S_OK;
1863     }
1864     return E_NOINTERFACE;
1865 }