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