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