diff --git a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec index 0524e7c3044..d874f8c8027 100644 --- a/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec +++ b/dlls/api-ms-win-core-path-l1-1-0/api-ms-win-core-path-l1-1-0.spec @@ -19,4 +19,4 @@ @ stub PathCchSkipRoot @ stub PathCchStripPrefix @ stub PathCchStripToRoot -@ stub PathIsUNCEx +@ stdcall PathIsUNCEx(wstr ptr) kernelbase.PathIsUNCEx diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec index 286dae0001c..b3b28872af6 100644 --- a/dlls/kernelbase/kernelbase.spec +++ b/dlls/kernelbase/kernelbase.spec @@ -1082,7 +1082,7 @@ @ stdcall PathIsSameRootA(str str) shlwapi.PathIsSameRootA @ stdcall PathIsSameRootW(wstr wstr) shlwapi.PathIsSameRootW @ stdcall PathIsUNCA(str) shlwapi.PathIsUNCA -# @ stub PathIsUNCEx +@ stdcall PathIsUNCEx(wstr ptr) @ stdcall PathIsUNCServerA(str) shlwapi.PathIsUNCServerA @ stdcall PathIsUNCServerShareA(str) shlwapi.PathIsUNCServerShareA @ stdcall PathIsUNCServerShareW(wstr) shlwapi.PathIsUNCServerShareW diff --git a/dlls/kernelbase/path.c b/dlls/kernelbase/path.c index 047017eb479..4aa39b4ae37 100644 --- a/dlls/kernelbase/path.c +++ b/dlls/kernelbase/path.c @@ -38,6 +38,12 @@ static SIZE_T strnlenW(const WCHAR *string, SIZE_T maxlen) return i; } +static BOOL is_prefixed_unc(const WCHAR *string) +{ + static const WCHAR prefixed_unc[] = {'\\', '\\', '?', '\\', 'U', 'N', 'C', '\\'}; + return !strncmpiW(string, prefixed_unc, ARRAY_SIZE(prefixed_unc)); +} + HRESULT WINAPI PathCchAddBackslash(WCHAR *path, SIZE_T size) { return PathCchAddBackslashEx(path, size, NULL, NULL); @@ -183,3 +189,18 @@ HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *ext hr = PathCchAddExtension(path, size, extension); return FAILED(hr) ? hr : S_OK; } + +BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server) +{ + const WCHAR *result = NULL; + + TRACE("%s %p\n", wine_dbgstr_w(path), server); + + if (is_prefixed_unc(path)) + result = path + 8; + else if (path[0] == '\\' && path[1] == '\\' && path[2] != '?') + result = path + 2; + + if (server) *server = result; + return result ? TRUE : FALSE; +} diff --git a/dlls/kernelbase/tests/path.c b/dlls/kernelbase/tests/path.c index 1d6f44ee769..3f7925df98a 100644 --- a/dlls/kernelbase/tests/path.c +++ b/dlls/kernelbase/tests/path.c @@ -37,6 +37,7 @@ HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension); HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size); HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension); +BOOL (WINAPI *pPathIsUNCEx)(const WCHAR *path, const WCHAR **server); static const struct { @@ -632,6 +633,75 @@ static void test_PathCchRenameExtension(void) } } +struct isuncex_test +{ + const CHAR *path; + INT server_offset; + BOOL ret; +}; + +static const struct isuncex_test isuncex_tests[] = +{ + {"\\\\", 2, TRUE}, + {"\\\\a\\", 2, TRUE}, + {"\\\\.\\", 2, TRUE}, + {"\\\\?\\UNC\\", 8, TRUE}, + {"\\\\?\\UNC\\a", 8, TRUE}, + {"\\\\?\\unc\\", 8, TRUE}, + {"\\\\?\\unc\\a", 8, TRUE}, + + {"", 0, FALSE}, + {"\\", 0, FALSE}, + {"C:\\", 0, FALSE}, + {"\\??\\", 0, FALSE}, + {"\\\\?\\", 0, FALSE}, + {"\\\\?\\UNC", 0, FALSE}, + {"\\\\?\\C:", 0, FALSE}, + {"\\\\?\\C:\\", 0, FALSE}, + {"\\\\?\\C:\\a", 0, FALSE}, + {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, FALSE} +}; + +static void test_PathIsUNCEx(void) +{ + WCHAR pathW[MAX_PATH]; + const WCHAR *server; + BOOL ret; + INT i; + + if (!pPathIsUNCEx) + { + win_skip("PathIsUNCEx(() is not available.\n"); + return; + } + + /* No NULL check for path pointers on Windows */ + if (0) + { + ret = pPathIsUNCEx(NULL, &server); + ok(ret == FALSE, "expect FALSE\n"); + } + + MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, pathW, ARRAY_SIZE(pathW)); + ret = pPathIsUNCEx(pathW, NULL); + ok(ret == FALSE, "expect FALSE\n"); + + for (i = 0; i < ARRAY_SIZE(isuncex_tests); i++) + { + const struct isuncex_test *t = isuncex_tests + i; + + MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW)); + server = (const WCHAR *)0xdeadbeef; + ret = pPathIsUNCEx(pathW, &server); + ok(ret == t->ret, "path \"%s\" expect return %d, got %d\n", t->path, t->ret, ret); + if (ret) + ok(server == pathW + t->server_offset, "path \"%s\" expect server offset %d, got %ld\n", t->path, + t->server_offset, (INT_PTR)(server - pathW)); + else + ok(!server, "expect server is null, got %p\n", server); + } +} + START_TEST(path) { HMODULE hmod = LoadLibraryA("kernelbase.dll"); @@ -643,6 +713,7 @@ START_TEST(path) pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension"); pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension"); pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension"); + pPathIsUNCEx = (void *)GetProcAddress(hmod, "PathIsUNCEx"); test_PathCchCombineEx(); test_PathCchAddBackslash(); @@ -651,4 +722,5 @@ START_TEST(path) test_PathCchFindExtension(); test_PathCchRemoveExtension(); test_PathCchRenameExtension(); + test_PathIsUNCEx(); } diff --git a/include/pathcch.h b/include/pathcch.h index 3057b6c1ec2..6973d6dda20 100644 --- a/include/pathcch.h +++ b/include/pathcch.h @@ -32,3 +32,4 @@ HRESULT WINAPI PathCchCombineEx(WCHAR *out, SIZE_T size, const WCHAR *path1, con HRESULT WINAPI PathCchFindExtension(const WCHAR *path, SIZE_T size, const WCHAR **extension); HRESULT WINAPI PathCchRemoveExtension(WCHAR *path, SIZE_T size); HRESULT WINAPI PathCchRenameExtension(WCHAR *path, SIZE_T size, const WCHAR *extension); +BOOL WINAPI PathIsUNCEx(const WCHAR *path, const WCHAR **server);