ole32: Handle optional WCHAR data when loading item moniker.
Signed-off-by: Nikolay Sivov <nsivov@codeweavers.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
7a98b0527a
commit
b676616700
|
@ -157,72 +157,106 @@ static HRESULT WINAPI ItemMonikerImpl_IsDirty(IMoniker* iface)
|
|||
return S_FALSE;
|
||||
}
|
||||
|
||||
static HRESULT item_moniker_load_string_record(IStream *stream, WCHAR **ret)
|
||||
{
|
||||
DWORD str_len, read_len, lenW, i;
|
||||
HRESULT hr = S_OK;
|
||||
char *buffer;
|
||||
WCHAR *str;
|
||||
|
||||
IStream_Read(stream, &str_len, sizeof(str_len), &read_len);
|
||||
if (read_len != sizeof(str_len))
|
||||
return E_FAIL;
|
||||
|
||||
if (!str_len)
|
||||
{
|
||||
heap_free(*ret);
|
||||
*ret = NULL;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
if (!(buffer = heap_alloc(str_len)))
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
IStream_Read(stream, buffer, str_len, &read_len);
|
||||
if (read_len != str_len)
|
||||
{
|
||||
heap_free(buffer);
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
/* Skip ansi buffer, it must be null terminated. */
|
||||
i = 0;
|
||||
while (i < str_len && buffer[i])
|
||||
i++;
|
||||
|
||||
if (buffer[i])
|
||||
{
|
||||
WARN("Expected null terminated ansi name.\n");
|
||||
hr = E_FAIL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (i < str_len - 1)
|
||||
{
|
||||
str_len -= i + 1;
|
||||
|
||||
if (str_len % sizeof(WCHAR))
|
||||
{
|
||||
WARN("Unexpected Unicode name length %d.\n", str_len);
|
||||
hr = E_FAIL;
|
||||
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
|
||||
{
|
||||
lenW = MultiByteToWideChar(CP_ACP, 0, buffer, -1, NULL, 0);
|
||||
str = heap_alloc(lenW * sizeof(WCHAR));
|
||||
if (str)
|
||||
MultiByteToWideChar(CP_ACP, 0, buffer, -1, str, lenW);
|
||||
}
|
||||
|
||||
if (str)
|
||||
{
|
||||
heap_free(*ret);
|
||||
*ret = str;
|
||||
}
|
||||
else
|
||||
hr = E_OUTOFMEMORY;
|
||||
|
||||
end:
|
||||
heap_free(buffer);
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
* ItemMoniker_Load
|
||||
******************************************************************************/
|
||||
static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker* iface,IStream* pStm)
|
||||
static HRESULT WINAPI ItemMonikerImpl_Load(IMoniker *iface, IStream *stream)
|
||||
{
|
||||
ItemMonikerImpl *This = impl_from_IMoniker(iface);
|
||||
HRESULT res;
|
||||
DWORD delimiterLength,nameLength,lenW;
|
||||
CHAR *itemNameA,*itemDelimiterA;
|
||||
ULONG bread;
|
||||
HRESULT hr;
|
||||
|
||||
TRACE("\n");
|
||||
TRACE("(%p, %p)\n", iface, stream);
|
||||
|
||||
/* for more details about data read by this function see comments of ItemMonikerImpl_Save function */
|
||||
/* 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. */
|
||||
|
||||
/* read item delimiter string length + 1 */
|
||||
res=IStream_Read(pStm,&delimiterLength,sizeof(DWORD),&bread);
|
||||
if (bread != sizeof(DWORD))
|
||||
return E_FAIL;
|
||||
hr = item_moniker_load_string_record(stream, &This->itemDelimiter);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = item_moniker_load_string_record(stream, &This->itemName);
|
||||
|
||||
/* read item delimiter string */
|
||||
if (!(itemDelimiterA=HeapAlloc(GetProcessHeap(),0,delimiterLength)))
|
||||
return E_OUTOFMEMORY;
|
||||
res=IStream_Read(pStm,itemDelimiterA,delimiterLength,&bread);
|
||||
if (bread != delimiterLength)
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
lenW = MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, NULL, 0 );
|
||||
This->itemDelimiter=HeapReAlloc(GetProcessHeap(),0,This->itemDelimiter,lenW*sizeof(WCHAR));
|
||||
if (!This->itemDelimiter)
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
MultiByteToWideChar( CP_ACP, 0, itemDelimiterA, -1, This->itemDelimiter, lenW );
|
||||
HeapFree( GetProcessHeap(), 0, itemDelimiterA );
|
||||
|
||||
/* read item name string length + 1*/
|
||||
res=IStream_Read(pStm,&nameLength,sizeof(DWORD),&bread);
|
||||
if (bread != sizeof(DWORD))
|
||||
return E_FAIL;
|
||||
|
||||
/* read item name string */
|
||||
if (!(itemNameA=HeapAlloc(GetProcessHeap(),0,nameLength)))
|
||||
return E_OUTOFMEMORY;
|
||||
res=IStream_Read(pStm,itemNameA,nameLength,&bread);
|
||||
if (bread != nameLength)
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, itemNameA );
|
||||
return E_FAIL;
|
||||
}
|
||||
|
||||
lenW = MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, NULL, 0 );
|
||||
This->itemName=HeapReAlloc(GetProcessHeap(),0,This->itemName,lenW*sizeof(WCHAR));
|
||||
if (!This->itemName)
|
||||
{
|
||||
HeapFree( GetProcessHeap(), 0, itemNameA );
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
MultiByteToWideChar( CP_ACP, 0, itemNameA, -1, This->itemName, lenW );
|
||||
HeapFree( GetProcessHeap(), 0, itemNameA );
|
||||
|
||||
return res;
|
||||
return hr;
|
||||
}
|
||||
|
||||
/******************************************************************************
|
||||
|
|
|
@ -1674,9 +1674,37 @@ static void test_file_monikers(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;
|
||||
IMoniker *moniker;
|
||||
DWORD moniker_type;
|
||||
DWORD moniker_type, i;
|
||||
DWORD hash;
|
||||
IBindCtx *bindctx;
|
||||
IMoniker *inverse;
|
||||
|
@ -1684,6 +1712,9 @@ static void test_item_moniker(void)
|
|||
static const WCHAR wszDelimiter[] = {'!',0};
|
||||
static const WCHAR wszObjectName[] = {'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);
|
||||
ok(hr == S_OK, "Failed to create item moniker, hr %#x.\n", hr);
|
||||
|
@ -1727,6 +1758,43 @@ static void test_item_moniker(void)
|
|||
expected_item_moniker_comparison_data5, sizeof(expected_item_moniker_comparison_data5),
|
||||
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);
|
||||
|
||||
hr = CreateItemMoniker(wszDelimiter, wszObjectName, &moniker);
|
||||
|
@ -1756,9 +1824,6 @@ static void test_item_moniker(void)
|
|||
"dwMkSys != MKSYS_ITEMMONIKER, instead was 0x%08x\n",
|
||||
moniker_type);
|
||||
|
||||
hr = CreateBindCtx(0, &bindctx);
|
||||
ok_ole_success(hr, CreateBindCtx);
|
||||
|
||||
/* IsRunning test */
|
||||
hr = IMoniker_IsRunning(moniker, NULL, NULL, NULL);
|
||||
ok(hr == E_INVALIDARG, "IMoniker_IsRunning should return E_INVALIDARG, not 0x%08x\n", hr);
|
||||
|
|
Loading…
Reference in New Issue