📄 tmarshal.c
字号:
/*
* TYPELIB Marshaler
*
* Copyright 2002,2005 Marcus Meissner
*
* The olerelay debug channel allows you to see calls marshalled by
* the typelib marshaller. It is not a generic COM relaying system.
*
* 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <ctype.h>
#define COBJMACROS
#define NONAMELESSUNION
#define NONAMELESSSTRUCT
#include "winerror.h"
#include "windef.h"
#include "winbase.h"
#include "winnls.h"
#include "winreg.h"
#include "winuser.h"
#include "ole2.h"
#include "propidl.h" /* for LPSAFEARRAY_User* functions */
#include "typelib.h"
#include "variant.h"
#include "wine/debug.h"
#include "wine/exception.h"
static const WCHAR IDispatchW[] = { 'I','D','i','s','p','a','t','c','h',0};
WINE_DEFAULT_DEBUG_CHANNEL(ole);
WINE_DECLARE_DEBUG_CHANNEL(olerelay);
#define ICOM_THIS_MULTI(impl,field,iface) impl* const This=(impl*)((char*)(iface) - offsetof(impl,field))
static HRESULT TMarshalDispatchChannel_Create(
IRpcChannelBuffer *pDelegateChannel, REFIID tmarshal_riid,
IRpcChannelBuffer **ppChannel);
typedef struct _marshal_state {
LPBYTE base;
int size;
int curoff;
} marshal_state;
/* used in the olerelay code to avoid having the L"" stuff added by debugstr_w */
static char *relaystr(WCHAR *in) {
char *tmp = (char *)debugstr_w(in);
tmp += 2;
tmp[strlen(tmp)-1] = '\0';
return tmp;
}
static HRESULT
xbuf_resize(marshal_state *buf, DWORD newsize)
{
if(buf->size >= newsize)
return S_FALSE;
if(buf->base)
{
buf->base = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, buf->base, newsize);
if(!buf->base)
return E_OUTOFMEMORY;
}
else
{
buf->base = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, newsize);
if(!buf->base)
return E_OUTOFMEMORY;
}
buf->size = newsize;
return S_OK;
}
static HRESULT
xbuf_add(marshal_state *buf, const BYTE *stuff, DWORD size)
{
HRESULT hr;
if(buf->size - buf->curoff < size)
{
hr = xbuf_resize(buf, buf->size + size + 100);
if(FAILED(hr)) return hr;
}
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) {
ERR("xbuf_get failed\n");
return hres;
}
if (xsize == 0) return S_OK;
hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
if (hres) {
ERR("Stream create failed %x\n",hres);
return hres;
}
hres = IStream_Write(pStm,buf->base+buf->curoff,xsize,&res);
if (hres) {
ERR("stream write %x\n",hres);
return hres;
}
memset(&seekto,0,sizeof(seekto));
hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
if (hres) {
ERR("Failed Seek %x\n",hres);
return hres;
}
hres = CoUnmarshalInterface(pStm,riid,(LPVOID*)pUnk);
if (hres) {
ERR("Unmarshalling interface %s failed with %x\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) {
LPBYTE tempbuf = NULL;
IStream *pStm = NULL;
STATSTG ststg;
ULARGE_INTEGER newpos;
LARGE_INTEGER seekto;
ULONG res;
DWORD xsize;
HRESULT hres;
if (!pUnk) {
/* this is valid, if for instance we serialize
* a VT_DISPATCH with NULL ptr which apparently
* can happen. S_OK to make sure we continue
* serializing.
*/
WARN("pUnk is NULL\n");
xsize = 0;
return xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
}
hres = E_FAIL;
TRACE("...%s...\n",debugstr_guid(riid));
hres = CreateStreamOnHGlobal(0,TRUE,&pStm);
if (hres) {
ERR("Stream create failed %x\n",hres);
goto fail;
}
hres = CoMarshalInterface(pStm,riid,pUnk,0,NULL,0);
if (hres) {
ERR("Marshalling interface %s failed with %x\n", debugstr_guid(riid), hres);
goto fail;
}
hres = IStream_Stat(pStm,&ststg,0);
if (hres) {
ERR("Stream stat failed\n");
goto fail;
}
tempbuf = HeapAlloc(GetProcessHeap(), 0, ststg.cbSize.u.LowPart);
memset(&seekto,0,sizeof(seekto));
hres = IStream_Seek(pStm,seekto,SEEK_SET,&newpos);
if (hres) {
ERR("Failed Seek %x\n",hres);
goto fail;
}
hres = IStream_Read(pStm,tempbuf,ststg.cbSize.u.LowPart,&res);
if (hres) {
ERR("Failed Read %x\n",hres);
goto fail;
}
xsize = ststg.cbSize.u.LowPart;
xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
hres = xbuf_add(buf,tempbuf,ststg.cbSize.u.LowPart);
HeapFree(GetProcessHeap(),0,tempbuf);
IStream_Release(pStm);
return hres;
fail:
xsize = 0;
xbuf_add(buf,(LPBYTE)&xsize,sizeof(xsize));
if (pStm) IUnknown_Release(pStm);
HeapFree(GetProcessHeap(), 0, tempbuf);
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;
LONG tlfnlen;
ITypeLib *tl;
sprintf( interfacekey, "Interface\\{%08x-%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)) {
ERR("No %s key found.\n",interfacekey);
return E_FAIL;
}
tlguidlen = sizeof(tlguid);
if (RegQueryValueExA(ikey,NULL,NULL,&type,(LPBYTE)tlguid,&tlguidlen)) {
ERR("Getting typelib guid failed.\n");
RegCloseKey(ikey);
return E_FAIL;
}
verlen = sizeof(ver);
if (RegQueryValueExA(ikey,"Version",NULL,&type,(LPBYTE)ver,&verlen)) {
ERR("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)) {
ERR("Could not get typelib fn?\n");
return E_FAIL;
}
MultiByteToWideChar(CP_ACP, 0, tlfn, -1, tlfnW, sizeof(tlfnW) / sizeof(tlfnW[0]));
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;
}
ITypeLib_Release(tl);
return hres;
}
/*
* Determine the number of functions including all inherited functions.
* Note for non-dual dispinterfaces we simply return the size of IDispatch.
*/
static HRESULT num_of_funcs(ITypeInfo *tinfo, unsigned int *num)
{
HRESULT hres;
TYPEATTR *attr;
ITypeInfo *tinfo2;
*num = 0;
hres = ITypeInfo_GetTypeAttr(tinfo, &attr);
if (hres) {
ERR("GetTypeAttr failed with %x\n",hres);
return hres;
}
if(attr->typekind == TKIND_DISPATCH && (attr->wTypeFlags & TYPEFLAG_FDUAL))
{
HREFTYPE href;
hres = ITypeInfo_GetRefTypeOfImplType(tinfo, -1, &href);
if(FAILED(hres))
{
ERR("Unable to get interface href from dual dispinterface\n");
goto end;
}
hres = ITypeInfo_GetRefTypeInfo(tinfo, href, &tinfo2);
if(FAILED(hres))
{
ERR("Unable to get interface from dual dispinterface\n");
goto end;
}
hres = num_of_funcs(tinfo2, num);
ITypeInfo_Release(tinfo2);
}
else
{
*num = attr->cbSizeVft / 4;
}
end:
ITypeInfo_ReleaseTypeAttr(tinfo, attr);
return hres;
}
#ifdef __i386__
#include "pshpack1.h"
typedef struct _TMAsmProxy {
BYTE popleax;
BYTE pushlval;
BYTE nr;
BYTE pushleax;
BYTE lcall;
DWORD xcall;
BYTE lret;
WORD bytestopop;
} TMAsmProxy;
#include "poppack.h"
#else /* __i386__ */
# warning You need to implement stubless proxies for your architecture
typedef struct _TMAsmProxy {
} TMAsmProxy;
#endif
typedef struct _TMProxyImpl {
LPVOID *lpvtbl;
const IRpcProxyBufferVtbl *lpvtbl2;
LONG ref;
TMAsmProxy *asmstubs;
ITypeInfo* tinfo;
IRpcChannelBuffer* chanbuf;
IID iid;
CRITICAL_SECTION crit;
IUnknown *outerunknown;
IDispatch *dispatch;
IRpcProxyBuffer *dispatch_proxy;
} 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);
ULONG refCount = InterlockedIncrement(&This->ref);
TRACE("(%p)->(ref before=%u)\n",This, refCount - 1);
return refCount;
}
static ULONG WINAPI
TMProxyImpl_Release(LPRPCPROXYBUFFER iface)
{
ICOM_THIS_MULTI(TMProxyImpl,lpvtbl2,iface);
ULONG refCount = InterlockedDecrement(&This->ref);
TRACE("(%p)->(ref before=%u)\n",This, refCount + 1);
if (!refCount)
{
if (This->dispatch_proxy) IRpcProxyBuffer_Release(This->dispatch_proxy);
This->crit.DebugInfo->Spare[0] = 0;
DeleteCriticalSection(&This->crit);
if (This->chanbuf) IRpcChannelBuffer_Release(This->chanbuf);
VirtualFree(This->asmstubs, 0, MEM_RELEASE);
HeapFree(GetProcessHeap(), 0, This->lpvtbl);
ITypeInfo_Release(This->tinfo);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -