From 44d57a615f2d2ca16b45f346f868a04b608cccdd Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Tue, 14 Sep 2021 11:47:56 +0300 Subject: [PATCH] ole32: Handle extra class moniker data on load/save. Signed-off-by: Nikolay Sivov Signed-off-by: Alexandre Julliard --- dlls/ole32/classmoniker.c | 60 +++++++++++++++++++++++--------------- dlls/ole32/tests/moniker.c | 56 ++++++++++++++++++++++++++++++++++- 2 files changed, 91 insertions(+), 25 deletions(-) diff --git a/dlls/ole32/classmoniker.c b/dlls/ole32/classmoniker.c index ac4854347c8..86c2639e8ec 100644 --- a/dlls/ole32/classmoniker.c +++ b/dlls/ole32/classmoniker.c @@ -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; diff --git a/dlls/ole32/tests/moniker.c b/dlls/ole32/tests/moniker.c index 86b47e28b89..afe40980dd9 100644 --- a/dlls/ole32/tests/moniker.c +++ b/dlls/ole32/tests/moniker.c @@ -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");