/* * 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 #include #include #include #include #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<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;jcImplTypes;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;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; if (relaydeb) { if (i) MESSAGE(","); if (i+1tinfo,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;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; if (relaydeb) { if (i) MESSAGE(","); if (i+1tinfo,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;iasmstubs+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;jcParams;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 * pushl %eax * call xCall * lret (+4) * * * arg3 arg2 arg1 */ 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: */ 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;icParams;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;icParams;i++) { ELEMDESC *elem = fdesc->lprgelemdescParam+i; if (((i+1)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;icParams;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; }