Commit 44360823 authored by Nikolay Sivov's avatar Nikolay Sivov Committed by Alexandre Julliard

oleaut32: Use WdtpInterfacePointer_* functions in VARIANT marshalling.

parent 52d30cc3
......@@ -472,6 +472,17 @@ static void test_marshal_HMETAFILEPICT(void)
HMETAFILEPICT_UserFree(&umcb.Flags, &hmfp2);
}
typedef struct
{
IUnknown IUnknown_iface;
LONG refs;
} TestUnknown;
static inline TestUnknown *impl_from_IUnknown(IUnknown *iface)
{
return CONTAINING_RECORD(iface, TestUnknown, IUnknown_iface);
}
static HRESULT WINAPI Test_IUnknown_QueryInterface(
LPUNKNOWN iface,
REFIID riid,
......@@ -492,12 +503,14 @@ static HRESULT WINAPI Test_IUnknown_QueryInterface(
static ULONG WINAPI Test_IUnknown_AddRef(LPUNKNOWN iface)
{
return 2; /* non-heap-based object */
TestUnknown *This = impl_from_IUnknown(iface);
return InterlockedIncrement(&This->refs);
}
static ULONG WINAPI Test_IUnknown_Release(LPUNKNOWN iface)
{
return 1; /* non-heap-based object */
TestUnknown *This = impl_from_IUnknown(iface);
return InterlockedDecrement(&This->refs);
}
static const IUnknownVtbl TestUnknown_Vtbl =
......@@ -542,7 +555,7 @@ static const IStreamVtbl TestStream_Vtbl =
/* the rest can be NULLs */
};
static IUnknown Test_Unknown = { &TestUnknown_Vtbl };
static TestUnknown Test_Unknown = { {&TestUnknown_Vtbl}, 1 };
static IStream Test_Stream = { &TestStream_Vtbl };
ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG *, ULONG, ULONG, IUnknown *, REFIID);
......@@ -582,7 +595,8 @@ static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx)
/* Now for a non-NULL pointer. The marshalled data are two size DWORDS and then
the result of CoMarshalInterface called with the LOWORD of the ctx */
unk = &Test_Unknown;
unk = &Test_Unknown.IUnknown_iface;
Test_Unknown.refs = 1;
CreateStreamOnHGlobal(h, TRUE, &stm);
CoMarshalInterface(stm, &IID_IUnknown, unk, LOWORD(ctx), NULL, MSHLFLAGS_NORMAL);
......@@ -591,6 +605,8 @@ static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx)
marshal_size = pos.u.LowPart;
marshal_data = GlobalLock(h);
trace("marshal_size %x\n", marshal_size);
todo_wine
ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, umcb_ctx);
size = WdtpInterfacePointer_UserSize(&umcb.Flags, ctx, 0, unk, &IID_IUnknown);
......@@ -599,6 +615,8 @@ static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx)
buffer = HeapAlloc(GetProcessHeap(), 0, size);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx);
buffer_end = WdtpInterfacePointer_UserMarshal(&umcb.Flags, ctx, buffer, unk, &IID_IUnknown);
todo_wine
ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs);
wireip = buffer;
ok(buffer_end == buffer + marshal_size + 2 * sizeof(DWORD), "buffer_end %p buffer %p\n", buffer_end, buffer);
......@@ -619,6 +637,7 @@ static void marshal_WdtpInterfacePointer(DWORD umcb_ctx, DWORD ctx)
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, buffer, size, umcb_ctx);
WdtpInterfacePointer_UserUnmarshal(&umcb.Flags, buffer, &unk2, &IID_IUnknown);
ok(unk2 != NULL, "IUnknown object didn't unmarshal properly\n");
ok(Test_Unknown.refs == 2, "got %d\n", Test_Unknown.refs);
HeapFree(GetProcessHeap(), 0, buffer);
init_user_marshal_cb(&umcb, &stub_msg, &rpc_msg, NULL, 0, MSHCTX_INPROC);
IUnknown_Release(unk2);
......@@ -651,7 +670,7 @@ static void test_marshal_STGMEDIUM(void)
unsigned char *buffer, *buffer_end, *expect_buffer, *expect_buffer_end;
ULONG size, expect_size;
STGMEDIUM med, med2;
IUnknown *unk = &Test_Unknown;
IUnknown *unk = &Test_Unknown.IUnknown_iface;
IStream *stm = &Test_Stream;
/* TYMED_NULL with pUnkForRelease */
......
......@@ -1386,31 +1386,31 @@ static void test_marshal_VARIANT(void)
V_UNKNOWN(&v) = &heap_unknown->IUnknown_iface;
rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
ok(stubMsg.BufferLength > 32, "size %d\n", stubMsg.BufferLength);
ok(stubMsg.BufferLength > 40, "size %d\n", stubMsg.BufferLength);
buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
memset(buffer, 0xcc, stubMsg.BufferLength);
next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
todo_wine
ok(heap_unknown->refs == 2, "got refcount %d\n", heap_unknown->refs);
wirev = (DWORD*)buffer;
wirev = check_variant_header(wirev, &v, next - buffer);
todo_wine
ok(*wirev == (DWORD_PTR)V_UNKNOWN(&v) /* Win9x */ ||
*wirev == (DWORD_PTR)V_UNKNOWN(&v) + 1 /* NT */, "wv[5] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == next - buffer - 0x20, "wv[6] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == next - buffer - 0x20, "wv[7] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == 0x574f454d, "wv[8] %08x\n", *wirev);
VariantInit(&v3);
V_VT(&v3) = VT_UNKNOWN;
V_UNKNOWN(&v3) = &heap_unknown->IUnknown_iface;
IUnknown_AddRef(V_UNKNOWN(&v3));
stubMsg.Buffer = buffer;
todo_wine
ok(heap_unknown->refs == 3, "got refcount %d\n", heap_unknown->refs);
next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
ok(V_UNKNOWN(&v) == V_UNKNOWN(&v3), "got %p expect %p\n", V_UNKNOWN(&v), V_UNKNOWN(&v3));
......@@ -1452,27 +1452,26 @@ static void test_marshal_VARIANT(void)
V_UNKNOWNREF(&v) = (IUnknown **)&heap_unknown;
rpcMsg.BufferLength = stubMsg.BufferLength = VARIANT_UserSize(&umcb.Flags, 0, &v);
ok(stubMsg.BufferLength > 36, "size %d\n", stubMsg.BufferLength);
ok(stubMsg.BufferLength >= 44, "size %d\n", stubMsg.BufferLength);
buffer = rpcMsg.Buffer = stubMsg.Buffer = stubMsg.BufferStart = alloc_aligned(stubMsg.BufferLength, &oldbuffer);
stubMsg.BufferEnd = stubMsg.Buffer + stubMsg.BufferLength;
memset(buffer, 0xcc, stubMsg.BufferLength);
ok(heap_unknown->refs == 1, "got refcount %d\n", heap_unknown->refs);
next = VARIANT_UserMarshal(&umcb.Flags, buffer, &v);
todo_wine
ok(heap_unknown->refs == 2, "got refcount %d\n", heap_unknown->refs);
wirev = (DWORD*)buffer;
wirev = check_variant_header(wirev, &v, next - buffer);
ok(*wirev == 4, "wv[5] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == (DWORD_PTR)heap_unknown /* Win9x, Win2000 */ ||
*wirev == (DWORD_PTR)heap_unknown + 1 /* XP */, "wv[6] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == next - buffer - 0x24, "wv[7] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == next - buffer - 0x24, "wv[8] %08x\n", *wirev);
wirev++;
todo_wine
ok(*wirev == 0x574f454d, "wv[9] %08x\n", *wirev);
VariantInit(&v3);
......@@ -1481,6 +1480,7 @@ static void test_marshal_VARIANT(void)
IUnknown_AddRef(V_UNKNOWN(&v3));
stubMsg.Buffer = buffer;
next = VARIANT_UserUnmarshal(&umcb.Flags, buffer, &v3);
ok(heap_unknown->refs == 2, "got refcount %d\n", heap_unknown->refs);
ok(V_VT(&v) == V_VT(&v3), "got vt %d expect %d\n", V_VT(&v), V_VT(&v3));
ok(*V_UNKNOWNREF(&v) == *V_UNKNOWNREF(&v3), "got %p expect %p\n", *V_UNKNOWNREF(&v), *V_UNKNOWNREF(&v3));
VARIANT_UserFree(&umcb.Flags, &v3);
......
......@@ -45,6 +45,11 @@ WINE_DEFAULT_DEBUG_CHANNEL(ole);
#define ALIGN_LENGTH(_Len, _Align) _Len = ALIGNED_LENGTH(_Len, _Align)
#define ALIGN_POINTER(_Ptr, _Align) _Ptr = ALIGNED_POINTER(_Ptr, _Align)
/* ole32 exports those, not defined in public headers */
ULONG __RPC_USER WdtpInterfacePointer_UserSize(ULONG*, ULONG, ULONG, IUnknown*, REFIID);
unsigned char * __RPC_USER WdtpInterfacePointer_UserMarshal(ULONG*, ULONG, unsigned char*, IUnknown*, REFIID);
unsigned char * __RPC_USER WdtpInterfacePointer_UserUnmarshal(ULONG*, unsigned char*, IUnknown**, REFIID);
static void dump_user_flags(const ULONG *pFlags)
{
if (HIWORD(*pFlags) == NDR_LOCAL_DATA_REPRESENTATION)
......@@ -256,21 +261,21 @@ static unsigned int get_type_alignment(ULONG *pFlags, VARTYPE vt)
return 7;
}
static unsigned interface_variant_size(const ULONG *pFlags, REFIID riid, IUnknown *punk)
/* WdtpInterfacePointer_UserSize takes care of 2 additional DWORDs to store marshalling buffer size */
static unsigned interface_variant_size(ULONG *pFlags, REFIID riid, IUnknown *punk)
{
ULONG size = 0;
HRESULT hr;
if (punk)
{
hr = CoGetMarshalSizeMax(&size, riid, punk, LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
if (FAILED(hr))
size = WdtpInterfacePointer_UserSize(pFlags, LOWORD(*pFlags), 0, punk, riid);
if (!size)
{
ERR("interface variant buffer size calculation failed, HRESULT=0x%x\n", hr);
ERR("interface variant buffer size calculation failed\n");
return 0;
}
}
size += sizeof(ULONG); /* we have to store the buffersize in the stream */
size += sizeof(ULONG);
TRACE("wire-size extra of interface variant is %d\n", size);
return size;
}
......@@ -312,116 +317,48 @@ static ULONG wire_extra_user_size(ULONG *pFlags, ULONG Start, VARIANT *pvar)
}
}
/* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer. returns Buffer on failure, new position otherwise */
static unsigned char* interface_variant_marshal(const ULONG *pFlags, unsigned char *Buffer,
/* helper: called for VT_DISPATCH variants to marshal the IDispatch* into the buffer */
static unsigned char* interface_variant_marshal(ULONG *pFlags, unsigned char *Buffer,
REFIID riid, IUnknown *punk)
{
IStream *working;
HGLOBAL working_mem;
void *working_memlocked;
unsigned char *oldpos;
ULONG size;
HRESULT hr;
TRACE("pFlags=%d, Buffer=%p, pUnk=%p\n", *pFlags, Buffer, punk);
/* first DWORD is used to store pointer itself, truncated on win64 */
if(!punk)
{
memset(Buffer, 0, sizeof(ULONG));
return Buffer + sizeof(ULONG);
}
oldpos = Buffer;
/* CoMarshalInterface needs a stream, whereas at this level we are operating in terms of buffers.
* We create a stream on an HGLOBAL, so we can simply do a memcpy to move it to the buffer.
* in rpcrt4/ndr_ole.c, a simple IStream implementation is wrapped around the buffer object,
* but that would be overkill here, hence this implementation. We save the size because the unmarshal
* code has no way to know how long the marshalled buffer is. */
size = interface_variant_size(pFlags, riid, punk);
working_mem = GlobalAlloc(0, size);
if (!working_mem) return oldpos;
hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
if (hr != S_OK) {
GlobalFree(working_mem);
return oldpos;
}
hr = CoMarshalInterface(working, riid, punk, LOWORD(*pFlags), NULL, MSHLFLAGS_NORMAL);
if (hr != S_OK) {
IStream_Release(working); /* this also releases the hglobal */
return oldpos;
else
{
*(DWORD*)Buffer = (DWORD_PTR)punk;
Buffer += sizeof(DWORD);
}
working_memlocked = GlobalLock(working_mem);
memcpy(Buffer, &size, sizeof(ULONG)); /* copy the buffersize */
memcpy(Buffer + sizeof(ULONG), working_memlocked, size - sizeof(ULONG));
GlobalUnlock(working_mem);
IStream_Release(working);
/* size includes the ULONG for the size written above */
TRACE("done, size=%d\n", size);
return Buffer + size;
return WdtpInterfacePointer_UserMarshal(pFlags, LOWORD(*pFlags), Buffer, punk, riid);
}
/* helper: called for VT_DISPATCH / VT_UNKNOWN variants to unmarshal the buffer. returns Buffer on failure, new position otherwise */
static unsigned char *interface_variant_unmarshal(const ULONG *pFlags, unsigned char *Buffer,
/* helper: called for VT_DISPATCH / VT_UNKNOWN variants to unmarshal the buffer */
static unsigned char *interface_variant_unmarshal(ULONG *pFlags, unsigned char *Buffer,
REFIID riid, IUnknown **ppunk)
{
IStream *working;
HGLOBAL working_mem;
void *working_memlocked;
unsigned char *oldpos;
ULONG size;
HRESULT hr;
DWORD ptr;
TRACE("pFlags=%d, Buffer=%p, ppUnk=%p\n", *pFlags, Buffer, ppunk);
oldpos = Buffer;
/* skip pointer part itself */
ptr = *(DWORD*)Buffer;
Buffer += sizeof(DWORD);
/* get the buffersize */
memcpy(&size, Buffer, sizeof(ULONG));
TRACE("buffersize=%d\n", size);
if(!size)
if(!ptr)
{
*ppunk = NULL;
return Buffer + sizeof(ULONG);
}
working_mem = GlobalAlloc(0, size);
if (!working_mem) return oldpos;
hr = CreateStreamOnHGlobal(working_mem, TRUE, &working);
if (hr != S_OK) {
GlobalFree(working_mem);
return oldpos;
return Buffer;
}
working_memlocked = GlobalLock(working_mem);
/* now we copy the contents of the marshalling buffer to working_memlocked, unlock it, and demarshal the stream */
memcpy(working_memlocked, Buffer + sizeof(ULONG), size);
GlobalUnlock(working_mem);
hr = CoUnmarshalInterface(working, riid, (void**)ppunk);
if (hr != S_OK) {
IStream_Release(working);
return oldpos;
}
IStream_Release(working); /* this also frees the underlying hglobal */
/* size includes the ULONG for the size written above */
TRACE("done, processed=%d bytes\n", size);
return Buffer + size;
return WdtpInterfacePointer_UserUnmarshal(pFlags, Buffer, ppunk, riid);
}
ULONG WINAPI VARIANT_UserSize(ULONG *pFlags, ULONG Start, VARIANT *pvar)
{
int align;
......@@ -519,19 +456,15 @@ unsigned char * WINAPI VARIANT_UserMarshal(ULONG *pFlags, unsigned char *Buffer,
Pos = VARIANT_UserMarshal(pFlags, Pos, V_VARIANTREF(pvar));
break;
case VT_UNKNOWN:
/* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
Pos = interface_variant_marshal(pFlags, Pos, &IID_IUnknown, V_UNKNOWN(pvar));
break;
case VT_UNKNOWN | VT_BYREF:
/* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
Pos = interface_variant_marshal(pFlags, Pos, &IID_IUnknown, *V_UNKNOWNREF(pvar));
break;
case VT_DISPATCH:
/* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
Pos = interface_variant_marshal(pFlags, Pos, &IID_IDispatch, (IUnknown*)V_DISPATCH(pvar));
break;
case VT_DISPATCH | VT_BYREF:
/* this should probably call WdtpInterfacePointer_UserMarshal in ole32.dll */
Pos = interface_variant_marshal(pFlags, Pos, &IID_IDispatch, (IUnknown*)*V_DISPATCHREF(pvar));
break;
case VT_RECORD:
......@@ -634,19 +567,15 @@ unsigned char * WINAPI VARIANT_UserUnmarshal(ULONG *pFlags, unsigned char *Buffe
Pos = VARIANT_UserUnmarshal(pFlags, Pos, V_VARIANTREF(pvar));
break;
case VT_UNKNOWN:
/* this should probably call WdtpInterfacePointer_UserUnmarshal in ole32.dll */
Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IUnknown, &V_UNKNOWN(pvar));
break;
case VT_UNKNOWN | VT_BYREF:
/* this should probably call WdtpInterfacePointer_UserUnmarshal in ole32.dll */
Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IUnknown, V_UNKNOWNREF(pvar));
break;
case VT_DISPATCH:
/* this should probably call WdtpInterfacePointer_UserUnmarshal in ole32.dll */
Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IDispatch, (IUnknown**)&V_DISPATCH(pvar));
break;
case VT_DISPATCH | VT_BYREF:
/* this should probably call WdtpInterfacePointer_UserUnmarshal in ole32.dll */
Pos = interface_variant_unmarshal(pFlags, Pos, &IID_IDispatch, (IUnknown**)V_DISPATCHREF(pvar));
break;
case VT_RECORD:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment