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