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