Sweden-Number/dlls/combase/marshal.c

510 lines
15 KiB
C

/*
* Copyright 2002 Juergen Schmied
* Copyright 2002 Marcus Meissner
* Copyright 2004 Mike Hearn, for CodeWeavers
* Copyright 2004 Rob Shearman, for CodeWeavers
*
* 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
*/
#define COBJMACROS
#include "objbase.h"
#include "combase_private.h"
#include "wine/debug.h"
#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(ole);
struct ftmarshaler
{
IUnknown IUnknown_inner;
IMarshal IMarshal_iface;
IUnknown *outer_unk;
LONG refcount;
};
static struct ftmarshaler *impl_ft_from_IUnknown(IUnknown *iface)
{
return CONTAINING_RECORD(iface, struct ftmarshaler, IUnknown_inner);
}
static struct ftmarshaler *impl_ft_from_IMarshal(IMarshal *iface)
{
return CONTAINING_RECORD(iface, struct ftmarshaler, IMarshal_iface);
}
/***********************************************************************
* CoMarshalHresult (combase.@)
*/
HRESULT WINAPI CoMarshalHresult(IStream *stream, HRESULT hresult)
{
return IStream_Write(stream, &hresult, sizeof(hresult), NULL);
}
/***********************************************************************
* CoUnmarshalHresult (combase.@)
*/
HRESULT WINAPI CoUnmarshalHresult(IStream *stream, HRESULT *phresult)
{
return IStream_Read(stream, phresult, sizeof(*phresult), NULL);
}
/***********************************************************************
* CoGetInterfaceAndReleaseStream (combase.@)
*/
HRESULT WINAPI CoGetInterfaceAndReleaseStream(IStream *stream, REFIID riid, void **obj)
{
HRESULT hr;
TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), obj);
if (!stream) return E_INVALIDARG;
hr = CoUnmarshalInterface(stream, riid, obj);
IStream_Release(stream);
return hr;
}
/***********************************************************************
* CoMarshalInterThreadInterfaceInStream (combase.@)
*/
HRESULT WINAPI CoMarshalInterThreadInterfaceInStream(REFIID riid, IUnknown *unk, IStream **stream)
{
ULARGE_INTEGER xpos;
LARGE_INTEGER seekto;
HRESULT hr;
TRACE("%s, %p, %p\n", debugstr_guid(riid), unk, stream);
hr = CreateStreamOnHGlobal(NULL, TRUE, stream);
if (FAILED(hr)) return hr;
hr = CoMarshalInterface(*stream, riid, unk, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
if (SUCCEEDED(hr))
{
memset(&seekto, 0, sizeof(seekto));
IStream_Seek(*stream, seekto, STREAM_SEEK_SET, &xpos);
}
else
{
IStream_Release(*stream);
*stream = NULL;
}
return hr;
}
static HRESULT WINAPI ftmarshaler_inner_QueryInterface(IUnknown *iface, REFIID riid, void **obj)
{
struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj);
*obj = NULL;
if (IsEqualIID(&IID_IUnknown, riid))
*obj = &marshaler->IUnknown_inner;
else if (IsEqualIID(&IID_IMarshal, riid))
*obj = &marshaler->IMarshal_iface;
else
{
FIXME("No interface for %s\n", debugstr_guid(riid));
return E_NOINTERFACE;
}
IUnknown_AddRef((IUnknown *)*obj);
return S_OK;
}
static ULONG WINAPI ftmarshaler_inner_AddRef(IUnknown *iface)
{
struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
ULONG refcount = InterlockedIncrement(&marshaler->refcount);
TRACE("%p, refcount %u\n", iface, refcount);
return refcount;
}
static ULONG WINAPI ftmarshaler_inner_Release(IUnknown *iface)
{
struct ftmarshaler *marshaler = impl_ft_from_IUnknown(iface);
ULONG refcount = InterlockedDecrement(&marshaler->refcount);
TRACE("%p, refcount %u\n", iface, refcount);
if (!refcount)
heap_free(marshaler);
return refcount;
}
static const IUnknownVtbl ftmarshaler_inner_vtbl =
{
ftmarshaler_inner_QueryInterface,
ftmarshaler_inner_AddRef,
ftmarshaler_inner_Release
};
static HRESULT WINAPI ftmarshaler_QueryInterface(IMarshal *iface, REFIID riid, void **obj)
{
struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj);
return IUnknown_QueryInterface(marshaler->outer_unk, riid, obj);
}
static ULONG WINAPI ftmarshaler_AddRef(IMarshal *iface)
{
struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
TRACE("%p\n", iface);
return IUnknown_AddRef(marshaler->outer_unk);
}
static ULONG WINAPI ftmarshaler_Release(IMarshal *iface)
{
struct ftmarshaler *marshaler = impl_ft_from_IMarshal(iface);
TRACE("%p\n", iface);
return IUnknown_Release(marshaler->outer_unk);
}
static HRESULT WINAPI ftmarshaler_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv,
DWORD dest_context, void *pvDestContext, DWORD mshlflags, CLSID *clsid)
{
TRACE("%s, %p, %#x, %p, %#x, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, clsid);
if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
*clsid = CLSID_InProcFreeMarshaler;
else
*clsid = CLSID_StdMarshal;
return S_OK;
}
static HRESULT WINAPI ftmarshaler_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv,
DWORD dest_context, void *pvDestContext, DWORD mshlflags, DWORD *size)
{
IMarshal *marshal = NULL;
HRESULT hr;
TRACE("%s, %p, %#x, %p, %#x, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, size);
/* If the marshalling happens inside the same process the interface pointer is
copied between the apartments */
if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
{
*size = sizeof(mshlflags) + sizeof(pv) + sizeof(DWORD) + sizeof(GUID);
return S_OK;
}
/* Use the standard marshaller to handle all other cases */
CoGetStandardMarshal(riid, pv, dest_context, pvDestContext, mshlflags, &marshal);
hr = IMarshal_GetMarshalSizeMax(marshal, riid, pv, dest_context, pvDestContext, mshlflags, size);
IMarshal_Release(marshal);
return hr;
}
static HRESULT WINAPI ftmarshaler_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid,
void *pv, DWORD dest_context, void *pvDestContext, DWORD mshlflags)
{
IMarshal *marshal = NULL;
HRESULT hr;
TRACE("%p, %s, %p, %#x, %p, %#x\n", stream, debugstr_guid(riid), pv,
dest_context, pvDestContext, mshlflags);
/* If the marshalling happens inside the same process the interface pointer is
copied between the apartments */
if (dest_context == MSHCTX_INPROC || dest_context == MSHCTX_CROSSCTX)
{
void *object;
DWORD constant = 0;
GUID unknown_guid = { 0 };
hr = IUnknown_QueryInterface((IUnknown *)pv, riid, &object);
if (FAILED(hr))
return hr;
/* don't hold a reference to table-weak marshaled interfaces */
if (mshlflags & MSHLFLAGS_TABLEWEAK)
IUnknown_Release((IUnknown *)object);
hr = IStream_Write(stream, &mshlflags, sizeof(mshlflags), NULL);
if (hr != S_OK) return STG_E_MEDIUMFULL;
hr = IStream_Write(stream, &object, sizeof(object), NULL);
if (hr != S_OK) return STG_E_MEDIUMFULL;
if (sizeof(object) == sizeof(DWORD))
{
hr = IStream_Write(stream, &constant, sizeof(constant), NULL);
if (hr != S_OK) return STG_E_MEDIUMFULL;
}
hr = IStream_Write(stream, &unknown_guid, sizeof(unknown_guid), NULL);
if (hr != S_OK) return STG_E_MEDIUMFULL;
return S_OK;
}
/* Use the standard marshaler to handle all other cases */
CoGetStandardMarshal(riid, pv, dest_context, pvDestContext, mshlflags, &marshal);
hr = IMarshal_MarshalInterface(marshal, stream, riid, pv, dest_context, pvDestContext, mshlflags);
IMarshal_Release(marshal);
return hr;
}
static HRESULT WINAPI ftmarshaler_UnmarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void **ppv)
{
DWORD mshlflags;
IUnknown *object;
DWORD constant;
GUID unknown_guid;
HRESULT hr;
TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv);
hr = IStream_Read(stream, &mshlflags, sizeof(mshlflags), NULL);
if (hr != S_OK) return STG_E_READFAULT;
hr = IStream_Read(stream, &object, sizeof(object), NULL);
if (hr != S_OK) return STG_E_READFAULT;
if (sizeof(object) == sizeof(DWORD))
{
hr = IStream_Read(stream, &constant, sizeof(constant), NULL);
if (hr != S_OK) return STG_E_READFAULT;
if (constant != 0)
FIXME("constant is 0x%x instead of 0\n", constant);
}
hr = IStream_Read(stream, &unknown_guid, sizeof(unknown_guid), NULL);
if (hr != S_OK) return STG_E_READFAULT;
hr = IUnknown_QueryInterface(object, riid, ppv);
if (!(mshlflags & (MSHLFLAGS_TABLEWEAK | MSHLFLAGS_TABLESTRONG)))
IUnknown_Release(object);
return hr;
}
static HRESULT WINAPI ftmarshaler_ReleaseMarshalData(IMarshal *iface, IStream *stream)
{
DWORD mshlflags;
IUnknown *object;
DWORD constant;
GUID unknown_guid;
HRESULT hr;
TRACE("%p\n", stream);
hr = IStream_Read(stream, &mshlflags, sizeof(mshlflags), NULL);
if (hr != S_OK) return STG_E_READFAULT;
hr = IStream_Read(stream, &object, sizeof(object), NULL);
if (hr != S_OK) return STG_E_READFAULT;
if (sizeof(object) == sizeof(DWORD))
{
hr = IStream_Read(stream, &constant, sizeof(constant), NULL);
if (hr != S_OK) return STG_E_READFAULT;
if (constant != 0)
FIXME("constant is 0x%x instead of 0\n", constant);
}
hr = IStream_Read(stream, &unknown_guid, sizeof(unknown_guid), NULL);
if (hr != S_OK) return STG_E_READFAULT;
IUnknown_Release(object);
return S_OK;
}
static HRESULT WINAPI ftmarshaler_DisconnectObject(IMarshal *iface, DWORD reserved)
{
TRACE("\n");
/* nothing to do */
return S_OK;
}
static const IMarshalVtbl ftmarshaler_vtbl =
{
ftmarshaler_QueryInterface,
ftmarshaler_AddRef,
ftmarshaler_Release,
ftmarshaler_GetUnmarshalClass,
ftmarshaler_GetMarshalSizeMax,
ftmarshaler_MarshalInterface,
ftmarshaler_UnmarshalInterface,
ftmarshaler_ReleaseMarshalData,
ftmarshaler_DisconnectObject
};
/***********************************************************************
* CoCreateFreeThreadedMarshaler (combase.@)
*/
HRESULT WINAPI CoCreateFreeThreadedMarshaler(IUnknown *outer, IUnknown **marshaler)
{
struct ftmarshaler *object;
TRACE("%p, %p\n", outer, marshaler);
object = heap_alloc(sizeof(*object));
if (!object)
return E_OUTOFMEMORY;
object->IUnknown_inner.lpVtbl = &ftmarshaler_inner_vtbl;
object->IMarshal_iface.lpVtbl = &ftmarshaler_vtbl;
object->refcount = 1;
object->outer_unk = outer ? outer : &object->IUnknown_inner;
*marshaler = &object->IUnknown_inner;
return S_OK;
}
/***********************************************************************
* CoGetMarshalSizeMax (combase.@)
*/
HRESULT WINAPI CoGetMarshalSizeMax(ULONG *size, REFIID riid, IUnknown *unk,
DWORD dest_context, void *pvDestContext, DWORD mshlFlags)
{
BOOL std_marshal = FALSE;
IMarshal *marshal;
HRESULT hr;
if (!unk)
return E_POINTER;
hr = IUnknown_QueryInterface(unk, &IID_IMarshal, (void **)&marshal);
if (hr != S_OK)
{
std_marshal = TRUE;
hr = CoGetStandardMarshal(riid, unk, dest_context, pvDestContext, mshlFlags, &marshal);
}
if (hr != S_OK)
return hr;
hr = IMarshal_GetMarshalSizeMax(marshal, riid, unk, dest_context, pvDestContext, mshlFlags, size);
if (!std_marshal)
/* add on the size of the whole OBJREF structure like native does */
*size += sizeof(OBJREF);
IMarshal_Release(marshal);
return hr;
}
static void dump_mshflags(MSHLFLAGS flags)
{
if (flags & MSHLFLAGS_TABLESTRONG)
TRACE(" MSHLFLAGS_TABLESTRONG");
if (flags & MSHLFLAGS_TABLEWEAK)
TRACE(" MSHLFLAGS_TABLEWEAK");
if (!(flags & (MSHLFLAGS_TABLESTRONG|MSHLFLAGS_TABLEWEAK)))
TRACE(" MSHLFLAGS_NORMAL");
if (flags & MSHLFLAGS_NOPING)
TRACE(" MSHLFLAGS_NOPING");
}
/***********************************************************************
* CoMarshalInterface (combase.@)
*/
HRESULT WINAPI CoMarshalInterface(IStream *stream, REFIID riid, IUnknown *unk,
DWORD dest_context, void *pvDestContext, DWORD mshlFlags)
{
CLSID marshaler_clsid;
IMarshal *marshal;
HRESULT hr;
TRACE("%p, %s, %p, %x, %p, ", stream, debugstr_guid(riid), unk, dest_context, pvDestContext);
dump_mshflags(mshlFlags);
TRACE("\n");
if (!unk || !stream)
return E_INVALIDARG;
hr = IUnknown_QueryInterface(unk, &IID_IMarshal, (void **)&marshal);
if (hr != S_OK)
hr = CoGetStandardMarshal(riid, unk, dest_context, pvDestContext, mshlFlags, &marshal);
if (hr != S_OK)
{
ERR("Failed to get marshaller, %#x\n", hr);
return hr;
}
hr = IMarshal_GetUnmarshalClass(marshal, riid, unk, dest_context, pvDestContext, mshlFlags,
&marshaler_clsid);
if (hr != S_OK)
{
ERR("IMarshal::GetUnmarshalClass failed, %#x\n", hr);
goto cleanup;
}
/* FIXME: implement handler marshaling too */
if (IsEqualCLSID(&marshaler_clsid, &CLSID_StdMarshal))
{
TRACE("Using standard marshaling\n");
}
else
{
OBJREF objref;
TRACE("Using custom marshaling\n");
objref.signature = OBJREF_SIGNATURE;
objref.iid = *riid;
objref.flags = OBJREF_CUSTOM;
objref.u_objref.u_custom.clsid = marshaler_clsid;
objref.u_objref.u_custom.cbExtension = 0;
objref.u_objref.u_custom.size = 0;
hr = IMarshal_GetMarshalSizeMax(marshal, riid, unk, dest_context, pvDestContext, mshlFlags,
&objref.u_objref.u_custom.size);
if (hr != S_OK)
{
ERR("Failed to get max size of marshal data, error %#x\n", hr);
goto cleanup;
}
/* write constant sized common header and OR_CUSTOM data into stream */
hr = IStream_Write(stream, &objref, FIELD_OFFSET(OBJREF, u_objref.u_custom.pData), NULL);
if (hr != S_OK)
{
ERR("Failed to write OR_CUSTOM header to stream with %#x\n", hr);
goto cleanup;
}
}
TRACE("Calling IMarshal::MarshalInterface\n");
hr = IMarshal_MarshalInterface(marshal, stream, riid, unk, dest_context, pvDestContext, mshlFlags);
if (hr != S_OK)
{
ERR("Failed to marshal the interface %s, hr %#x\n", debugstr_guid(riid), hr);
goto cleanup;
}
cleanup:
IMarshal_Release(marshal);
TRACE("completed with hr %#x\n", hr);
return hr;
}