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