mirror of
https://github.com/ApfelTeeSaft/reactos.git
synced 2026-08-27 03:43:36 +00:00
[SHLWAPI][SHLWAPI_APITEST][SDK] Support NextPathA/W (#9039)
Implementing missing features... JIRA issue: CORE-19278 - Implement NextPathA and NextPathW functions. - Modify shlwapi.spec. - Add prototypes into <shlwapi_undoc.h>. - Add NextPath testcase.
This commit is contained in:
@@ -446,8 +446,8 @@
|
||||
446 stdcall -noname PathFileExistsAndAttributesW(wstr ptr)
|
||||
447 stdcall -noname FixSlashesAndColonA(str)
|
||||
448 stdcall -noname FixSlashesAndColonW(wstr)
|
||||
449 stub -noname NextPathA
|
||||
450 stub -noname NextPathW
|
||||
449 stdcall -noname NextPathA(str ptr long)
|
||||
450 stdcall -noname NextPathW(wstr ptr long)
|
||||
451 stdcall -noname CharUpperNoDBCSA(str)
|
||||
452 stdcall -noname CharUpperNoDBCSW(wstr)
|
||||
453 stdcall -noname CharLowerNoDBCSA(str)
|
||||
|
||||
@@ -878,3 +878,82 @@ SHDialogBox(
|
||||
SHDIALOG data = { fn, pThis };
|
||||
return DialogBoxParamA(hInstance, lpTemplateName, hWndParent, SHDialogProc, (LPARAM)&data);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* NextPathA [SHLWAPI.449]
|
||||
*
|
||||
* See NextPathW.
|
||||
*/
|
||||
EXTERN_C PSTR WINAPI
|
||||
NextPathA(
|
||||
_In_ PCSTR pszStart,
|
||||
_Out_writes_(cchDest) PSTR pszDest,
|
||||
_In_ UINT cchDest)
|
||||
{
|
||||
if (!pszStart)
|
||||
return NULL;
|
||||
|
||||
PCSTR pchStart = pszStart;
|
||||
while (*pchStart == ';')
|
||||
++pchStart;
|
||||
|
||||
if (!*pchStart)
|
||||
return NULL;
|
||||
|
||||
PSTR pchEnd = StrChrA(pchStart, ';');
|
||||
if (!pchEnd)
|
||||
pchEnd = (PSTR)(pchStart + lstrlenA(pchStart));
|
||||
|
||||
const UINT cchSegment = (UINT)(pchEnd - pchStart);
|
||||
const UINT cchToCopy = min(cchSegment + 1, cchDest);
|
||||
lstrcpynA(pszDest, pchStart, cchToCopy);
|
||||
pszDest[cchSegment] = ANSI_NULL;
|
||||
|
||||
PathRemoveBlanksA(pszDest);
|
||||
if (!*pszDest)
|
||||
return NULL;
|
||||
|
||||
return (*pchEnd == ';') ? (pchEnd + 1) : pchEnd;
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
* NextPathW [SHLWAPI.450]
|
||||
*
|
||||
* Extracts the next path from a semicolon-separated path string (Unicode version)
|
||||
*
|
||||
* @param pszStart Parsing start position (semicolon-separated path string)
|
||||
* @param pszDest Buffer to store the extracted path
|
||||
* @param cchDest Buffer size (number of characters)
|
||||
* @return Pointer to the beginning of the next path. NULL if there are no more paths.
|
||||
*/
|
||||
EXTERN_C PWSTR WINAPI
|
||||
NextPathW(
|
||||
_In_ PCWSTR pszStart,
|
||||
_Out_writes_(cchDest) PWSTR pszDest,
|
||||
_In_ UINT cchDest)
|
||||
{
|
||||
if (!pszStart)
|
||||
return NULL;
|
||||
|
||||
PCWSTR pchStart = pszStart;
|
||||
while (*pchStart == L';')
|
||||
++pchStart;
|
||||
|
||||
if (!*pchStart)
|
||||
return NULL;
|
||||
|
||||
PWSTR pchEnd = StrChrW(pchStart, L';');
|
||||
if (!pchEnd)
|
||||
pchEnd = (PWSTR)(pchStart + lstrlenW(pchStart));
|
||||
|
||||
const UINT cchSegment = (UINT)(pchEnd - pchStart);
|
||||
const UINT cchToCopy = min(cchSegment + 1, cchDest);
|
||||
lstrcpynW(pszDest, pchStart, cchToCopy);
|
||||
pszDest[cchSegment] = UNICODE_NULL;
|
||||
|
||||
PathRemoveBlanksW(pszDest);
|
||||
if (!*pszDest)
|
||||
return NULL;
|
||||
|
||||
return (*pchEnd == L';') ? (pchEnd + 1) : pchEnd;
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ list(APPEND SOURCE
|
||||
IShellFolderHelpers.cpp
|
||||
IsQSForward.cpp
|
||||
IStreamPidl.cpp
|
||||
NextPath.c
|
||||
PathFileExistsDefExtAndAttributesW.c
|
||||
PathFindOnPath.c
|
||||
PathIsUNC.c
|
||||
|
||||
@@ -0,0 +1,158 @@
|
||||
/*
|
||||
* PROJECT: ReactOS api tests
|
||||
* LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
|
||||
* PURPOSE: Tests for NextPathA/W
|
||||
* COPYRIGHT: Copyright 2026 Katayama Hirofumi MZ <[email protected]>
|
||||
*/
|
||||
|
||||
#include <apitest.h>
|
||||
#include <shlwapi.h>
|
||||
|
||||
typedef PSTR (WINAPI *FN_NextPathA)(PCSTR, PSTR, UINT);
|
||||
typedef PWSTR (WINAPI *FN_NextPathW)(PCWSTR, PWSTR, UINT);
|
||||
|
||||
static FN_NextPathA s_pNextPathA = NULL;
|
||||
static FN_NextPathW s_pNextPathW = NULL;
|
||||
|
||||
static void TEST_NextPathA(void)
|
||||
{
|
||||
PSTR pch;
|
||||
CHAR sz[MAX_PATH];
|
||||
|
||||
/* NULL pszStart returns NULL */
|
||||
pch = s_pNextPathA(NULL, sz, _countof(sz));
|
||||
ok(pch == NULL, "pch was %p\n", pch);
|
||||
|
||||
/* Basic semicolon-separated paths */
|
||||
pch = s_pNextPathA("C:\\TEST1;C:\\TEST2;C:\\TEST3", sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST1");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST2");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST3");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "pch was %p\n", pch);
|
||||
|
||||
/* Whitespace-only segment */
|
||||
pch = s_pNextPathA("C:\\TEST1; ;C:\\TEST3", sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST1");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "pch was %p\n", pch);
|
||||
|
||||
/* Empty string: no paths at all */
|
||||
pch = s_pNextPathA("", sz, _countof(sz));
|
||||
ok(pch == NULL, "empty string: pch was %p\n", pch);
|
||||
|
||||
/* Leading semicolons are skipped */
|
||||
pch = s_pNextPathA(";;;C:\\TEST1", sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST1");
|
||||
ok(pch != NULL, "leading semicolons: pch should not be NULL\n");
|
||||
|
||||
/* Trailing semicolon */
|
||||
pch = s_pNextPathA("C:\\TEST1;", sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST1");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "trailing semicolon: pch was %p\n", pch);
|
||||
|
||||
/* Only semicolons */
|
||||
pch = s_pNextPathA(";;;", sz, _countof(sz));
|
||||
ok(pch == NULL, "only semicolons: pch was %p\n", pch);
|
||||
|
||||
/* Path with surrounding spaces */
|
||||
pch = s_pNextPathA(" C:\\TEST1 ;C:\\TEST2", sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST1");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok_str(sz, "C:\\TEST2");
|
||||
|
||||
/* Single path, no semicolon */
|
||||
pch = s_pNextPathA("C:\\SINGLE", sz, _countof(sz));
|
||||
ok_str(sz, "C:\\SINGLE");
|
||||
pch = s_pNextPathA(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "single path: pch was %p\n", pch);
|
||||
|
||||
/* cchDest = 0 */
|
||||
sz[0] = '*';
|
||||
sz[1] = ANSI_NULL;
|
||||
pch = s_pNextPathA("C:\\TEST1;C:\\TEST2;C:\\TEST3", sz, 0);
|
||||
ok_str(pch, "C:\\TEST2;C:\\TEST3");
|
||||
ok_str(sz, "*");
|
||||
}
|
||||
|
||||
static void TEST_NextPathW(void)
|
||||
{
|
||||
PWSTR pch;
|
||||
WCHAR sz[MAX_PATH];
|
||||
|
||||
/* NULL pszStart returns NULL */
|
||||
pch = s_pNextPathW(NULL, sz, _countof(sz));
|
||||
ok(pch == NULL, "pch was %p\n", pch);
|
||||
|
||||
/* Basic semicolon-separated paths */
|
||||
pch = s_pNextPathW(L"C:\\TEST1;C:\\TEST2;C:\\TEST3", sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST1");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST2");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST3");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "pch was %p\n", pch);
|
||||
|
||||
/* Whitespace-only segment */
|
||||
pch = s_pNextPathW(L"C:\\TEST1; ;C:\\TEST3", sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST1");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "pch was %p\n", pch);
|
||||
|
||||
/* Empty string */
|
||||
pch = s_pNextPathW(L"", sz, _countof(sz));
|
||||
ok(pch == NULL, "empty string: pch was %p\n", pch);
|
||||
|
||||
/* Leading semicolons are skipped */
|
||||
pch = s_pNextPathW(L";;;C:\\TEST1", sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST1");
|
||||
ok(pch != NULL, "leading semicolons: pch should not be NULL\n");
|
||||
|
||||
/* Trailing semicolon */
|
||||
pch = s_pNextPathW(L"C:\\TEST1;", sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST1");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "trailing semicolon: pch was %p\n", pch);
|
||||
|
||||
/* Only semicolons */
|
||||
pch = s_pNextPathW(L";;;", sz, _countof(sz));
|
||||
ok(pch == NULL, "only semicolons: pch was %p\n", pch);
|
||||
|
||||
/* Path with surrounding spaces */
|
||||
pch = s_pNextPathW(L" C:\\TEST1 ;C:\\TEST2", sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST1");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\TEST2");
|
||||
|
||||
/* Single path, no semicolon */
|
||||
pch = s_pNextPathW(L"C:\\SINGLE", sz, _countof(sz));
|
||||
ok_wstr(sz, L"C:\\SINGLE");
|
||||
pch = s_pNextPathW(pch, sz, _countof(sz));
|
||||
ok(pch == NULL, "single path: pch was %p\n", pch);
|
||||
|
||||
/* cchDest = 0 */
|
||||
sz[0] = L'*';
|
||||
sz[1] = UNICODE_NULL;
|
||||
pch = s_pNextPathW(L"C:\\TEST1;C:\\TEST2;C:\\TEST3", sz, 0);
|
||||
ok_wstr(pch, L"C:\\TEST2;C:\\TEST3");
|
||||
ok_wstr(sz, L"*");
|
||||
}
|
||||
|
||||
START_TEST(NextPath)
|
||||
{
|
||||
HINSTANCE hSHLWAPI = GetModuleHandleA("shlwapi");
|
||||
s_pNextPathA = (FN_NextPathA)GetProcAddress(hSHLWAPI, MAKEINTRESOURCEA(449));
|
||||
s_pNextPathW = (FN_NextPathW)GetProcAddress(hSHLWAPI, MAKEINTRESOURCEA(450));
|
||||
if (!s_pNextPathA || !s_pNextPathW)
|
||||
{
|
||||
skip("NextPath not found\n");
|
||||
return;
|
||||
}
|
||||
|
||||
TEST_NextPathA();
|
||||
TEST_NextPathW();
|
||||
}
|
||||
@@ -8,6 +8,7 @@ extern void func_PathFindOnPath(void);
|
||||
extern void func_IShellFolderHelpers(void);
|
||||
extern void func_IsQSForward(void);
|
||||
extern void func_IStreamPidl(void);
|
||||
extern void func_NextPath(void);
|
||||
extern void func_PathIsUNC(void);
|
||||
extern void func_PathIsUNCServer(void);
|
||||
extern void func_PathIsUNCServerShare(void);
|
||||
@@ -33,6 +34,7 @@ const struct test winetest_testlist[] =
|
||||
{ "IShellFolderHelpers", func_IShellFolderHelpers },
|
||||
{ "IsQSForward", func_IsQSForward },
|
||||
{ "IStreamPidl", func_IStreamPidl },
|
||||
{ "NextPath", func_NextPath },
|
||||
{ "PathIsUNC", func_PathIsUNC },
|
||||
{ "PathIsUNCServer", func_PathIsUNCServer },
|
||||
{ "PathIsUNCServerShare", func_PathIsUNCServerShare },
|
||||
|
||||
@@ -60,10 +60,25 @@ SHRestrictionLookup(
|
||||
|
||||
BOOL WINAPI SHAboutInfoA(LPSTR lpszDest, DWORD dwDestLen);
|
||||
BOOL WINAPI SHAboutInfoW(LPWSTR lpszDest, DWORD dwDestLen);
|
||||
|
||||
PSTR WINAPI
|
||||
NextPathA(
|
||||
_In_ PCSTR pszStart,
|
||||
_Out_writes_(cchDest) PSTR pszDest,
|
||||
_In_ UINT cchDest);
|
||||
|
||||
PWSTR WINAPI
|
||||
NextPathW(
|
||||
_In_ PCWSTR pszStart,
|
||||
_Out_writes_(cchDest) PWSTR pszDest,
|
||||
_In_ UINT cchDest);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define SHAboutInfo SHAboutInfoW
|
||||
#define NextPath NextPathW
|
||||
#else
|
||||
#define SHAboutInfo SHAboutInfoA
|
||||
#define NextPath NextPathA
|
||||
#endif
|
||||
|
||||
HRESULT WINAPI CLSIDFromStringWrap(_In_ LPCWSTR idstr, _Out_ CLSID *id);
|
||||
|
||||
Reference in New Issue
Block a user