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

ole32: Handle optional WCHAR data when loading item moniker.

parent 7a98b052
...@@ -157,72 +157,106 @@ static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface) ...@@ -157,72 +157,106 @@ static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface)
return S_FALSE; return S_FALSE;
} }
/****************************************************************************** static HRESULT item_moniker_load_string_record(IStream *stream, WCHAR **ret)
* ItemMoniker_Load
******************************************************************************/
static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm)
{ {
ItemMonikerImpl *This = impl_from_IMoniker(iface); DWORD str_len, read_len, lenW, i;
HRESULT res; HRESULT hr = S_OK;
DWORD delimiterLength,nameLength,lenW; char *buffer;
CHAR *itemNameA,*itemDelimiterA; WCHAR *str;
ULONG bread;
TRACE("\n");
/* for more details about data read by this function see comments of ItemMonikerImpl_Save function */ IStream_Read(stream, &str_len, sizeof(str_len), &read_len);
if (read_len != sizeof(str_len))
/* read item delimiter string length + 1 */
res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread);
if (bread != sizeof(DWORD))
return E_FAIL; return E_FAIL;
/* read item delimiter string */ if (!str_len)
if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength))) {
heap_free(*ret);
*ret = NULL;
return S_OK;
}
if (!(buffer = heap_alloc(str_len)))
return E_OUTOFMEMORY; return E_OUTOFMEMORY;
res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread);
if (bread != delimiterLength) IStream_Read(stream, buffer, str_len, &read_len);
if (read_len != str_len)
{ {
HeapFree( GetProcessHeap(), 0, itemDelimiterA ); heap_free(buffer);
return E_FAIL; return E_FAIL;
} }
lenW = MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, NULL, 0 ); /* Skip ansi buffer, it must be null terminated. */
This->itemDelimiter=HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,lenW*sizeof(WCHAR)); i = 0;
if (!This->itemDelimiter) while (i < str_len && buffer[i])
i++;
if (buffer[i])
{ {
HeapFree( GetProcessHeap(), 0, itemDelimiterA ); WARN("Expected null terminated ansi name.\n");
return E_OUTOFMEMORY; hr = E_FAIL;
goto end;
} }
MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, This->itemDelimiter, lenW );
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
/* read item name string length + 1*/ if (i < str_len - 1)
res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread); {
if (bread != sizeof(DWORD)) str_len -= i + 1;
return E_FAIL;
/* read item name string */ if (str_len % sizeof(WCHAR))
if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength))) {
return E_OUTOFMEMORY; WARN("Unexpected Unicode name length %d.\n", str_len);
res=IStream_Read(pStm,itemNameA,nameLength,&bread); hr = E_FAIL;
if (bread != nameLength) goto end;
}
str = heap_alloc(str_len + sizeof(WCHAR));
if (str)
{
memcpy(str, &buffer[i + 1], str_len);
str[str_len / sizeof(WCHAR)] = 0;
}
}
else
{ {
HeapFree( GetProcessHeap(), 0, itemNameA ); lenW = MultiByteToWideChar(CP_ACP, 0, buffer, -1, NULL, 0);
return E_FAIL; str = heap_alloc(lenW * sizeof(WCHAR));
if (str)
MultiByteToWideChar(CP_ACP, 0, buffer, -1, str, lenW);
} }
lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 ); if (str)
This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR));
if (!This->itemName)
{ {
HeapFree( GetProcessHeap(), 0, itemNameA ); heap_free(*ret);
return E_OUTOFMEMORY; *ret = str;
} }
MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW ); else
HeapFree( GetProcessHeap(), 0, itemNameA ); hr = E_OUTOFMEMORY;
return res; end:
heap_free(buffer);
return hr;
}
/******************************************************************************
* ItemMoniker_Load
******************************************************************************/
static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker *iface, IStream *stream)
{
ItemMonikerImpl *This = impl_from_IMoniker(iface);
HRESULT hr;
TRACE("(%p, %p)\n", iface, stream);
/* Delimiter and name use the same record structure: 4 bytes byte-length field, followed by
string data. Data starts with single byte null-terminated string, WCHAR non-terminated
string optionally follows. Length of WCHAR string is determined as a difference between total
byte-length and single byte string length. */
hr = item_moniker_load_string_record(stream, &This->itemDelimiter);
if (SUCCEEDED(hr))
hr = item_moniker_load_string_record(stream, &This->itemName);
return hr;
} }
/****************************************************************************** /******************************************************************************
......
...@@ -1674,9 +1674,37 @@ static void test_file_monikers(void) ...@@ -1674,9 +1674,37 @@ static void test_file_monikers(void)
static void test_item_moniker(void) static void test_item_moniker(void)
{ {
static const char item_moniker_unicode_delim_stream[] =
{
0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, '!',
0x00, 0x02, 0x00, 0x00, 0x00, 'A', 0x00,
};
static const char item_moniker_unicode_item_stream[] =
{
0x02, 0x00, 0x00, 0x00, '!', 0x00, 0x05, 0x00,
0x00, 0x00, 0xff, 0xff, 0x00, 'B', 0x00,
};
static const char item_moniker_unicode_delim_item_stream[] =
{
0x05, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, '!',
0x00, 0x06, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff,
0x00, 'C', 0x00,
};
static struct
{
const char *data;
int data_len;
const WCHAR *display_name;
}
item_moniker_data[] =
{
{ item_moniker_unicode_delim_stream, sizeof(item_moniker_unicode_delim_stream), L"!A" },
{ item_moniker_unicode_item_stream, sizeof(item_moniker_unicode_item_stream), L"!B" },
{ item_moniker_unicode_delim_item_stream, sizeof(item_moniker_unicode_delim_item_stream), L"!C" },
};
IMoniker *moniker, *moniker2;
HRESULT hr; HRESULT hr;
IMoniker *moniker; DWORD moniker_type, i;
DWORD moniker_type;
DWORD hash; DWORD hash;
IBindCtx *bindctx; IBindCtx *bindctx;
IMoniker *inverse; IMoniker *inverse;
...@@ -1684,6 +1712,9 @@ static void test_item_moniker(void) ...@@ -1684,6 +1712,9 @@ static void test_item_moniker(void)
static const WCHAR wszDelimiter[] = {'!',0}; static const WCHAR wszDelimiter[] = {'!',0};
static const WCHAR wszObjectName[] = {'T','e','s','t',0}; static const WCHAR wszObjectName[] = {'T','e','s','t',0};
static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 }; static const WCHAR expected_display_name[] = { '!','T','e','s','t',0 };
WCHAR *display_name;
LARGE_INTEGER pos;
IStream *stream;
hr = CreateItemMoniker(NULL, wszObjectName, &moniker); hr = CreateItemMoniker(NULL, wszObjectName, &moniker);
ok(hr == S_OK, "Failed to create item moniker, hr %#x.\n", hr); ok(hr == S_OK, "Failed to create item moniker, hr %#x.\n", hr);
...@@ -1727,6 +1758,43 @@ static void test_item_moniker(void) ...@@ -1727,6 +1758,43 @@ static void test_item_moniker(void)
expected_item_moniker_comparison_data5, sizeof(expected_item_moniker_comparison_data5), expected_item_moniker_comparison_data5, sizeof(expected_item_moniker_comparison_data5),
58, L"abTest"); 58, L"abTest");
/* Serialize and load back. */
hr = CreateItemMoniker(NULL, L"object", &moniker2);
ok(hr == S_OK, "Failed to create item moniker, hr %#x.\n", hr);
hr = CreateStreamOnHGlobal(NULL, TRUE, &stream);
ok(hr == S_OK, "Failed to create a stream, hr %#x.\n", hr);
hr = CreateBindCtx(0, &bindctx);
ok(hr == S_OK, "Failed to create bind context, hr %#x.\n", hr);
for (i = 0; i < ARRAY_SIZE(item_moniker_data); ++i)
{
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "Failed to seek stream, hr %#x.\n", hr);
hr = IStream_Write(stream, item_moniker_data[i].data, item_moniker_data[i].data_len, NULL);
ok(hr == S_OK, "Failed to write stream contents, hr %#x.\n", hr);
pos.QuadPart = 0;
hr = IStream_Seek(stream, pos, STREAM_SEEK_SET, NULL);
ok(hr == S_OK, "Failed to seek stream, hr %#x.\n", hr);
hr = IMoniker_Load(moniker2, stream);
ok(hr == S_OK, "Failed to load moniker, hr %#x.\n", hr);
hr = IMoniker_GetDisplayName(moniker2, bindctx, NULL, &display_name);
ok(hr == S_OK, "Failed to get display name, hr %#x.\n", hr);
ok(!lstrcmpW(display_name, item_moniker_data[i].display_name), "%d: unexpected display name %s.\n",
i, wine_dbgstr_w(display_name));
CoTaskMemFree(display_name);
}
IStream_Release(stream);
IMoniker_Release(moniker2);
IMoniker_Release(moniker); IMoniker_Release(moniker);
hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker); hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker);
...@@ -1756,9 +1824,6 @@ static void test_item_moniker(void) ...@@ -1756,9 +1824,6 @@ static void test_item_moniker(void)
"dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n", "dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
moniker_type); moniker_type);
hr = CreateBindCtx(0, &bindctx);
ok_ole_success(hr, CreateBindCtx);
/* IsRunning test */ /* IsRunning test */
hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL); hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr); ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);
......
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