Add IFontEventsDisp and IProvideMultipleClassInfo.
[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     FUNCDESC    *fdesc;
308     HRESULT     hres;
309
310     n=0;
311     while (1) {
312         hres = ITypeInfo_GetFuncDesc(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_R8:
449         return sizeof(double)/sizeof(DWORD);
450     case VT_CY:
451         return sizeof(CY)/sizeof(DWORD);
452     case VT_DATE:
453         return sizeof(DATE)/sizeof(DWORD);
454     case VT_VARIANT:
455         return (sizeof(VARIANT)+3)/sizeof(DWORD);
456     default:
457         return 1;
458     }
459 }
460
461 static int
462 _xsize(TYPEDESC *td) {
463     switch (td->vt) {
464     case VT_DATE:
465         return sizeof(DATE);
466     case VT_VARIANT:
467         return sizeof(VARIANT)+3;
468     case VT_CARRAY: {
469         int i, arrsize = 1;
470         ARRAYDESC *adesc = td->u.lpadesc;
471
472         for (i=0;i<adesc->cDims;i++)
473             arrsize *= adesc->rgbounds[i].cElements;
474         return arrsize*_xsize(&adesc->tdescElem);
475     }
476     case VT_UI2:
477     case VT_I2:
478         return 2;
479     case VT_UI1:
480     case VT_I1:
481         return 1;
482     default:
483         return 4;
484     }
485 }
486
487 static HRESULT
488 serialize_param(
489     ITypeInfo           *tinfo,
490     BOOL                writeit,
491     BOOL                debugout,
492     BOOL                dealloc,
493     TYPEDESC            *tdesc,
494     DWORD               *arg,
495     marshal_state       *buf)
496 {
497     HRESULT hres = S_OK;
498
499     TRACE("(tdesc.vt %d)\n",tdesc->vt);
500
501     switch (tdesc->vt) {
502     case VT_EMPTY: /* nothing. empty variant for instance */
503         return S_OK;
504     case VT_BOOL:
505     case VT_ERROR:
506     case VT_UINT:
507     case VT_I4:
508     case VT_R4:
509     case VT_UI4:
510         hres = S_OK;
511         if (debugout) TRACE_(olerelay)("%lx",*arg);
512         if (writeit)
513             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
514         return hres;
515     case VT_I2:
516     case VT_UI2:
517         hres = S_OK;
518         if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff);
519         if (writeit)
520             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
521         return hres;
522     case VT_I1:
523     case VT_UI1:
524         hres = S_OK;
525         if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff);
526         if (writeit)
527             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
528         return hres;
529     case VT_I4|VT_BYREF:
530         hres = S_OK;
531         if (debugout) TRACE_(olerelay)("&0x%lx",*arg);
532         if (writeit)
533             hres = xbuf_add(buf,(LPBYTE)(DWORD*)*arg,sizeof(DWORD));
534         /* do not dealloc at this time */
535         return hres;
536     case VT_VARIANT: {
537         TYPEDESC        tdesc2;
538         VARIANT         *vt = (VARIANT*)arg;
539         DWORD           vttype = V_VT(vt);
540
541         if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
542         tdesc2.vt = vttype;
543         if (writeit) {
544             hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
545             if (hres) return hres;
546         }
547         /* need to recurse since we need to free the stuff */
548         hres = serialize_param(tinfo,writeit,debugout,dealloc,&tdesc2,(DWORD*)&(V_I4(vt)),buf);
549         if (debugout) TRACE_(olerelay)(")");
550         return hres;
551     }
552     case VT_BSTR|VT_BYREF: {
553         if (debugout) TRACE_(olerelay)("[byref]'%s'", *(BSTR*)*arg ? relaystr(*((BSTR*)*arg)) : "<bstr NULL>");
554         if (writeit) {
555             /* ptr to ptr to magic widestring, basically */
556             BSTR *bstr = (BSTR *) *arg;
557             DWORD len;
558             if (!*bstr) {
559                 /* -1 means "null string" which is equivalent to empty string */
560                 len = -1;     
561                 hres = xbuf_add(buf, (LPBYTE)&len,sizeof(DWORD));
562                 if (hres) return hres;
563             } else {
564                 len = *((DWORD*)*bstr-1)/sizeof(WCHAR);
565                 hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
566                 if (hres) return hres;
567                 hres = xbuf_add(buf,(LPBYTE)*bstr,len * sizeof(WCHAR));
568                 if (hres) return hres;
569             }
570         }
571
572         if (dealloc && arg) {
573             BSTR *str = *((BSTR **)arg);
574             SysFreeString(*str);
575         }
576         return S_OK;
577     }
578     
579     case VT_BSTR: {
580         if (debugout) {
581             if (*arg)
582                    TRACE_(olerelay)("%s",relaystr((WCHAR*)*arg));
583             else
584                     TRACE_(olerelay)("<bstr NULL>");
585         }
586         if (writeit) {
587             BSTR bstr = (BSTR)*arg;
588             DWORD len;
589             if (!bstr) {
590                 len = -1;
591                 hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
592                 if (hres) return hres;
593             } else {
594                 len = *((DWORD*)bstr-1)/sizeof(WCHAR);
595                 hres = xbuf_add(buf,(LPBYTE)&len,sizeof(DWORD));
596                 if (hres) return hres;
597                 hres = xbuf_add(buf,(LPBYTE)bstr,len * sizeof(WCHAR));
598                 if (hres) return hres;
599             }
600         }
601
602         if (dealloc && arg)
603             SysFreeString((BSTR)*arg);
604         return S_OK;
605     }
606     case VT_PTR: {
607         DWORD cookie;
608         BOOL        derefhere = TRUE;
609
610         if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
611             ITypeInfo   *tinfo2;
612             TYPEATTR    *tattr;
613
614             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
615             if (hres) {
616                 ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
617                 return hres;
618             }
619             ITypeInfo_GetTypeAttr(tinfo2,&tattr);
620             switch (tattr->typekind) {
621             case TKIND_ENUM:    /* confirmed */
622             case TKIND_RECORD:  /* FIXME: mostly untested */
623                 derefhere=TRUE;
624                 break;
625             case TKIND_ALIAS:   /* FIXME: untested */
626             case TKIND_DISPATCH:        /* will be done in VT_USERDEFINED case */
627             case TKIND_INTERFACE:       /* will be done in VT_USERDEFINED case */
628                 derefhere=FALSE;
629                 break;
630             default:
631                 FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
632                 derefhere=FALSE;
633                 break;
634             }
635             ITypeInfo_Release(tinfo2);
636         }
637
638         if (debugout) TRACE_(olerelay)("*");
639         /* Write always, so the other side knows when it gets a NULL pointer.
640          */
641         cookie = *arg ? 0x42424242 : 0;
642         hres = xbuf_add(buf,(LPBYTE)&cookie,sizeof(cookie));
643         if (hres)
644             return hres;
645         if (!*arg) {
646             if (debugout) TRACE_(olerelay)("NULL");
647             return S_OK;
648         }
649         hres = serialize_param(tinfo,writeit,debugout,dealloc,tdesc->u.lptdesc,(DWORD*)*arg,buf);
650         if (derefhere && dealloc) HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
651         return hres;
652     }
653     case VT_UNKNOWN:
654         if (debugout) TRACE_(olerelay)("unk(0x%lx)",*arg);
655         if (writeit)
656             hres = _marshal_interface(buf,&IID_IUnknown,(LPUNKNOWN)*arg);
657         return hres;
658     case VT_DISPATCH:
659         if (debugout) TRACE_(olerelay)("idisp(0x%lx)",*arg);
660         if (writeit)
661             hres = _marshal_interface(buf,&IID_IDispatch,(LPUNKNOWN)*arg);
662         return hres;
663     case VT_VOID:
664         if (debugout) TRACE_(olerelay)("<void>");
665         return S_OK;
666     case VT_USERDEFINED: {
667         ITypeInfo       *tinfo2;
668         TYPEATTR        *tattr;
669
670         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
671         if (hres) {
672             ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
673             return hres;
674         }
675         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
676         switch (tattr->typekind) {
677         case TKIND_DISPATCH:
678         case TKIND_INTERFACE:
679             if (writeit)
680                hres=_marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
681             if (dealloc)
682                 IUnknown_Release((LPUNKNOWN)arg);
683             break;
684         case TKIND_RECORD: {
685             int i;
686             if (debugout) TRACE_(olerelay)("{");
687             for (i=0;i<tattr->cVars;i++) {
688                 VARDESC *vdesc;
689                 ELEMDESC *elem2;
690                 TYPEDESC *tdesc2;
691
692                 hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
693                 if (hres) {
694                     ERR("Could not get vardesc of %d\n",i);
695                     return hres;
696                 }
697                 /* Need them for hack below */
698                 /*
699                 memset(names,0,sizeof(names));
700                 hres = ITypeInfo_GetNames(tinfo2,vdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
701                 if (nrofnames > sizeof(names)/sizeof(names[0])) {
702                     ERR("Need more names!\n");
703                 }
704                 if (!hres && debugout)
705                     TRACE_(olerelay)("%s=",relaystr(names[0]));
706                 */
707                 elem2 = &vdesc->elemdescVar;
708                 tdesc2 = &elem2->tdesc;
709                 hres = serialize_param(
710                     tinfo2,
711                     writeit,
712                     debugout,
713                     dealloc,
714                     tdesc2,
715                     (DWORD*)(((LPBYTE)arg)+vdesc->u.oInst),
716                     buf
717                 );
718                 ITypeInfo_ReleaseVarDesc(tinfo2, vdesc);
719                 if (hres!=S_OK)
720                     return hres;
721                 if (debugout && (i<(tattr->cVars-1)))
722                     TRACE_(olerelay)(",");
723             }
724             if (debugout) TRACE_(olerelay)("}");
725             break;
726         }
727         case TKIND_ALIAS:
728             return serialize_param(tinfo2,writeit,debugout,dealloc,&tattr->tdescAlias,arg,buf);
729         case TKIND_ENUM:
730             hres = S_OK;
731             if (debugout) TRACE_(olerelay)("%lx",*arg);
732             if (writeit)
733                 hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
734             return hres;
735         default:
736             FIXME("Unhandled typekind %d\n",tattr->typekind);
737             hres = E_FAIL;
738             break;
739         }
740         ITypeInfo_Release(tinfo2);
741         return hres;
742     }
743     case VT_CARRAY: {
744         ARRAYDESC *adesc = tdesc->u.lpadesc;
745         int i, arrsize = 1;
746
747         if (debugout) TRACE_(olerelay)("carr");
748         for (i=0;i<adesc->cDims;i++) {
749             if (debugout) TRACE_(olerelay)("[%ld]",adesc->rgbounds[i].cElements);
750             arrsize *= adesc->rgbounds[i].cElements;
751         }
752         if (debugout) TRACE_(olerelay)("(vt %d)",adesc->tdescElem.vt);
753         if (debugout) TRACE_(olerelay)("[");
754         for (i=0;i<arrsize;i++) {
755             hres = serialize_param(tinfo, writeit, debugout, dealloc, &adesc->tdescElem, (DWORD*)((LPBYTE)arg+i*_xsize(&adesc->tdescElem)), buf);
756             if (hres)
757                 return hres;
758             if (debugout && (i<arrsize-1)) TRACE_(olerelay)(",");
759         }
760         if (debugout) TRACE_(olerelay)("]");
761         return S_OK;
762     }
763     default:
764         ERR("Unhandled marshal type %d.\n",tdesc->vt);
765         return S_OK;
766     }
767 }
768
769 static HRESULT
770 deserialize_param(
771     ITypeInfo           *tinfo,
772     BOOL                readit,
773     BOOL                debugout,
774     BOOL                alloc,
775     TYPEDESC            *tdesc,
776     DWORD               *arg,
777     marshal_state       *buf)
778 {
779     HRESULT hres = S_OK;
780
781     TRACE("vt %d at %p\n",tdesc->vt,arg);
782
783     while (1) {
784         switch (tdesc->vt) {
785         case VT_EMPTY:
786             if (debugout) TRACE_(olerelay)("<empty>");
787             return S_OK;
788         case VT_NULL:
789             if (debugout) TRACE_(olerelay)("<null>");
790             return S_OK;
791         case VT_VARIANT: {
792             VARIANT     *vt = (VARIANT*)arg;
793
794             if (readit) {
795                 DWORD   vttype;
796                 TYPEDESC        tdesc2;
797                 hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
798                 if (hres) {
799                     FIXME("vt type not read?\n");
800                     return hres;
801                 }
802                 memset(&tdesc2,0,sizeof(tdesc2));
803                 tdesc2.vt = vttype;
804                 V_VT(vt)  = vttype;
805                 if (debugout) TRACE_(olerelay)("Vt(%ld)(",vttype);
806                 hres = deserialize_param(tinfo, readit, debugout, alloc, &tdesc2, (DWORD*)&(V_I4(vt)), buf);
807                 TRACE_(olerelay)(")");
808                 return hres;
809             } else {
810                 VariantInit(vt);
811                 return S_OK;
812             }
813         }
814         case VT_ERROR:
815         case VT_BOOL:
816         case VT_I4:
817         case VT_UINT:
818         case VT_R4:
819         case VT_UI4:
820             if (readit) {
821                 hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
822                 if (hres) ERR("Failed to read integer 4 byte\n");
823             }
824             if (debugout) TRACE_(olerelay)("%lx",*arg);
825             return hres;
826         case VT_I2:
827         case VT_UI2:
828             if (readit) {
829                 DWORD x;
830                 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
831                 if (hres) ERR("Failed to read integer 4 byte\n");
832                 memcpy(arg,&x,2);
833             }
834             if (debugout) TRACE_(olerelay)("%04lx",*arg & 0xffff);
835             return hres;
836         case VT_I1:
837         case VT_UI1:
838             if (readit) {
839                 DWORD x;
840                 hres = xbuf_get(buf,(LPBYTE)&x,sizeof(DWORD));
841                 if (hres) ERR("Failed to read integer 4 byte\n");
842                 memcpy(arg,&x,1);
843             }
844             if (debugout) TRACE_(olerelay)("%02lx",*arg & 0xff);
845             return hres;
846         case VT_I4|VT_BYREF:
847             hres = S_OK;
848             if (alloc)
849                 *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
850             if (readit) {
851                 hres = xbuf_get(buf,(LPBYTE)*arg,sizeof(DWORD));
852                 if (hres) ERR("Failed to read integer 4 byte\n");
853             }
854             if (debugout) TRACE_(olerelay)("&0x%lx",*(DWORD*)*arg);
855             return hres;
856         case VT_BSTR|VT_BYREF: {
857             BSTR **bstr = (BSTR **)arg;
858             WCHAR       *str;
859             DWORD       len;
860
861             if (readit) {
862                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
863                 if (hres) {
864                     ERR("failed to read bstr klen\n");
865                     return hres;
866                 }
867                 if (len == -1) {
868                     *bstr = CoTaskMemAlloc(sizeof(BSTR *));
869                     **bstr = NULL;
870                     if (debugout) TRACE_(olerelay)("<bstr NULL>");
871                 } else {
872                     str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR));
873                     hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR));
874                     if (hres) {
875                         ERR("Failed to read BSTR.\n");
876                         return hres;
877                     }
878                     *bstr = CoTaskMemAlloc(sizeof(BSTR *));
879                     **bstr = SysAllocStringLen(str,len);
880                     if (debugout) TRACE_(olerelay)("%s",relaystr(str));
881                     HeapFree(GetProcessHeap(),0,str);
882                 }
883             } else {
884                 *bstr = NULL;
885             }
886             return S_OK;
887         }
888         case VT_BSTR: {
889             WCHAR       *str;
890             DWORD       len;
891
892             if (readit) {
893                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
894                 if (hres) {
895                     ERR("failed to read bstr klen\n");
896                     return hres;
897                 }
898                 if (len == -1) {
899                     *arg = 0;
900                     if (debugout) TRACE_(olerelay)("<bstr NULL>");
901                 } else {
902                     str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,(len+1)*sizeof(WCHAR));
903                     hres = xbuf_get(buf,(LPBYTE)str,len*sizeof(WCHAR));
904                     if (hres) {
905                         ERR("Failed to read BSTR.\n");
906                         return hres;
907                     }
908                     *arg = (DWORD)SysAllocStringLen(str,len);
909                     if (debugout) TRACE_(olerelay)("%s",relaystr(str));
910                     HeapFree(GetProcessHeap(),0,str);
911                 }
912             } else {
913                 *arg = 0;
914             }
915             return S_OK;
916         }
917         case VT_PTR: {
918             DWORD       cookie;
919             BOOL        derefhere = TRUE;
920
921             if (tdesc->u.lptdesc->vt == VT_USERDEFINED) {
922                 ITypeInfo       *tinfo2;
923                 TYPEATTR        *tattr;
924
925                 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.lptdesc->u.hreftype,&tinfo2);
926                 if (hres) {
927                     ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.lptdesc->u.hreftype);
928                     return hres;
929                 }
930                 ITypeInfo_GetTypeAttr(tinfo2,&tattr);
931                 switch (tattr->typekind) {
932                 case TKIND_ENUM:        /* confirmed */
933                 case TKIND_RECORD:      /* FIXME: mostly untested */
934                     derefhere=TRUE;
935                     break;
936                 case TKIND_ALIAS:       /* FIXME: untested */
937                 case TKIND_DISPATCH:    /* will be done in VT_USERDEFINED case */
938                 case TKIND_INTERFACE:   /* will be done in VT_USERDEFINED case */
939                     derefhere=FALSE;
940                     break;
941                 default:
942                     FIXME("unhandled switch cases tattr->typekind %d\n", tattr->typekind);
943                     derefhere=FALSE;
944                     break;
945                 }
946                 ITypeInfo_Release(tinfo2);
947             }
948             /* read it in all cases, we need to know if we have 
949              * NULL pointer or not.
950              */
951             hres = xbuf_get(buf,(LPBYTE)&cookie,sizeof(cookie));
952             if (hres) {
953                 ERR("Failed to load pointer cookie.\n");
954                 return hres;
955             }
956             if (cookie != 0x42424242) {
957                 /* we read a NULL ptr from the remote side */
958                 if (debugout) TRACE_(olerelay)("NULL");
959                 *arg = 0;
960                 return S_OK;
961             }
962             if (debugout) TRACE_(olerelay)("*");
963             if (alloc) {
964                 /* Allocate space for the referenced struct */
965                 if (derefhere)
966                     *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,_xsize(tdesc->u.lptdesc));
967             }
968             if (derefhere)
969                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, (LPDWORD)*arg, buf);
970             else
971                 return deserialize_param(tinfo, readit, debugout, alloc, tdesc->u.lptdesc, arg, buf);
972         }
973         case VT_UNKNOWN:
974             /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
975             if (alloc)
976                 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
977             hres = S_OK;
978             if (readit)
979                 hres = _unmarshal_interface(buf,&IID_IUnknown,(LPUNKNOWN*)arg);
980             if (debugout)
981                 TRACE_(olerelay)("unk(%p)",arg);
982             return hres;
983         case VT_DISPATCH:
984             hres = S_OK;
985             if (readit)
986                 hres = _unmarshal_interface(buf,&IID_IDispatch,(LPUNKNOWN*)arg);
987             if (debugout)
988                 TRACE_(olerelay)("idisp(%p)",arg);
989             return hres;
990         case VT_VOID:
991             if (debugout) TRACE_(olerelay)("<void>");
992             return S_OK;
993         case VT_USERDEFINED: {
994             ITypeInfo   *tinfo2;
995             TYPEATTR    *tattr;
996
997             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
998             if (hres) {
999                 ERR("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
1000                 return hres;
1001             }
1002             hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1003             if (hres) {
1004                 ERR("Could not get typeattr in VT_USERDEFINED.\n");
1005             } else {
1006                 switch (tattr->typekind) {
1007                 case TKIND_DISPATCH:
1008                 case TKIND_INTERFACE:
1009                     if (readit)
1010                         hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
1011                     break;
1012                 case TKIND_RECORD: {
1013                     int i;
1014
1015                     if (alloc)
1016                         *arg = (DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,tattr->cbSizeInstance);
1017
1018                     if (debugout) TRACE_(olerelay)("{");
1019                     for (i=0;i<tattr->cVars;i++) {
1020                         VARDESC *vdesc;
1021
1022                         hres = ITypeInfo2_GetVarDesc(tinfo2, i, &vdesc);
1023                         if (hres) {
1024                             ERR("Could not get vardesc of %d\n",i);
1025                             return hres;
1026                         }
1027                         hres = deserialize_param(
1028                             tinfo2,
1029                             readit,
1030                             debugout,
1031                             alloc,
1032                             &vdesc->elemdescVar.tdesc,
1033                             (DWORD*)(((LPBYTE)*arg)+vdesc->u.oInst),
1034                             buf
1035                         );
1036                         if (debugout && (i<tattr->cVars-1)) TRACE_(olerelay)(",");
1037                     }
1038                     if (debugout) TRACE_(olerelay)("}");
1039                     break;
1040                 }
1041                 case TKIND_ALIAS:
1042                     return deserialize_param(tinfo2,readit,debugout,alloc,&tattr->tdescAlias,arg,buf);
1043                 case TKIND_ENUM:
1044                     if (readit) {
1045                         hres = xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
1046                         if (hres) ERR("Failed to read enum (4 byte)\n");
1047                     }
1048                     if (debugout) TRACE_(olerelay)("%lx",*arg);
1049                     return hres;
1050                 default:
1051                     ERR("Unhandled typekind %d\n",tattr->typekind);
1052                     hres = E_FAIL;
1053                     break;
1054                 }
1055             }
1056             if (hres)
1057                 ERR("failed to stuballoc in TKIND_RECORD.\n");
1058             ITypeInfo_Release(tinfo2);
1059             return hres;
1060         }
1061         case VT_CARRAY: {
1062             /* arg is pointing to the start of the array. */
1063             ARRAYDESC *adesc = tdesc->u.lpadesc;
1064             int         arrsize,i;
1065             arrsize = 1;
1066             if (adesc->cDims > 1) FIXME("cDims > 1 in VT_CARRAY. Does it work?\n");
1067             for (i=0;i<adesc->cDims;i++)
1068                 arrsize *= adesc->rgbounds[i].cElements;
1069             for (i=0;i<arrsize;i++)
1070                 deserialize_param(
1071                     tinfo,
1072                     readit,
1073                     debugout,
1074                     alloc,
1075                     &adesc->tdescElem,
1076                     (DWORD*)((LPBYTE)(arg)+i*_xsize(&adesc->tdescElem)),
1077                     buf
1078                 );
1079             return S_OK;
1080         }
1081         default:
1082             ERR("No handler for VT type %d!\n",tdesc->vt);
1083             return S_OK;
1084         }
1085     }
1086 }
1087
1088 /* Searches function, also in inherited interfaces */
1089 static HRESULT
1090 _get_funcdesc(
1091     ITypeInfo *tinfo, int iMethod, ITypeInfo **tactual, FUNCDESC **fdesc, BSTR *iname, BSTR *fname)
1092 {
1093     int i = 0, j = 0;
1094     HRESULT hres;
1095
1096     if (fname) *fname = NULL;
1097     if (iname) *iname = NULL;
1098
1099     *tactual = tinfo;
1100     ITypeInfo_AddRef(*tactual);
1101
1102     while (1) {
1103         hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
1104         if (hres) {
1105             ITypeInfo   *tinfo2;
1106             HREFTYPE    href;
1107             TYPEATTR    *attr;
1108
1109             hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
1110             if (hres) {
1111                 ERR("GetTypeAttr failed with %lx\n",hres);
1112                 return hres;
1113             }
1114             /* Not found, so look in inherited ifaces. */
1115             for (j=0;j<attr->cImplTypes;j++) {
1116                 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
1117                 if (hres) {
1118                     ERR("Did not find a reftype for interface offset %d?\n",j);
1119                     break;
1120                 }
1121                 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1122                 if (hres) {
1123                     ERR("Did not find a typeinfo for reftype %ld?\n",href);
1124                     continue;
1125                 }
1126                 hres = _get_funcdesc(tinfo2,iMethod,tactual,fdesc,iname,fname);
1127                 ITypeInfo_Release(tinfo2);
1128                 if (!hres) return S_OK;
1129             }
1130             return hres;
1131         }
1132         if (((*fdesc)->oVft/4) == iMethod) {
1133             if (fname)
1134                 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1135             if (iname)
1136                 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1137             return S_OK;
1138         }
1139         i++;
1140     }
1141 }
1142
1143 static DWORD
1144 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1145 {
1146     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
1147     FUNCDESC            *fdesc;
1148     HRESULT             hres;
1149     int                 i, relaydeb = TRACE_ON(olerelay);
1150     marshal_state       buf;
1151     RPCOLEMESSAGE       msg;
1152     ULONG               status;
1153     BSTR                fname,iname;
1154     BSTR                names[10];
1155     UINT                nrofnames;
1156     DWORD               remoteresult = 0;
1157     ITypeInfo           *tinfo;
1158
1159     EnterCriticalSection(&tpinfo->crit);
1160
1161     hres = _get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname);
1162     if (hres) {
1163         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1164         ITypeInfo_Release(tinfo);
1165         LeaveCriticalSection(&tpinfo->crit);
1166         return E_FAIL;
1167     }
1168
1169     if (!tpinfo->chanbuf)
1170     {
1171         WARN("Tried to use disconnected proxy\n");
1172         ITypeInfo_Release(tinfo);
1173         LeaveCriticalSection(&tpinfo->crit);
1174         return RPC_E_DISCONNECTED;
1175     }
1176
1177     if (relaydeb) {
1178        TRACE_(olerelay)("->");
1179         if (iname)
1180             TRACE_(olerelay)("%s:",relaystr(iname));
1181         if (fname)
1182             TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1183         else
1184             TRACE_(olerelay)("%d",method);
1185         TRACE_(olerelay)("(");
1186     }
1187
1188     if (iname) SysFreeString(iname);
1189     if (fname) SysFreeString(fname);
1190
1191     memset(&buf,0,sizeof(buf));
1192
1193     /* normal typelib driven serializing */
1194
1195     /* Need them for hack below */
1196     memset(names,0,sizeof(names));
1197     if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1198         nrofnames = 0;
1199     if (nrofnames > sizeof(names)/sizeof(names[0]))
1200         ERR("Need more names!\n");
1201
1202     xargs = args;
1203     for (i=0;i<fdesc->cParams;i++) {
1204         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1205         if (relaydeb) {
1206             if (i) TRACE_(olerelay)(",");
1207             if (i+1<nrofnames && names[i+1])
1208                 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1209         }
1210         /* No need to marshal other data than FIN and any VT_PTR. */
1211         if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags) && (elem->tdesc.vt != VT_PTR)) {
1212             xargs+=_argsize(elem->tdesc.vt);
1213             if (relaydeb) TRACE_(olerelay)("[out]");
1214             continue;
1215         }
1216         hres = serialize_param(
1217             tinfo,
1218             elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags,
1219             relaydeb,
1220             FALSE,
1221             &elem->tdesc,
1222             xargs,
1223             &buf
1224         );
1225
1226         if (hres) {
1227             ERR("Failed to serialize param, hres %lx\n",hres);
1228             break;
1229         }
1230         xargs+=_argsize(elem->tdesc.vt);
1231     }
1232     if (relaydeb) TRACE_(olerelay)(")");
1233
1234     memset(&msg,0,sizeof(msg));
1235     msg.cbBuffer = buf.curoff;
1236     msg.iMethod  = method;
1237     hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
1238     if (hres) {
1239         ERR("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
1240         LeaveCriticalSection(&tpinfo->crit);
1241         return hres;
1242     }
1243     memcpy(msg.Buffer,buf.base,buf.curoff);
1244     if (relaydeb) TRACE_(olerelay)("\n");
1245     hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
1246     if (hres) {
1247         ERR("RpcChannelBuffer SendReceive failed, %lx\n",hres);
1248         LeaveCriticalSection(&tpinfo->crit);
1249         return hres;
1250     }
1251
1252     if (relaydeb) TRACE_(olerelay)(" status = %08lx (",status);
1253     if (buf.base)
1254         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1255     else
1256         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1257     buf.size = msg.cbBuffer;
1258     memcpy(buf.base,msg.Buffer,buf.size);
1259     buf.curoff = 0;
1260
1261     /* generic deserializer using typelib description */
1262     xargs = args;
1263     status = S_OK;
1264     for (i=0;i<fdesc->cParams;i++) {
1265         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1266
1267         if (relaydeb) {
1268             if (i) TRACE_(olerelay)(",");
1269             if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1270         }
1271         /* No need to marshal other data than FOUT and any VT_PTR */
1272         if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) && (elem->tdesc.vt != VT_PTR)) {
1273             xargs += _argsize(elem->tdesc.vt);
1274             if (relaydeb) TRACE_(olerelay)("[in]");
1275             continue;
1276         }
1277         hres = deserialize_param(
1278             tinfo,
1279             elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1280             relaydeb,
1281             FALSE,
1282             &(elem->tdesc),
1283             xargs,
1284             &buf
1285         );
1286         if (hres) {
1287             ERR("Failed to unmarshall param, hres %lx\n",hres);
1288             status = hres;
1289             break;
1290         }
1291         xargs += _argsize(elem->tdesc.vt);
1292     }
1293
1294     hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1295     if (hres != S_OK)
1296         return hres;
1297     if (relaydeb) TRACE_(olerelay)(") = %08lx\n", remoteresult);
1298
1299     if (status != S_OK) /* OLE/COM internal error */
1300         return status;
1301
1302     HeapFree(GetProcessHeap(),0,buf.base);
1303     ITypeInfo_Release(tinfo);
1304     LeaveCriticalSection(&tpinfo->crit);
1305     return remoteresult;
1306 }
1307
1308 HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1309 {
1310     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1311
1312     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1313
1314     if (proxy->outerunknown)
1315         return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1316
1317     FIXME("No interface\n");
1318     return E_NOINTERFACE;
1319 }
1320
1321 ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1322 {
1323     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1324
1325     TRACE("\n");
1326
1327     if (proxy->outerunknown)
1328         return IUnknown_AddRef(proxy->outerunknown);
1329
1330     return 2; /* FIXME */
1331 }
1332
1333 ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1334 {
1335     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1336
1337     TRACE("\n");
1338
1339     if (proxy->outerunknown)
1340         return IUnknown_Release(proxy->outerunknown);
1341
1342     return 1; /* FIXME */
1343 }
1344
1345 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1346 {
1347     TMProxyImpl *This = (TMProxyImpl *)iface;
1348     HRESULT hr;
1349
1350     TRACE("(%p)\n", pctinfo);
1351
1352     if (!This->dispatch)
1353     {
1354         hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
1355                                      (LPVOID *)&This->dispatch);
1356     }
1357     if (This->dispatch)
1358         hr = IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1359
1360     return hr;
1361 }
1362
1363 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1364 {
1365     TMProxyImpl *This = (TMProxyImpl *)iface;
1366     HRESULT hr = S_OK;
1367
1368     TRACE("(%d, %lx, %p)\n", iTInfo, lcid, ppTInfo);
1369
1370     if (!This->dispatch)
1371     {
1372         hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
1373                                      (LPVOID *)&This->dispatch);
1374     }
1375     if (This->dispatch)
1376         hr = IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1377
1378     return hr;
1379 }
1380
1381 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1382 {
1383     TMProxyImpl *This = (TMProxyImpl *)iface;
1384     HRESULT hr;
1385
1386     TRACE("(%s, %p, %d, 0x%lx, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1387
1388     if (!This->dispatch)
1389     {
1390         hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
1391                                      (LPVOID *)&This->dispatch);
1392     }
1393     if (This->dispatch)
1394         hr = IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1395                                      cNames, lcid, rgDispId);
1396
1397     return hr;
1398 }
1399
1400 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1401                                             WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1402                                             EXCEPINFO * pExcepInfo, UINT * puArgErr)
1403 {
1404     TMProxyImpl *This = (TMProxyImpl *)iface;
1405     HRESULT hr;
1406
1407     TRACE("(%ld, %s, 0x%lx, 0x%x, %p, %p, %p, %p)\n", dispIdMember, debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
1408
1409     if (!This->dispatch)
1410     {
1411         hr = IUnknown_QueryInterface(This->outerunknown, &IID_IDispatch,
1412                                      (LPVOID *)&This->dispatch);
1413     }
1414     if (This->dispatch)
1415         hr = IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1416                               wFlags, pDispParams, pVarResult, pExcepInfo,
1417                               puArgErr);
1418
1419     return hr;
1420 }
1421
1422 static HRESULT WINAPI
1423 PSFacBuf_CreateProxy(
1424     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1425     IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1426 {
1427     HRESULT     hres;
1428     ITypeInfo   *tinfo;
1429     int         i, nroffuncs;
1430     FUNCDESC    *fdesc;
1431     TMProxyImpl *proxy;
1432     TYPEATTR    *typeattr;
1433
1434     TRACE("(...%s...)\n",debugstr_guid(riid));
1435     hres = _get_typeinfo_for_iid(riid,&tinfo);
1436     if (hres) {
1437         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1438         return hres;
1439     }
1440     nroffuncs = _nroffuncs(tinfo);
1441     proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1442     if (!proxy) return E_OUTOFMEMORY;
1443
1444     assert(sizeof(TMAsmProxy) == 12);
1445
1446     proxy->dispatch = NULL;
1447     proxy->outerunknown = pUnkOuter;
1448     proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1449     if (!proxy->asmstubs) {
1450         ERR("Could not commit pages for proxy thunks\n");
1451         CoTaskMemFree(proxy);
1452         return E_OUTOFMEMORY;
1453     }
1454
1455     InitializeCriticalSection(&proxy->crit);
1456
1457     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1458     for (i=0;i<nroffuncs;i++) {
1459         TMAsmProxy      *xasm = proxy->asmstubs+i;
1460
1461         switch (i) {
1462         case 0:
1463                 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
1464                 break;
1465         case 1:
1466                 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
1467                 break;
1468         case 2:
1469                 proxy->lpvtbl[i] = ProxyIUnknown_Release;
1470                 break;
1471         default: {
1472                 int j;
1473                 /* nrofargs without This */
1474                 int nrofargs;
1475                 ITypeInfo *tinfo2;
1476                 hres = _get_funcdesc(tinfo,i,&tinfo2,&fdesc,NULL,NULL);
1477                 ITypeInfo_Release(tinfo2);
1478                 if (hres) {
1479                     ERR("GetFuncDesc %lx should not fail here.\n",hres);
1480                     return hres;
1481                 }
1482                 /* some args take more than 4 byte on the stack */
1483                 nrofargs = 0;
1484                 for (j=0;j<fdesc->cParams;j++)
1485                     nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
1486
1487 #ifdef __i386__
1488                 if (fdesc->callconv != CC_STDCALL) {
1489                     ERR("calling convention is not stdcall????\n");
1490                     return E_FAIL;
1491                 }
1492 /* popl %eax    -       return ptr
1493  * pushl <nr>
1494  * pushl %eax
1495  * call xCall
1496  * lret <nr> (+4)
1497  *
1498  *
1499  * arg3 arg2 arg1 <method> <returnptr>
1500  */
1501                 xasm->popleax   = 0x58;
1502                 xasm->pushlval  = 0x6a;
1503                 xasm->nr        = i;
1504                 xasm->pushleax  = 0x50;
1505                 xasm->lcall     = 0xe8; /* relative jump */
1506                 xasm->xcall     = (DWORD)xCall;
1507                 xasm->xcall     -= (DWORD)&(xasm->lret);
1508                 xasm->lret      = 0xc2;
1509                 xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
1510                 proxy->lpvtbl[i] = xasm;
1511                 break;
1512 #else
1513                 FIXME("not implemented on non i386\n");
1514                 return E_FAIL;
1515 #endif
1516             }
1517         }
1518     }
1519
1520     /* if we derive from IDispatch then defer to its proxy for its methods */
1521     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
1522     if (hres == S_OK)
1523     {
1524         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
1525         {
1526             proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
1527             proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
1528             proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
1529             proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
1530         }
1531         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
1532     }
1533
1534     proxy->lpvtbl2      = &tmproxyvtable;
1535     /* one reference for the proxy */
1536     proxy->ref          = 1;
1537     proxy->tinfo        = tinfo;
1538     memcpy(&proxy->iid,riid,sizeof(*riid));
1539     proxy->chanbuf      = 0;
1540     *ppv                = (LPVOID)proxy;
1541     *ppProxy            = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1542     IUnknown_AddRef((IUnknown *)*ppv);
1543     return S_OK;
1544 }
1545
1546 typedef struct _TMStubImpl {
1547     const IRpcStubBufferVtbl   *lpvtbl;
1548     LONG                        ref;
1549
1550     LPUNKNOWN                   pUnk;
1551     ITypeInfo                   *tinfo;
1552     IID                         iid;
1553 } TMStubImpl;
1554
1555 static HRESULT WINAPI
1556 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1557 {
1558     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1559         *ppv = (LPVOID)iface;
1560         IRpcStubBuffer_AddRef(iface);
1561         return S_OK;
1562     }
1563     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1564     return E_NOINTERFACE;
1565 }
1566
1567 static ULONG WINAPI
1568 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1569 {
1570     TMStubImpl *This = (TMStubImpl *)iface;
1571     ULONG refCount = InterlockedIncrement(&This->ref);
1572         
1573     TRACE("(%p)->(ref before=%lu)\n", This, refCount - 1);
1574
1575     return refCount;
1576 }
1577
1578 static ULONG WINAPI
1579 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1580 {
1581     TMStubImpl *This = (TMStubImpl *)iface;
1582     ULONG refCount = InterlockedDecrement(&This->ref);
1583
1584     TRACE("(%p)->(ref before=%lu)\n", This, refCount + 1);
1585
1586     if (!refCount)
1587     {
1588         IRpcStubBuffer_Disconnect(iface);
1589         ITypeInfo_Release(This->tinfo);
1590         CoTaskMemFree(This);
1591     }
1592     return refCount;
1593 }
1594
1595 static HRESULT WINAPI
1596 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1597 {
1598     TMStubImpl *This = (TMStubImpl *)iface;
1599
1600     TRACE("(%p)->(%p)\n", This, pUnkServer);
1601
1602     IUnknown_AddRef(pUnkServer);
1603     This->pUnk = pUnkServer;
1604     return S_OK;
1605 }
1606
1607 static void WINAPI
1608 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1609 {
1610     TMStubImpl *This = (TMStubImpl *)iface;
1611
1612     TRACE("(%p)->()\n", This);
1613
1614     if (This->pUnk)
1615     {
1616         IUnknown_Release(This->pUnk);
1617         This->pUnk = NULL;
1618     }
1619 }
1620
1621 static HRESULT WINAPI
1622 TMStubImpl_Invoke(
1623     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1624 {
1625     int         i;
1626     FUNCDESC    *fdesc;
1627     TMStubImpl *This = (TMStubImpl *)iface;
1628     HRESULT     hres;
1629     DWORD       *args, res, *xargs, nrofargs;
1630     marshal_state       buf;
1631     UINT        nrofnames;
1632     BSTR        names[10];
1633     BSTR        iname = NULL;
1634     ITypeInfo   *tinfo;
1635
1636     memset(&buf,0,sizeof(buf));
1637     buf.size    = xmsg->cbBuffer;
1638     buf.base    = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
1639     memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
1640     buf.curoff  = 0;
1641
1642     TRACE("...\n");
1643
1644     if (xmsg->iMethod < 3) {
1645         ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
1646         return E_UNEXPECTED;
1647     }
1648
1649     hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL);
1650     if (hres) {
1651         ERR("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1652         return hres;
1653     }
1654
1655     if (iname && !lstrcmpW(iname, IDispatchW))
1656     {
1657         ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
1658         ITypeInfo_Release(tinfo);
1659         return E_UNEXPECTED;
1660     }
1661
1662     if (iname) SysFreeString (iname);
1663
1664     /* Need them for hack below */
1665     memset(names,0,sizeof(names));
1666     ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1667     if (nrofnames > sizeof(names)/sizeof(names[0])) {
1668         ERR("Need more names!\n");
1669     }
1670
1671     /*dump_FUNCDESC(fdesc);*/
1672     nrofargs = 0;
1673     for (i=0;i<fdesc->cParams;i++)
1674         nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1675     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1676     if (!args) return E_OUTOFMEMORY;
1677
1678     /* Allocate all stuff used by call. */
1679     xargs = args+1;
1680     for (i=0;i<fdesc->cParams;i++) {
1681         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1682
1683         hres = deserialize_param(
1684            tinfo,
1685            elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags,
1686            FALSE,
1687            TRUE,
1688            &(elem->tdesc),
1689            xargs,
1690            &buf
1691         );
1692         xargs += _argsize(elem->tdesc.vt);
1693         if (hres) {
1694             ERR("Failed to deserialize param %s, hres %lx\n",relaystr(names[i+1]),hres);
1695             break;
1696         }
1697     }
1698
1699     hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1700     if (hres) {
1701         ERR("Does not support iface %s, returning %lx\n",debugstr_guid(&(This->iid)), hres);
1702         return hres;
1703     }
1704     res = _invoke(
1705         (*((FARPROC**)args[0]))[fdesc->oVft/4],
1706         fdesc->callconv,
1707         (xargs-args),
1708         args
1709     );
1710     IUnknown_Release((LPUNKNOWN)args[0]);
1711     buf.curoff = 0;
1712
1713     xargs = args+1;
1714     for (i=0;i<fdesc->cParams;i++) {
1715         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1716         hres = serialize_param(
1717            tinfo,
1718            elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT,
1719            FALSE,
1720            TRUE,
1721            &elem->tdesc,
1722            xargs,
1723            &buf
1724         );
1725         xargs += _argsize(elem->tdesc.vt);
1726         if (hres) {
1727             ERR("Failed to stuballoc param, hres %lx\n",hres);
1728             break;
1729         }
1730     }
1731
1732     hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
1733     if (hres != S_OK)
1734         return hres;
1735
1736     ITypeInfo_Release(tinfo);
1737     HeapFree(GetProcessHeap(), 0, args);
1738
1739     xmsg->cbBuffer      = buf.curoff;
1740     if (rpcchanbuf)
1741     {
1742         hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
1743         if (hres != S_OK)
1744             ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08lx\n", hres);
1745     }
1746     else
1747     {
1748         /* FIXME: remove this case when we start sending an IRpcChannelBuffer
1749          * object with builtin OLE */
1750         RPC_STATUS status = I_RpcGetBuffer((RPC_MESSAGE *)xmsg);
1751         if (status != RPC_S_OK)
1752         {
1753             ERR("I_RpcGetBuffer failed with error %ld\n", status);
1754             hres = E_FAIL;
1755         }
1756     }
1757
1758     if (hres == S_OK)
1759         memcpy(xmsg->Buffer, buf.base, buf.curoff);
1760
1761     HeapFree(GetProcessHeap(), 0, buf.base);
1762
1763     TRACE("returning\n");
1764     return hres;
1765 }
1766
1767 static LPRPCSTUBBUFFER WINAPI
1768 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1769     FIXME("Huh (%s)?\n",debugstr_guid(riid));
1770     return NULL;
1771 }
1772
1773 static ULONG WINAPI
1774 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1775     TMStubImpl *This = (TMStubImpl *)iface;
1776
1777     FIXME("()\n");
1778     return This->ref; /*FIXME? */
1779 }
1780
1781 static HRESULT WINAPI
1782 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1783     return E_NOTIMPL;
1784 }
1785
1786 static void WINAPI
1787 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1788     return;
1789 }
1790
1791 static const IRpcStubBufferVtbl tmstubvtbl = {
1792     TMStubImpl_QueryInterface,
1793     TMStubImpl_AddRef,
1794     TMStubImpl_Release,
1795     TMStubImpl_Connect,
1796     TMStubImpl_Disconnect,
1797     TMStubImpl_Invoke,
1798     TMStubImpl_IsIIDSupported,
1799     TMStubImpl_CountRefs,
1800     TMStubImpl_DebugServerQueryInterface,
1801     TMStubImpl_DebugServerRelease
1802 };
1803
1804 static HRESULT WINAPI
1805 PSFacBuf_CreateStub(
1806     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1807     IRpcStubBuffer** ppStub
1808 ) {
1809     HRESULT hres;
1810     ITypeInfo   *tinfo;
1811     TMStubImpl  *stub;
1812
1813     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1814     hres = _get_typeinfo_for_iid(riid,&tinfo);
1815     if (hres) {
1816         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1817         return hres;
1818     }
1819     stub = CoTaskMemAlloc(sizeof(TMStubImpl));
1820     if (!stub)
1821         return E_OUTOFMEMORY;
1822     stub->lpvtbl        = &tmstubvtbl;
1823     stub->ref           = 1;
1824     stub->tinfo         = tinfo;
1825     memcpy(&(stub->iid),riid,sizeof(*riid));
1826     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1827     *ppStub             = (LPRPCSTUBBUFFER)stub;
1828     TRACE("IRpcStubBuffer: %p\n", stub);
1829     if (hres)
1830         ERR("Connect to pUnkServer failed?\n");
1831     return hres;
1832 }
1833
1834 static const IPSFactoryBufferVtbl psfacbufvtbl = {
1835     PSFacBuf_QueryInterface,
1836     PSFacBuf_AddRef,
1837     PSFacBuf_Release,
1838     PSFacBuf_CreateProxy,
1839     PSFacBuf_CreateStub
1840 };
1841
1842 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1843 static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
1844
1845 /***********************************************************************
1846  *           TMARSHAL_DllGetClassObject
1847  */
1848 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1849 {
1850     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1851         *ppv = &lppsfac;
1852         return S_OK;
1853     }
1854     return E_NOINTERFACE;
1855 }