| /* |
| * TYPELIB Marshaler |
| * |
| * Copyright 2002 Marcus Meissner |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include "config.h" |
| |
| #include <assert.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <stdio.h> |
| #include <ctype.h> |
| |
| #include "winerror.h" |
| #include "winnls.h" |
| #include "winreg.h" |
| #include "winuser.h" |
| |
| #include "ole2.h" |
| #include "wine/unicode.h" |
| #include "wine/obj_base.h" |
| #include "wine/obj_channel.h" |
| #include "wine/obj_storage.h" |
| #include "heap.h" |
| #include "ole2disp.h" |
| #include "typelib.h" |
| #include "wine/debug.h" |
| #include "ntddk.h" |
| |
| static const WCHAR riidW[5] = {'r','i','i','d',0}; |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(ole); |
| WINE_DECLARE_DEBUG_CHANNEL(olerelay); |
| |
| typedef struct _marshal_state { |
| LPBYTE base; |
| int size; |
| int curoff; |
| |
| BOOL thisisiid; |
| IID iid; /* HACK: for VT_VOID */ |
| } marshal_state; |
| |
| static HRESULT |
| xbuf_add(marshal_state *buf, LPBYTE stuff, DWORD size) { |
| while (buf->size - buf->curoff < size) { |
| if (buf->base) { |
| buf->size += 100; |
| buf->base = HeapReAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,buf->base,buf->size); |
| if (!buf->base) |
| return E_OUTOFMEMORY; |
| } else { |
| buf->base = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,32); |
| buf->size = 32; |
| if (!buf->base) |
| return E_OUTOFMEMORY; |
| } |
| } |
| memcpy(buf->base+buf->curoff,stuff,size); |
| buf->curoff += size; |
| return S_OK; |
| } |
| |
| static HRESULT |
| xbuf_get(marshal_state *buf, LPBYTE stuff, DWORD size) { |
| if (buf->size < buf->curoff+size) return E_FAIL; |
| memcpy(stuff,buf->base+buf->curoff,size); |
| buf->curoff += size; |
| return S_OK; |
| } |
| |
| static HRESULT |
| xbuf_skip(marshal_state *buf, DWORD size) { |
| if (buf->size < buf->curoff+size) return E_FAIL; |
| buf->curoff += size; |
| return S_OK; |
| } |
| |
| static HRESULT |
| _unmarshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN *pUnk) { |
| IStream *pStm; |
| ULARGE_INTEGER newpos; |
| LARGE_INTEGER seekto; |
| ULONG res; |
| HRESULT hres; |
| DWORD xsize; |
| |
| TRACE("...%s...\n",debugstr_guid(riid)); |
| *pUnk = NULL; |
| hres = xbuf_get(buf,(LPBYTE)&xsize,sizeof(xsize)); |
| if (hres) return hres; |
| if (xsize == 0) return S_OK; |
| hres = CreateStreamOnHGlobal(0,TRUE,&pStm); |
| if (hres) { |
| FIXME("Stream create failed %lx\n",hres); |
| return hres; |
| } |
| hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res); |
| if (hres) { FIXME("stream write %lx\n",hres); return hres; } |
| memset(&seekto,0,sizeof(seekto)); |
| hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); |
| if (hres) { FIXME("Failed Seek %lx\n",hres); return hres;} |
| hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk); |
| if (hres) { |
| FIXME("Marshaling interface %s failed with %lx\n",debugstr_guid(riid),hres); |
| return hres; |
| } |
| IStream_Release(pStm); |
| return xbuf_skip(buf,xsize); |
| } |
| |
| static HRESULT |
| _marshal_interface(marshal_state *buf, REFIID riid, LPUNKNOWN pUnk) { |
| LPUNKNOWN newiface; |
| LPBYTE tempbuf; |
| IStream *pStm; |
| STATSTG ststg; |
| ULARGE_INTEGER newpos; |
| LARGE_INTEGER seekto; |
| ULONG res; |
| DWORD xsize; |
| HRESULT hres; |
| |
| hres = S_OK; |
| if (!pUnk) |
| goto fail; |
| |
| TRACE("...%s...\n",debugstr_guid(riid)); |
| hres=IUnknown_QueryInterface(pUnk,riid,(LPVOID*)&newiface); |
| if (hres) { |
| TRACE("%p does not support iface %s\n",pUnk,debugstr_guid(riid)); |
| goto fail; |
| } |
| hres = CreateStreamOnHGlobal(0,TRUE,&pStm); |
| if (hres) { |
| FIXME("Stream create failed %lx\n",hres); |
| goto fail; |
| } |
| hres = CoMarshalInterface(pStm,riid,newiface,0,NULL,0); |
| IUnknown_Release(newiface); |
| if (hres) { |
| FIXME("Marshaling interface %s failed with %lx\n", |
| debugstr_guid(riid),hres |
| ); |
| goto fail; |
| } |
| hres = IStream_Stat(pStm,&ststg,0); |
| tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.s.LowPart); |
| memset(&seekto,0,sizeof(seekto)); |
| hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos); |
| if (hres) { FIXME("Failed Seek %lx\n",hres); goto fail;} |
| hres = IStream_Read(pStm,tempbuf,ststg.cbSize.s.LowPart,&res); |
| if (hres) { FIXME("Failed Read %lx\n",hres); goto fail;} |
| IStream_Release(pStm); |
| xsize = ststg.cbSize.s.LowPart; |
| xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); |
| hres = xbuf_add(buf,tempbuf,ststg.cbSize.s.LowPart); |
| HeapFree(GetProcessHeap(),0,tempbuf); |
| return hres; |
| fail: |
| xsize = 0; |
| xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize)); |
| return hres; |
| } |
| |
| /********************* OLE Proxy/Stub Factory ********************************/ |
| static HRESULT WINAPI |
| PSFacBuf_QueryInterface(LPPSFACTORYBUFFER iface, REFIID iid, LPVOID *ppv) { |
| if (IsEqualIID(iid,&IID_IPSFactoryBuffer)||IsEqualIID(iid,&IID_IUnknown)) { |
| *ppv = (LPVOID)iface; |
| /* No ref counting, static class */ |
| return S_OK; |
| } |
| FIXME("(%s) unknown IID?\n",debugstr_guid(iid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI PSFacBuf_AddRef(LPPSFACTORYBUFFER iface) { return 2; } |
| static ULONG WINAPI PSFacBuf_Release(LPPSFACTORYBUFFER iface) { return 1; } |
| |
| static HRESULT |
| _get_typeinfo_for_iid(REFIID riid, ITypeInfo**ti) { |
| HRESULT hres; |
| HKEY ikey; |
| char tlguid[200],typelibkey[300],interfacekey[300],ver[100]; |
| char tlfn[260]; |
| OLECHAR tlfnW[260]; |
| DWORD tlguidlen, verlen, type, tlfnlen; |
| ITypeLib *tl; |
| |
| sprintf( interfacekey, "Interface\\{%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}\\Typelib", |
| riid->Data1, riid->Data2, riid->Data3, |
| riid->Data4[0], riid->Data4[1], riid->Data4[2], riid->Data4[3], |
| riid->Data4[4], riid->Data4[5], riid->Data4[6], riid->Data4[7] |
| ); |
| |
| if (RegOpenKeyA(HKEY_CLASSES_ROOT,interfacekey,&ikey)) { |
| FIXME("No %s key found.\n",interfacekey); |
| return E_FAIL; |
| } |
| type = (1<<REG_SZ); |
| tlguidlen = sizeof(tlguid); |
| if (RegQueryValueExA(ikey,NULL,NULL,&type,tlguid,&tlguidlen)) { |
| FIXME("Getting typelib guid failed.\n"); |
| RegCloseKey(ikey); |
| return E_FAIL; |
| } |
| type = (1<<REG_SZ); |
| verlen = sizeof(ver); |
| if (RegQueryValueExA(ikey,"Version",NULL,&type,ver,&verlen)) { |
| FIXME("Could not get version value?\n"); |
| RegCloseKey(ikey); |
| return E_FAIL; |
| } |
| RegCloseKey(ikey); |
| sprintf(typelibkey,"Typelib\\%s\\%s\\0\\win32",tlguid,ver); |
| tlfnlen = sizeof(tlfn); |
| if (RegQueryValueA(HKEY_CLASSES_ROOT,typelibkey,tlfn,&tlfnlen)) { |
| FIXME("Could not get typelib fn?\n"); |
| return E_FAIL; |
| } |
| MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, -1); |
| hres = LoadTypeLib(tlfnW,&tl); |
| if (hres) { |
| ERR("Failed to load typelib for %s, but it should be there.\n",debugstr_guid(riid)); |
| return hres; |
| } |
| hres = ITypeLib_GetTypeInfoOfGuid(tl,riid,ti); |
| if (hres) { |
| ERR("typelib does not contain info for %s?\n",debugstr_guid(riid)); |
| ITypeLib_Release(tl); |
| return hres; |
| } |
| /* FIXME: do this? ITypeLib_Release(tl); */ |
| return hres; |
| } |
| |
| /* Determine nr of functions. Since we use the toplevel interface and all |
| * inherited ones have lower numbers, we are ok to not to descent into |
| * the inheritance tree I think. |
| */ |
| static int _nroffuncs(ITypeInfo *tinfo) { |
| int n, max = 0; |
| FUNCDESC *fdesc; |
| HRESULT hres; |
| |
| n=0; |
| while (1) { |
| hres = ITypeInfo_GetFuncDesc(tinfo,n,&fdesc); |
| if (fdesc->oVft/4 > max) |
| max = fdesc->oVft/4; |
| if (hres) |
| return max+1; |
| n++; |
| } |
| /*NOTREACHED*/ |
| } |
| |
| typedef struct _TMAsmProxy { |
| BYTE popleax; |
| BYTE pushlval; |
| BYTE nr; |
| BYTE pushleax; |
| BYTE lcall; |
| DWORD xcall; |
| BYTE lret; |
| WORD bytestopop; |
| } WINE_PACKED TMAsmProxy; |
| |
| typedef struct _TMProxyImpl { |
| DWORD *lpvtbl; |
| ICOM_VTABLE(IRpcProxyBuffer) *lpvtbl2; |
| DWORD ref; |
| |
| TMAsmProxy *asmstubs; |
| ITypeInfo* tinfo; |
| IRpcChannelBuffer* chanbuf; |
| IID iid; |
| } TMProxyImpl; |
| |
| static HRESULT WINAPI |
| TMProxyImpl_QueryInterface(LPRPCPROXYBUFFER iface, REFIID riid, LPVOID *ppv) { |
| TRACE("()\n"); |
| if (IsEqualIID(riid,&IID_IUnknown)||IsEqualIID(riid,&IID_IRpcProxyBuffer)) { |
| *ppv = (LPVOID)iface; |
| IRpcProxyBuffer_AddRef(iface); |
| return S_OK; |
| } |
| FIXME("no interface for %s\n",debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI |
| TMProxyImpl_AddRef(LPRPCPROXYBUFFER iface) { |
| ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); |
| |
| TRACE("()\n"); |
| This->ref++; |
| return This->ref; |
| } |
| |
| static ULONG WINAPI |
| TMProxyImpl_Release(LPRPCPROXYBUFFER iface) { |
| ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); |
| |
| TRACE("()\n"); |
| This->ref--; |
| if (This->ref) return This->ref; |
| if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf); |
| HeapFree(GetProcessHeap(),0,This); |
| return 0; |
| } |
| |
| static HRESULT WINAPI |
| TMProxyImpl_Connect( |
| LPRPCPROXYBUFFER iface,IRpcChannelBuffer* pRpcChannelBuffer |
| ) { |
| ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); |
| |
| TRACE("(%p)\n",pRpcChannelBuffer); |
| This->chanbuf = pRpcChannelBuffer; |
| IRpcChannelBuffer_AddRef(This->chanbuf); |
| return S_OK; |
| } |
| |
| static void WINAPI |
| TMProxyImpl_Disconnect(LPRPCPROXYBUFFER iface) { |
| ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface); |
| |
| FIXME("()\n"); |
| IRpcChannelBuffer_Release(This->chanbuf); |
| This->chanbuf = NULL; |
| } |
| |
| |
| static ICOM_VTABLE(IRpcProxyBuffer) tmproxyvtable = { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| TMProxyImpl_QueryInterface, |
| TMProxyImpl_AddRef, |
| TMProxyImpl_Release, |
| TMProxyImpl_Connect, |
| TMProxyImpl_Disconnect |
| }; |
| |
| static HRESULT |
| marshall_param( |
| ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf |
| ) { |
| int relaydeb = TRACE_ON(olerelay); |
| HRESULT hres; |
| |
| if (!tdesc) tdesc = &(elem->tdesc); |
| switch (tdesc->vt) { |
| case VT_NULL: |
| return S_OK; |
| case VT_BSTR: { /* DWORD size, string data */ |
| |
| if (*arg) { |
| DWORD *bstr = ((DWORD*)(*arg))-1; |
| |
| if (relaydeb) MESSAGE("%s",debugstr_w((LPWSTR)(bstr+1))); |
| return xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4); |
| } else { |
| DWORD xnull = 0; |
| |
| return xbuf_add(buf,(LPBYTE)&xnull,sizeof(xnull)); |
| } |
| } |
| case VT_BOOL: |
| case VT_I4: |
| if (relaydeb) MESSAGE("%ld",*arg); |
| return xbuf_add(buf,(LPBYTE)arg,4); |
| case VT_VARIANT: { |
| /* We use ourselves to marshal the value further */ |
| TYPEDESC tdesc2; |
| VARIANT *vt = (VARIANT*)arg; |
| DWORD vttype = V_VT(vt); |
| |
| hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); |
| if (hres) return hres; |
| tdesc2.vt = vttype; |
| if (relaydeb) MESSAGE("Vt %ld ",vttype); |
| /* shield your eyes, bad pointer voodoo below */ |
| return marshall_param(tinfo,elem,&tdesc2,(DWORD*)&(V_I4(vt)),buf); |
| } |
| case VT_PTR: |
| return marshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf); |
| case VT_VOID: |
| hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)arg); |
| if (hres) { |
| FIXME("Failed unmarshaling VT_VOID with guid %s?\n",debugstr_guid(&(buf->iid))); |
| } |
| return hres; |
| case VT_USERDEFINED: { |
| ITypeInfo *tinfo2; |
| TYPEATTR *tattr; |
| |
| /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/ |
| hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); |
| if (hres) { |
| FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); |
| return hres; |
| } |
| ITypeInfo_GetTypeAttr(tinfo2,&tattr); |
| switch (tattr->typekind) { |
| case TKIND_INTERFACE: |
| if (relaydeb) MESSAGE("if(%p), vtbl %p",arg,(LPVOID)*arg); |
| hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)arg); |
| break; |
| case TKIND_RECORD: |
| if (relaydeb) MESSAGE("record %p",arg); |
| if (buf->thisisiid) |
| memcpy(&(buf->iid),arg,sizeof(buf->iid)); |
| hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance); |
| break; |
| default: |
| FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); |
| hres = E_FAIL; |
| break; |
| } |
| ITypeInfo_Release(tinfo2); |
| return hres; |
| } |
| default: |
| ERR("Cannot marshal type %d\n",tdesc->vt); |
| /*dump_ELEMDESC(elem);*/ |
| return E_FAIL; |
| } |
| return S_OK; |
| } |
| |
| static HRESULT |
| unmarshall_param( |
| ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf |
| ) { |
| HRESULT hres = S_OK; |
| int relaydeb = TRACE_ON(olerelay); |
| |
| if (!tdesc) tdesc = &(elem->tdesc); |
| switch (tdesc->vt) { |
| case VT_I4: { |
| DWORD x; |
| xbuf_get(buf,(LPBYTE)&x,sizeof(x)); |
| *arg = x; |
| if (relaydeb) MESSAGE("%ld ",x); |
| return S_OK; |
| } |
| case VT_PTR: |
| if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) && |
| (tdesc->u.lptdesc->vt != VT_VOID) |
| ) |
| hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)(*arg),buf); |
| else |
| hres = unmarshall_param(tinfo,elem,tdesc->u.lptdesc,arg,buf); |
| if (relaydeb) MESSAGE("%p ",(LPVOID)*arg); |
| return S_OK; |
| case VT_USERDEFINED: { |
| ITypeInfo *tinfo2; |
| TYPEATTR *tattr; |
| |
| if (relaydeb) MESSAGE("%p",arg); |
| hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); |
| if (hres) { |
| FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); |
| return hres; |
| } |
| hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); |
| if (hres) { |
| FIXME("Could not get typeattr in VT_USERDEFINED.\n"); |
| return hres; |
| } |
| switch (tattr->typekind) { |
| case TKIND_INTERFACE: |
| hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg); |
| break; |
| case TKIND_RECORD: |
| hres = xbuf_get(buf,(LPBYTE)arg,tattr->cbSizeInstance); |
| break; |
| default: |
| hres = E_FAIL; |
| FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); |
| } |
| ITypeInfo_Release(tinfo2); |
| return hres; |
| } |
| case VT_VOID: |
| /* Hacky. If we are LPVOID* we apparently have to guess the IID |
| * for the interface. This sucks pretty badly. */ |
| return _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg); |
| default: ERR("Cannot unmarshal type %d\n",tdesc->vt); |
| return E_FAIL; |
| } |
| return S_OK; |
| } |
| |
| /* Searches function, also in inherited interfaces */ |
| static HRESULT |
| _get_funcdesc( |
| ITypeInfo *tinfo, int iMethod, FUNCDESC **fdesc, |
| BSTR *iname, BSTR *fname |
| ) { |
| int i = 0, j = 0; |
| HRESULT hres; |
| |
| if (fname) *fname = NULL; |
| if (iname) *iname = NULL; |
| |
| while (1) { |
| hres = ITypeInfo_GetFuncDesc(tinfo, i, fdesc); |
| if (hres) { |
| ITypeInfo *tinfo2; |
| HREFTYPE href; |
| TYPEATTR *attr; |
| |
| hres = ITypeInfo_GetTypeAttr(tinfo, &attr); |
| if (hres) { |
| FIXME("GetTypeAttr failed with %lx\n",hres); |
| return hres; |
| } |
| /* Not found, so look in inherited ifaces. */ |
| for (j=0;j<attr->cImplTypes;j++) { |
| hres = ITypeInfo_GetRefTypeOfImplType(tinfo, j, &href); |
| if (hres) { |
| FIXME("Did not find a reftype for interface offset %d?\n",j); |
| break; |
| } |
| hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2); |
| if (hres) { |
| FIXME("Did not find a typeinfo for reftype %ld?\n",href); |
| continue; |
| } |
| hres = _get_funcdesc(tinfo2,iMethod,fdesc,iname,fname); |
| ITypeInfo_Release(tinfo2); |
| if (!hres) return S_OK; |
| } |
| return E_FAIL; |
| } |
| if (((*fdesc)->oVft/4) == iMethod) { |
| if (fname) |
| ITypeInfo_GetDocumentation(tinfo,(*fdesc)->memid,fname,NULL,NULL,NULL); |
| if (iname) |
| ITypeInfo_GetDocumentation(tinfo,-1,iname,NULL,NULL,NULL); |
| return S_OK; |
| } |
| i++; |
| } |
| return E_FAIL; |
| } |
| |
| /* how much space do we use on stack in DWORD steps. */ |
| static int |
| _argsize(DWORD vt_type) { |
| switch (vt_type) { |
| case VT_VARIANT: |
| return (sizeof(VARIANT)+3)/sizeof(DWORD); |
| default: |
| return 1; |
| } |
| } |
| |
| static DWORD |
| xCall(LPVOID retptr, int method, TMProxyImpl *tpinfo /*, args */) { |
| DWORD *args = ((DWORD*)&tpinfo)+1, *xargs; |
| FUNCDESC *fdesc; |
| HRESULT hres; |
| int i, relaydeb = TRACE_ON(olerelay); |
| marshal_state buf; |
| RPCOLEMESSAGE msg; |
| ULONG status; |
| BSTR fname,iname; |
| BSTR names[10]; |
| int nrofnames; |
| |
| hres = _get_funcdesc(tpinfo->tinfo,method,&fdesc,&iname,&fname); |
| if (hres) { |
| ERR("Did not find typeinfo/funcdesc entry for method %d!\n",method); |
| return 0; |
| } |
| |
| /*dump_FUNCDESC(fdesc);*/ |
| if (relaydeb) { |
| TRACE_(olerelay)("->"); |
| if (iname) |
| MESSAGE("%s:",debugstr_w(iname)); |
| if (fname) |
| MESSAGE("%s(%d)",debugstr_w(fname),method); |
| else |
| MESSAGE("%d",method); |
| MESSAGE("("); |
| if (iname) SysFreeString(iname); |
| if (fname) SysFreeString(fname); |
| } |
| /* Need them for hack below */ |
| memset(names,0,sizeof(names)); |
| ITypeInfo_GetNames(tpinfo->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); |
| if (nrofnames > sizeof(names)/sizeof(names[0])) { |
| ERR("Need more names!\n"); |
| } |
| memset(&buf,0,sizeof(buf)); |
| buf.iid = IID_IUnknown; |
| if (method == 0) { |
| xbuf_add(&buf,(LPBYTE)args[0],sizeof(IID)); |
| if (relaydeb) MESSAGE("riid=%s,[out]",debugstr_guid((REFIID)args[0])); |
| } else { |
| xargs = args; |
| for (i=0;i<fdesc->cParams;i++) { |
| ELEMDESC *elem = fdesc->lprgelemdescParam+i; |
| if (relaydeb) { |
| if (i) MESSAGE(","); |
| if (i+1<nrofnames && names[i+1]) |
| MESSAGE("%s=",debugstr_w(names[i+1])); |
| } |
| if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW)) { |
| buf.thisisiid = TRUE; |
| } else { |
| buf.thisisiid = FALSE; |
| } |
| /* No need to marshal other data than FIN */ |
| if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN)) { |
| xargs+=_argsize(elem->tdesc.vt); |
| if (relaydeb) MESSAGE("[out]"); |
| continue; |
| } |
| hres = marshall_param(tpinfo->tinfo,elem,NULL,xargs,&buf); |
| xargs+=_argsize(elem->tdesc.vt); |
| if (hres) { |
| FIXME("Failed to marshall param, hres %lx\n",hres); |
| break; |
| } |
| } |
| } |
| if (relaydeb) MESSAGE(")"); |
| memset(&msg,0,sizeof(msg)); |
| msg.cbBuffer = buf.curoff; |
| msg.iMethod = method; |
| hres = IRpcChannelBuffer_GetBuffer(tpinfo->chanbuf,&msg,&(tpinfo->iid)); |
| if (hres) { |
| FIXME("RpcChannelBuffer GetBuffer failed, %lx\n",hres); |
| return hres; |
| } |
| memcpy(msg.Buffer,buf.base,buf.curoff); |
| hres = IRpcChannelBuffer_SendReceive(tpinfo->chanbuf,&msg,&status); |
| if (hres) { |
| FIXME("RpcChannelBuffer SendReceive failed, %lx\n",hres); |
| return hres; |
| } |
| if (relaydeb) MESSAGE(" = %08lx (",status); |
| if (buf.base) |
| buf.base = HeapReAlloc(GetProcessHeap(),0,buf.base,msg.cbBuffer); |
| else |
| buf.base = HeapAlloc(GetProcessHeap(),0,msg.cbBuffer); |
| buf.size = msg.cbBuffer; |
| memcpy(buf.base,msg.Buffer,buf.size); |
| buf.curoff = 0; |
| if (method == 0) { |
| _unmarshal_interface(&buf,(REFIID)args[0],(LPUNKNOWN*)args[1]); |
| if (relaydeb) MESSAGE("[in],%p",*((DWORD**)args[1])); |
| } else { |
| xargs = args; |
| for (i=0;i<fdesc->cParams;i++) { |
| ELEMDESC *elem = fdesc->lprgelemdescParam+i; |
| |
| if (relaydeb) { |
| if (i) MESSAGE(","); |
| if (i+1<nrofnames && names[i+1]) MESSAGE("%s=",debugstr_w(names[i+1])); |
| } |
| /* No need to marshal other data than FOUT I think */ |
| if (!(elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT)) { |
| xargs += _argsize(elem->tdesc.vt); |
| if (relaydeb) MESSAGE("[in]"); |
| continue; |
| } |
| hres = unmarshall_param(tpinfo->tinfo,elem,&(elem->tdesc),xargs,&buf); |
| xargs += _argsize(elem->tdesc.vt); |
| if (hres) { |
| FIXME("Failed to unmarshall param, hres %lx\n",hres); |
| break; |
| } |
| } |
| } |
| if (relaydeb) MESSAGE(")\n"); |
| HeapFree(GetProcessHeap(),0,buf.base); |
| return status; |
| } |
| |
| static HRESULT WINAPI |
| PSFacBuf_CreateProxy( |
| LPPSFACTORYBUFFER iface, IUnknown* pUnkOuter, REFIID riid, |
| IRpcProxyBuffer **ppProxy, LPVOID *ppv |
| ) { |
| HRESULT hres; |
| ITypeInfo *tinfo; |
| int i, nroffuncs; |
| FUNCDESC *fdesc; |
| TMProxyImpl *proxy; |
| |
| TRACE("(...%s...)\n",debugstr_guid(riid)); |
| hres = _get_typeinfo_for_iid(riid,&tinfo); |
| if (hres) { |
| FIXME("No typeinfo for %s?\n",debugstr_guid(riid)); |
| return hres; |
| } |
| nroffuncs = _nroffuncs(tinfo); |
| proxy = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMProxyImpl)); |
| if (!proxy) return E_OUTOFMEMORY; |
| proxy->asmstubs=HeapAlloc(GetProcessHeap(),0,sizeof(TMAsmProxy)*nroffuncs); |
| |
| assert(sizeof(TMAsmProxy) == 12); |
| |
| proxy->lpvtbl = HeapAlloc(GetProcessHeap(),0,sizeof(LPBYTE)*nroffuncs); |
| for (i=0;i<nroffuncs;i++) { |
| int nrofargs; |
| TMAsmProxy *xasm = proxy->asmstubs+i; |
| |
| /* nrofargs without This */ |
| switch (i) { |
| case 0: nrofargs = 2; |
| break; |
| case 1: case 2: nrofargs = 0; |
| break; |
| default: { |
| int j; |
| hres = _get_funcdesc(tinfo,i,&fdesc,NULL,NULL); |
| if (hres) { |
| FIXME("GetFuncDesc %lx should not fail here.\n",hres); |
| return hres; |
| } |
| /* some args take more than 4 byte on the stack */ |
| nrofargs = 0; |
| for (j=0;j<fdesc->cParams;j++) |
| nrofargs += _argsize(fdesc->lprgelemdescParam[j].tdesc.vt); |
| |
| if (fdesc->callconv != CC_STDCALL) { |
| ERR("calling convention is not stdcall????\n"); |
| return E_FAIL; |
| } |
| break; |
| } |
| } |
| /* popl %eax - return ptr |
| * pushl <nr> |
| * pushl %eax |
| * call xCall |
| * lret <nr> (+4) |
| * |
| * |
| * arg3 arg2 arg1 <method> <returnptr> |
| */ |
| xasm->popleax = 0x58; |
| xasm->pushlval = 0x6a; |
| xasm->nr = i; |
| xasm->pushleax = 0x50; |
| xasm->lcall = 0xe8; /* relative jump */ |
| xasm->xcall = (DWORD)xCall; |
| xasm->xcall -= (DWORD)&(xasm->lret); |
| xasm->lret = 0xc2; |
| xasm->bytestopop= (nrofargs+2)*4; /* pop args, This, iMethod */ |
| proxy->lpvtbl[i] = (DWORD)xasm; |
| } |
| proxy->lpvtbl2 = &tmproxyvtable; |
| proxy->ref = 2; |
| proxy->tinfo = tinfo; |
| memcpy(&proxy->iid,riid,sizeof(*riid)); |
| *ppv = (LPVOID)proxy; |
| *ppProxy = (IRpcProxyBuffer *)&(proxy->lpvtbl2); |
| return S_OK; |
| } |
| |
| typedef struct _TMStubImpl { |
| ICOM_VTABLE(IRpcStubBuffer) *lpvtbl; |
| DWORD ref; |
| |
| LPUNKNOWN pUnk; |
| ITypeInfo *tinfo; |
| IID iid; |
| } TMStubImpl; |
| |
| static HRESULT WINAPI |
| TMStubImpl_QueryInterface(LPRPCSTUBBUFFER iface, REFIID riid, LPVOID *ppv) { |
| if (IsEqualIID(riid,&IID_IRpcStubBuffer)||IsEqualIID(riid,&IID_IUnknown)){ |
| *ppv = (LPVOID)iface; |
| IRpcStubBuffer_AddRef(iface); |
| return S_OK; |
| } |
| FIXME("%s, not supported IID.\n",debugstr_guid(riid)); |
| return E_NOINTERFACE; |
| } |
| |
| static ULONG WINAPI |
| TMStubImpl_AddRef(LPRPCSTUBBUFFER iface) { |
| ICOM_THIS(TMStubImpl,iface); |
| |
| This->ref++; |
| return This->ref; |
| } |
| |
| static ULONG WINAPI |
| TMStubImpl_Release(LPRPCSTUBBUFFER iface) { |
| ICOM_THIS(TMStubImpl,iface); |
| |
| This->ref--; |
| if (This->ref) |
| return This->ref; |
| HeapFree(GetProcessHeap(),0,This); |
| return 0; |
| } |
| |
| static HRESULT WINAPI |
| TMStubImpl_Connect(LPRPCSTUBBUFFER iface, LPUNKNOWN pUnkServer) { |
| ICOM_THIS(TMStubImpl,iface); |
| |
| IUnknown_AddRef(pUnkServer); |
| This->pUnk = pUnkServer; |
| return S_OK; |
| } |
| |
| static void WINAPI |
| TMStubImpl_Disconnect(LPRPCSTUBBUFFER iface) { |
| ICOM_THIS(TMStubImpl,iface); |
| |
| IUnknown_Release(This->pUnk); |
| This->pUnk = NULL; |
| return; |
| } |
| |
| static HRESULT |
| stuballoc_param( |
| ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf |
| ) { |
| HRESULT hres; |
| |
| while (1) { |
| switch (tdesc->vt) { |
| case VT_VARIANT: { |
| DWORD vttype; |
| VARIANT *vt = (VARIANT*)arg; |
| TYPEDESC tdesc2; |
| |
| hres = xbuf_get(buf,(LPBYTE)&vttype,sizeof(vttype)); |
| if (hres) return hres; |
| memset(&tdesc2,0,sizeof(tdesc)); |
| tdesc2.vt = vttype; |
| V_VT(vt) = vttype; |
| return stuballoc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf); |
| } |
| case VT_BOOL: case VT_I4: |
| xbuf_get(buf,(LPBYTE)arg,sizeof(DWORD)); |
| return S_OK; |
| case VT_BSTR: { |
| WCHAR *str; |
| DWORD len; |
| |
| hres = xbuf_get(buf,(LPBYTE)&len,sizeof(DWORD)); |
| if (hres) |
| return hres; |
| str = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,len+sizeof(WCHAR)); |
| hres = xbuf_get(buf,(LPBYTE)str,len); |
| if (hres) return hres; |
| *arg = (DWORD)SysAllocStringLen(str,len); |
| HeapFree(GetProcessHeap(),0,str); |
| return S_OK; |
| } |
| case VT_PTR: |
| if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) && |
| (tdesc->u.lptdesc->vt != VT_VOID) |
| ) { |
| *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(LPVOID)); |
| arg = (DWORD*)*arg; |
| } |
| tdesc = tdesc->u.lptdesc; |
| break; |
| case VT_UNKNOWN: |
| /* FIXME: UNKNOWN is unknown ..., but allocate 4 byte for it */ |
| *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); |
| return S_OK; |
| case VT_VOID: |
| *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)); |
| hres = S_OK; |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) |
| hres = _unmarshal_interface(buf,&(buf->iid),(LPUNKNOWN*)arg); |
| return hres; |
| case VT_USERDEFINED: { |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FIN) { |
| ITypeInfo *tinfo2; |
| TYPEATTR *tattr; |
| |
| hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); |
| if (hres) { |
| FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); |
| return hres; |
| } |
| hres = ITypeInfo_GetTypeAttr(tinfo2,&tattr); |
| if (hres) { |
| FIXME("Could not get typeattr in VT_USERDEFINED.\n"); |
| return hres; |
| } |
| switch (tattr->typekind) { |
| case TKIND_INTERFACE: |
| hres = _unmarshal_interface(buf,&(tattr->guid),(LPUNKNOWN*)arg); |
| break; |
| case TKIND_RECORD: |
| *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,tattr->cbSizeInstance); |
| hres = xbuf_get(buf,(LPBYTE)*arg,tattr->cbSizeInstance); |
| if (buf->thisisiid) |
| memcpy(&(buf->iid),(LPBYTE)*arg,sizeof(buf->iid)); |
| break; |
| default: |
| FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); |
| hres = E_FAIL; |
| break; |
| } |
| ITypeInfo_Release(tinfo2); |
| return hres; |
| } else { |
| *arg = (DWORD)HeapAlloc(GetProcessHeap(),0,sizeof(LPVOID)); |
| return S_OK; |
| } |
| } |
| default: |
| ERR("No handler for VT type %d, just allocating 4 bytes.\n",tdesc->vt); |
| *arg=(DWORD)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(DWORD)); |
| return S_OK; |
| } |
| } |
| } |
| |
| static HRESULT |
| stubunalloc_param( |
| ITypeInfo *tinfo, ELEMDESC *elem, TYPEDESC *tdesc, DWORD *arg, marshal_state *buf |
| ) { |
| HRESULT hres = S_OK; |
| |
| if (!tdesc) tdesc = &(elem->tdesc); |
| |
| switch (tdesc->vt) { |
| case VT_BOOL: |
| case VT_I4: |
| hres = S_OK; |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) |
| hres = xbuf_add(buf,(LPBYTE)arg,sizeof(DWORD)); |
| return hres; |
| case VT_VARIANT: { |
| TYPEDESC tdesc2; |
| VARIANT *vt = (VARIANT*)arg; |
| DWORD vttype = V_VT(vt); |
| |
| tdesc2.vt = vttype; |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { |
| hres = xbuf_add(buf,(LPBYTE)&vttype,sizeof(vttype)); |
| if (hres) return hres; |
| } |
| /* need to recurse since we need to free the stuff */ |
| hres = stubunalloc_param(tinfo,elem,&tdesc2,&(V_I4(vt)),buf); |
| return hres; |
| } |
| case VT_BSTR: { |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { |
| DWORD *bstr = ((DWORD*)(*arg))-1; |
| |
| hres = xbuf_add(buf,(LPBYTE)bstr,bstr[0]+4); |
| if (hres) |
| return hres; |
| } |
| SysFreeString((BSTR)*arg); |
| return S_OK; |
| } |
| case VT_PTR: |
| /*FIXME("VT_PTR *arg is %p\n",(LPVOID)*arg);*/ |
| if ((tdesc->u.lptdesc->vt != VT_USERDEFINED) && |
| (tdesc->u.lptdesc->vt != VT_VOID) |
| ) { |
| hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,arg,buf); |
| } else { |
| hres = stubunalloc_param(tinfo,elem,tdesc->u.lptdesc,(DWORD*)*arg,buf); |
| HeapFree(GetProcessHeap(),0,(LPVOID)*arg); |
| } |
| return hres; |
| case VT_UNKNOWN: |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { |
| FIXME("Marshaling back VT_UNKNOWN %lx\n",*arg); |
| hres = xbuf_add(buf,(LPBYTE)*arg,sizeof(DWORD)); |
| } |
| HeapFree(GetProcessHeap(),0,(LPVOID)*arg); |
| return hres; |
| case VT_VOID: |
| hres = S_OK; |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) |
| hres = _marshal_interface(buf,&(buf->iid),(LPUNKNOWN)*arg); |
| return hres; |
| case VT_USERDEFINED: { |
| ITypeInfo *tinfo2; |
| TYPEATTR *tattr; |
| |
| if (elem->u.paramdesc.wParamFlags & PARAMFLAG_FOUT) { |
| /*FIXME("VT_USERDEFINED arg is %p, *arg is %p\n",arg,*arg);*/ |
| hres = ITypeInfo_GetRefTypeInfo(tinfo,tdesc->u.hreftype,&tinfo2); |
| if (hres) { |
| FIXME("Could not get typeinfo of hreftype %lx for VT_USERDEFINED.\n",tdesc->u.hreftype); |
| return hres; |
| } |
| ITypeInfo_GetTypeAttr(tinfo2,&tattr); |
| switch (tattr->typekind) { |
| case TKIND_INTERFACE: |
| hres = _marshal_interface(buf,&(tattr->guid),(LPUNKNOWN)*arg); |
| break; |
| case TKIND_RECORD: |
| hres = xbuf_add(buf,(LPBYTE)arg,tattr->cbSizeInstance); |
| break; |
| default: |
| FIXME("Don't know how to marshal type kind %d\n",tattr->typekind); |
| hres = E_FAIL; |
| break; |
| } |
| ITypeInfo_Release(tinfo2); |
| } |
| return hres; |
| } |
| default: |
| ERR("Unhandled marshal type %d.\n",tdesc->vt); |
| HeapFree(GetProcessHeap(),0,(LPVOID)*arg); |
| return S_OK; |
| } |
| } |
| |
| static HRESULT WINAPI |
| TMStubImpl_Invoke( |
| LPRPCSTUBBUFFER iface, RPCOLEMESSAGE* xmsg,IRpcChannelBuffer*rpcchanbuf |
| ) { |
| int i; |
| FUNCDESC *fdesc; |
| ICOM_THIS(TMStubImpl,iface); |
| HRESULT hres; |
| DWORD *args, res, *xargs, nrofargs; |
| marshal_state buf; |
| int nrofnames; |
| BSTR names[10]; |
| |
| memset(&buf,0,sizeof(buf)); |
| buf.size = xmsg->cbBuffer; |
| buf.base = xmsg->Buffer; |
| buf.curoff = 0; |
| buf.iid = IID_IUnknown; |
| |
| TRACE("...\n"); |
| if (xmsg->iMethod == 0) { /* QI */ |
| IID xiid; |
| /* in: IID, out: <iface> */ |
| |
| xbuf_get(&buf,(LPBYTE)&xiid,sizeof(xiid)); |
| buf.curoff = 0; |
| hres = _marshal_interface(&buf,&xiid,This->pUnk); |
| xmsg->Buffer = buf.base; /* Might have been reallocated */ |
| xmsg->cbBuffer = buf.size; |
| return hres; |
| } |
| hres = _get_funcdesc(This->tinfo,xmsg->iMethod,&fdesc,NULL,NULL); |
| if (hres) { |
| FIXME("GetFuncDesc on method %ld failed with %lx\n",xmsg->iMethod,hres); |
| return hres; |
| } |
| /* Need them for hack below */ |
| memset(names,0,sizeof(names)); |
| ITypeInfo_GetNames(This->tinfo,fdesc->memid,names,sizeof(names)/sizeof(names[0]),&nrofnames); |
| if (nrofnames > sizeof(names)/sizeof(names[0])) { |
| ERR("Need more names!\n"); |
| } |
| |
| /*dump_FUNCDESC(fdesc);*/ |
| nrofargs = 0; |
| for (i=0;i<fdesc->cParams;i++) |
| nrofargs += _argsize(fdesc->lprgelemdescParam[i].tdesc.vt); |
| args = HeapAlloc(GetProcessHeap(),0,(nrofargs+1)*sizeof(DWORD)); |
| if (!args) return E_OUTOFMEMORY; |
| |
| /* Allocate all stuff used by call. */ |
| xargs = args+1; |
| for (i=0;i<fdesc->cParams;i++) { |
| ELEMDESC *elem = fdesc->lprgelemdescParam+i; |
| |
| if (((i+1)<nrofnames) && !lstrcmpW(names[i+1],riidW)) |
| buf.thisisiid = TRUE; |
| else |
| buf.thisisiid = FALSE; |
| hres = stuballoc_param(This->tinfo,elem,&(elem->tdesc),xargs,&buf); |
| xargs += _argsize(elem->tdesc.vt); |
| if (hres) { |
| FIXME("Failed to stuballoc param %s, hres %lx\n",debugstr_w(names[i+1]),hres); |
| break; |
| } |
| } |
| hres = IUnknown_QueryInterface(This->pUnk,&(This->iid),(LPVOID*)&(args[0])); |
| if (hres) { |
| ERR("Does not support iface %s\n",debugstr_guid(&(This->iid))); |
| return hres; |
| } |
| res = _invoke( |
| (*((LPVOID**)args[0]))[fdesc->oVft/4], |
| fdesc->callconv, |
| (xargs-args), |
| args |
| ); |
| IUnknown_Release((LPUNKNOWN)args[0]); |
| buf.curoff = 0; |
| xargs = args+1; |
| for (i=0;i<fdesc->cParams;i++) { |
| ELEMDESC *elem = fdesc->lprgelemdescParam+i; |
| hres = stubunalloc_param(This->tinfo,elem,NULL,xargs,&buf); |
| xargs += _argsize(elem->tdesc.vt); |
| if (hres) { |
| FIXME("Failed to stuballoc param, hres %lx\n",hres); |
| break; |
| } |
| } |
| /* might need to use IRpcChannelBuffer_GetBuffer ? */ |
| xmsg->cbBuffer = buf.curoff; |
| xmsg->Buffer = buf.base; |
| HeapFree(GetProcessHeap(),0,args); |
| return res; |
| } |
| |
| static LPRPCSTUBBUFFER WINAPI |
| TMStubImpl_IsIIDSupported(LPRPCSTUBBUFFER iface, REFIID riid) { |
| FIXME("Huh (%s)?\n",debugstr_guid(riid)); |
| return NULL; |
| } |
| |
| static ULONG WINAPI |
| TMStubImpl_CountRefs(LPRPCSTUBBUFFER iface) { |
| ICOM_THIS(TMStubImpl,iface); |
| |
| return This->ref; /*FIXME? */ |
| } |
| |
| static HRESULT WINAPI |
| TMStubImpl_DebugServerQueryInterface(LPRPCSTUBBUFFER iface, LPVOID *ppv) { |
| return E_NOTIMPL; |
| } |
| |
| static void WINAPI |
| TMStubImpl_DebugServerRelease(LPRPCSTUBBUFFER iface, LPVOID ppv) { |
| return; |
| } |
| |
| ICOM_VTABLE(IRpcStubBuffer) tmstubvtbl = { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| TMStubImpl_QueryInterface, |
| TMStubImpl_AddRef, |
| TMStubImpl_Release, |
| TMStubImpl_Connect, |
| TMStubImpl_Disconnect, |
| TMStubImpl_Invoke, |
| TMStubImpl_IsIIDSupported, |
| TMStubImpl_CountRefs, |
| TMStubImpl_DebugServerQueryInterface, |
| TMStubImpl_DebugServerRelease |
| }; |
| |
| static HRESULT WINAPI |
| PSFacBuf_CreateStub( |
| LPPSFACTORYBUFFER iface, REFIID riid,IUnknown *pUnkServer, |
| IRpcStubBuffer** ppStub |
| ) { |
| HRESULT hres; |
| ITypeInfo *tinfo; |
| TMStubImpl *stub; |
| |
| TRACE("(%s,%p,%p)\n",debugstr_guid(riid),pUnkServer,ppStub); |
| hres = _get_typeinfo_for_iid(riid,&tinfo); |
| if (hres) { |
| FIXME("No typeinfo for %s?\n",debugstr_guid(riid)); |
| return hres; |
| } |
| stub = HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,sizeof(TMStubImpl)); |
| if (!stub) |
| return E_OUTOFMEMORY; |
| stub->lpvtbl = &tmstubvtbl; |
| stub->ref = 1; |
| stub->tinfo = tinfo; |
| memcpy(&(stub->iid),riid,sizeof(*riid)); |
| hres = IRpcStubBuffer_Connect((LPRPCSTUBBUFFER)stub,pUnkServer); |
| *ppStub = (LPRPCSTUBBUFFER)stub; |
| if (hres) |
| FIXME("Connect to pUnkServer failed?\n"); |
| return hres; |
| } |
| |
| static ICOM_VTABLE(IPSFactoryBuffer) psfacbufvtbl = { |
| ICOM_MSVTABLE_COMPAT_DummyRTTIVALUE |
| PSFacBuf_QueryInterface, |
| PSFacBuf_AddRef, |
| PSFacBuf_Release, |
| PSFacBuf_CreateProxy, |
| PSFacBuf_CreateStub |
| }; |
| |
| /* This is the whole PSFactoryBuffer object, just the vtableptr */ |
| static ICOM_VTABLE(IPSFactoryBuffer) *lppsfac = &psfacbufvtbl; |
| |
| /*********************************************************************** |
| * DllGetClassObject [OLE32.63] |
| */ |
| HRESULT WINAPI |
| TypeLibFac_DllGetClassObject(REFCLSID rclsid, REFIID iid,LPVOID *ppv) |
| { |
| if (IsEqualIID(iid,&IID_IPSFactoryBuffer)) { |
| *ppv = &lppsfac; |
| return S_OK; |
| } |
| return E_NOINTERFACE; |
| } |