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