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