Added a framework for testing CreateProcess and a few tests.
[wine] / dlls / oleaut32 / tmarshal.c
1 /*
2  *      TYPELIB Marshaler
3  *
4  *      Copyright 2002  Marcus Meissner
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <ctype.h>
28
29 #include "winerror.h"
30 #include "winnls.h"
31 #include "winreg.h"
32 #include "winuser.h"
33
34 #include "ole2.h"
35 #include "wine/unicode.h"
36 #include "wine/obj_base.h"
37 #include "wine/obj_channel.h"
38 #include "wine/obj_storage.h"
39 #include "heap.h"
40 #include "ole2disp.h"
41 #include "typelib.h"
42 #include "wine/debug.h"
43 #include "ntddk.h"
44
45 static const WCHAR riidW[5] = {'r','i','i','d',0};
46
47 WINE_DEFAULT_DEBUG_CHANNEL(ole);
48 WINE_DECLARE_DEBUG_CHANNEL(olerelay);
49
50 typedef struct _marshal_state {
51     LPBYTE      base;
52     int         size;
53     int         curoff;
54
55     BOOL        thisisiid;
56     IID         iid;    /* HACK: for VT_VOID */
57 } marshal_state;
58
59 static HRESULT
60 xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) {
61     while (buf->size - buf->curoff < size) {
62         if (buf->base) {
63             buf->size += 100;
64             buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size);
65             if (!buf->base)
66                 return E_OUTOFMEMORY;
67         } else {
68             buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32);
69             buf->size = 32;
70             if (!buf->base)
71                 return E_OUTOFMEMORY;
72         }
73     }
74     memcpy(buf->base+buf->curoff,stuff,size);
75     buf->curoff += size;
76     return S_OK;
77 }
78
79 static HRESULT
80 xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) {
81     if (buf->size < buf->curoff+size) return E_FAIL;
82     memcpy(stuff,buf->base+buf->curoff,size);
83     buf->curoff += size;
84     return S_OK;
85 }
86
87 static HRESULT
88 xbuf_skip(marshal_state *buf, DWORD size) {
89     if (buf->size < buf->curoff+size) return E_FAIL;
90     buf->curoff += size;
91     return S_OK;
92 }
93
94 static HRESULT
95 _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) {
96     IStream             *pStm;
97     ULARGE_INTEGER      newpos;
98     LARGE_INTEGER       seekto;
99     ULONG               res;
100     HRESULT             hres;
101     DWORD               xsize;
102
103     TRACE("...%s...\n",debugstr_guid(riid));
104     *pUnk = NULL;
105     hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize));
106     if (hres) return hres;
107     if (xsize == 0) return S_OK;
108     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
109     if (hres) {
110         FIXME("Stream create failed %lx\n",hres);
111         return hres;
112     }
113     hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
114     if (hres) { FIXME("stream write %lx\n",hres); return hres; }
115     memset(&seekto,0,sizeof(seekto));
116     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
117     if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;}
118     hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
119     if (hres) {
120         FIXME("Marshaling interface %s failed with %lx\n",debugstr_guid(riid),hres);
121         return hres;
122     }
123     IStream_Release(pStm);
124     return xbuf_skip(buf,xsize);
125 }
126
127 static HRESULT
128 _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) {
129     LPUNKNOWN           newiface;
130     LPBYTE              tempbuf;
131     IStream             *pStm;
132     STATSTG             ststg;
133     ULARGE_INTEGER      newpos;
134     LARGE_INTEGER       seekto;
135     ULONG               res;
136     DWORD               xsize;
137     HRESULT             hres;
138
139     hres = S_OK;
140     if (!pUnk)
141         goto fail;
142
143     TRACE("...%s...\n",debugstr_guid(riid));
144     hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface);
145     if (hres) {
146         TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid));
147         goto fail;
148     }
149     hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
150     if (hres) {
151         FIXME("Stream create failed %lx\n",hres);
152         goto fail;
153     }
154     hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0);
155     IUnknown_Release(newiface);
156     if (hres) {
157         FIXME("Marshaling interface %s failed with %lx\n",
158                 debugstr_guid(riid),hres
159         );
160         goto fail;
161     }
162     hres = IStream_Stat(pStm,&ststg,0);
163     tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.s.LowPart);
164     memset(&seekto,0,sizeof(seekto));
165     hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
166     if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;}
167     hres = IStream_Read(pStm,tempbuf,ststg.cbSize.s.LowPart,&res);
168     if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;}
169     IStream_Release(pStm);
170     xsize = ststg.cbSize.s.LowPart;
171     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
172     hres = xbuf_add(buf,tempbuf,ststg.cbSize.s.LowPart);
173     HeapFree(GetProcessHeap(),0,tempbuf);
174     return hres;
175 fail:
176     xsize = 0;
177     xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
178     return hres;
179 }
180
181 /********************* OLE Proxy/Stub Factory ********************************/
182 static HRESULT WINAPI
183 PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) {
184     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) {
185         *ppv = (LPVOID)iface; 
186         /* No ref counting, static class */
187         return S_OK;
188     }
189     FIXME("(%s) unknown IID?\n",debugstr_guid(iid));
190     return E_NOINTERFACE;
191 }
192
193 static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; }
194 static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; }
195
196 static HRESULT
197 _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) {
198     HRESULT     hres;
199     HKEY        ikey;
200     char        tlguid[200],typelibkey[300],interfacekey[300],ver[100];
201     char        tlfn[260];
202     OLECHAR     tlfnW[260];
203     DWORD       tlguidlen, verlen, type, tlfnlen;
204     ITypeLib    *tl;
205
206     sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib",
207         riid->Data1, riid->Data2, riid->Data3,
208         riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3],
209         riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7]
210     );
211
212     if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) {
213         FIXME("No %s key found.\n",interfacekey);
214         return E_FAIL;
215     }
216     type = (1<<REG_SZ);
217     tlguidlen = sizeof(tlguid);
218     if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) {
219         FIXME("Getting typelib guid failed.\n");
220         RegCloseKey(ikey);
221         return E_FAIL;
222     }
223     type = (1<<REG_SZ);
224     verlen = sizeof(ver);
225     if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) {
226         FIXME("Could not get version value?\n");
227         RegCloseKey(ikey);
228         return E_FAIL;
229     }
230     RegCloseKey(ikey);
231     sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver);
232     tlfnlen = sizeof(tlfn);
233     if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) {
234         FIXME("Could not get typelib fn?\n");
235         return E_FAIL;
236     }
237     MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1);
238     hres = LoadTypeLib(tlfnW,&tl);
239     if (hres) {
240         ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid));
241         return hres;
242     }
243     hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti);
244     if (hres) {
245         ERR("typelib does not contain info for %s?\n",debugstr_guid(riid));
246         ITypeLib_Release(tl);
247         return hres;
248     }
249     /* FIXME: do this?  ITypeLib_Release(tl); */
250     return hres;
251 }
252
253 /* Determine nr of functions. Since we use the toplevel interface and all
254  * inherited ones have lower numbers, we are ok to not to descent into 
255  * the inheritance tree I think.
256  */
257 static int _nroffuncs(ITypeInfo *tinfo) {
258     int         n, max = 0;
259     FUNCDESC    *fdesc;
260     HRESULT     hres;
261
262     n=0;
263     while (1) {
264         hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc);
265         if (fdesc->oVft/4 > max)
266             max = fdesc->oVft/4;
267         if (hres)
268             return max+1;
269         n++;
270     }
271     /*NOTREACHED*/
272 }
273
274 typedef struct _TMAsmProxy {
275     BYTE        popleax;
276     BYTE        pushlval;
277     BYTE        nr;
278     BYTE        pushleax;
279     BYTE        lcall;
280     DWORD       xcall;
281     BYTE        lret;
282     WORD        bytestopop;
283 } WINE_PACKED TMAsmProxy;
284
285 typedef struct _TMProxyImpl {
286     DWORD                               *lpvtbl;
287     ICOM_VTABLE(IRpcProxyBuffer)        *lpvtbl2;
288     DWORD                               ref;
289
290     TMAsmProxy                          *asmstubs;
291     ITypeInfo*                          tinfo;
292     IRpcChannelBuffer*                  chanbuf;
293     IID                                 iid;
294 } TMProxyImpl;
295
296 static HRESULT WINAPI
297 TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) {
298     TRACE("()\n");
299     if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) {
300         *ppv = (LPVOID)iface;
301         IRpcProxyBuffer_AddRef(iface);
302         return S_OK;
303     }
304     FIXME("no interface for %s\n",debugstr_guid(riid));
305     return E_NOINTERFACE;
306 }
307
308 static ULONG WINAPI
309 TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) {
310     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
311
312     TRACE("()\n");
313     This->ref++;
314     return This->ref;
315 }
316
317 static ULONG WINAPI
318 TMProxyImpl_Release(LPRPCPROXYBUFFER iface) {
319     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
320
321     TRACE("()\n");
322     This->ref--;
323     if (This->ref) return This->ref;
324     if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
325     HeapFree(GetProcessHeap(),0,This);
326     return 0;
327 }
328
329 static HRESULT WINAPI
330 TMProxyImpl_Connect(
331     LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer
332 ) {
333     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
334
335     TRACE("(%p)\n",pRpcChannelBuffer);
336     This->chanbuf = pRpcChannelBuffer;
337     IRpcChannelBuffer_AddRef(This->chanbuf);
338     return S_OK;
339 }
340
341 static void WINAPI
342 TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) {
343     ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
344
345     FIXME("()\n");
346     IRpcChannelBuffer_Release(This->chanbuf);
347     This->chanbuf = NULL;
348 }
349
350
351 static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = {
352     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
353     TMProxyImpl_QueryInterface,
354     TMProxyImpl_AddRef,
355     TMProxyImpl_Release,
356     TMProxyImpl_Connect,
357     TMProxyImpl_Disconnect
358 };
359
360 static HRESULT
361 marshall_param(
362     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
363 ) {
364     int relaydeb = TRACE_ON(olerelay);
365     HRESULT     hres;
366
367     if (!tdesc) tdesc = &(elem->tdesc);
368     switch (tdesc->vt) {
369     case VT_NULL:
370         return S_OK;
371     case VT_BSTR: {     /* DWORD size, string data */
372             DWORD *bstr = ((DWORD*)(*arg))-1;
373
374             if (relaydeb) MESSAGE("%s",debugstr_w((LPWSTR)(bstr+1)));
375             return xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
376         }
377     case VT_BOOL:
378     case VT_I4:
379         if (relaydeb) MESSAGE("%ld",*arg);
380         return xbuf_add(buf,(LPBYTE)arg,4);
381     case VT_VARIANT: {
382         /* We use ourselves to marshal the value further */
383         TYPEDESC tdesc2;
384         VARIANT *vt = (VARIANT*)arg;
385         DWORD vttype = V_VT(vt);
386
387         hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
388         if (hres) return hres;
389         tdesc2.vt = vttype;
390         if (relaydeb) MESSAGE("Vt %ld ",vttype);
391         /* shield your eyes, bad pointer voodoo below */
392         return marshall_param(tinfo,elem,&tdesc2,(DWORD*)&(V_I4(vt)),buf);
393     }
394     case VT_PTR:
395         return marshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf);
396     case VT_VOID:
397         hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)arg);
398         if (hres) {
399             FIXME("Failed unmarshaling VT_VOID with guid %s?\n",debugstr_guid(&(buf->iid)));
400         }
401         return hres;
402     case VT_USERDEFINED: {
403         ITypeInfo       *tinfo2;
404         TYPEATTR        *tattr;
405
406         /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/
407         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
408         if (hres) {
409             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
410             return hres;
411         }
412         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
413         switch (tattr->typekind) {
414         case TKIND_INTERFACE:
415             if (relaydeb) MESSAGE("if(%p), vtbl %p",arg,(LPVOID)*arg);
416             hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
417             break;
418         case TKIND_RECORD:
419             if (relaydeb) MESSAGE("record %p",arg);
420             if (buf->thisisiid)
421                 memcpy(&(buf->iid),arg,sizeof(buf->iid));
422             hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance);
423             break;
424         default:
425             FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
426             hres = E_FAIL;
427             break;
428         }
429         ITypeInfo_Release(tinfo2);
430         return hres;
431     }
432     default:
433         ERR("Cannot marshal type %d\n",tdesc->vt);
434         /*dump_ELEMDESC(elem);*/
435         return E_FAIL;
436     }
437     return S_OK;
438 }
439
440 static HRESULT
441 unmarshall_param(
442     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
443 ) {
444     HRESULT hres = S_OK;
445     int relaydeb = TRACE_ON(olerelay);
446
447     if (!tdesc) tdesc = &(elem->tdesc);
448     switch (tdesc->vt) {
449     case VT_I4: {
450         DWORD x;
451         xbuf_get(buf,(LPBYTE)&x,sizeof(x));
452         *arg = x;
453         if (relaydeb) MESSAGE("%ld ",x);
454         return S_OK;
455     }
456     case VT_PTR:
457         if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
458             (tdesc->u.lptdesc->vt != VT_VOID)
459         )
460             hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)(*arg),buf);
461         else
462             hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,arg,buf);
463         if (relaydeb) MESSAGE("%p ",(LPVOID)*arg);
464         return S_OK;
465     case VT_USERDEFINED: {
466         ITypeInfo       *tinfo2;
467         TYPEATTR        *tattr;
468
469         if (relaydeb) MESSAGE("%p",arg);
470         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
471         if (hres) {
472             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
473             return hres;
474         }
475         hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
476         if (hres) {
477             FIXME("Could not get typeattr in VT_USERDEFINED.\n");
478             return hres;
479         }
480         switch (tattr->typekind) {
481         case TKIND_INTERFACE:
482             hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
483             break;
484         case TKIND_RECORD:
485             hres = xbuf_get(buf,(LPBYTE)arg,tattr->cbSizeInstance);
486             break;
487         default:
488             hres = E_FAIL;
489             FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
490         }
491         ITypeInfo_Release(tinfo2);
492         return hres;
493     }
494     case VT_VOID: 
495         /* Hacky. If we are LPVOID* we apparently have to guess the IID
496          * for the interface. This sucks pretty badly. */
497         return _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg);
498     default:    ERR("Cannot unmarshal type %d\n",tdesc->vt);
499                 return E_FAIL;
500     }
501     return S_OK;
502 }
503
504 /* Searches function, also in inherited interfaces */
505 static HRESULT
506 _get_funcdesc(
507         ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc,
508         BSTR *iname, BSTR *fname
509 ) {
510     int i = 0, j = 0;
511     HRESULT hres;
512
513     if (fname) *fname = NULL;
514     if (iname) *iname = NULL;
515
516     while (1) {
517         hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
518         if (hres) {
519             ITypeInfo   *tinfo2;
520             HREFTYPE    href;
521             TYPEATTR    *attr;
522
523             hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
524             if (hres) {
525                 FIXME("GetTypeAttr failed with %lx\n",hres);
526                 return hres;
527             }
528             /* Not found, so look in inherited ifaces. */
529             for (j=0;j<attr->cImplTypes;j++) {
530                 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
531                 if (hres) {
532                     FIXME("Did not find a reftype for interface offset %d?\n",j);
533                     break;
534                 }
535                 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
536                 if (hres) {
537                     FIXME("Did not find a typeinfo for reftype %ld?\n",href);
538                     continue;
539                 }
540                 hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
541                 ITypeInfo_Release(tinfo2);
542                 if (!hres) return S_OK;
543             }
544             return E_FAIL;
545         }
546         if (((*fdesc)->oVft/4) == iMethod) {
547             if (fname)
548                 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
549             if (iname)
550                 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
551             return S_OK;
552         }
553         i++;
554     }
555     return E_FAIL;
556 }
557
558 /* how much space do we use on stack in DWORD steps. */
559 static int 
560 _argsize(DWORD vt_type) {
561     switch (vt_type) {
562     case VT_VARIANT:
563         return (sizeof(VARIANT)+3)/sizeof(DWORD);
564     default:
565         return 1;
566     }
567 }
568
569 static DWORD
570 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
571     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
572     FUNCDESC            *fdesc;
573     HRESULT             hres;
574     int                 i, relaydeb = TRACE_ON(olerelay);
575     marshal_state       buf;
576     RPCOLEMESSAGE       msg;
577     ULONG               status;
578     BSTR                fname,iname;
579     BSTR                names[10];
580     int                 nrofnames;
581
582     hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
583     if (hres) {
584         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
585         return 0;
586     }
587
588     /*dump_FUNCDESC(fdesc);*/
589     if (relaydeb) {
590         TRACE_(olerelay)("->");
591         if (iname)
592             MESSAGE("%s:",debugstr_w(iname));
593         if (fname)
594             MESSAGE("%s(%d)",debugstr_w(fname),method);
595         else
596             MESSAGE("%d",method);
597         MESSAGE("(");
598         if (iname) SysFreeString(iname);
599         if (fname) SysFreeString(fname);
600     }
601     /* Need them for hack below */
602     memset(names,0,sizeof(names));
603     ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
604     if (nrofnames > sizeof(names)/sizeof(names[0])) {
605         ERR("Need more names!\n");
606     }
607     memset(&buf,0,sizeof(buf));
608     buf.iid = IID_IUnknown;
609     if (method == 0) {
610         xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
611         if (relaydeb) MESSAGE("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
612     } else {
613         xargs = args;
614         for (i=0;i<fdesc->cParams;i++) {
615             ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
616             if (relaydeb) {
617                 if (i) MESSAGE(",");
618                 if (i+1<nrofnames && names[i+1])
619                     MESSAGE("%s=",debugstr_w(names[i+1]));
620             }
621             if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW)) {
622                 buf.thisisiid = TRUE;
623             } else {
624                 buf.thisisiid = FALSE;
625             }
626             /* No need to marshal other data than FIN */
627             if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
628                 xargs+=_argsize(elem->tdesc.vt);
629                 if (relaydeb) MESSAGE("[out]");
630                 continue;
631             }
632             hres = marshall_param(tpinfo->tinfo,elem,NULL,xargs,&buf);
633             xargs+=_argsize(elem->tdesc.vt);
634             if (hres) {
635                 FIXME("Failed to marshall param, hres %lx\n",hres);
636                 break;
637             }
638         }
639     }
640     if (relaydeb) MESSAGE(")");
641     memset(&msg,0,sizeof(msg));
642     msg.cbBuffer = buf.curoff;
643     msg.iMethod  = method;
644     hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
645     if (hres) {
646         FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
647         return hres;
648     }
649     memcpy(msg.Buffer,buf.base,buf.curoff);
650     hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
651     if (hres) {
652         FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres);
653         return hres;
654     }
655     if (relaydeb) MESSAGE(" = %08lx (",status);
656     if (buf.base)
657         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
658     else
659         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
660     buf.size = msg.cbBuffer;
661     memcpy(buf.base,msg.Buffer,buf.size);
662     buf.curoff = 0;
663     if (method == 0) {
664         _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
665         if (relaydeb) MESSAGE("[in],%p",*((DWORD**)args[1]));
666     } else {
667         xargs = args;
668         for (i=0;i<fdesc->cParams;i++) {
669             ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
670
671             if (relaydeb) {
672                 if (i) MESSAGE(",");
673                 if (i+1<nrofnames && names[i+1]) MESSAGE("%s=",debugstr_w(names[i+1]));
674             }
675             /* No need to marshal other data than FOUT I think */
676             if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
677                 xargs += _argsize(elem->tdesc.vt);
678                 if (relaydeb) MESSAGE("[in]");
679                 continue;
680             }
681             hres = unmarshall_param(tpinfo->tinfo,elem,&(elem->tdesc),xargs,&buf);
682             xargs += _argsize(elem->tdesc.vt);
683             if (hres) {
684                 FIXME("Failed to unmarshall param, hres %lx\n",hres);
685                 break;
686             }
687         }
688     }
689     if (relaydeb) MESSAGE(")\n");
690     HeapFree(GetProcessHeap(),0,buf.base);
691     return status;
692 }
693
694 static HRESULT WINAPI
695 PSFacBuf_CreateProxy(
696     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
697     IRpcProxyBuffer **ppProxy, LPVOID *ppv
698 ) {
699     HRESULT     hres;
700     ITypeInfo   *tinfo;
701     int         i, nroffuncs;
702     FUNCDESC    *fdesc;
703     TMProxyImpl *proxy;
704     
705     TRACE("(...%s...)\n",debugstr_guid(riid));
706     hres = _get_typeinfo_for_iid(riid,&tinfo);
707     if (hres) {
708         FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
709         return hres;
710     }
711     nroffuncs = _nroffuncs(tinfo);
712     proxy = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMProxyImpl));
713     if (!proxy) return E_OUTOFMEMORY;
714     proxy->asmstubs=HeapAlloc(GetProcessHeap(),0,sizeof(TMAsmProxy)*nroffuncs);
715
716     assert(sizeof(TMAsmProxy) == 12);
717
718     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
719     for (i=0;i<nroffuncs;i++) {
720         int             nrofargs;
721         TMAsmProxy      *xasm = proxy->asmstubs+i;
722
723         /* nrofargs without This */
724         switch (i) {
725         case 0: nrofargs = 2;
726                 break;
727         case 1: case 2: nrofargs = 0;
728                 break;
729         default: {
730                 int j;
731                 hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
732                 if (hres) {
733                     FIXME("GetFuncDesc %lx should not fail here.\n",hres);
734                     return hres;
735                 }
736                 /* some args take more than 4 byte on the stack */
737                 nrofargs = 0;
738                 for (j=0;j<fdesc->cParams;j++)
739                     nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
740
741                 if (fdesc->callconv != CC_STDCALL) {
742                     ERR("calling convention is not stdcall????\n");
743                     return E_FAIL;
744                 }
745                 break;
746             }
747         }
748 /* popl %eax    -       return ptr
749  * pushl <nr>
750  * pushl %eax
751  * call xCall
752  * lret <nr> (+4)
753  *
754  *
755  * arg3 arg2 arg1 <method> <returnptr>
756  */
757         xasm->popleax   = 0x58;
758         xasm->pushlval  = 0x6a;
759         xasm->nr        = i;
760         xasm->pushleax  = 0x50;
761         xasm->lcall     = 0xe8; /* relative jump */
762         xasm->xcall     = (DWORD)xCall;
763         xasm->xcall     -= (DWORD)&(xasm->lret);
764         xasm->lret      = 0xc2;
765         xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
766         proxy->lpvtbl[i] = (DWORD)xasm;
767     }
768     proxy->lpvtbl2      = &tmproxyvtable;
769     proxy->ref          = 2;
770     proxy->tinfo        = tinfo;
771     memcpy(&proxy->iid,riid,sizeof(*riid));
772     *ppv                = (LPVOID)proxy;
773     *ppProxy            = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
774     return S_OK;
775 }
776
777 typedef struct _TMStubImpl {
778     ICOM_VTABLE(IRpcStubBuffer) *lpvtbl;
779     DWORD                       ref;
780
781     LPUNKNOWN                   pUnk;
782     ITypeInfo                   *tinfo;
783     IID                         iid;
784 } TMStubImpl;
785
786 static HRESULT WINAPI
787 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
788     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
789         *ppv = (LPVOID)iface;
790         IRpcStubBuffer_AddRef(iface);
791         return S_OK;
792     }
793     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
794     return E_NOINTERFACE;
795 }
796
797 static ULONG WINAPI
798 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) {
799     ICOM_THIS(TMStubImpl,iface);
800
801     This->ref++;
802     return This->ref;
803 }
804
805 static ULONG WINAPI
806 TMStubImpl_Release(LPRPCSTUBBUFFER iface) {
807     ICOM_THIS(TMStubImpl,iface);
808
809     This->ref--;
810     if (This->ref)
811         return This->ref;
812     HeapFree(GetProcessHeap(),0,This);
813     return 0;
814 }
815
816 static HRESULT WINAPI
817 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) {
818     ICOM_THIS(TMStubImpl,iface);
819
820     IUnknown_AddRef(pUnkServer);
821     This->pUnk = pUnkServer;
822     return S_OK;
823 }
824
825 static void WINAPI
826 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) {
827     ICOM_THIS(TMStubImpl,iface);
828
829     IUnknown_Release(This->pUnk);
830     This->pUnk = NULL;
831     return;
832 }
833
834 static HRESULT
835 stuballoc_param(
836     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
837 ) {
838     HRESULT hres;
839
840     while (1) {
841         switch (tdesc->vt) {
842         case VT_VARIANT: {
843             DWORD       vttype;
844             VARIANT     *vt = (VARIANT*)arg;
845             TYPEDESC    tdesc2;
846
847             hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
848             if (hres) return hres;
849             memset(&tdesc2,0,sizeof(tdesc));
850             tdesc2.vt = vttype;
851             V_VT(vt)  = vttype;
852             return stuballoc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf);
853         }
854         case VT_BOOL: case VT_I4:
855             xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
856             return S_OK;
857         case VT_BSTR: {
858                 WCHAR   *str;
859                 DWORD   len;
860
861                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
862                 if (hres)
863                     return hres;
864                 str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
865                 hres = xbuf_get(buf,(LPBYTE)str,len);
866                 if (hres) return hres;
867                 *arg = (DWORD)SysAllocStringLen(str,len);
868                 HeapFree(GetProcessHeap(),0,str);
869                 return S_OK;
870             }
871         case VT_PTR:
872             if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
873                 (tdesc->u.lptdesc->vt != VT_VOID)
874             ) {
875                 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
876                 arg = (DWORD*)*arg;
877             }
878             tdesc = tdesc->u.lptdesc;
879             break;
880         case VT_UNKNOWN:
881             /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
882             *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
883             return S_OK;
884         case VT_VOID:
885             *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID));
886             hres = S_OK;
887             if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)
888                 hres = _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg);
889             return hres;
890         case VT_USERDEFINED: {
891             if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) {
892                 ITypeInfo       *tinfo2;
893                 TYPEATTR        *tattr;
894
895                 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
896                 if (hres) {
897                     FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
898                     return hres;
899                 }
900                 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
901                 if (hres) {
902                     FIXME("Could not get typeattr in VT_USERDEFINED.\n");
903                     return hres;
904                 }
905                 switch (tattr->typekind) {
906                 case TKIND_INTERFACE:
907                     hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
908                     break;
909                 case TKIND_RECORD:
910                     *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
911                     hres = xbuf_get(buf,(LPBYTE)*arg,tattr->cbSizeInstance);
912                     if (buf->thisisiid)
913                         memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
914                     break;
915                 default:
916                     FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
917                     hres = E_FAIL;
918                     break;
919                 }
920                 ITypeInfo_Release(tinfo2);
921                 return hres;
922             } else {
923                 *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID));
924                 return S_OK;
925             }
926         }
927         default:
928             ERR("No handler for VT type %d, just allocating 4 bytes.\n",tdesc->vt);
929             *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
930             return S_OK;
931         }
932     }
933 }
934
935 static HRESULT
936 stubunalloc_param(
937     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
938 ) {
939     HRESULT hres = S_OK;
940
941     if (!tdesc) tdesc = &(elem->tdesc);
942
943     switch (tdesc->vt) {
944     case VT_BOOL:
945     case VT_I4: 
946         hres = S_OK;
947         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)
948             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
949         return hres;
950     case VT_VARIANT: {
951         TYPEDESC        tdesc2;
952         VARIANT         *vt = (VARIANT*)arg;
953         DWORD           vttype = V_VT(vt);
954
955         tdesc2.vt = vttype;
956         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
957             hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
958             if (hres) return hres;
959         }
960         /* need to recurse since we need to free the stuff */
961         hres = stubunalloc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf);
962         return hres;
963     }
964     case VT_BSTR: {
965         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
966             DWORD *bstr = ((DWORD*)(*arg))-1;
967
968             hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
969             if (hres)
970                 return hres;
971         }
972         SysFreeString((BSTR)*arg);
973         return S_OK;
974     }
975     case VT_PTR:
976         /*FIXME("VT_PTR *arg is %p\n",(LPVOID)*arg);*/
977         if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
978             (tdesc->u.lptdesc->vt != VT_VOID)
979         ) {
980             hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,arg,buf);
981         } else {
982             hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf);
983             HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
984         }
985         return hres;
986     case VT_UNKNOWN:
987         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
988             FIXME("Marshaling back VT_UNKNOWN %lx\n",*arg);
989             hres = xbuf_add(buf,(LPBYTE)*arg,sizeof(DWORD));
990         }
991         HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
992         return hres;
993     case VT_VOID:
994         hres = S_OK;
995         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)
996             hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)*arg);
997         return hres;
998     case VT_USERDEFINED: {
999         ITypeInfo       *tinfo2;
1000         TYPEATTR        *tattr;
1001
1002         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
1003             /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/
1004             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1005             if (hres) {
1006                 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
1007                 return hres;
1008             }
1009             ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1010             switch (tattr->typekind) {
1011             case TKIND_INTERFACE:
1012                 hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)*arg);
1013                 break;
1014             case TKIND_RECORD:
1015                 hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance);
1016                 break;
1017             default:
1018                 FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
1019                 hres = E_FAIL;
1020                 break;
1021             }
1022             ITypeInfo_Release(tinfo2);
1023         }
1024         return hres;
1025     }
1026     default:
1027         ERR("Unhandled marshal type %d.\n",tdesc->vt);
1028         HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
1029         return S_OK;
1030     }
1031 }
1032
1033 static HRESULT WINAPI
1034 TMStubImpl_Invoke(
1035     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf
1036 ) {
1037     int         i;
1038     FUNCDESC    *fdesc;
1039     ICOM_THIS(TMStubImpl,iface);
1040     HRESULT     hres;
1041     DWORD       *args, res, *xargs, nrofargs;
1042     marshal_state       buf;
1043     int         nrofnames;
1044     BSTR        names[10];
1045
1046     memset(&buf,0,sizeof(buf));
1047     buf.size    = xmsg->cbBuffer;
1048     buf.base    = xmsg->Buffer;
1049     buf.curoff  = 0;
1050     buf.iid     = IID_IUnknown;
1051
1052     TRACE("...\n");
1053     if (xmsg->iMethod == 0) { /* QI */
1054         IID             xiid;
1055         /* in: IID, out: <iface> */
1056
1057         xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
1058         buf.curoff = 0;
1059         hres = _marshal_interface(&buf,&xiid,This->pUnk);
1060         xmsg->Buffer    = buf.base; /* Might have been reallocated */
1061         xmsg->cbBuffer  = buf.size;
1062         return hres;
1063     }
1064     hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
1065     if (hres) {
1066         FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1067         return hres;
1068     }
1069     /* Need them for hack below */
1070     memset(names,0,sizeof(names));
1071     ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1072     if (nrofnames > sizeof(names)/sizeof(names[0])) {
1073         ERR("Need more names!\n");
1074     }
1075
1076     /*dump_FUNCDESC(fdesc);*/
1077     nrofargs = 0;
1078     for (i=0;i<fdesc->cParams;i++)
1079         nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1080     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1081     if (!args) return E_OUTOFMEMORY;
1082
1083     /* Allocate all stuff used by call. */
1084     xargs = args+1;
1085     for (i=0;i<fdesc->cParams;i++) {
1086         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1087
1088         if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW))
1089             buf.thisisiid = TRUE;
1090         else
1091             buf.thisisiid = FALSE;
1092         hres   = stuballoc_param(This->tinfo,elem,&(elem->tdesc),xargs,&buf);
1093         xargs += _argsize(elem->tdesc.vt);
1094         if (hres) {
1095             FIXME("Failed to stuballoc param %s, hres %lx\n",debugstr_w(names[i+1]),hres);
1096             break;
1097         }
1098     }
1099     hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1100     if (hres) {
1101         ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
1102         return hres;
1103     }
1104     res = _invoke(
1105             (*((LPVOID**)args[0]))[fdesc->oVft/4],
1106             fdesc->callconv,
1107             (xargs-args),
1108             args
1109     );
1110     IUnknown_Release((LPUNKNOWN)args[0]);
1111     buf.curoff = 0;
1112     xargs = args+1;
1113     for (i=0;i<fdesc->cParams;i++) {
1114         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1115         hres = stubunalloc_param(This->tinfo,elem,NULL,xargs,&buf);
1116         xargs += _argsize(elem->tdesc.vt);
1117         if (hres) {
1118             FIXME("Failed to stuballoc param, hres %lx\n",hres);
1119             break;
1120         }
1121     }
1122     /* might need to use IRpcChannelBuffer_GetBuffer ? */
1123     xmsg->cbBuffer      = buf.curoff;
1124     xmsg->Buffer        = buf.base;
1125     HeapFree(GetProcessHeap(),0,args);
1126     return res;
1127 }
1128
1129 static LPRPCSTUBBUFFER WINAPI
1130 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1131     FIXME("Huh (%s)?\n",debugstr_guid(riid));
1132     return NULL;
1133 }
1134
1135 static ULONG WINAPI
1136 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1137     ICOM_THIS(TMStubImpl,iface);
1138
1139     return This->ref; /*FIXME? */
1140 }
1141
1142 static HRESULT WINAPI
1143 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1144     return E_NOTIMPL;
1145 }
1146
1147 static void WINAPI
1148 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1149     return;
1150 }
1151
1152 ICOM_VTABLE(IRpcStubBuffer) tmstubvtbl = {
1153     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1154     TMStubImpl_QueryInterface,
1155     TMStubImpl_AddRef,
1156     TMStubImpl_Release,
1157     TMStubImpl_Connect,
1158     TMStubImpl_Disconnect,
1159     TMStubImpl_Invoke,
1160     TMStubImpl_IsIIDSupported,
1161     TMStubImpl_CountRefs,
1162     TMStubImpl_DebugServerQueryInterface,
1163     TMStubImpl_DebugServerRelease
1164 };
1165
1166 static HRESULT WINAPI
1167 PSFacBuf_CreateStub(
1168     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1169     IRpcStubBuffer** ppStub
1170 ) {
1171     HRESULT hres;
1172     ITypeInfo   *tinfo;
1173     TMStubImpl  *stub;
1174
1175     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1176     hres = _get_typeinfo_for_iid(riid,&tinfo);
1177     if (hres) {
1178         FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
1179         return hres;
1180     }
1181     stub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMStubImpl));
1182     if (!stub)
1183         return E_OUTOFMEMORY;
1184     stub->lpvtbl        = &tmstubvtbl;
1185     stub->ref           = 1;
1186     stub->tinfo         = tinfo;
1187     memcpy(&(stub->iid),riid,sizeof(*riid));
1188     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1189     *ppStub             = (LPRPCSTUBBUFFER)stub;
1190     if (hres)
1191         FIXME("Connect to pUnkServer failed?\n");
1192     return hres;
1193 }
1194
1195 static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
1196     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1197     PSFacBuf_QueryInterface,
1198     PSFacBuf_AddRef,
1199     PSFacBuf_Release,
1200     PSFacBuf_CreateProxy,
1201     PSFacBuf_CreateStub
1202 };
1203
1204 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1205 static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
1206
1207 /***********************************************************************
1208  *           DllGetClassObject [OLE32.63]
1209  */
1210 HRESULT WINAPI
1211 TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1212 {
1213     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1214         *ppv = &lppsfac;
1215         return S_OK;
1216     }
1217     return E_NOINTERFACE;
1218 }