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