Better implementation of GetCalendarInfo{A,W}, not perfect.
[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
373             if (*arg) {
374                 DWORD *bstr = ((DWORD*)(*arg))-1;
375
376                 if (relaydeb) MESSAGE("%s",debugstr_w((LPWSTR)(bstr+1)));
377                 return xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
378             } else {
379                 DWORD xnull = 0;
380
381                 return xbuf_add(buf,(LPBYTE)&xnull,sizeof(xnull));
382             }
383         }
384     case VT_BOOL:
385     case VT_I4:
386         if (relaydeb) MESSAGE("%ld",*arg);
387         return xbuf_add(buf,(LPBYTE)arg,4);
388     case VT_VARIANT: {
389         /* We use ourselves to marshal the value further */
390         TYPEDESC tdesc2;
391         VARIANT *vt = (VARIANT*)arg;
392         DWORD vttype = V_VT(vt);
393
394         hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
395         if (hres) return hres;
396         tdesc2.vt = vttype;
397         if (relaydeb) MESSAGE("Vt %ld ",vttype);
398         /* shield your eyes, bad pointer voodoo below */
399         return marshall_param(tinfo,elem,&tdesc2,(DWORD*)&(V_I4(vt)),buf);
400     }
401     case VT_PTR:
402         return marshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf);
403     case VT_VOID:
404         hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)arg);
405         if (hres) {
406             FIXME("Failed unmarshaling VT_VOID with guid %s?\n",debugstr_guid(&(buf->iid)));
407         }
408         return hres;
409     case VT_USERDEFINED: {
410         ITypeInfo       *tinfo2;
411         TYPEATTR        *tattr;
412
413         /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/
414         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
415         if (hres) {
416             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
417             return hres;
418         }
419         ITypeInfo_GetTypeAttr(tinfo2,&tattr);
420         switch (tattr->typekind) {
421         case TKIND_INTERFACE:
422             if (relaydeb) MESSAGE("if(%p), vtbl %p",arg,(LPVOID)*arg);
423             hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg);
424             break;
425         case TKIND_RECORD:
426             if (relaydeb) MESSAGE("record %p",arg);
427             if (buf->thisisiid)
428                 memcpy(&(buf->iid),arg,sizeof(buf->iid));
429             hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance);
430             break;
431         default:
432             FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
433             hres = E_FAIL;
434             break;
435         }
436         ITypeInfo_Release(tinfo2);
437         return hres;
438     }
439     default:
440         ERR("Cannot marshal type %d\n",tdesc->vt);
441         /*dump_ELEMDESC(elem);*/
442         return E_FAIL;
443     }
444     return S_OK;
445 }
446
447 static HRESULT
448 unmarshall_param(
449     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
450 ) {
451     HRESULT hres = S_OK;
452     int relaydeb = TRACE_ON(olerelay);
453
454     if (!tdesc) tdesc = &(elem->tdesc);
455     switch (tdesc->vt) {
456     case VT_I4: {
457         DWORD x;
458         xbuf_get(buf,(LPBYTE)&x,sizeof(x));
459         *arg = x;
460         if (relaydeb) MESSAGE("%ld ",x);
461         return S_OK;
462     }
463     case VT_PTR:
464         if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
465             (tdesc->u.lptdesc->vt != VT_VOID)
466         )
467             hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)(*arg),buf);
468         else
469             hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,arg,buf);
470         if (relaydeb) MESSAGE("%p ",(LPVOID)*arg);
471         return S_OK;
472     case VT_USERDEFINED: {
473         ITypeInfo       *tinfo2;
474         TYPEATTR        *tattr;
475
476         if (relaydeb) MESSAGE("%p",arg);
477         hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
478         if (hres) {
479             FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
480             return hres;
481         }
482         hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
483         if (hres) {
484             FIXME("Could not get typeattr in VT_USERDEFINED.\n");
485             return hres;
486         }
487         switch (tattr->typekind) {
488         case TKIND_INTERFACE:
489             hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
490             break;
491         case TKIND_RECORD:
492             hres = xbuf_get(buf,(LPBYTE)arg,tattr->cbSizeInstance);
493             break;
494         default:
495             hres = E_FAIL;
496             FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
497         }
498         ITypeInfo_Release(tinfo2);
499         return hres;
500     }
501     case VT_VOID: 
502         /* Hacky. If we are LPVOID* we apparently have to guess the IID
503          * for the interface. This sucks pretty badly. */
504         return _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg);
505     default:    ERR("Cannot unmarshal type %d\n",tdesc->vt);
506                 return E_FAIL;
507     }
508     return S_OK;
509 }
510
511 /* Searches function, also in inherited interfaces */
512 static HRESULT
513 _get_funcdesc(
514         ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc,
515         BSTR *iname, BSTR *fname
516 ) {
517     int i = 0, j = 0;
518     HRESULT hres;
519
520     if (fname) *fname = NULL;
521     if (iname) *iname = NULL;
522
523     while (1) {
524         hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc);
525         if (hres) {
526             ITypeInfo   *tinfo2;
527             HREFTYPE    href;
528             TYPEATTR    *attr;
529
530             hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
531             if (hres) {
532                 FIXME("GetTypeAttr failed with %lx\n",hres);
533                 return hres;
534             }
535             /* Not found, so look in inherited ifaces. */
536             for (j=0;j<attr->cImplTypes;j++) {
537                 hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href);
538                 if (hres) {
539                     FIXME("Did not find a reftype for interface offset %d?\n",j);
540                     break;
541                 }
542                 hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
543                 if (hres) {
544                     FIXME("Did not find a typeinfo for reftype %ld?\n",href);
545                     continue;
546                 }
547                 hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname);
548                 ITypeInfo_Release(tinfo2);
549                 if (!hres) return S_OK;
550             }
551             return E_FAIL;
552         }
553         if (((*fdesc)->oVft/4) == iMethod) {
554             if (fname)
555                 ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL);
556             if (iname)
557                 ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL);
558             return S_OK;
559         }
560         i++;
561     }
562     return E_FAIL;
563 }
564
565 /* how much space do we use on stack in DWORD steps. */
566 static int 
567 _argsize(DWORD vt_type) {
568     switch (vt_type) {
569     case VT_VARIANT:
570         return (sizeof(VARIANT)+3)/sizeof(DWORD);
571     default:
572         return 1;
573     }
574 }
575
576 static DWORD
577 xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) {
578     DWORD               *args = ((DWORD*)&tpinfo)+1, *xargs;
579     FUNCDESC            *fdesc;
580     HRESULT             hres;
581     int                 i, relaydeb = TRACE_ON(olerelay);
582     marshal_state       buf;
583     RPCOLEMESSAGE       msg;
584     ULONG               status;
585     BSTR                fname,iname;
586     BSTR                names[10];
587     int                 nrofnames;
588
589     hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname);
590     if (hres) {
591         ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method);
592         return 0;
593     }
594
595     /*dump_FUNCDESC(fdesc);*/
596     if (relaydeb) {
597         TRACE_(olerelay)("->");
598         if (iname)
599             MESSAGE("%s:",debugstr_w(iname));
600         if (fname)
601             MESSAGE("%s(%d)",debugstr_w(fname),method);
602         else
603             MESSAGE("%d",method);
604         MESSAGE("(");
605         if (iname) SysFreeString(iname);
606         if (fname) SysFreeString(fname);
607     }
608     /* Need them for hack below */
609     memset(names,0,sizeof(names));
610     ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
611     if (nrofnames > sizeof(names)/sizeof(names[0])) {
612         ERR("Need more names!\n");
613     }
614     memset(&buf,0,sizeof(buf));
615     buf.iid = IID_IUnknown;
616     if (method == 0) {
617         xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID));
618         if (relaydeb) MESSAGE("riid=%s,[out]",debugstr_guid((REFIID)args[0]));
619     } else {
620         xargs = args;
621         for (i=0;i<fdesc->cParams;i++) {
622             ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
623             if (relaydeb) {
624                 if (i) MESSAGE(",");
625                 if (i+1<nrofnames && names[i+1])
626                     MESSAGE("%s=",debugstr_w(names[i+1]));
627             }
628             if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW)) {
629                 buf.thisisiid = TRUE;
630             } else {
631                 buf.thisisiid = FALSE;
632             }
633             /* No need to marshal other data than FIN */
634             if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) {
635                 xargs+=_argsize(elem->tdesc.vt);
636                 if (relaydeb) MESSAGE("[out]");
637                 continue;
638             }
639             hres = marshall_param(tpinfo->tinfo,elem,NULL,xargs,&buf);
640             xargs+=_argsize(elem->tdesc.vt);
641             if (hres) {
642                 FIXME("Failed to marshall param, hres %lx\n",hres);
643                 break;
644             }
645         }
646     }
647     if (relaydeb) MESSAGE(")");
648     memset(&msg,0,sizeof(msg));
649     msg.cbBuffer = buf.curoff;
650     msg.iMethod  = method;
651     hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid));
652     if (hres) {
653         FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres);
654         return hres;
655     }
656     memcpy(msg.Buffer,buf.base,buf.curoff);
657     hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status);
658     if (hres) {
659         FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres);
660         return hres;
661     }
662     if (relaydeb) MESSAGE(" = %08lx (",status);
663     if (buf.base)
664         buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer);
665     else
666         buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer);
667     buf.size = msg.cbBuffer;
668     memcpy(buf.base,msg.Buffer,buf.size);
669     buf.curoff = 0;
670     if (method == 0) {
671         _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]);
672         if (relaydeb) MESSAGE("[in],%p",*((DWORD**)args[1]));
673     } else {
674         xargs = args;
675         for (i=0;i<fdesc->cParams;i++) {
676             ELEMDESC    *elem = fdesc->lprgelemdescParam+i;
677
678             if (relaydeb) {
679                 if (i) MESSAGE(",");
680                 if (i+1<nrofnames && names[i+1]) MESSAGE("%s=",debugstr_w(names[i+1]));
681             }
682             /* No need to marshal other data than FOUT I think */
683             if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) {
684                 xargs += _argsize(elem->tdesc.vt);
685                 if (relaydeb) MESSAGE("[in]");
686                 continue;
687             }
688             hres = unmarshall_param(tpinfo->tinfo,elem,&(elem->tdesc),xargs,&buf);
689             xargs += _argsize(elem->tdesc.vt);
690             if (hres) {
691                 FIXME("Failed to unmarshall param, hres %lx\n",hres);
692                 break;
693             }
694         }
695     }
696     if (relaydeb) MESSAGE(")\n");
697     HeapFree(GetProcessHeap(),0,buf.base);
698     return status;
699 }
700
701 static HRESULT WINAPI
702 PSFacBuf_CreateProxy(
703     LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid,
704     IRpcProxyBuffer **ppProxy, LPVOID *ppv
705 ) {
706     HRESULT     hres;
707     ITypeInfo   *tinfo;
708     int         i, nroffuncs;
709     FUNCDESC    *fdesc;
710     TMProxyImpl *proxy;
711     
712     TRACE("(...%s...)\n",debugstr_guid(riid));
713     hres = _get_typeinfo_for_iid(riid,&tinfo);
714     if (hres) {
715         FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
716         return hres;
717     }
718     nroffuncs = _nroffuncs(tinfo);
719     proxy = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMProxyImpl));
720     if (!proxy) return E_OUTOFMEMORY;
721     proxy->asmstubs=HeapAlloc(GetProcessHeap(),0,sizeof(TMAsmProxy)*nroffuncs);
722
723     assert(sizeof(TMAsmProxy) == 12);
724
725     proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs);
726     for (i=0;i<nroffuncs;i++) {
727         int             nrofargs;
728         TMAsmProxy      *xasm = proxy->asmstubs+i;
729
730         /* nrofargs without This */
731         switch (i) {
732         case 0: nrofargs = 2;
733                 break;
734         case 1: case 2: nrofargs = 0;
735                 break;
736         default: {
737                 int j;
738                 hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL);
739                 if (hres) {
740                     FIXME("GetFuncDesc %lx should not fail here.\n",hres);
741                     return hres;
742                 }
743                 /* some args take more than 4 byte on the stack */
744                 nrofargs = 0;
745                 for (j=0;j<fdesc->cParams;j++)
746                     nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt);
747
748                 if (fdesc->callconv != CC_STDCALL) {
749                     ERR("calling convention is not stdcall????\n");
750                     return E_FAIL;
751                 }
752                 break;
753             }
754         }
755 /* popl %eax    -       return ptr
756  * pushl <nr>
757  * pushl %eax
758  * call xCall
759  * lret <nr> (+4)
760  *
761  *
762  * arg3 arg2 arg1 <method> <returnptr>
763  */
764         xasm->popleax   = 0x58;
765         xasm->pushlval  = 0x6a;
766         xasm->nr        = i;
767         xasm->pushleax  = 0x50;
768         xasm->lcall     = 0xe8; /* relative jump */
769         xasm->xcall     = (DWORD)xCall;
770         xasm->xcall     -= (DWORD)&(xasm->lret);
771         xasm->lret      = 0xc2;
772         xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */
773         proxy->lpvtbl[i] = (DWORD)xasm;
774     }
775     proxy->lpvtbl2      = &tmproxyvtable;
776     proxy->ref          = 2;
777     proxy->tinfo        = tinfo;
778     memcpy(&proxy->iid,riid,sizeof(*riid));
779     *ppv                = (LPVOID)proxy;
780     *ppProxy            = (IRpcProxyBuffer *)&(proxy->lpvtbl2);
781     return S_OK;
782 }
783
784 typedef struct _TMStubImpl {
785     ICOM_VTABLE(IRpcStubBuffer) *lpvtbl;
786     DWORD                       ref;
787
788     LPUNKNOWN                   pUnk;
789     ITypeInfo                   *tinfo;
790     IID                         iid;
791 } TMStubImpl;
792
793 static HRESULT WINAPI
794 TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) {
795     if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){
796         *ppv = (LPVOID)iface;
797         IRpcStubBuffer_AddRef(iface);
798         return S_OK;
799     }
800     FIXME("%s, not supported IID.\n",debugstr_guid(riid));
801     return E_NOINTERFACE;
802 }
803
804 static ULONG WINAPI
805 TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) {
806     ICOM_THIS(TMStubImpl,iface);
807
808     This->ref++;
809     return This->ref;
810 }
811
812 static ULONG WINAPI
813 TMStubImpl_Release(LPRPCSTUBBUFFER iface) {
814     ICOM_THIS(TMStubImpl,iface);
815
816     This->ref--;
817     if (This->ref)
818         return This->ref;
819     HeapFree(GetProcessHeap(),0,This);
820     return 0;
821 }
822
823 static HRESULT WINAPI
824 TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) {
825     ICOM_THIS(TMStubImpl,iface);
826
827     IUnknown_AddRef(pUnkServer);
828     This->pUnk = pUnkServer;
829     return S_OK;
830 }
831
832 static void WINAPI
833 TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) {
834     ICOM_THIS(TMStubImpl,iface);
835
836     IUnknown_Release(This->pUnk);
837     This->pUnk = NULL;
838     return;
839 }
840
841 static HRESULT
842 stuballoc_param(
843     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
844 ) {
845     HRESULT hres;
846
847     while (1) {
848         switch (tdesc->vt) {
849         case VT_VARIANT: {
850             DWORD       vttype;
851             VARIANT     *vt = (VARIANT*)arg;
852             TYPEDESC    tdesc2;
853
854             hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype));
855             if (hres) return hres;
856             memset(&tdesc2,0,sizeof(tdesc));
857             tdesc2.vt = vttype;
858             V_VT(vt)  = vttype;
859             return stuballoc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf);
860         }
861         case VT_BOOL: case VT_I4:
862             xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD));
863             return S_OK;
864         case VT_BSTR: {
865                 WCHAR   *str;
866                 DWORD   len;
867
868                 hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD));
869                 if (hres)
870                     return hres;
871                 str  = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR));
872                 hres = xbuf_get(buf,(LPBYTE)str,len);
873                 if (hres) return hres;
874                 *arg = (DWORD)SysAllocStringLen(str,len);
875                 HeapFree(GetProcessHeap(),0,str);
876                 return S_OK;
877             }
878         case VT_PTR:
879             if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
880                 (tdesc->u.lptdesc->vt != VT_VOID)
881             ) {
882                 *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID));
883                 arg = (DWORD*)*arg;
884             }
885             tdesc = tdesc->u.lptdesc;
886             break;
887         case VT_UNKNOWN:
888             /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */
889             *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
890             return S_OK;
891         case VT_VOID:
892             *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID));
893             hres = S_OK;
894             if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)
895                 hres = _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg);
896             return hres;
897         case VT_USERDEFINED: {
898             if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) {
899                 ITypeInfo       *tinfo2;
900                 TYPEATTR        *tattr;
901
902                 hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
903                 if (hres) {
904                     FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
905                     return hres;
906                 }
907                 hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr);
908                 if (hres) {
909                     FIXME("Could not get typeattr in VT_USERDEFINED.\n");
910                     return hres;
911                 }
912                 switch (tattr->typekind) {
913                 case TKIND_INTERFACE:
914                     hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg);
915                     break;
916                 case TKIND_RECORD:
917                     *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance);
918                     hres = xbuf_get(buf,(LPBYTE)*arg,tattr->cbSizeInstance);
919                     if (buf->thisisiid)
920                         memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid));
921                     break;
922                 default:
923                     FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
924                     hres = E_FAIL;
925                     break;
926                 }
927                 ITypeInfo_Release(tinfo2);
928                 return hres;
929             } else {
930                 *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID));
931                 return S_OK;
932             }
933         }
934         default:
935             ERR("No handler for VT type %d, just allocating 4 bytes.\n",tdesc->vt);
936             *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD));
937             return S_OK;
938         }
939     }
940 }
941
942 static HRESULT
943 stubunalloc_param(
944     ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf
945 ) {
946     HRESULT hres = S_OK;
947
948     if (!tdesc) tdesc = &(elem->tdesc);
949
950     switch (tdesc->vt) {
951     case VT_BOOL:
952     case VT_I4: 
953         hres = S_OK;
954         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)
955             hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD));
956         return hres;
957     case VT_VARIANT: {
958         TYPEDESC        tdesc2;
959         VARIANT         *vt = (VARIANT*)arg;
960         DWORD           vttype = V_VT(vt);
961
962         tdesc2.vt = vttype;
963         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
964             hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype));
965             if (hres) return hres;
966         }
967         /* need to recurse since we need to free the stuff */
968         hres = stubunalloc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf);
969         return hres;
970     }
971     case VT_BSTR: {
972         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
973             DWORD *bstr = ((DWORD*)(*arg))-1;
974
975             hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4);
976             if (hres)
977                 return hres;
978         }
979         SysFreeString((BSTR)*arg);
980         return S_OK;
981     }
982     case VT_PTR:
983         /*FIXME("VT_PTR *arg is %p\n",(LPVOID)*arg);*/
984         if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) &&
985             (tdesc->u.lptdesc->vt != VT_VOID)
986         ) {
987             hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,arg,buf);
988         } else {
989             hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf);
990             HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
991         }
992         return hres;
993     case VT_UNKNOWN:
994         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
995             FIXME("Marshaling back VT_UNKNOWN %lx\n",*arg);
996             hres = xbuf_add(buf,(LPBYTE)*arg,sizeof(DWORD));
997         }
998         HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
999         return hres;
1000     case VT_VOID:
1001         hres = S_OK;
1002         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)
1003             hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)*arg);
1004         return hres;
1005     case VT_USERDEFINED: {
1006         ITypeInfo       *tinfo2;
1007         TYPEATTR        *tattr;
1008
1009         if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) {
1010             /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/
1011             hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2);
1012             if (hres) {
1013                 FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype);
1014                 return hres;
1015             }
1016             ITypeInfo_GetTypeAttr(tinfo2,&tattr);
1017             switch (tattr->typekind) {
1018             case TKIND_INTERFACE:
1019                 hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)*arg);
1020                 break;
1021             case TKIND_RECORD:
1022                 hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance);
1023                 break;
1024             default:
1025                 FIXME("Don't know how to marshal type kind %d\n",tattr->typekind);
1026                 hres = E_FAIL;
1027                 break;
1028             }
1029             ITypeInfo_Release(tinfo2);
1030         }
1031         return hres;
1032     }
1033     default:
1034         ERR("Unhandled marshal type %d.\n",tdesc->vt);
1035         HeapFree(GetProcessHeap(),0,(LPVOID)*arg);
1036         return S_OK;
1037     }
1038 }
1039
1040 static HRESULT WINAPI
1041 TMStubImpl_Invoke(
1042     LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf
1043 ) {
1044     int         i;
1045     FUNCDESC    *fdesc;
1046     ICOM_THIS(TMStubImpl,iface);
1047     HRESULT     hres;
1048     DWORD       *args, res, *xargs, nrofargs;
1049     marshal_state       buf;
1050     int         nrofnames;
1051     BSTR        names[10];
1052
1053     memset(&buf,0,sizeof(buf));
1054     buf.size    = xmsg->cbBuffer;
1055     buf.base    = xmsg->Buffer;
1056     buf.curoff  = 0;
1057     buf.iid     = IID_IUnknown;
1058
1059     TRACE("...\n");
1060     if (xmsg->iMethod == 0) { /* QI */
1061         IID             xiid;
1062         /* in: IID, out: <iface> */
1063
1064         xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid));
1065         buf.curoff = 0;
1066         hres = _marshal_interface(&buf,&xiid,This->pUnk);
1067         xmsg->Buffer    = buf.base; /* Might have been reallocated */
1068         xmsg->cbBuffer  = buf.size;
1069         return hres;
1070     }
1071     hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL);
1072     if (hres) {
1073         FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres);
1074         return hres;
1075     }
1076     /* Need them for hack below */
1077     memset(names,0,sizeof(names));
1078     ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames);
1079     if (nrofnames > sizeof(names)/sizeof(names[0])) {
1080         ERR("Need more names!\n");
1081     }
1082
1083     /*dump_FUNCDESC(fdesc);*/
1084     nrofargs = 0;
1085     for (i=0;i<fdesc->cParams;i++)
1086         nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt);
1087     args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD));
1088     if (!args) return E_OUTOFMEMORY;
1089
1090     /* Allocate all stuff used by call. */
1091     xargs = args+1;
1092     for (i=0;i<fdesc->cParams;i++) {
1093         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1094
1095         if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW))
1096             buf.thisisiid = TRUE;
1097         else
1098             buf.thisisiid = FALSE;
1099         hres   = stuballoc_param(This->tinfo,elem,&(elem->tdesc),xargs,&buf);
1100         xargs += _argsize(elem->tdesc.vt);
1101         if (hres) {
1102             FIXME("Failed to stuballoc param %s, hres %lx\n",debugstr_w(names[i+1]),hres);
1103             break;
1104         }
1105     }
1106     hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0]));
1107     if (hres) {
1108         ERR("Does not support iface %s\n",debugstr_guid(&(This->iid)));
1109         return hres;
1110     }
1111     res = _invoke(
1112             (*((LPVOID**)args[0]))[fdesc->oVft/4],
1113             fdesc->callconv,
1114             (xargs-args),
1115             args
1116     );
1117     IUnknown_Release((LPUNKNOWN)args[0]);
1118     buf.curoff = 0;
1119     xargs = args+1;
1120     for (i=0;i<fdesc->cParams;i++) {
1121         ELEMDESC        *elem = fdesc->lprgelemdescParam+i;
1122         hres = stubunalloc_param(This->tinfo,elem,NULL,xargs,&buf);
1123         xargs += _argsize(elem->tdesc.vt);
1124         if (hres) {
1125             FIXME("Failed to stuballoc param, hres %lx\n",hres);
1126             break;
1127         }
1128     }
1129     /* might need to use IRpcChannelBuffer_GetBuffer ? */
1130     xmsg->cbBuffer      = buf.curoff;
1131     xmsg->Buffer        = buf.base;
1132     HeapFree(GetProcessHeap(),0,args);
1133     return res;
1134 }
1135
1136 static LPRPCSTUBBUFFER WINAPI
1137 TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) {
1138     FIXME("Huh (%s)?\n",debugstr_guid(riid));
1139     return NULL;
1140 }
1141
1142 static ULONG WINAPI
1143 TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) {
1144     ICOM_THIS(TMStubImpl,iface);
1145
1146     return This->ref; /*FIXME? */
1147 }
1148
1149 static HRESULT WINAPI
1150 TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) {
1151     return E_NOTIMPL;
1152 }
1153
1154 static void WINAPI
1155 TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) {
1156     return;
1157 }
1158
1159 ICOM_VTABLE(IRpcStubBuffer) tmstubvtbl = {
1160     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1161     TMStubImpl_QueryInterface,
1162     TMStubImpl_AddRef,
1163     TMStubImpl_Release,
1164     TMStubImpl_Connect,
1165     TMStubImpl_Disconnect,
1166     TMStubImpl_Invoke,
1167     TMStubImpl_IsIIDSupported,
1168     TMStubImpl_CountRefs,
1169     TMStubImpl_DebugServerQueryInterface,
1170     TMStubImpl_DebugServerRelease
1171 };
1172
1173 static HRESULT WINAPI
1174 PSFacBuf_CreateStub(
1175     LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer,
1176     IRpcStubBuffer** ppStub
1177 ) {
1178     HRESULT hres;
1179     ITypeInfo   *tinfo;
1180     TMStubImpl  *stub;
1181
1182     TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub);
1183     hres = _get_typeinfo_for_iid(riid,&tinfo);
1184     if (hres) {
1185         FIXME("No typeinfo for %s?\n",debugstr_guid(riid));
1186         return hres;
1187     }
1188     stub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMStubImpl));
1189     if (!stub)
1190         return E_OUTOFMEMORY;
1191     stub->lpvtbl        = &tmstubvtbl;
1192     stub->ref           = 1;
1193     stub->tinfo         = tinfo;
1194     memcpy(&(stub->iid),riid,sizeof(*riid));
1195     hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer);
1196     *ppStub             = (LPRPCSTUBBUFFER)stub;
1197     if (hres)
1198         FIXME("Connect to pUnkServer failed?\n");
1199     return hres;
1200 }
1201
1202 static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = {
1203     ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE
1204     PSFacBuf_QueryInterface,
1205     PSFacBuf_AddRef,
1206     PSFacBuf_Release,
1207     PSFacBuf_CreateProxy,
1208     PSFacBuf_CreateStub
1209 };
1210
1211 /* This is the whole PSFactoryBuffer object, just the vtableptr */
1212 static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl;
1213
1214 /***********************************************************************
1215  *           DllGetClassObject [OLE32.63]
1216  */
1217 HRESULT WINAPI
1218 TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv)
1219 {
1220     if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) {
1221         *ppv = &lppsfac;
1222         return S_OK;
1223     }
1224     return E_NOINTERFACE;
1225 }