diff --git a/dlls/comsvcs/main.c b/dlls/comsvcs/main.c index 7bfde03b34e..9ab77dfceda 100644 --- a/dlls/comsvcs/main.c +++ b/dlls/comsvcs/main.c @@ -57,6 +57,7 @@ struct new_moniker IROTData IROTData_iface; LONG refcount; CLSID clsid; + WCHAR *progid; }; static HRESULT new_moniker_parse_displayname(IBindCtx *pbc, LPOLESTR name, ULONG *eaten, IMoniker **ret); @@ -481,7 +482,10 @@ static ULONG WINAPI new_moniker_Release(IMoniker* iface) TRACE("%p, refcount %u.\n", iface, refcount); if (!refcount) + { + heap_free(moniker->progid); heap_free(moniker); + } return refcount; } @@ -508,10 +512,10 @@ static HRESULT WINAPI new_moniker_IsDirty(IMoniker* iface) static HRESULT WINAPI new_moniker_Load(IMoniker *iface, IStream *stream) { struct new_moniker *moniker = impl_from_IMoniker(iface); - ULARGE_INTEGER pad; + DWORD progid_len = 0, len, pad = ~0u; + WCHAR *progid = NULL; CLSID clsid; HRESULT hr; - DWORD len; TRACE("%p, %p.\n", iface, stream); @@ -519,29 +523,49 @@ static HRESULT WINAPI new_moniker_Load(IMoniker *iface, IStream *stream) if (FAILED(hr)) return hr; - pad.QuadPart = 1; - hr = IStream_Read(stream, &pad, sizeof(pad), &len); - if (FAILED(hr)) - return hr; + if (SUCCEEDED(hr)) + hr = IStream_Read(stream, &progid_len, sizeof(progid_len), &len); - if (pad.QuadPart != 0) - return E_FAIL; + if (SUCCEEDED(hr) && progid_len) + { + if (!(progid = heap_alloc(progid_len))) + return E_OUTOFMEMORY; + hr = IStream_Read(stream, progid, progid_len, &len); + } - moniker->clsid = clsid; + /* Skip terminator. */ + if (SUCCEEDED(hr)) + hr = IStream_Read(stream, &pad, sizeof(pad), &len); - return S_OK; + if (SUCCEEDED(hr) && pad == 0) + { + moniker->clsid = clsid; + heap_free(moniker->progid); + moniker->progid = progid; + progid = NULL; + } + + heap_free(progid); + + return hr; } static HRESULT WINAPI new_moniker_Save(IMoniker *iface, IStream *stream, BOOL clear_dirty) { struct new_moniker *moniker = impl_from_IMoniker(iface); - static const ULARGE_INTEGER pad; - ULONG written; + ULONG written, pad = 0, progid_len = 0; HRESULT hr; TRACE("%p, %p, %d.\n", iface, stream, clear_dirty); + if (moniker->progid) + progid_len = lstrlenW(moniker->progid) * sizeof(WCHAR); + hr = IStream_Write(stream, &moniker->clsid, sizeof(moniker->clsid), &written); + if (SUCCEEDED(hr)) + hr = IStream_Write(stream, &progid_len, sizeof(progid_len), &written); + if (SUCCEEDED(hr) && progid_len) + hr = IStream_Write(stream, moniker->progid, progid_len, &written); if (SUCCEEDED(hr)) hr = IStream_Write(stream, &pad, sizeof(pad), &written); @@ -550,12 +574,16 @@ static HRESULT WINAPI new_moniker_Save(IMoniker *iface, IStream *stream, BOOL cl static HRESULT WINAPI new_moniker_GetSizeMax(IMoniker *iface, ULARGE_INTEGER *size) { + struct new_moniker *moniker = impl_from_IMoniker(iface); + TRACE("%p, %p.\n", iface, size); if (!size) return E_POINTER; size->QuadPart = sizeof(CLSID) + 2 * sizeof(DWORD); + if (moniker->progid) + size->QuadPart += lstrlenW(moniker->progid) * sizeof(WCHAR); return S_OK; } @@ -867,15 +895,21 @@ static HRESULT guid_from_string(const WCHAR *s, GUID *ret) static HRESULT new_moniker_parse_displayname(IBindCtx *pbc, LPOLESTR name, ULONG *eaten, IMoniker **ret) { struct new_moniker *moniker; + WCHAR *progid = NULL, *str; GUID guid; *ret = NULL; if (wcsnicmp(name, L"new:", 4)) return MK_E_SYNTAX; + str = name + 4; - if (!guid_from_string(name + 4, &guid) && FAILED(CLSIDFromProgID(name + 4, &guid))) - return MK_E_SYNTAX; + if (!guid_from_string(str, &guid)) + { + if (FAILED(CLSIDFromProgID(str, &guid))) + return MK_E_SYNTAX; + progid = str; + } moniker = heap_alloc_zero(sizeof(*moniker)); if (!moniker) @@ -885,6 +919,15 @@ static HRESULT new_moniker_parse_displayname(IBindCtx *pbc, LPOLESTR name, ULONG moniker->IROTData_iface.lpVtbl = &new_moniker_rotdata_vtbl; moniker->refcount = 1; moniker->clsid = guid; + if (progid) + { + if (!(moniker->progid = heap_alloc((lstrlenW(progid) + 1) * sizeof(WCHAR)))) + { + IMoniker_Release(&moniker->IMoniker_iface); + return E_OUTOFMEMORY; + } + lstrcpyW(moniker->progid, progid); + } *ret = &moniker->IMoniker_iface; diff --git a/dlls/comsvcs/tests/comsvcs.c b/dlls/comsvcs/tests/comsvcs.c index 3b15a1f7e64..e6717e0ea3e 100644 --- a/dlls/comsvcs/tests/comsvcs.c +++ b/dlls/comsvcs/tests/comsvcs.c @@ -293,23 +293,90 @@ static void create_dispenser(void) IDispenserManager_Release(dispenser); } +static void test_new_moniker_serialize(const WCHAR *clsid, const WCHAR *progid, IMoniker *moniker) +{ + DWORD expected_size, progid_len = 0; + ULARGE_INTEGER size; + IStream *stream; + HGLOBAL hglobal; + CLSID guid; + HRESULT hr; + DWORD *ptr; + + hr = IMoniker_GetSizeMax(moniker, NULL); + ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); + + expected_size = sizeof(GUID) + 2 * sizeof(DWORD); + if (progid) + { + progid_len = lstrlenW(progid) * sizeof(*progid); + expected_size += progid_len; + } + + size.QuadPart = 0; + hr = IMoniker_GetSizeMax(moniker, &size); + ok(hr == S_OK, "Failed to get size, hr %#x.\n", hr); + ok(size.QuadPart == expected_size, "Unexpected size %s, expected %#x.\n", wine_dbgstr_longlong(size.QuadPart), + expected_size); + + hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); + ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr); + + hr = IMoniker_Save(moniker, stream, FALSE); + ok(hr == S_OK, "Failed to save moniker, hr %#x.\n", hr); + + hr = GetHGlobalFromStream(stream, &hglobal); + ok(hr == S_OK, "Failed to get a handle, hr %#x.\n", hr); + + ptr = GlobalLock(hglobal); + ok(!!ptr, "Failed to get data pointer.\n"); + + hr = CLSIDFromString(clsid, &guid); + ok(hr == S_OK, "Failed to get CLSID, hr %#x.\n", hr); + ok(IsEqualGUID((GUID *)ptr, &guid), "Unexpected buffer content.\n"); + ptr += sizeof(GUID)/sizeof(DWORD); + + /* Serialization format: + + GUID guid; + DWORD progid_len; + WCHAR progid[progid_len/2]; + DWORD null; + */ + + if (progid) + { + ok(*ptr == progid_len, "Unexpected progid length.\n"); + ptr++; + ok(!memcmp(ptr, progid, progid_len), "Unexpected progid.\n"); + ptr += progid_len / sizeof(DWORD); + } + else + { + ok(*ptr == 0, "Unexpected progid length.\n"); + ptr++; + } + ok(*ptr == 0, "Unexpected terminator.\n"); + + GlobalUnlock(hglobal); + + IStream_Release(stream); +} + static void test_new_moniker(void) { IMoniker *moniker, *moniker2, *inverse, *class_moniker, *moniker_left; IRunningObjectTable *rot; IUnknown *obj, *obj2; BIND_OPTS2 bind_opts; - ULARGE_INTEGER size; DWORD moniker_type; IROTData *rot_data; IBindCtx *bindctx; FILETIME filetime; DWORD hash, eaten; - IStream *stream; - HGLOBAL hglobal; CLSID clsid; HRESULT hr; - void *ptr; + WCHAR *str; hr = CreateBindCtx(0, &bindctx); ok(hr == S_OK, "Failed to create bind context, hr %#x.\n", hr); @@ -424,36 +491,7 @@ todo_wine ok(obj == NULL, "Unexpected return value.\n"); /* Serialization. */ - hr = IMoniker_GetSizeMax(moniker, NULL); - ok(hr == E_POINTER, "Unexpected hr %#x.\n", hr); - - size.QuadPart = 0; - hr = IMoniker_GetSizeMax(moniker, &size); - ok(hr == S_OK, "Failed to get size, hr %#x.\n", hr); - ok(size.QuadPart == (sizeof(GUID) + 2 * sizeof(DWORD)), "Unexpected size %s.\n", - wine_dbgstr_longlong(size.QuadPart)); - - hr = CreateStreamOnHGlobal(NULL, TRUE, &stream); - ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr); - - hr = IMoniker_Save(moniker, stream, FALSE); - ok(hr == S_OK, "Failed to save moniker, hr %#x.\n", hr); - - hr = GetHGlobalFromStream(stream, &hglobal); - ok(hr == S_OK, "Failed to get a handle, hr %#x.\n", hr); - - ptr = GlobalLock(hglobal); - ok(!!ptr, "Failed to get data pointer.\n"); - - hr = CLSIDFromString(L"{20d04fe0-3aea-1069-a2d8-08002b30309d}", &clsid); - ok(hr == S_OK, "Failed to get CLSID, hr %#x.\n", hr); - ok(IsEqualGUID((GUID *)ptr, &clsid), "Unexpected buffer content.\n"); - ok(*(DWORD *)((BYTE *)ptr + sizeof(GUID)) == 0, "Unexpected buffer content.\n"); - ok(*(DWORD *)((BYTE *)ptr + sizeof(GUID) + sizeof(DWORD)) == 0, "Unexpected buffer content.\n"); - - GlobalUnlock(hglobal); - - IStream_Release(stream); + test_new_moniker_serialize(L"{20d04fe0-3aea-1069-a2d8-08002b30309d}", NULL, moniker); hr = IMoniker_IsDirty(moniker); ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr); @@ -483,6 +521,15 @@ todo_wine ok(hr == S_OK, "Failed to parse display name, hr %#x.\n", hr); ok(eaten, "Unexpected eaten length %u.\n", eaten); + hr = CLSIDFromProgID(L"msxml2.domdocument", &clsid); + ok(hr == S_OK, "Failed to get clsid, hr %#x.\n", hr); + + hr = StringFromCLSID(&clsid, &str); + ok(hr == S_OK, "Failed to get guid string, hr %#x.\n", hr); + + test_new_moniker_serialize(str, L"msxml2.domdocument", moniker); + CoTaskMemFree(str); + hr = IMoniker_BindToObject(moniker, bindctx, NULL, &IID_IUnknown, (void **)&obj); ok(hr == S_OK, "Failed to bind to object, hr %#x.\n", hr); EXPECT_REF(obj, 1);