wined3d: Set SFLAG_INSYSMEM when WINED3DLOCK_DISCARD is passed to IWineD3DSurfaceImpl...
[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, const BYTE *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 /*
324  * Determine the number of functions including all inherited functions.
325  * Note for non-dual dispinterfaces we simply return the size of IDispatch.
326  */
327 static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num)
328 {
329     HRESULT hres;
330     TYPEATTR *attr;
331     ITypeInfo *tinfo2;
332
333     *num = 0;
334     hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
335     if (hres) {
336         ERR("GetTypeAttr failed with %x\n",hres);
337         return hres;
338     }
339
340     if(attr->typekind == TKIND_DISPATCH && (attr->wTypeFlags & TYPEFLAG_FDUAL))
341     {
342         HREFTYPE href;
343         hres = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
344         if(FAILED(hres))
345         {
346             ERR("Unable to get interface href from dual dispinterface\n");
347             goto end;
348         }
349         hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
350         if(FAILED(hres))
351         {
352             ERR("Unable to get interface from dual dispinterface\n");
353             goto end;
354         }
355         hres = num_of_funcs(tinfo2, num);
356         ITypeInfo_Release(tinfo2);
357     }
358     else
359     {
360         *num = attr->cbSizeVft / 4;
361     }
362
363  end:
364     ITypeInfo_ReleaseTypeAttr(tinfo, attr);
365     return hres;
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(const 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         const 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
1219     if(attr->typekind == TKIND_DISPATCH)
1220     {
1221         if(attr->wTypeFlags & TYPEFLAG_FDUAL)
1222         {
1223             HREFTYPE href;
1224             ITypeInfo *tinfo2;
1225
1226             hr = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
1227             if(FAILED(hr))
1228             {
1229                 ERR("Cannot get interface href from dual dispinterface\n");
1230                 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1231                 return hr;
1232             }
1233             hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
1234             if(FAILED(hr))
1235             {
1236                 ERR("Cannot get interface from dual dispinterface\n");
1237                 ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1238                 return hr;
1239             }
1240             hr = get_funcdesc(tinfo2, iMethod, tactual, fdesc, iname, fname, num);
1241             ITypeInfo_Release(tinfo2);
1242             ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1243             return hr;
1244         }
1245         ERR("Shouldn't be called with a non-dual dispinterface\n");
1246         return E_FAIL;
1247     }
1248
1249     impl_types = attr->cImplTypes;
1250     ITypeInfo_ReleaseTypeAttr(tinfo, attr);
1251
1252     for (i = 0; i < impl_types; i++)
1253     {
1254         HREFTYPE href;
1255         ITypeInfo *pSubTypeInfo;
1256         UINT sub_funcs;
1257
1258         hr = ITypeInfo_GetRefTypeOfImplType(tinfo, i, &href);
1259         if (FAILED(hr)) return hr;
1260         hr = ITypeInfo_GetRefTypeInfo(tinfo, href, &pSubTypeInfo);
1261         if (FAILED(hr)) return hr;
1262
1263         hr = get_funcdesc(pSubTypeInfo, iMethod, tactual, fdesc, iname, fname, &sub_funcs);
1264         inherited_funcs += sub_funcs;
1265         ITypeInfo_Release(pSubTypeInfo);
1266         if(SUCCEEDED(hr)) return hr;
1267     }
1268     if(iMethod < inherited_funcs)
1269     {
1270         ERR("shouldn't be here\n");
1271         return E_INVALIDARG;
1272     }
1273
1274     for(i = inherited_funcs; i <= iMethod; i++)
1275     {
1276         hr = ITypeInfoImpl_GetInternalFuncDesc(tinfo, i - inherited_funcs, fdesc);
1277         if(FAILED(hr))
1278         {
1279             if(num) *num = i;
1280             return hr;
1281         }
1282     }
1283
1284     /* found it. We don't care about num so zero it */
1285     if(num) *num = 0;
1286     *tactual = tinfo;
1287     ITypeInfo_AddRef(*tactual);
1288     if (fname) ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
1289     if (iname) ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
1290     return S_OK;
1291 }
1292
1293 static inline BOOL is_in_elem(const ELEMDESC *elem)
1294 {
1295     return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN || !elem->u.paramdesc.wParamFlags);
1296 }
1297
1298 static inline BOOL is_out_elem(const ELEMDESC *elem)
1299 {
1300     return (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT || !elem->u.paramdesc.wParamFlags);
1301 }
1302
1303 static DWORD
1304 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */)
1305 {
1306     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
1307     const FUNCDESC      *fdesc;
1308     HRESULT             hres;
1309     int                 i, relaydeb = TRACE_ON(olerelay);
1310     marshal_state       buf;
1311     RPCOLEMESSAGE       msg;
1312     ULONG               status;
1313     BSTR                fname,iname;
1314     BSTR                names[10];
1315     UINT                nrofnames;
1316     DWORD               remoteresult = 0;
1317     ITypeInfo           *tinfo;
1318     IRpcChannelBuffer *chanbuf;
1319
1320     EnterCriticalSection(&tpinfo->crit);
1321
1322     hres = get_funcdesc(tpinfo->tinfo,method,&tinfo,&fdesc,&iname,&fname,NULL);
1323     if (hres) {
1324         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
1325         LeaveCriticalSection(&tpinfo->crit);
1326         return E_FAIL;
1327     }
1328
1329     if (!tpinfo->chanbuf)
1330     {
1331         WARN("Tried to use disconnected proxy\n");
1332         ITypeInfo_Release(tinfo);
1333         LeaveCriticalSection(&tpinfo->crit);
1334         return RPC_E_DISCONNECTED;
1335     }
1336     chanbuf = tpinfo->chanbuf;
1337     IRpcChannelBuffer_AddRef(chanbuf);
1338
1339     LeaveCriticalSection(&tpinfo->crit);
1340
1341     if (relaydeb) {
1342        TRACE_(olerelay)("->");
1343         if (iname)
1344             TRACE_(olerelay)("%s:",relaystr(iname));
1345         if (fname)
1346             TRACE_(olerelay)("%s(%d)",relaystr(fname),method);
1347         else
1348             TRACE_(olerelay)("%d",method);
1349         TRACE_(olerelay)("(");
1350     }
1351
1352     if (iname) SysFreeString(iname);
1353     if (fname) SysFreeString(fname);
1354
1355     memset(&buf,0,sizeof(buf));
1356
1357     /* normal typelib driven serializing */
1358
1359     /* Need them for hack below */
1360     memset(names,0,sizeof(names));
1361     if (ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames))
1362         nrofnames = 0;
1363     if (nrofnames > sizeof(names)/sizeof(names[0]))
1364         ERR("Need more names!\n");
1365
1366     xargs = args;
1367     for (i=0;i<fdesc->cParams;i++) {
1368         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1369         if (relaydeb) {
1370             if (i) TRACE_(olerelay)(",");
1371             if (i+1<nrofnames && names[i+1])
1372                 TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1373         }
1374         /* No need to marshal other data than FIN and any VT_PTR. */
1375         if (!is_in_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1376             xargs+=_argsize(elem->tdesc.vt);
1377             if (relaydeb) TRACE_(olerelay)("[out]");
1378             continue;
1379         }
1380         hres = serialize_param(
1381             tinfo,
1382             is_in_elem(elem),
1383             relaydeb,
1384             FALSE,
1385             &elem->tdesc,
1386             xargs,
1387             &buf
1388         );
1389
1390         if (hres) {
1391             ERR("Failed to serialize param, hres %x\n",hres);
1392             break;
1393         }
1394         xargs+=_argsize(elem->tdesc.vt);
1395     }
1396     if (relaydeb) TRACE_(olerelay)(")");
1397
1398     memset(&msg,0,sizeof(msg));
1399     msg.cbBuffer = buf.curoff;
1400     msg.iMethod  = method;
1401     hres = IRpcChannelBuffer_GetBuffer(chanbuf,&msg,&(tpinfo->iid));
1402     if (hres) {
1403         ERR("RpcChannelBuffer GetBuffer failed, %x\n",hres);
1404         goto exit;
1405     }
1406     memcpy(msg.Buffer,buf.base,buf.curoff);
1407     if (relaydeb) TRACE_(olerelay)("\n");
1408     hres = IRpcChannelBuffer_SendReceive(chanbuf,&msg,&status);
1409     if (hres) {
1410         ERR("RpcChannelBuffer SendReceive failed, %x\n",hres);
1411         goto exit;
1412     }
1413
1414     if (relaydeb) TRACE_(olerelay)(" status = %08x (",status);
1415     if (buf.base)
1416         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
1417     else
1418         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
1419     buf.size = msg.cbBuffer;
1420     memcpy(buf.base,msg.Buffer,buf.size);
1421     buf.curoff = 0;
1422
1423     /* generic deserializer using typelib description */
1424     xargs = args;
1425     status = S_OK;
1426     for (i=0;i<fdesc->cParams;i++) {
1427         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1428
1429         if (relaydeb) {
1430             if (i) TRACE_(olerelay)(",");
1431             if (i+1<nrofnames && names[i+1]) TRACE_(olerelay)("%s=",relaystr(names[i+1]));
1432         }
1433         /* No need to marshal other data than FOUT and any VT_PTR */
1434         if (!is_out_elem(elem) && (elem->tdesc.vt != VT_PTR)) {
1435             xargs += _argsize(elem->tdesc.vt);
1436             if (relaydeb) TRACE_(olerelay)("[in]");
1437             continue;
1438         }
1439         hres = deserialize_param(
1440             tinfo,
1441             is_out_elem(elem),
1442             relaydeb,
1443             FALSE,
1444             &(elem->tdesc),
1445             xargs,
1446             &buf
1447         );
1448         if (hres) {
1449             ERR("Failed to unmarshall param, hres %x\n",hres);
1450             status = hres;
1451             break;
1452         }
1453         xargs += _argsize(elem->tdesc.vt);
1454     }
1455
1456     hres = xbuf_get(&buf, (LPBYTE)&remoteresult, sizeof(DWORD));
1457     if (hres != S_OK)
1458         goto exit;
1459     if (relaydeb) TRACE_(olerelay)(") = %08x\n", remoteresult);
1460
1461     hres = remoteresult;
1462
1463 exit:
1464     for (i = 0; i < nrofnames; i++)
1465         SysFreeString(names[i]);
1466     HeapFree(GetProcessHeap(),0,buf.base);
1467     IRpcChannelBuffer_Release(chanbuf);
1468     ITypeInfo_Release(tinfo);
1469     TRACE("-- 0x%08x\n", hres);
1470     return hres;
1471 }
1472
1473 static HRESULT WINAPI ProxyIUnknown_QueryInterface(IUnknown *iface, REFIID riid, void **ppv)
1474 {
1475     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1476
1477     TRACE("(%s, %p)\n", debugstr_guid(riid), ppv);
1478
1479     if (proxy->outerunknown)
1480         return IUnknown_QueryInterface(proxy->outerunknown, riid, ppv);
1481
1482     FIXME("No interface\n");
1483     return E_NOINTERFACE;
1484 }
1485
1486 static ULONG WINAPI ProxyIUnknown_AddRef(IUnknown *iface)
1487 {
1488     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1489
1490     TRACE("\n");
1491
1492     if (proxy->outerunknown)
1493         return IUnknown_AddRef(proxy->outerunknown);
1494
1495     return 2; /* FIXME */
1496 }
1497
1498 static ULONG WINAPI ProxyIUnknown_Release(IUnknown *iface)
1499 {
1500     TMProxyImpl *proxy = (TMProxyImpl *)iface;
1501
1502     TRACE("\n");
1503
1504     if (proxy->outerunknown)
1505         return IUnknown_Release(proxy->outerunknown);
1506
1507     return 1; /* FIXME */
1508 }
1509
1510 static HRESULT WINAPI ProxyIDispatch_GetTypeInfoCount(LPDISPATCH iface, UINT * pctinfo)
1511 {
1512     TMProxyImpl *This = (TMProxyImpl *)iface;
1513
1514     TRACE("(%p)\n", pctinfo);
1515
1516     return IDispatch_GetTypeInfoCount(This->dispatch, pctinfo);
1517 }
1518
1519 static HRESULT WINAPI ProxyIDispatch_GetTypeInfo(LPDISPATCH iface, UINT iTInfo, LCID lcid, ITypeInfo** ppTInfo)
1520 {
1521     TMProxyImpl *This = (TMProxyImpl *)iface;
1522
1523     TRACE("(%d, %x, %p)\n", iTInfo, lcid, ppTInfo);
1524
1525     return IDispatch_GetTypeInfo(This->dispatch, iTInfo, lcid, ppTInfo);
1526 }
1527
1528 static HRESULT WINAPI ProxyIDispatch_GetIDsOfNames(LPDISPATCH iface, REFIID riid, LPOLESTR * rgszNames, UINT cNames, LCID lcid, DISPID * rgDispId)
1529 {
1530     TMProxyImpl *This = (TMProxyImpl *)iface;
1531
1532     TRACE("(%s, %p, %d, 0x%x, %p)\n", debugstr_guid(riid), rgszNames, cNames, lcid, rgDispId);
1533
1534     return IDispatch_GetIDsOfNames(This->dispatch, riid, rgszNames,
1535                                    cNames, lcid, rgDispId);
1536 }
1537
1538 static HRESULT WINAPI ProxyIDispatch_Invoke(LPDISPATCH iface, DISPID dispIdMember, REFIID riid, LCID lcid,
1539                                             WORD wFlags, DISPPARAMS * pDispParams, VARIANT * pVarResult,
1540                                             EXCEPINFO * pExcepInfo, UINT * puArgErr)
1541 {
1542     TMProxyImpl *This = (TMProxyImpl *)iface;
1543
1544     TRACE("(%d, %s, 0x%x, 0x%x, %p, %p, %p, %p)\n", dispIdMember,
1545           debugstr_guid(riid), lcid, wFlags, pDispParams, pVarResult,
1546           pExcepInfo, puArgErr);
1547
1548     return IDispatch_Invoke(This->dispatch, dispIdMember, riid, lcid,
1549                             wFlags, pDispParams, pVarResult, pExcepInfo,
1550                             puArgErr);
1551 }
1552
1553 typedef struct
1554 {
1555     const IRpcChannelBufferVtbl *lpVtbl;
1556     LONG                  refs;
1557     /* the IDispatch-derived interface we are handling */
1558         IID                   tmarshal_iid;
1559     IRpcChannelBuffer    *pDelegateChannel;
1560 } TMarshalDispatchChannel;
1561
1562 static HRESULT WINAPI TMarshalDispatchChannel_QueryInterface(LPRPCCHANNELBUFFER iface, REFIID riid, LPVOID *ppv)
1563 {
1564     *ppv = NULL;
1565     if (IsEqualIID(riid,&IID_IRpcChannelBuffer) || IsEqualIID(riid,&IID_IUnknown))
1566     {
1567         *ppv = (LPVOID)iface;
1568         IUnknown_AddRef(iface);
1569         return S_OK;
1570     }
1571     return E_NOINTERFACE;
1572 }
1573
1574 static ULONG WINAPI TMarshalDispatchChannel_AddRef(LPRPCCHANNELBUFFER iface)
1575 {
1576     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1577     return InterlockedIncrement(&This->refs);
1578 }
1579
1580 static ULONG WINAPI TMarshalDispatchChannel_Release(LPRPCCHANNELBUFFER iface)
1581 {
1582     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1583     ULONG ref;
1584
1585     ref = InterlockedDecrement(&This->refs);
1586     if (ref)
1587         return ref;
1588
1589         IRpcChannelBuffer_Release(This->pDelegateChannel);
1590     HeapFree(GetProcessHeap(), 0, This);
1591     return 0;
1592 }
1593
1594 static HRESULT WINAPI TMarshalDispatchChannel_GetBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg, REFIID riid)
1595 {
1596     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1597     TRACE("(%p, %s)\n", olemsg, debugstr_guid(riid));
1598     /* Note: we are pretending to invoke a method on the interface identified
1599      * by tmarshal_iid so that we can re-use the IDispatch proxy/stub code
1600      * without the RPC runtime getting confused by not exporting an IDispatch interface */
1601     return IRpcChannelBuffer_GetBuffer(This->pDelegateChannel, olemsg, &This->tmarshal_iid);
1602 }
1603
1604 static HRESULT WINAPI TMarshalDispatchChannel_SendReceive(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE *olemsg, ULONG *pstatus)
1605 {
1606     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1607     TRACE("(%p, %p)\n", olemsg, pstatus);
1608     return IRpcChannelBuffer_SendReceive(This->pDelegateChannel, olemsg, pstatus);
1609 }
1610
1611 static HRESULT WINAPI TMarshalDispatchChannel_FreeBuffer(LPRPCCHANNELBUFFER iface, RPCOLEMESSAGE* olemsg)
1612 {
1613     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1614     TRACE("(%p)\n", olemsg);
1615     return IRpcChannelBuffer_FreeBuffer(This->pDelegateChannel, olemsg);
1616 }
1617
1618 static HRESULT WINAPI TMarshalDispatchChannel_GetDestCtx(LPRPCCHANNELBUFFER iface, DWORD* pdwDestContext, void** ppvDestContext)
1619 {
1620     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1621     TRACE("(%p,%p)\n", pdwDestContext, ppvDestContext);
1622     return IRpcChannelBuffer_GetDestCtx(This->pDelegateChannel, pdwDestContext, ppvDestContext);
1623 }
1624
1625 static HRESULT WINAPI TMarshalDispatchChannel_IsConnected(LPRPCCHANNELBUFFER iface)
1626 {
1627     TMarshalDispatchChannel *This = (TMarshalDispatchChannel *)iface;
1628     TRACE("()\n");
1629     return IRpcChannelBuffer_IsConnected(This->pDelegateChannel);
1630 }
1631
1632 static const IRpcChannelBufferVtbl TMarshalDispatchChannelVtbl =
1633 {
1634     TMarshalDispatchChannel_QueryInterface,
1635     TMarshalDispatchChannel_AddRef,
1636     TMarshalDispatchChannel_Release,
1637     TMarshalDispatchChannel_GetBuffer,
1638     TMarshalDispatchChannel_SendReceive,
1639     TMarshalDispatchChannel_FreeBuffer,
1640     TMarshalDispatchChannel_GetDestCtx,
1641     TMarshalDispatchChannel_IsConnected
1642 };
1643
1644 static HRESULT TMarshalDispatchChannel_Create(
1645     IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
1646     IRpcChannelBuffer **ppChannel)
1647 {
1648     TMarshalDispatchChannel *This = HeapAlloc(GetProcessHeap(), 0, sizeof(*This));
1649     if (!This)
1650         return E_OUTOFMEMORY;
1651
1652     This->lpVtbl = &TMarshalDispatchChannelVtbl;
1653     This->refs = 1;
1654     IRpcChannelBuffer_AddRef(pDelegateChannel);
1655     This->pDelegateChannel = pDelegateChannel;
1656     This->tmarshal_iid = *tmarshal_riid;
1657
1658     *ppChannel = (IRpcChannelBuffer *)&This->lpVtbl;
1659     return S_OK;
1660 }
1661
1662
1663 static inline HRESULT get_facbuf_for_iid(REFIID riid, IPSFactoryBuffer **facbuf)
1664 {
1665     HRESULT       hr;
1666     CLSID         clsid;
1667
1668     if ((hr = CoGetPSClsid(riid, &clsid)))
1669         return hr;
1670     return CoGetClassObject(&clsid, CLSCTX_INPROC_SERVER, NULL,
1671                              &IID_IPSFactoryBuffer, (LPVOID*)facbuf);
1672 }
1673
1674 static HRESULT init_proxy_entry_point(TMProxyImpl *proxy, unsigned int num)
1675 {
1676     int j;
1677     /* nrofargs without This */
1678     int nrofargs;
1679     ITypeInfo *tinfo2;
1680     TMAsmProxy  *xasm = proxy->asmstubs + num;
1681     HRESULT hres;
1682     const FUNCDESC *fdesc;
1683
1684     hres = get_funcdesc(proxy->tinfo, num, &tinfo2, &fdesc, NULL, NULL, NULL);
1685     if (hres) {
1686         ERR("GetFuncDesc %x should not fail here.\n",hres);
1687         return hres;
1688     }
1689     ITypeInfo_Release(tinfo2);
1690     /* some args take more than 4 byte on the stack */
1691     nrofargs = 0;
1692     for (j=0;j<fdesc->cParams;j++)
1693         nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
1694
1695 #ifdef __i386__
1696     if (fdesc->callconv != CC_STDCALL) {
1697         ERR("calling convention is not stdcall????\n");
1698         return E_FAIL;
1699     }
1700 /* popl %eax    -       return ptr
1701  * pushl <nr>
1702  * pushl %eax
1703  * call xCall
1704  * lret <nr> (+4)
1705  *
1706  *
1707  * arg3 arg2 arg1 <method> <returnptr>
1708  */
1709     xasm->popleax       = 0x58;
1710     xasm->pushlval      = 0x6a;
1711     xasm->nr            = num;
1712     xasm->pushleax      = 0x50;
1713     xasm->lcall         = 0xe8; /* relative jump */
1714     xasm->xcall         = (DWORD)xCall;
1715     xasm->xcall        -= (DWORD)&(xasm->lret);
1716     xasm->lret          = 0xc2;
1717     xasm->bytestopop    = (nrofargs+2)*4; /* pop args, This, iMethod */
1718     proxy->lpvtbl[num]  = xasm;
1719 #else
1720     FIXME("not implemented on non i386\n");
1721     return E_FAIL;
1722 #endif
1723     return S_OK;
1724 }
1725
1726 static HRESULT WINAPI
1727 PSFacBuf_CreateProxy(
1728     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
1729     IRpcProxyBuffer **ppProxy, LPVOID *ppv)
1730 {
1731     HRESULT     hres;
1732     ITypeInfo   *tinfo;
1733     unsigned int i, nroffuncs;
1734     TMProxyImpl *proxy;
1735     TYPEATTR    *typeattr;
1736     BOOL        defer_to_dispatch = FALSE;
1737
1738     TRACE("(...%s...)\n",debugstr_guid(riid));
1739     hres = _get_typeinfo_for_iid(riid,&tinfo);
1740     if (hres) {
1741         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
1742         return hres;
1743     }
1744
1745     hres = num_of_funcs(tinfo, &nroffuncs);
1746     if (FAILED(hres)) {
1747         ERR("Cannot get number of functions for typeinfo %s\n",debugstr_guid(riid));
1748         ITypeInfo_Release(tinfo);
1749         return hres;
1750     }
1751
1752     proxy = CoTaskMemAlloc(sizeof(TMProxyImpl));
1753     if (!proxy) return E_OUTOFMEMORY;
1754
1755     assert(sizeof(TMAsmProxy) == 12);
1756
1757     proxy->dispatch = NULL;
1758     proxy->dispatch_proxy = NULL;
1759     proxy->outerunknown = pUnkOuter;
1760     proxy->asmstubs = VirtualAlloc(NULL, sizeof(TMAsmProxy) * nroffuncs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
1761     if (!proxy->asmstubs) {
1762         ERR("Could not commit pages for proxy thunks\n");
1763         CoTaskMemFree(proxy);
1764         return E_OUTOFMEMORY;
1765     }
1766     proxy->lpvtbl2      = &tmproxyvtable;
1767     /* one reference for the proxy */
1768     proxy->ref          = 1;
1769     proxy->tinfo        = tinfo;
1770     memcpy(&proxy->iid,riid,sizeof(*riid));
1771     proxy->chanbuf      = 0;
1772
1773     InitializeCriticalSection(&proxy->crit);
1774     proxy->crit.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": TMProxyImpl.crit");
1775
1776     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
1777
1778     /* if we derive from IDispatch then defer to its proxy for its methods */
1779     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
1780     if (hres == S_OK)
1781     {
1782         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
1783         {
1784             IPSFactoryBuffer *factory_buffer;
1785             hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1786             if (hres == S_OK)
1787             {
1788                 hres = IPSFactoryBuffer_CreateProxy(factory_buffer, NULL,
1789                     &IID_IDispatch, &proxy->dispatch_proxy,
1790                     (void **)&proxy->dispatch);
1791                 IPSFactoryBuffer_Release(factory_buffer);
1792             }
1793             if ((hres == S_OK) && (nroffuncs < 7))
1794             {
1795                 ERR("nroffuncs calculated incorrectly (%d)\n", nroffuncs);
1796                 hres = E_UNEXPECTED;
1797             }
1798             if (hres == S_OK)
1799             {
1800                 defer_to_dispatch = TRUE;
1801             }
1802         }
1803         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
1804     }
1805
1806     for (i=0;i<nroffuncs;i++) {
1807         switch (i) {
1808         case 0:
1809                 proxy->lpvtbl[i] = ProxyIUnknown_QueryInterface;
1810                 break;
1811         case 1:
1812                 proxy->lpvtbl[i] = ProxyIUnknown_AddRef;
1813                 break;
1814         case 2:
1815                 proxy->lpvtbl[i] = ProxyIUnknown_Release;
1816                 break;
1817         case 3:
1818                 if(!defer_to_dispatch)
1819                 {
1820                     hres = init_proxy_entry_point(proxy, i);
1821                     if(FAILED(hres)) return hres;
1822                 }
1823                 else proxy->lpvtbl[3] = ProxyIDispatch_GetTypeInfoCount;
1824                 break;
1825         case 4:
1826                 if(!defer_to_dispatch)
1827                 {
1828                     hres = init_proxy_entry_point(proxy, i);
1829                     if(FAILED(hres)) return hres;
1830                 }
1831                 else proxy->lpvtbl[4] = ProxyIDispatch_GetTypeInfo;
1832                 break;
1833         case 5:
1834                 if(!defer_to_dispatch)
1835                 {
1836                     hres = init_proxy_entry_point(proxy, i);
1837                     if(FAILED(hres)) return hres;
1838                 }
1839                 else proxy->lpvtbl[5] = ProxyIDispatch_GetIDsOfNames;
1840                 break;
1841         case 6:
1842                 if(!defer_to_dispatch)
1843                 {
1844                     hres = init_proxy_entry_point(proxy, i);
1845                     if(FAILED(hres)) return hres;
1846                 }
1847                 else proxy->lpvtbl[6] = ProxyIDispatch_Invoke;
1848                 break;
1849         default:
1850                 hres = init_proxy_entry_point(proxy, i);
1851                 if(FAILED(hres)) return hres;
1852         }
1853     }
1854
1855     if (hres == S_OK)
1856     {
1857         *ppv            = (LPVOID)proxy;
1858         *ppProxy                = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
1859         IUnknown_AddRef((IUnknown *)*ppv);
1860         return S_OK;
1861     }
1862     else
1863         TMProxyImpl_Release((IRpcProxyBuffer *)&proxy->lpvtbl2);
1864     return hres;
1865 }
1866
1867 typedef struct _TMStubImpl {
1868     const IRpcStubBufferVtbl   *lpvtbl;
1869     LONG                        ref;
1870
1871     LPUNKNOWN                   pUnk;
1872     ITypeInfo                   *tinfo;
1873     IID                         iid;
1874     IRpcStubBuffer              *dispatch_stub;
1875     BOOL                        dispatch_derivative;
1876 } TMStubImpl;
1877
1878 static HRESULT WINAPI
1879 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv)
1880 {
1881     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
1882         *ppv = (LPVOID)iface;
1883         IRpcStubBuffer_AddRef(iface);
1884         return S_OK;
1885     }
1886     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
1887     return E_NOINTERFACE;
1888 }
1889
1890 static ULONG WINAPI
1891 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface)
1892 {
1893     TMStubImpl *This = (TMStubImpl *)iface;
1894     ULONG refCount = InterlockedIncrement(&This->ref);
1895         
1896     TRACE("(%p)->(ref before=%u)\n", This, refCount - 1);
1897
1898     return refCount;
1899 }
1900
1901 static ULONG WINAPI
1902 TMStubImpl_Release(LPRPCSTUBBUFFER iface)
1903 {
1904     TMStubImpl *This = (TMStubImpl *)iface;
1905     ULONG refCount = InterlockedDecrement(&This->ref);
1906
1907     TRACE("(%p)->(ref before=%u)\n", This, refCount + 1);
1908
1909     if (!refCount)
1910     {
1911         IRpcStubBuffer_Disconnect(iface);
1912         ITypeInfo_Release(This->tinfo);
1913         if (This->dispatch_stub)
1914             IRpcStubBuffer_Release(This->dispatch_stub);
1915         CoTaskMemFree(This);
1916     }
1917     return refCount;
1918 }
1919
1920 static HRESULT WINAPI
1921 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer)
1922 {
1923     TMStubImpl *This = (TMStubImpl *)iface;
1924
1925     TRACE("(%p)->(%p)\n", This, pUnkServer);
1926
1927     IUnknown_AddRef(pUnkServer);
1928     This->pUnk = pUnkServer;
1929
1930     if (This->dispatch_stub)
1931         IRpcStubBuffer_Connect(This->dispatch_stub, pUnkServer);
1932
1933     return S_OK;
1934 }
1935
1936 static void WINAPI
1937 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface)
1938 {
1939     TMStubImpl *This = (TMStubImpl *)iface;
1940
1941     TRACE("(%p)->()\n", This);
1942
1943     if (This->pUnk)
1944     {
1945         IUnknown_Release(This->pUnk);
1946         This->pUnk = NULL;
1947     }
1948
1949     if (This->dispatch_stub)
1950         IRpcStubBuffer_Disconnect(This->dispatch_stub);
1951 }
1952
1953 static HRESULT WINAPI
1954 TMStubImpl_Invoke(
1955     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf)
1956 {
1957     int         i;
1958     const FUNCDESC *fdesc;
1959     TMStubImpl *This = (TMStubImpl *)iface;
1960     HRESULT     hres;
1961     DWORD       *args = NULL, res, *xargs, nrofargs;
1962     marshal_state       buf;
1963     UINT        nrofnames = 0;
1964     BSTR        names[10];
1965     BSTR        iname = NULL;
1966     ITypeInfo   *tinfo = NULL;
1967
1968     TRACE("...\n");
1969
1970     if (xmsg->iMethod < 3) {
1971         ERR("IUnknown methods cannot be marshaled by the typelib marshaler\n");
1972         return E_UNEXPECTED;
1973     }
1974
1975     if (This->dispatch_derivative && xmsg->iMethod < sizeof(IDispatchVtbl)/sizeof(void *))
1976     {
1977         IPSFactoryBuffer *factory_buffer;
1978         hres = get_facbuf_for_iid(&IID_IDispatch, &factory_buffer);
1979         if (hres == S_OK)
1980         {
1981             hres = IPSFactoryBuffer_CreateStub(factory_buffer, &IID_IDispatch,
1982                 This->pUnk, &This->dispatch_stub);
1983             IPSFactoryBuffer_Release(factory_buffer);
1984         }
1985         if (hres != S_OK)
1986             return hres;
1987         return IRpcStubBuffer_Invoke(This->dispatch_stub, xmsg, rpcchanbuf);
1988     }
1989
1990     memset(&buf,0,sizeof(buf));
1991     buf.size    = xmsg->cbBuffer;
1992     buf.base    = HeapAlloc(GetProcessHeap(), 0, xmsg->cbBuffer);
1993     memcpy(buf.base, xmsg->Buffer, xmsg->cbBuffer);
1994     buf.curoff  = 0;
1995
1996     hres = get_funcdesc(This->tinfo,xmsg->iMethod,&tinfo,&fdesc,&iname,NULL,NULL);
1997     if (hres) {
1998         ERR("GetFuncDesc on method %d failed with %x\n",xmsg->iMethod,hres);
1999         return hres;
2000     }
2001
2002     if (iname && !lstrcmpW(iname, IDispatchW))
2003     {
2004         ERR("IDispatch cannot be marshaled by the typelib marshaler\n");
2005         hres = E_UNEXPECTED;
2006         SysFreeString (iname);
2007         goto exit;
2008     }
2009
2010     if (iname) SysFreeString (iname);
2011
2012     /* Need them for hack below */
2013     memset(names,0,sizeof(names));
2014     ITypeInfo_GetNames(tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
2015     if (nrofnames > sizeof(names)/sizeof(names[0])) {
2016         ERR("Need more names!\n");
2017     }
2018
2019     /*dump_FUNCDESC(fdesc);*/
2020     nrofargs = 0;
2021     for (i=0;i<fdesc->cParams;i++)
2022         nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
2023     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
2024     if (!args)
2025     {
2026         hres = E_OUTOFMEMORY;
2027         goto exit;
2028     }
2029
2030     /* Allocate all stuff used by call. */
2031     xargs = args+1;
2032     for (i=0;i<fdesc->cParams;i++) {
2033         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
2034
2035         hres = deserialize_param(
2036            tinfo,
2037            is_in_elem(elem),
2038            FALSE,
2039            TRUE,
2040            &(elem->tdesc),
2041            xargs,
2042            &buf
2043         );
2044         xargs += _argsize(elem->tdesc.vt);
2045         if (hres) {
2046             ERR("Failed to deserialize param %s, hres %x\n",relaystr(names[i+1]),hres);
2047             break;
2048         }
2049     }
2050
2051     args[0] = (DWORD)This->pUnk;
2052
2053     __TRY
2054     {
2055         res = _invoke(
2056             (*((FARPROC**)args[0]))[fdesc->oVft/4],
2057             fdesc->callconv,
2058             (xargs-args),
2059             args
2060         );
2061     }
2062     __EXCEPT(NULL)
2063     {
2064         DWORD dwExceptionCode = GetExceptionCode();
2065         ERR("invoke call failed with exception 0x%08x (%d)\n", dwExceptionCode, dwExceptionCode);
2066         if (FAILED(dwExceptionCode))
2067             hres = dwExceptionCode;
2068         else
2069             hres = HRESULT_FROM_WIN32(dwExceptionCode);
2070     }
2071     __ENDTRY
2072
2073     if (hres != S_OK)
2074         goto exit;
2075
2076     buf.curoff = 0;
2077
2078     xargs = args+1;
2079     for (i=0;i<fdesc->cParams;i++) {
2080         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
2081         hres = serialize_param(
2082            tinfo,
2083            is_out_elem(elem),
2084            FALSE,
2085            TRUE,
2086            &elem->tdesc,
2087            xargs,
2088            &buf
2089         );
2090         xargs += _argsize(elem->tdesc.vt);
2091         if (hres) {
2092             ERR("Failed to stuballoc param, hres %x\n",hres);
2093             break;
2094         }
2095     }
2096
2097     hres = xbuf_add (&buf, (LPBYTE)&res, sizeof(DWORD));
2098
2099     if (hres != S_OK)
2100         goto exit;
2101
2102     xmsg->cbBuffer      = buf.curoff;
2103     hres = IRpcChannelBuffer_GetBuffer(rpcchanbuf, xmsg, &This->iid);
2104     if (hres != S_OK)
2105         ERR("IRpcChannelBuffer_GetBuffer failed with error 0x%08x\n", hres);
2106
2107     if (hres == S_OK)
2108         memcpy(xmsg->Buffer, buf.base, buf.curoff);
2109
2110 exit:
2111     for (i = 0; i < nrofnames; i++)
2112         SysFreeString(names[i]);
2113
2114     ITypeInfo_Release(tinfo);
2115     HeapFree(GetProcessHeap(), 0, args);
2116
2117     HeapFree(GetProcessHeap(), 0, buf.base);
2118
2119     TRACE("returning\n");
2120     return hres;
2121 }
2122
2123 static LPRPCSTUBBUFFER WINAPI
2124 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
2125     FIXME("Huh (%s)?\n",debugstr_guid(riid));
2126     return NULL;
2127 }
2128
2129 static ULONG WINAPI
2130 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
2131     TMStubImpl *This = (TMStubImpl *)iface;
2132
2133     FIXME("()\n");
2134     return This->ref; /*FIXME? */
2135 }
2136
2137 static HRESULT WINAPI
2138 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
2139     return E_NOTIMPL;
2140 }
2141
2142 static void WINAPI
2143 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
2144     return;
2145 }
2146
2147 static const IRpcStubBufferVtbl tmstubvtbl = {
2148     TMStubImpl_QueryInterface,
2149     TMStubImpl_AddRef,
2150     TMStubImpl_Release,
2151     TMStubImpl_Connect,
2152     TMStubImpl_Disconnect,
2153     TMStubImpl_Invoke,
2154     TMStubImpl_IsIIDSupported,
2155     TMStubImpl_CountRefs,
2156     TMStubImpl_DebugServerQueryInterface,
2157     TMStubImpl_DebugServerRelease
2158 };
2159
2160 static HRESULT WINAPI
2161 PSFacBuf_CreateStub(
2162     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
2163     IRpcStubBuffer** ppStub
2164 ) {
2165     HRESULT hres;
2166     ITypeInfo   *tinfo;
2167     TMStubImpl  *stub;
2168     TYPEATTR *typeattr;
2169
2170     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
2171
2172     hres = _get_typeinfo_for_iid(riid,&tinfo);
2173     if (hres) {
2174         ERR("No typeinfo for %s?\n",debugstr_guid(riid));
2175         return hres;
2176     }
2177
2178     stub = CoTaskMemAlloc(sizeof(TMStubImpl));
2179     if (!stub)
2180         return E_OUTOFMEMORY;
2181     stub->lpvtbl        = &tmstubvtbl;
2182     stub->ref           = 1;
2183     stub->tinfo         = tinfo;
2184     stub->dispatch_stub = NULL;
2185     stub->dispatch_derivative = FALSE;
2186     memcpy(&(stub->iid),riid,sizeof(*riid));
2187     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
2188     *ppStub             = (LPRPCSTUBBUFFER)stub;
2189     TRACE("IRpcStubBuffer: %p\n", stub);
2190     if (hres)
2191         ERR("Connect to pUnkServer failed?\n");
2192
2193     /* if we derive from IDispatch then defer to its stub for some of its methods */
2194     hres = ITypeInfo_GetTypeAttr(tinfo, &typeattr);
2195     if (hres == S_OK)
2196     {
2197         if (typeattr->wTypeFlags & TYPEFLAG_FDISPATCHABLE)
2198             stub->dispatch_derivative = TRUE;
2199         ITypeInfo_ReleaseTypeAttr(tinfo, typeattr);
2200     }
2201
2202     return hres;
2203 }
2204
2205 static const IPSFactoryBufferVtbl psfacbufvtbl = {
2206     PSFacBuf_QueryInterface,
2207     PSFacBuf_AddRef,
2208     PSFacBuf_Release,
2209     PSFacBuf_CreateProxy,
2210     PSFacBuf_CreateStub
2211 };
2212
2213 /* This is the whole PSFactoryBuffer object, just the vtableptr */
2214 static const IPSFactoryBufferVtbl *lppsfac = &psfacbufvtbl;
2215
2216 /***********************************************************************
2217  *           TMARSHAL_DllGetClassObject
2218  */
2219 HRESULT TMARSHAL_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
2220 {
2221     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
2222         *ppv = &lppsfac;
2223         return S_OK;
2224     }
2225     return E_NOINTERFACE;
2226 }