ole32: Handle extra class moniker data on load/save.

Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Nikolay Sivov 2021-09-14 11:47:56 +03:00 committed by Alexandre Julliard
parent 7013f068f3
commit 44d57a615f
2 changed files with 91 additions and 25 deletions

View File

@ -30,6 +30,7 @@
#include "winbase.h"
#include "winuser.h"
#include "wine/debug.h"
#include "wine/heap.h"
#include "ole2.h"
#include "moniker.h"
@ -49,6 +50,7 @@ typedef struct ClassMoniker
CLSID clsid;
DWORD data_len;
} header;
WCHAR *data;
IUnknown *pMarshal; /* custom marshaler */
} ClassMoniker;
@ -126,23 +128,18 @@ static ULONG WINAPI ClassMoniker_AddRef(IMoniker* iface)
return InterlockedIncrement(&This->ref);
}
/******************************************************************************
* ClassMoniker_Release
******************************************************************************/
static ULONG WINAPI ClassMoniker_Release(IMoniker* iface)
{
ClassMoniker *This = impl_from_IMoniker(iface);
ULONG ref;
ClassMoniker *moniker = impl_from_IMoniker(iface);
ULONG ref = InterlockedDecrement(&moniker->ref);
TRACE("(%p)\n",This);
TRACE("%p refcount %d\n", iface, ref);
ref = InterlockedDecrement(&This->ref);
/* destroy the object if there are no more references to it */
if (ref == 0)
if (!ref)
{
if (This->pMarshal) IUnknown_Release(This->pMarshal);
HeapFree(GetProcessHeap(),0,This);
if (moniker->pMarshal) IUnknown_Release(moniker->pMarshal);
heap_free(moniker->data);
heap_free(moniker);
}
return ref;
@ -190,8 +187,15 @@ static HRESULT WINAPI ClassMoniker_Load(IMoniker *iface, IStream *stream)
if (moniker->header.data_len)
{
FIXME("Moniker data of length %u was ignored.\n", moniker->header.data_len);
moniker->header.data_len = 0;
heap_free(moniker->data);
if (!(moniker->data = heap_alloc(moniker->header.data_len)))
{
WARN("Failed to allocate moniker data of size %u.\n", moniker->header.data_len);
moniker->header.data_len = 0;
return E_OUTOFMEMORY;
}
hr = IStream_Read(stream, moniker->data, moniker->header.data_len, &length);
if (hr != S_OK || length != moniker->header.data_len) return STG_E_READFAULT;
}
return S_OK;
@ -200,21 +204,25 @@ static HRESULT WINAPI ClassMoniker_Load(IMoniker *iface, IStream *stream)
static HRESULT WINAPI ClassMoniker_Save(IMoniker *iface, IStream *stream, BOOL clear_dirty)
{
ClassMoniker *moniker = impl_from_IMoniker(iface);
HRESULT hr;
TRACE("%p, %p, %d\n", iface, stream, clear_dirty);
return IStream_Write(stream, &moniker->header, sizeof(moniker->header), NULL);
hr = IStream_Write(stream, &moniker->header, sizeof(moniker->header), NULL);
if (SUCCEEDED(hr) && moniker->header.data_len)
hr = IStream_Write(stream, moniker->data, moniker->header.data_len, NULL);
return hr;
}
/******************************************************************************
* ClassMoniker_GetSizeMax
******************************************************************************/
static HRESULT WINAPI ClassMoniker_GetSizeMax(IMoniker* iface,
ULARGE_INTEGER* pcbSize)/* Pointer to size of stream needed to save object */
static HRESULT WINAPI ClassMoniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *size)
{
TRACE("(%p)\n", pcbSize);
ClassMoniker *moniker = impl_from_IMoniker(iface);
pcbSize->QuadPart = sizeof(CLSID) + sizeof(DWORD);
TRACE("%p, %p\n", iface, size);
size->QuadPart = sizeof(moniker->header) + moniker->header.data_len;
return S_OK;
}
@ -500,13 +508,17 @@ static HRESULT WINAPI ClassMoniker_GetDisplayName(IMoniker *iface,
if (pmkToLeft)
return E_INVALIDARG;
if (!(*name = CoTaskMemAlloc(name_len * sizeof(WCHAR))))
if (!(*name = CoTaskMemAlloc(name_len * sizeof(WCHAR) + moniker->header.data_len)))
return E_OUTOFMEMORY;
swprintf(*name, name_len, L"clsid:%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X:",
swprintf(*name, name_len, L"clsid:%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
guid->Data1, guid->Data2, guid->Data3, guid->Data4[0], guid->Data4[1], guid->Data4[2],
guid->Data4[3], guid->Data4[4], guid->Data4[5], guid->Data4[6], guid->Data4[7]);
if (moniker->header.data_len)
lstrcatW(*name, moniker->data);
lstrcatW(*name, L":");
TRACE("Returning %s\n", debugstr_w(*name));
return S_OK;

View File

@ -1769,12 +1769,17 @@ static void test_class_moniker(void)
{
IMoniker *moniker, *moniker2, *inverse, *reduced, *anti;
IEnumMoniker *enummoniker;
ULONG length, eaten;
ULARGE_INTEGER size;
LARGE_INTEGER pos;
IROTData *rotdata;
HRESULT hr;
DWORD hash;
IBindCtx *bindctx;
IUnknown *unknown;
FILETIME filetime;
ULONG eaten;
IStream *stream;
BYTE buffer[100];
hr = CreateBindCtx(0, &bindctx);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
@ -1792,6 +1797,9 @@ todo_wine
TEST_DISPLAY_NAME(moniker, L"clsid:11111111-0000-0000-2222-444444444444;extra data:");
TEST_MONIKER_TYPE(moniker, MKSYS_CLASSMONIKER);
hr = IMoniker_GetSizeMax(moniker, &size);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(size.LowPart == 44, "Unexpected size %u.\n", size.LowPart);
TEST_MONIKER_TYPE(moniker2, MKSYS_CLASSMONIKER);
@ -1805,9 +1813,55 @@ todo_wine
IMoniker_Release(moniker);
}
/* From persistent state */
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = CreateClassMoniker(&GUID_NULL, &moniker);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMoniker_GetSizeMax(moniker, &size);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(size.QuadPart == 20, "Unexpected size %u.\n", size.LowPart);
hr = IStream_Write(stream, &CLSID_StdComponentCategoriesMgr, sizeof(CLSID), NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
length = 5 * sizeof(WCHAR);
hr = IStream_Write(stream, &length, sizeof(length), NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IStream_Write(stream, L"data", length, NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMoniker_Load(moniker, stream);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IMoniker_GetSizeMax(moniker, &size);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(size.QuadPart == 30, "Unexpected size %u.\n", size.LowPart);
TEST_DISPLAY_NAME(moniker, L"clsid:0002E005-0000-0000-C000-000000000046data:");
/* Extra data does not affect comparison */
hr = IMoniker_QueryInterface(moniker, &IID_IROTData, (void **)&rotdata);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
hr = IROTData_GetComparisonData(rotdata, buffer, sizeof(buffer), &length);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(length == sizeof(expected_class_moniker_comparison_data), "Unexpected comparison data length %u.\n", length);
ok(!memcmp(buffer, expected_class_moniker_comparison_data, length), "Unexpected data.\n");
IROTData_Release(rotdata);
IStream_Release(stream);
IMoniker_Release(moniker);
hr = CreateClassMoniker(&CLSID_StdComponentCategoriesMgr, &moniker);
ok_ole_success(hr, CreateClassMoniker);
hr = IMoniker_GetSizeMax(moniker, &size);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(size.LowPart == 20, "Unexpected size %u.\n", size.LowPart);
hr = IMoniker_QueryInterface(moniker, &CLSID_ClassMoniker, (void **)&unknown);
ok(hr == S_OK, "Unexpected hr %#x.\n", hr);
ok(unknown == (IUnknown *)moniker, "Unexpected interface.\n");