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