mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-26 19:33:31 +00:00
[SHLWAPI][SHLWAPI_APITEST][SDK] Support IStream_ReadPidl and IStream_WritePidl (#8918)
Implementing missing features... JIRA issue: CORE-19278 - Implement IStream_ReadPidl and IStream_WritePidl functions. - Add prototypes to <shlwapi_undoc.h>. - Add IStreamPidl testcase.
This commit is contained in:
@@ -30,6 +30,9 @@
|
||||
#define NO_SHLWAPI_REG
|
||||
#define NO_SHLWAPI_PATH
|
||||
#include "shlwapi.h"
|
||||
#ifdef __REACTOS__
|
||||
#include "shlobj.h"
|
||||
#endif
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(shell);
|
||||
@@ -673,3 +676,75 @@ HRESULT WINAPI IStream_Size(IStream *lpStream, ULARGE_INTEGER* lpulSize)
|
||||
*lpulSize = statstg.cbSize;
|
||||
return hRet;
|
||||
}
|
||||
|
||||
#ifdef __REACTOS__
|
||||
/*************************************************************************
|
||||
* IStream_ReadPidl [SHLWAPI.512]
|
||||
*
|
||||
* https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/util/istream/readpidl.htm
|
||||
*/
|
||||
HRESULT WINAPI
|
||||
IStream_ReadPidl(_In_ IStream *pstm, _Out_ LPITEMIDLIST *ppidlOut)
|
||||
{
|
||||
LPITEMIDLIST pidl, pidlEnd;
|
||||
LPSHITEMID pItem;
|
||||
UINT cbSize;
|
||||
HRESULT hr;
|
||||
|
||||
*ppidlOut = NULL;
|
||||
|
||||
hr = SHIStream_Read(pstm, &cbSize, sizeof(cbSize));
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
|
||||
if (cbSize < sizeof(USHORT))
|
||||
return E_INVALIDARG;
|
||||
|
||||
pidl = CoTaskMemAlloc(cbSize);
|
||||
if (!pidl)
|
||||
return E_OUTOFMEMORY;
|
||||
|
||||
hr = SHIStream_Read(pstm, pidl, cbSize);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
CoTaskMemFree(pidl);
|
||||
return hr;
|
||||
}
|
||||
|
||||
pidlEnd = (LPITEMIDLIST)((PBYTE)pidl + cbSize - sizeof(USHORT));
|
||||
for (pItem = &pidl->mkid; pItem <= (LPSHITEMID)pidlEnd;
|
||||
pItem = (LPSHITEMID)((PBYTE)pItem + pItem->cb))
|
||||
{
|
||||
if (!pItem->cb)
|
||||
break;
|
||||
}
|
||||
|
||||
if ((LPITEMIDLIST)pItem == pidlEnd && !pItem->cb)
|
||||
{
|
||||
*ppidlOut = pidl;
|
||||
hr = S_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
CoTaskMemFree(pidl);
|
||||
hr = E_INVALIDARG;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* IStream_WritePidl [SHLWAPI.513]
|
||||
*
|
||||
* https://www.geoffchappell.com/studies/windows/shell/shlwapi/api/util/istream/writepidl.htm
|
||||
*/
|
||||
HRESULT WINAPI
|
||||
IStream_WritePidl(_In_ IStream *pstm, _In_ LPCITEMIDLIST pidlWrite)
|
||||
{
|
||||
UINT cbSize = ILGetSize(pidlWrite);
|
||||
HRESULT hr = SHIStream_Write(pstm, &cbSize, sizeof(cbSize));
|
||||
if (FAILED(hr))
|
||||
return hr;
|
||||
return SHIStream_Write(pstm, pidlWrite, cbSize);
|
||||
}
|
||||
#endif /* def __REACTOS__ */
|
||||
|
||||
@@ -509,8 +509,8 @@
|
||||
509 stdcall -noname IUnknown_OnFocusChangeIS(ptr ptr long)
|
||||
510 stdcall -noname SHLockSharedEx(ptr long long)
|
||||
511 stdcall -noname PathFileExistsDefExtAndAttributesW(wstr long ptr)
|
||||
512 stub -ordinal IStream_ReadPidl
|
||||
513 stub -ordinal IStream_WritePidl
|
||||
512 stdcall -noname IStream_ReadPidl(ptr ptr)
|
||||
513 stdcall -noname IStream_WritePidl(ptr ptr)
|
||||
514 stdcall -noname IUnknown_ProfferService(ptr ptr ptr ptr)
|
||||
515 stdcall -ordinal SHGetViewStatePropertyBag(ptr wstr long ptr ptr)
|
||||
516 stdcall -noname SKGetValueW(long wstr wstr ptr ptr ptr)
|
||||
|
||||
@@ -8,6 +8,7 @@ list(APPEND SOURCE
|
||||
AssocQueryString.c
|
||||
IShellFolderHelpers.cpp
|
||||
IsQSForward.cpp
|
||||
IStreamPidl.cpp
|
||||
PathFileExistsDefExtAndAttributesW.c
|
||||
PathFindOnPath.c
|
||||
PathIsUNC.c
|
||||
|
||||
@@ -0,0 +1,390 @@
|
||||
/*
|
||||
* PROJECT: ReactOS api tests
|
||||
* LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later)
|
||||
* PURPOSE: Tests for g_fnIStream_ReadPidl and g_fnIStream_WritePidl
|
||||
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <[email protected]>
|
||||
*/
|
||||
|
||||
#include <apitest.h>
|
||||
#include <shlwapi.h>
|
||||
#include <shlobj.h>
|
||||
#include <shlwapi_undoc.h>
|
||||
|
||||
typedef HRESULT (WINAPI *FN_IStream_ReadPidl)(IStream *, _Out_ LPITEMIDLIST *);
|
||||
typedef HRESULT (WINAPI *FN_IStream_WritePidl)(IStream *, LPCITEMIDLIST);
|
||||
typedef UINT (WINAPI *FN_ILGetSize)(LPCITEMIDLIST);
|
||||
|
||||
static FN_IStream_ReadPidl g_fnIStream_ReadPidl = NULL;
|
||||
static FN_IStream_WritePidl g_fnIStream_WritePidl = NULL;
|
||||
static FN_ILGetSize g_fnILGetSize = NULL;
|
||||
|
||||
static LPITEMIDLIST MakeSimplePidl(const BYTE *data, UINT dataLen)
|
||||
{
|
||||
UINT cbItem = (UINT)(sizeof(USHORT) + dataLen);
|
||||
UINT cbTotal = cbItem + sizeof(USHORT);
|
||||
LPITEMIDLIST pidl = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);
|
||||
if (!pidl)
|
||||
return NULL;
|
||||
ZeroMemory(pidl, cbTotal);
|
||||
pidl->mkid.cb = (USHORT)cbItem;
|
||||
if (dataLen)
|
||||
memcpy(pidl->mkid.abID, data, dataLen);
|
||||
return pidl;
|
||||
}
|
||||
|
||||
static void RewindStream(IStream *pstm)
|
||||
{
|
||||
LARGE_INTEGER li;
|
||||
li.QuadPart = 0;
|
||||
pstm->Seek(li, STREAM_SEEK_SET, NULL);
|
||||
}
|
||||
|
||||
static void Test_RoundTrip_SimplePidl(void)
|
||||
{
|
||||
const BYTE data[] = {0x11, 0x22, 0x33};
|
||||
LPITEMIDLIST pidlSrc = MakeSimplePidl(data, sizeof(data));
|
||||
LPITEMIDLIST pidlDst = NULL;
|
||||
HRESULT hr;
|
||||
IStream *pstm;
|
||||
|
||||
ok(pidlSrc != NULL, "pidlSrc was NULL.\n");
|
||||
if (!pidlSrc)
|
||||
{
|
||||
skip("pidlSrc was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pstm = SHCreateMemStream(NULL, 0);
|
||||
ok(pstm != NULL, "pstm was NULL.\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = g_fnIStream_WritePidl(pstm, pidlSrc);
|
||||
ok_hr(hr, S_OK);
|
||||
|
||||
RewindStream(pstm);
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidlDst);
|
||||
ok_hr(hr, S_OK);
|
||||
ok(pidlDst != NULL, "pidlDst was NULL\n");
|
||||
|
||||
if (pidlDst)
|
||||
{
|
||||
UINT cbSrc = g_fnILGetSize(pidlSrc);
|
||||
UINT cbDst = g_fnILGetSize(pidlDst);
|
||||
ok_int(cbSrc, cbDst);
|
||||
ok_int(memcmp(pidlSrc, pidlDst, cbSrc), 0);
|
||||
CoTaskMemFree(pidlDst);
|
||||
}
|
||||
|
||||
pstm->Release();
|
||||
CoTaskMemFree(pidlSrc);
|
||||
}
|
||||
|
||||
static void Test_RoundTrip_EmptyPidl(void)
|
||||
{
|
||||
LPITEMIDLIST pidlSrc = (LPITEMIDLIST)CoTaskMemAlloc(sizeof(USHORT));
|
||||
LPITEMIDLIST pidlDst = NULL;
|
||||
HRESULT hr;
|
||||
IStream *pstm;
|
||||
|
||||
ok(pidlSrc != NULL, "CoTaskMemAlloc failed\n");
|
||||
if (!pidlSrc)
|
||||
{
|
||||
skip("pidlSrc was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ZeroMemory(pidlSrc, sizeof(USHORT));
|
||||
|
||||
pstm = SHCreateMemStream(NULL, 0);
|
||||
ok(pstm != NULL, "pstm was NULL\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = g_fnIStream_WritePidl(pstm, pidlSrc);
|
||||
ok_hr(hr, S_OK);
|
||||
|
||||
RewindStream(pstm);
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidlDst);
|
||||
ok_hr(hr, S_OK);
|
||||
ok(pidlDst != NULL, "pidlDst was NULL\n");
|
||||
|
||||
if (pidlDst)
|
||||
{
|
||||
UINT cbSrc = g_fnILGetSize(pidlSrc);
|
||||
UINT cbDst = g_fnILGetSize(pidlDst);
|
||||
ok_int(cbSrc, cbDst);
|
||||
ok_int(memcmp(pidlSrc, pidlDst, cbSrc), 0);
|
||||
CoTaskMemFree(pidlDst);
|
||||
}
|
||||
|
||||
pstm->Release();
|
||||
CoTaskMemFree(pidlSrc);
|
||||
}
|
||||
|
||||
static void Test_RoundTrip_MultiItemPidl(void)
|
||||
{
|
||||
UINT cbTotal = 4 + 5 + 2;
|
||||
LPITEMIDLIST pidlSrc = (LPITEMIDLIST)CoTaskMemAlloc(cbTotal);
|
||||
LPITEMIDLIST pidlDst = NULL;
|
||||
PBYTE p;
|
||||
HRESULT hr;
|
||||
IStream *pstm;
|
||||
|
||||
ok(pidlSrc != NULL, "CoTaskMemAlloc failed\n");
|
||||
if (!pidlSrc)
|
||||
{
|
||||
skip("pidlSrc was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ZeroMemory(pidlSrc, cbTotal);
|
||||
p = (PBYTE)pidlSrc;
|
||||
|
||||
*(USHORT *)p = 4; p += 2;
|
||||
*p++ = 0xAA; *p++ = 0xBB;
|
||||
|
||||
*(USHORT *)p = 5; p += 2;
|
||||
*p++ = 0x01; *p++ = 0x02; *p++ = 0x03;
|
||||
|
||||
pstm = SHCreateMemStream(NULL, 0);
|
||||
ok(pstm != NULL, "pstm was NULL\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = g_fnIStream_WritePidl(pstm, pidlSrc);
|
||||
ok_hr(hr, S_OK);
|
||||
|
||||
RewindStream(pstm);
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidlDst);
|
||||
ok_hr(hr, S_OK);
|
||||
ok(pidlDst != NULL, "pidlDst was NULL\n");
|
||||
|
||||
if (pidlDst)
|
||||
{
|
||||
ok_int(g_fnILGetSize(pidlSrc), g_fnILGetSize(pidlDst));
|
||||
ok_int(memcmp(pidlSrc, pidlDst, g_fnILGetSize(pidlSrc)), 0);
|
||||
CoTaskMemFree(pidlDst);
|
||||
}
|
||||
|
||||
pstm->Release();
|
||||
CoTaskMemFree(pidlSrc);
|
||||
}
|
||||
|
||||
static void Test_Read_EmptyStream(void)
|
||||
{
|
||||
IStream *pstm = SHCreateMemStream(NULL, 0);
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
HRESULT hr;
|
||||
|
||||
ok(pstm != NULL, "pstm was NULL\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidl);
|
||||
ok(FAILED(hr), "hr was wrongly succeeded\n");
|
||||
ok(pidl == NULL, "pidl was not NULL\n");
|
||||
|
||||
pstm->Release();
|
||||
}
|
||||
|
||||
static void Test_Read_TooSmallCbSize(void)
|
||||
{
|
||||
IStream *pstm = SHCreateMemStream(NULL, 0);
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
UINT cbSize = 1;
|
||||
ULONG cbWritten;
|
||||
HRESULT hr;
|
||||
|
||||
ok(pstm != NULL, "pstm was NULL.\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pstm->Write(&cbSize, sizeof(cbSize), &cbWritten);
|
||||
|
||||
RewindStream(pstm);
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidl);
|
||||
ok(FAILED(hr), "hr was 0x%X\n", hr);
|
||||
ok(pidl == NULL, "pidl was not NULL\n");
|
||||
|
||||
pstm->Release();
|
||||
}
|
||||
|
||||
static void Test_Read_TruncatedData(void)
|
||||
{
|
||||
IStream *pstm = SHCreateMemStream(NULL, 0);
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
UINT cbSize = 100;
|
||||
ULONG cbWritten;
|
||||
HRESULT hr;
|
||||
|
||||
ok(pstm != NULL, "pstm was NULL.\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pstm->Write(&cbSize, sizeof(cbSize), &cbWritten);
|
||||
|
||||
RewindStream(pstm);
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidl);
|
||||
ok(FAILED(hr), "hr was 0x%X\n", hr);
|
||||
ok(pidl == NULL, "pidl was not NULL\n");
|
||||
|
||||
pstm->Release();
|
||||
}
|
||||
|
||||
static void Test_Read_MissingTerminator(void)
|
||||
{
|
||||
IStream *pstm = SHCreateMemStream(NULL, 0);
|
||||
LPITEMIDLIST pidl = NULL;
|
||||
UINT cbSize = 4;
|
||||
BYTE rawData[4] = {0x04, 0x00, 0x11, 0x22};
|
||||
ULONG cbWritten;
|
||||
HRESULT hr;
|
||||
|
||||
ok(pstm != NULL, "pstm was NULL.\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
pstm->Write(&cbSize, sizeof(cbSize), &cbWritten);
|
||||
pstm->Write(rawData, cbSize, &cbWritten);
|
||||
|
||||
RewindStream(pstm);
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidl);
|
||||
ok(FAILED(hr), "hr was 0x%X\n", hr);
|
||||
ok(pidl == NULL, "pidl was not NULL\n");
|
||||
|
||||
pstm->Release();
|
||||
}
|
||||
|
||||
static void Test_Write_StreamPosition(void)
|
||||
{
|
||||
const BYTE data[] = {0xDE, 0xAD};
|
||||
LPITEMIDLIST pidlSrc = MakeSimplePidl(data, sizeof(data));
|
||||
IStream *pstm = SHCreateMemStream(NULL, 0);
|
||||
ULARGE_INTEGER pos;
|
||||
LARGE_INTEGER zero;
|
||||
HRESULT hr;
|
||||
UINT expectedPos;
|
||||
|
||||
ok(pidlSrc != NULL, "pidlSrc was NULL\n");
|
||||
if (!pidlSrc)
|
||||
{
|
||||
skip("pidlSrc was NULL\n");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(pstm != NULL, "pstm was NULL.\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
zero.QuadPart = 0;
|
||||
|
||||
hr = g_fnIStream_WritePidl(pstm, pidlSrc);
|
||||
ok_hr(hr, S_OK);
|
||||
|
||||
pstm->Seek(zero, STREAM_SEEK_CUR, &pos);
|
||||
|
||||
expectedPos = sizeof(UINT) + g_fnILGetSize(pidlSrc);
|
||||
ok_eq_longlong(pos.QuadPart, expectedPos);
|
||||
|
||||
pstm->Release();
|
||||
CoTaskMemFree(pidlSrc);
|
||||
}
|
||||
|
||||
static void Test_Read_OutputNullOnFailure(void)
|
||||
{
|
||||
IStream *pstm = SHCreateMemStream(NULL, 0);
|
||||
LPITEMIDLIST pidl = (LPITEMIDLIST)UlongToPtr(0xDEADBEEF);
|
||||
HRESULT hr;
|
||||
|
||||
ok(pstm != NULL, "pstm was NULL.\n");
|
||||
if (!pstm)
|
||||
{
|
||||
skip("pstm was NULL.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
hr = g_fnIStream_ReadPidl(pstm, &pidl);
|
||||
ok(FAILED(hr), "hr was 0x%X\n", hr);
|
||||
ok(pidl == NULL, "pidl was not NULL\n");
|
||||
|
||||
pstm->Release();
|
||||
}
|
||||
|
||||
START_TEST(IStreamPidl)
|
||||
{
|
||||
HINSTANCE hSHLWAPI = LoadLibraryW(L"shlwapi");
|
||||
if (!hSHLWAPI)
|
||||
{
|
||||
skip("shlwapi not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
g_fnIStream_ReadPidl = (FN_IStream_ReadPidl)GetProcAddress(hSHLWAPI, MAKEINTRESOURCEA(512));
|
||||
g_fnIStream_WritePidl = (FN_IStream_WritePidl)GetProcAddress(hSHLWAPI, MAKEINTRESOURCEA(513));
|
||||
if (!g_fnIStream_ReadPidl || !g_fnIStream_WritePidl)
|
||||
{
|
||||
skip("IStream_ReadPidl or IStream_WritePidl not found\n");
|
||||
FreeLibrary(hSHLWAPI);
|
||||
return;
|
||||
}
|
||||
|
||||
HINSTANCE hSHELL32 = LoadLibraryW(L"shell32");
|
||||
if (!hSHELL32)
|
||||
{
|
||||
skip("shell32 not found\n");
|
||||
FreeLibrary(hSHLWAPI);
|
||||
return;
|
||||
}
|
||||
|
||||
g_fnILGetSize = (FN_ILGetSize)GetProcAddress(hSHELL32, "ILGetSize");
|
||||
if (!g_fnILGetSize)
|
||||
{
|
||||
skip("ILGetSize not found\n");
|
||||
FreeLibrary(hSHELL32);
|
||||
FreeLibrary(hSHLWAPI);
|
||||
return;
|
||||
}
|
||||
|
||||
HRESULT hrCoInit = CoInitialize(NULL);
|
||||
|
||||
Test_RoundTrip_SimplePidl();
|
||||
Test_RoundTrip_EmptyPidl();
|
||||
Test_RoundTrip_MultiItemPidl();
|
||||
Test_Read_EmptyStream();
|
||||
Test_Read_TooSmallCbSize();
|
||||
Test_Read_TruncatedData();
|
||||
Test_Read_MissingTerminator();
|
||||
Test_Write_StreamPosition();
|
||||
Test_Read_OutputNullOnFailure();
|
||||
|
||||
if (SUCCEEDED(hrCoInit))
|
||||
CoUninitialize();
|
||||
|
||||
FreeLibrary(hSHELL32);
|
||||
FreeLibrary(hSHLWAPI);
|
||||
}
|
||||
@@ -6,6 +6,7 @@ extern void func_PathFileExistsDefExtAndAttributesW(void);
|
||||
extern void func_PathFindOnPath(void);
|
||||
extern void func_IShellFolderHelpers(void);
|
||||
extern void func_IsQSForward(void);
|
||||
extern void func_IStreamPidl(void);
|
||||
extern void func_isuncpath(void);
|
||||
extern void func_isuncpathserver(void);
|
||||
extern void func_isuncpathservershare(void);
|
||||
@@ -27,6 +28,7 @@ const struct test winetest_testlist[] =
|
||||
{ "PathFindOnPath", func_PathFindOnPath },
|
||||
{ "IShellFolderHelpers", func_IShellFolderHelpers },
|
||||
{ "IsQSForward", func_IsQSForward },
|
||||
{ "IStreamPidl", func_IStreamPidl },
|
||||
{ "PathIsUNC", func_isuncpath },
|
||||
{ "PathIsUNCServer", func_isuncpathserver },
|
||||
{ "PathIsUNCServerShare", func_isuncpathservershare },
|
||||
|
||||
@@ -144,6 +144,9 @@ HRESULT WINAPI SHWriteDataBlockList(IStream* lpStream, LPDBLIST lpList);
|
||||
HRESULT WINAPI SHReadDataBlockList(IStream* lpStream, LPDBLIST* lppList);
|
||||
VOID WINAPI SHFreeDataBlockList(LPDBLIST lpList);
|
||||
|
||||
HRESULT WINAPI IStream_ReadPidl(_In_ IStream *pstm, _Out_ LPITEMIDLIST *ppidlOut);
|
||||
HRESULT WINAPI IStream_WritePidl(_In_ IStream *pstm, _In_ LPCITEMIDLIST pidlWrite);
|
||||
|
||||
LONG
|
||||
WINAPI
|
||||
RegCreateKeyExWrapW(
|
||||
|
||||
Reference in New Issue
Block a user