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