⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 tmarshal.c

📁 这是一个开放源代码的与WINNT/WIN2K/WIN2003兼容的操作系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
 *	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 + -