509 lines
15 KiB
C
509 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 "wine/debug.h"
|
|
#include "wine/heap.h"
|
|
#include "wine/orpc.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;
|
|
}
|