makefiles: Don't use standard libs for programs that specify -nodefaultlibs.
[wine/zf.git] / dlls / kernelbase / tests / path.c
blob2ee7b512b31db7dea138b50ecce756e1df287582
1 /*
2 * Path tests for kernelbase.dll
4 * Copyright 2017 Michael Müller
5 * Copyright 2018 Zhiyi Zhang
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #include <stdarg.h>
23 #include <windef.h>
24 #include <winbase.h>
25 #include <stdlib.h>
26 #include <winerror.h>
27 #include <winnls.h>
28 #include <pathcch.h>
29 #include <strsafe.h>
31 #include "wine/test.h"
33 HRESULT (WINAPI *pPathAllocCanonicalize)(const WCHAR *path_in, DWORD flags, WCHAR **path_out);
34 HRESULT (WINAPI *pPathAllocCombine)(const WCHAR *path1, const WCHAR *path2, DWORD flags, WCHAR **out);
35 HRESULT (WINAPI *pPathCchAddBackslash)(WCHAR *out, SIZE_T size);
36 HRESULT (WINAPI *pPathCchAddBackslashEx)(WCHAR *out, SIZE_T size, WCHAR **endptr, SIZE_T *remaining);
37 HRESULT (WINAPI *pPathCchAddExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
38 HRESULT (WINAPI *pPathCchAppend)(WCHAR *path1, SIZE_T size, const WCHAR *path2);
39 HRESULT (WINAPI *pPathCchAppendEx)(WCHAR *path1, SIZE_T size, const WCHAR *path2, DWORD flags);
40 HRESULT (WINAPI *pPathCchCanonicalize)(WCHAR *out, SIZE_T size, const WCHAR *in);
41 HRESULT (WINAPI *pPathCchCanonicalizeEx)(WCHAR *out, SIZE_T size, const WCHAR *in, DWORD flags);
42 HRESULT (WINAPI *pPathCchCombine)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2);
43 HRESULT (WINAPI *pPathCchCombineEx)(WCHAR *out, SIZE_T size, const WCHAR *path1, const WCHAR *path2, DWORD flags);
44 HRESULT (WINAPI *pPathCchFindExtension)(const WCHAR *path, SIZE_T size, const WCHAR **extension);
45 BOOL (WINAPI *pPathCchIsRoot)(const WCHAR *path);
46 HRESULT (WINAPI *pPathCchRemoveBackslash)(WCHAR *path, SIZE_T path_size);
47 HRESULT (WINAPI *pPathCchRemoveBackslashEx)(WCHAR *path, SIZE_T path_size, WCHAR **path_end, SIZE_T *free_size);
48 HRESULT (WINAPI *pPathCchRemoveExtension)(WCHAR *path, SIZE_T size);
49 HRESULT (WINAPI *pPathCchRemoveFileSpec)(WCHAR *path, SIZE_T size);
50 HRESULT (WINAPI *pPathCchRenameExtension)(WCHAR *path, SIZE_T size, const WCHAR *extension);
51 HRESULT (WINAPI *pPathCchSkipRoot)(const WCHAR *path, const WCHAR **root_end);
52 HRESULT (WINAPI *pPathCchStripPrefix)(WCHAR *path, SIZE_T size);
53 HRESULT (WINAPI *pPathCchStripToRoot)(WCHAR *path, SIZE_T size);
54 BOOL (WINAPI *pPathIsUNCEx)(const WCHAR *path, const WCHAR **server);
56 struct alloccanonicalize_test
58 const CHAR *path_in;
59 const CHAR *path_out;
60 DWORD flags;
61 HRESULT hr;
64 static const struct alloccanonicalize_test alloccanonicalize_tests[] =
66 /* Malformed path */
67 {"C:a", "C:a", 0, S_OK},
68 {"\\\\?\\C:", "C:\\", 0, S_OK},
69 {"\\\\?C:\\a", "\\\\?C:\\a", 0, S_OK},
70 {"\\\\?UNC\\a", "\\\\?UNC\\a", 0, S_OK},
71 {"\\\\?\\UNCa", "\\\\?\\UNCa", 0, S_OK},
72 {"\\\\?C:a", "\\\\?C:a", 0, S_OK},
74 /* No . */
75 {"*", "*", 0, S_OK},
76 {"", "\\", 0, S_OK},
77 {"C:", "C:", 0, S_OK},
78 {"C:\\", "C:\\", 0, S_OK},
79 {"\\\\?\\C:\\a", "C:\\a", 0, S_OK},
80 {"\\\\?\\UNC\\a", "\\\\a", 0, S_OK},
82 /* . */
83 {".", "\\", 0, S_OK},
84 {"..", "\\", 0, S_OK},
85 {"...", "\\", 0, S_OK},
86 {"*.", "*.", 0, S_OK},
87 {"*.\\", "*.\\", 0, S_OK},
88 {"*.\\", "*.\\", 0, S_OK},
89 {"*..", "*.", 0, S_OK},
90 {"*..\\", "*..\\", 0, S_OK},
91 {"*...", "*.", 0, S_OK},
92 {"*...\\", "*...\\", 0, S_OK},
93 {"*....", "*.", 0, S_OK},
94 {"*....\\", "*....\\", 0, S_OK},
95 {".a", ".a", 0, S_OK},
96 {".a\\", ".a\\", 0, S_OK},
97 {"a.", "a", 0, S_OK},
98 {"a.\\", "a.\\", 0, S_OK},
99 {".a.", ".a", 0, S_OK},
100 {"a.b", "a.b", 0, S_OK},
101 {".a.b.", ".a.b", 0, S_OK},
102 {"a\\.", "a", 0, S_OK},
103 {"a\\.\\b", "a\\b", 0, S_OK},
104 {"a\\.b", "a\\.b", 0, S_OK},
105 {"a\\.b\\", "a\\.b\\", 0, S_OK},
106 {":.", ":", 0, S_OK},
107 {"::.", "::\\", 0, S_OK},
108 {":::.", ":::", 0, S_OK},
109 {"C:.", "C:\\", 0, S_OK},
110 {"C:.\\", "C:.\\", 0, S_OK},
111 {"C:.\\.", "C:\\", 0, S_OK},
112 {"C:\\.", "C:\\", 0, S_OK},
113 {"C:\\.\\", "C:\\", 0, S_OK},
114 {"C:\\a.", "C:\\a", 0, S_OK},
115 {"C:\\a.\\", "C:\\a.\\", 0, S_OK},
116 {"C:\\.a", "C:\\.a", 0, S_OK},
117 {"C:\\.a\\", "C:\\.a\\", 0, S_OK},
118 {"C:\\a\\.", "C:\\a", 0, S_OK},
119 {"C:\\a\\\\.", "C:\\a\\", 0, S_OK},
120 {"C:\\a\\\\\\.", "C:\\a\\\\", 0, S_OK},
121 {".\\", "\\", 0, S_OK},
122 {"\\.", "\\", 0, S_OK},
123 {"\\\\.", "\\\\", 0, S_OK},
124 {"\\\\.\\", "\\\\", 0, S_OK},
125 {"\\\\\\.", "\\\\", 0, S_OK},
126 {"\\\\.\\\\", "\\\\\\", 0, S_OK},
127 {"\\\\\\\\.", "\\\\\\", 0, S_OK},
128 {"\\?\\.", "\\?", 0, S_OK},
129 {"\\\\?\\.", "\\\\?", 0, S_OK},
130 {"\\192.168.1.1\\a", "\\192.168.1.1\\a", 0, S_OK},
131 {"\\a.168.1.1\\a", "\\a.168.1.1\\a", 0, S_OK},
132 {"\\\\192.168.1.1\\a", "\\\\192.168.1.1\\a", 0, S_OK},
133 {"\\\\a.168.1.1\\b", "\\\\a.168.1.1\\b", 0, S_OK},
134 {"\\\\?\\C:.", "C:\\", 0, S_OK},
135 {"\\\\?\\C:\\.", "C:\\", 0, S_OK},
136 {"\\\\?\\UNC\\.", "\\\\", 0, S_OK},
137 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\.",
138 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, S_OK},
140 /* .. */
141 {"..a", "..a", 0, S_OK},
142 {"..a\\", "..a\\", 0, S_OK},
143 {"...a", "...a", 0, S_OK},
144 {"...a\\", "...a\\", 0, S_OK},
145 {"....a", "....a", 0, S_OK},
146 {"a..", "a", 0, S_OK},
147 {"a..\\", "a..\\", 0, S_OK},
148 {"a...", "a", 0, S_OK},
149 {"a...\\", "a...\\", 0, S_OK},
150 {"a....", "a", 0, S_OK},
151 {"a....\\", "a....\\", 0, S_OK},
152 {"..a..", "..a", 0, S_OK},
153 {"a..b", "a..b", 0, S_OK},
154 {"..a..b..", "..a..b", 0, S_OK},
155 {"a\\..", "\\", 0, S_OK},
156 {"a\\..\\", "\\", 0, S_OK},
157 {"a\\..\\b", "\\b", 0, S_OK},
158 {":..", ":", 0, S_OK},
159 {"::..", "::\\", 0, S_OK},
160 {":::..", ":::", 0, S_OK},
161 {"C:..", "C:\\", 0, S_OK},
162 {"C:...", "C:\\", 0, S_OK},
163 {"C:..\\", "C:..\\", 0, S_OK},
164 {"C:..\\\\", "C:..\\\\", 0, S_OK},
165 {"C:...\\", "C:...\\", 0, S_OK},
166 {"C:\\..", "C:\\", 0, S_OK},
167 {"C:\\..a", "C:\\..a", 0, S_OK},
168 {"C:\\..a\\", "C:\\..a\\", 0, S_OK},
169 {"C:\\...a", "C:\\...a", 0, S_OK},
170 {"C:\\...a\\", "C:\\...a\\", 0, S_OK},
171 {"C:\\....a", "C:\\....a", 0, S_OK},
172 {"C:\\....a\\", "C:\\....a\\", 0, S_OK},
173 {"C:\\a..", "C:\\a", 0, S_OK},
174 {"C:\\a..\\", "C:\\a..\\", 0, S_OK},
175 {"C:\\\\..", "C:\\", 0, S_OK},
176 {"C:\\..\\", "C:\\", 0, S_OK},
177 {"C:\\...\\", "C:\\...\\", 0, S_OK},
178 {"C:\\a\\..", "C:\\", 0, S_OK},
179 {"C:\\a\\b..", "C:\\a\\b", 0, S_OK},
180 {"C:\\a\\\\..", "C:\\a", 0, S_OK},
181 {"C:\\a\\\\\\..", "C:\\a\\", 0, S_OK},
182 {"C:\\a\\..\\b", "C:\\b", 0, S_OK},
183 {"C:\\a\\..\\\\b", "C:\\\\b", 0, S_OK},
184 {"..\\", "\\", 0, S_OK},
185 {"...\\", "...\\", 0, S_OK},
186 {"\\..", "\\", 0, S_OK},
187 {"\\...", "\\", 0, S_OK},
188 {"\\\\..", "\\\\", 0, S_OK},
189 {"\\\\\\..", "\\", 0, S_OK},
190 {"\\\\..\\", "\\\\", 0, S_OK},
191 {"\\\\\\..", "\\", 0, S_OK},
192 {"\\\\..\\\\", "\\\\\\", 0, S_OK},
193 {"\\\\\\\\..", "\\\\", 0, S_OK},
194 {"\\?\\..", "\\", 0, S_OK},
195 {"\\a\\..", "\\", 0, S_OK},
196 {"\\\\?\\..", "\\", 0, S_OK},
197 {"\\\\a\\..", "\\", 0, S_OK},
198 {"\\a\\..\\b", "\\b", 0, S_OK},
199 {"\\a\\b\\..", "\\a", 0, S_OK},
200 {"\\?\\UNC\\..", "\\?", 0, S_OK},
201 {"\\?\\C:\\..", "\\?", 0, S_OK},
202 {"\\\\?\\C:..", "C:\\", 0, S_OK},
203 {"\\\\?\\C:\\..", "C:\\", 0, S_OK},
204 {"\\\\?\\UNC\\..", "\\\\", 0, S_OK},
205 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}..",
206 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", 0, S_OK},
207 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\..",
208 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, S_OK},
209 {"\\\\?\\UNC\\a\\b\\..", "\\\\a", 0, S_OK},
210 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b\\..",
211 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 0, S_OK},
213 /* . and .. */
214 {"C:\\a\\.\\b\\..\\", "C:\\a\\", 0, S_OK},
215 {"\\a\\.\\b\\..\\", "\\a\\", 0, S_OK},
216 {"\\?\\a\\.\\b\\..\\", "\\?\\a\\", 0, S_OK},
217 {"\\\\.\\a\\.\\b\\..\\", "\\\\a\\", 0, S_OK},
218 {"\\\\?\\a\\.\\b\\..\\", "\\\\?\\a\\", 0, S_OK},
219 {"\\\\.\\..", "\\\\", 0, S_OK},
221 /* PATHCCH_ALLOW_LONG_PATHS */
222 /* Input path with prefix \\?\ and length of MAXPATH + 1, HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) = 0x800700ce */
223 {"\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
224 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
225 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", NULL, 0, 0x800700ce},
226 /* Input path with prefix C:\ and length of MAXPATH + 1 */
227 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
228 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
229 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", NULL, 0, 0x800700ce},
230 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
231 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
232 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
233 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
234 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
235 /* Input path with prefix C: and length of MAXPATH + 1 */
236 {"C:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
237 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
238 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
239 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
240 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
241 /* Input path with prefix C:\ and length of MAXPATH + 1 and with .. */
242 {"C:\\..\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
243 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
244 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
245 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
246 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
247 /* Input path with prefix \\?\ and length of MAXPATH + 1 */
248 {"\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
249 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
250 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
251 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
252 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
253 /* Input path with prefix \ and length of MAXPATH + 1 */
254 {"\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
255 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
256 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
257 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
258 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
259 /* Input path with length of MAXPATH with PATHCCH_ALLOW_LONG_PATHS disabled*/
260 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
261 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
262 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
263 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
264 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, S_OK},
265 /* Input path with length of MAXPATH */
266 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
267 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
268 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
269 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
270 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", PATHCCH_ALLOW_LONG_PATHS, S_OK},
272 /* Flags added after Windows 10 1709 */
273 /* PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS */
274 /* PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS without PATHCCH_ALLOW_LONG_PATHS */
275 {"", NULL, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, E_INVALIDARG},
276 /* Input path with prefix C:\ and length of MAXPATH + 1 and PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS */
277 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
278 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
279 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
280 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
281 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
282 PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, S_OK},
284 /* PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
285 /* PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS without PATHCCH_ALLOW_LONG_PATHS */
286 {"", NULL, PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, E_INVALIDARG},
287 /* Both PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
288 {"", "\\", PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS,
289 E_INVALIDARG},
290 /* Input path with prefix C:\ and length of MAXPATH + 1 and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
291 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
292 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
293 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "\\\\?\\C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
294 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
295 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
296 PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, S_OK},
297 /* Input path with prefix C:\ and length of MAXPATH and PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS */
298 {"C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
299 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
300 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "C:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
301 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
302 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
303 PATHCCH_ALLOW_LONG_PATHS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS, S_OK},
305 /* PATHCCH_DO_NOT_NORMALIZE_SEGMENTS */
306 /* No effect for spaces */
307 {"a ", "a ", 0, S_OK},
308 {"C:\\a ", "C:\\a ", 0, S_OK},
309 {"C:\\a \\", "C:\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
310 {"C:\\a\\ ", "C:\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
311 {"C:\\a ", "C:\\a ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
312 {"C:\\a ", "C:\\a ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
313 {"C:\\a. ", "C:\\a. ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
314 {"\\a \\", "\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
315 {"\\a\\ ", "\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
316 {"\\\\a \\", "\\\\a \\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
317 {"\\\\a\\ ", "\\\\a\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
318 {"\\\\?\\ ", "\\\\?\\ ", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
319 /* Keep trailing dot */
320 {"*..", "*..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
321 {".", "\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
322 {"..", "\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
323 {":.", ":.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
324 {"::.", "::.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
325 {":::.", ":::.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
326 {":..", ":..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
327 {"::..", "::..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
328 {":::..", ":::..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
329 {"C:.", "C:.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
330 {"C:..", "C:..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
331 {"C:...", "C:...", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
332 {"C:\\a\\.", "C:\\a", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
333 {"C:\\a\\..", "C:\\", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
334 {"C:\\a.", "C:\\a.", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
335 {"C:\\a..", "C:\\a..", PATHCCH_DO_NOT_NORMALIZE_SEGMENTS, S_OK},
337 /* PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH */
338 {"C:\\a\\", "\\\\?\\C:\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
339 {"", NULL, PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH | PATHCCH_ALLOW_LONG_PATHS, E_INVALIDARG},
340 {"\\a\\", "\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
341 {"\\\\?\\C:\\a\\", "\\\\?\\C:\\a\\", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
342 /* Implication of PATHCCH_DO_NOT_NORMALIZE_SEGMENTS by PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH */
343 {"\\a.", "\\a.", PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH, S_OK},
345 /* PATHCCH_ENSURE_TRAILING_SLASH */
346 {"\\", "\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
347 {"C:\\", "C:\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
348 {"C:\\a\\.", "C:\\a\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK},
349 {"C:\\a", "C:\\a\\", PATHCCH_ENSURE_TRAILING_SLASH, S_OK}
352 static void test_PathAllocCanonicalize(void)
354 WCHAR path_inW[1024], path_maxW[PATHCCH_MAX_CCH + 1];
355 WCHAR *path_outW;
356 CHAR path_outA[1024];
357 BOOL skip_new_flags = TRUE;
358 HRESULT hr;
359 INT i;
361 if (!pPathAllocCanonicalize)
363 win_skip("PathAllocCanonicalize() is not available.\n");
364 return;
367 /* No NULL check for path on Windows */
368 if (0)
370 hr = pPathAllocCanonicalize(NULL, 0, &path_outW);
371 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
374 MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
375 hr = pPathAllocCanonicalize(path_inW, 0, NULL);
376 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
378 /* Test longest path */
379 for (i = 0; i < ARRAY_SIZE(path_maxW) - 1; i++) path_maxW[i] = 'a';
380 path_maxW[PATHCCH_MAX_CCH] = '\0';
381 path_outW = (WCHAR *)0xdeadbeef;
382 hr = pPathAllocCanonicalize(path_maxW, PATHCCH_ALLOW_LONG_PATHS, &path_outW);
383 ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
384 HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
385 ok(path_outW == NULL, "expect path_outW null, got %p\n", path_outW);
387 path_maxW[PATHCCH_MAX_CCH - 1] = '\0';
388 hr = pPathAllocCanonicalize(path_maxW, PATHCCH_ALLOW_LONG_PATHS, &path_outW);
389 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
390 LocalFree(path_outW);
392 /* Check if flags added after Windows 10 1709 are supported */
393 MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
394 hr = pPathAllocCanonicalize(path_inW, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS, &path_outW);
395 if (hr == E_INVALIDARG) skip_new_flags = FALSE;
397 for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
399 const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
401 if (((PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
402 | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
403 | PATHCCH_ENSURE_TRAILING_SLASH)
404 & t->flags)
405 && skip_new_flags)
407 win_skip("Skip testing new flags added after Windows 10 1709\n");
408 return;
411 MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
412 hr = pPathAllocCanonicalize(path_inW, t->flags, &path_outW);
413 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
414 if (SUCCEEDED(hr))
416 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
417 ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
418 t->path_out, path_outA);
419 LocalFree(path_outW);
424 struct combine_test
426 const CHAR *path1;
427 const CHAR *path2;
428 const CHAR *result;
431 static const struct combine_test combine_tests[] =
433 /* normal paths */
434 {"C:\\", "a", "C:\\a" },
435 {"C:\\b", "..\\a", "C:\\a" },
436 {"C:", "a", "C:\\a" },
437 {"C:\\", ".", "C:\\" },
438 {"C:\\", "..", "C:\\" },
439 {"C:\\a", "", "C:\\a" },
440 {"\\", "a", "\\a"},
441 {"\\a", "b", "\\a\\b" },
443 /* normal UNC paths */
444 {"\\\\192.168.1.1\\test", "a", "\\\\192.168.1.1\\test\\a" },
445 {"\\\\192.168.1.1\\test", "..", "\\\\192.168.1.1" },
446 {"\\\\", "a", "\\\\a"},
447 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", "a",
448 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a"},
450 /* NT paths */
451 {"\\\\?\\C:\\", "a", "C:\\a" },
452 {"\\\\?\\C:\\", "..", "C:\\" },
453 {"\\\\?\\C:", "a", "C:\\a"},
455 /* NT UNC path */
456 {"\\\\?\\UNC\\", "a", "\\\\a"},
457 {"\\\\?\\UNC\\192.168.1.1\\test", "a", "\\\\192.168.1.1\\test\\a" },
458 {"\\\\?\\UNC\\192.168.1.1\\test", "..", "\\\\192.168.1.1" },
460 /* Second path begins with a single backslash */
461 {"C:a\\b", "\\1", "C:\\1"},
462 {"C:\\a\\b", "\\1", "C:\\1"},
463 {"\\a\\b", "\\1", "\\1"},
464 {"\\\\a\\b", "\\1", "\\\\a\\b\\1"},
465 {"\\\\a\\b\\c", "\\1", "\\\\a\\b\\1"},
466 {"\\\\?\\UNC\\a", "\\1", "\\\\a\\1"},
467 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a", "\\1",
468 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1"},
469 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", "\\1",
470 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1"},
471 {"C:\\a\\b", "\\", "C:\\"},
473 /* Second path is fully qualified */
474 {"X:\\", "C:", "C:\\"},
475 {"X:\\", "C:\\", "C:\\"},
476 {"X:\\", "\\\\", "\\\\"},
477 {"X:\\", "\\\\?\\C:", "C:\\"},
478 {"X:\\", "\\\\?\\C:\\", "C:\\"},
479 {"X:\\", "\\\\?\\UNC\\", "\\\\"},
480 {"X:\\", "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
481 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\"},
483 /* Canonicalization */
484 {"C:\\a", ".\\b", "C:\\a\\b"},
485 {"C:\\a", "..\\b", "C:\\b"},
487 /* Other */
488 {"", "", "\\"},
489 {"a", "b", "a\\b"}
492 static void test_PathAllocCombine(void)
494 WCHAR path1W[PATHCCH_MAX_CCH];
495 WCHAR path2W[PATHCCH_MAX_CCH];
496 WCHAR *resultW;
497 CHAR resultA[PATHCCH_MAX_CCH];
498 HRESULT hr;
499 INT i;
501 if (!pPathAllocCombine)
503 win_skip("PathAllocCombine() is not available.\n");
504 return;
507 resultW = (WCHAR *)0xdeadbeef;
508 hr = pPathAllocCombine(NULL, NULL, 0, &resultW);
509 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
510 ok(resultW == NULL, "expect resultW null, got %p\n", resultW);
512 MultiByteToWideChar(CP_ACP, 0, "\\a", -1, path1W, ARRAY_SIZE(path1W));
513 hr = pPathAllocCombine(path1W, NULL, 0, &resultW);
514 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
515 WideCharToMultiByte(CP_ACP, 0, resultW, -1, resultA, ARRAY_SIZE(resultA), NULL, NULL);
516 ok(!lstrcmpA(resultA, "\\a"), "expect \\a, got %s\n", resultA);
517 LocalFree(resultW);
519 MultiByteToWideChar(CP_ACP, 0, "\\b", -1, path2W, ARRAY_SIZE(path2W));
520 hr = pPathAllocCombine(NULL, path2W, 0, &resultW);
521 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
522 WideCharToMultiByte(CP_ACP, 0, resultW, -1, resultA, ARRAY_SIZE(resultA), NULL, NULL);
523 ok(!lstrcmpA(resultA, "\\b"), "expect \\b, got %s\n", resultA);
524 LocalFree(resultW);
526 hr = pPathAllocCombine(path1W, path2W, 0, NULL);
527 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
529 for (i = 0; i < ARRAY_SIZE(combine_tests); i++)
531 const struct combine_test *t = combine_tests + i;
533 MultiByteToWideChar(CP_ACP, 0, t->path1, -1, path1W, ARRAY_SIZE(path1W));
534 MultiByteToWideChar(CP_ACP, 0, t->path2, -1, path2W, ARRAY_SIZE(path2W));
535 hr = pPathAllocCombine(path1W, path2W, 0, &resultW);
536 ok(hr == S_OK, "combine %s %s expect hr %#x, got %#x\n", t->path1, t->path2, S_OK, hr);
537 if (SUCCEEDED(hr))
539 WideCharToMultiByte(CP_ACP, 0, resultW, -1, resultA, ARRAY_SIZE(resultA), NULL, NULL);
540 ok(!lstrcmpA(resultA, t->result), "combine %s %s expect result %s, got %s\n", t->path1, t->path2, t->result,
541 resultA);
542 LocalFree(resultW);
547 static void test_PathCchCombine(void)
549 WCHAR expected[PATHCCH_MAX_CCH] = {'C', ':', '\\', 'a', 0};
550 WCHAR p1[PATHCCH_MAX_CCH] = {'C', ':', '\\', 0};
551 WCHAR p2[PATHCCH_MAX_CCH] = {'a', 0};
552 WCHAR output[PATHCCH_MAX_CCH];
553 HRESULT hr;
554 INT i;
556 if (!pPathCchCombine)
558 win_skip("PathCchCombine() is not available.\n");
559 return;
562 hr = pPathCchCombine(output, 5, NULL, NULL);
563 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
565 hr = pPathCchCombine(NULL, 2, p1, p2);
566 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
568 memset(output, 0xff, sizeof(output));
569 hr = pPathCchCombine(output, 0, p1, p2);
570 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
571 ok(output[0] == 0xffff, "Expected output buffer to be unchanged\n");
573 memset(output, 0xff, sizeof(output));
574 hr = pPathCchCombine(output, 1, p1, p2);
575 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Expected STRSAFE_E_INSUFFICIENT_BUFFER, got %08x\n", hr);
576 ok(output[0] == 0, "Expected output buffer to contain NULL string\n");
578 memset(output, 0xff, sizeof(output));
579 hr = pPathCchCombine(output, 4, p1, p2);
580 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Expected STRSAFE_E_INSUFFICIENT_BUFFER, got %08x\n", hr);
581 ok(output[0] == 0x0, "Expected output buffer to contain NULL string\n");
583 memset(output, 0xff, sizeof(output));
584 hr = pPathCchCombine(output, 5, p1, p2);
585 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
586 ok(!lstrcmpW(output, expected), "Combination of %s + %s returned %s, expected %s\n", wine_dbgstr_w(p1),
587 wine_dbgstr_w(p2), wine_dbgstr_w(output), wine_dbgstr_w(expected));
589 hr = pPathCchCombine(output, PATHCCH_MAX_CCH + 1, p1, p2);
590 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
592 hr = pPathCchCombine(output, PATHCCH_MAX_CCH, p1, p2);
593 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
595 for (i = 0; i < ARRAY_SIZE(combine_tests); i++)
597 MultiByteToWideChar(CP_ACP, 0, combine_tests[i].path1, -1, p1, ARRAY_SIZE(p1));
598 MultiByteToWideChar(CP_ACP, 0, combine_tests[i].path2, -1, p2, ARRAY_SIZE(p2));
599 MultiByteToWideChar(CP_ACP, 0, combine_tests[i].result, -1, expected, ARRAY_SIZE(expected));
601 hr = pPathCchCombine(output, ARRAY_SIZE(output), p1, p2);
602 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
603 ok(!lstrcmpW(output, expected), "Combining %s with %s returned %s, expected %s\n", wine_dbgstr_w(p1),
604 wine_dbgstr_w(p2), wine_dbgstr_w(output), wine_dbgstr_w(expected));
608 static void test_PathCchCombineEx(void)
610 WCHAR expected[MAX_PATH] = {'C',':','\\','a',0};
611 WCHAR p1[MAX_PATH] = {'C',':','\\',0};
612 WCHAR p2[MAX_PATH] = {'a',0};
613 WCHAR output[MAX_PATH];
614 HRESULT hr;
615 int i;
617 if (!pPathCchCombineEx)
619 win_skip("PathCchCombineEx() is not available.\n");
620 return;
623 output[0] = 0xff;
624 hr = pPathCchCombineEx(output, 5, NULL, NULL, 0);
625 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
626 ok(output[0] == 0, "Expected output buffer to be empty\n");
628 output[0] = 0xff;
629 hr = pPathCchCombineEx(NULL, 2, p1, p2, 0);
630 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
631 ok(output[0] == 0xff, "Expected output buffer to be unchanged\n");
633 memset(output, 0xff, sizeof(output));
634 hr = pPathCchCombineEx(output, 0, p1, p2, 0);
635 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
636 ok(output[0] == 0xffff, "Expected output buffer to be unchanged\n");
638 memset(output, 0xff, sizeof(output));
639 hr = pPathCchCombineEx(output, 1, p1, p2, 0);
640 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Expected STRSAFE_E_INSUFFICIENT_BUFFER, got %08x\n", hr);
641 ok(output[0] == 0, "Expected output buffer to contain NULL string\n");
643 memset(output, 0xff, sizeof(output));
644 hr = pPathCchCombineEx(output, 4, p1, p2, 0);
645 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Expected STRSAFE_E_INSUFFICIENT_BUFFER, got %08x\n", hr);
646 ok(output[0] == 0x0, "Expected output buffer to contain NULL string\n");
648 output[0] = 0xff;
649 hr = pPathCchCombineEx(output, PATHCCH_MAX_CCH + 1, p1, p2, 0);
650 ok(hr == E_INVALIDARG, "Expected E_INVALIDARG, got %08x\n", hr);
651 ok(output[0] == 0xff, "Expected output buffer to be 0xff\n");
653 hr = pPathCchCombineEx(output, PATHCCH_MAX_CCH, p1, p2, 0);
654 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
656 memset(output, 0xff, sizeof(output));
657 hr = pPathCchCombineEx(output, 5, p1, p2, 0);
658 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
659 ok(!lstrcmpW(output, expected),
660 "Combination of %s + %s returned %s, expected %s\n",
661 wine_dbgstr_w(p1), wine_dbgstr_w(p2), wine_dbgstr_w(output), wine_dbgstr_w(expected));
663 for (i = 0; i < ARRAY_SIZE(combine_tests); i++)
665 MultiByteToWideChar(CP_ACP, 0, combine_tests[i].path1, -1, p1, MAX_PATH);
666 MultiByteToWideChar(CP_ACP, 0, combine_tests[i].path2, -1, p2, MAX_PATH);
667 MultiByteToWideChar(CP_ACP, 0, combine_tests[i].result, -1, expected, MAX_PATH);
669 hr = pPathCchCombineEx(output, MAX_PATH, p1, p2, 0);
670 ok(hr == S_OK, "Expected S_OK, got %08x\n", hr);
671 ok(!lstrcmpW(output, expected), "Combining %s with %s returned %s, expected %s\n",
672 wine_dbgstr_w(p1), wine_dbgstr_w(p2), wine_dbgstr_w(output), wine_dbgstr_w(expected));
676 struct addbackslash_test
678 const char *path;
679 const char *result;
680 HRESULT hr;
681 SIZE_T size;
682 SIZE_T remaining;
685 static const struct addbackslash_test addbackslash_tests[] =
687 { "C:", "C:\\", S_OK, MAX_PATH, MAX_PATH - 3 },
688 { "a.txt", "a.txt\\", S_OK, MAX_PATH, MAX_PATH - 6 },
689 { "a/b", "a/b\\", S_OK, MAX_PATH, MAX_PATH - 4 },
691 { "C:\\", "C:\\", S_FALSE, MAX_PATH, MAX_PATH - 3 },
692 { "C:\\", "C:\\", S_FALSE, 4, 1 },
694 { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 2, 0 },
695 { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 3, 1 },
696 { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 2, 0 },
697 { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 3, 0 },
698 { "C:\\", "C:\\", STRSAFE_E_INSUFFICIENT_BUFFER, 0, 0 },
699 { "C:", "C:", STRSAFE_E_INSUFFICIENT_BUFFER, 0, 0 },
702 static void test_PathCchAddBackslash(void)
704 WCHAR pathW[MAX_PATH];
705 unsigned int i;
706 HRESULT hr;
708 if (!pPathCchAddBackslash)
710 win_skip("PathCchAddBackslash() is not available.\n");
711 return;
714 pathW[0] = 0;
715 hr = pPathCchAddBackslash(pathW, 0);
716 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
717 ok(pathW[0] == 0, "Unexpected path.\n");
719 pathW[0] = 0;
720 hr = pPathCchAddBackslash(pathW, 1);
721 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
722 ok(pathW[0] == 0, "Unexpected path.\n");
724 pathW[0] = 0;
725 hr = pPathCchAddBackslash(pathW, 2);
726 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
727 ok(pathW[0] == 0, "Unexpected path.\n");
729 for (i = 0; i < ARRAY_SIZE(addbackslash_tests); i++)
731 const struct addbackslash_test *test = &addbackslash_tests[i];
732 char path[MAX_PATH];
734 MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, ARRAY_SIZE(pathW));
735 hr = pPathCchAddBackslash(pathW, test->size);
736 ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr);
738 WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, ARRAY_SIZE(path), NULL, NULL);
739 ok(!strcmp(path, test->result), "%u: unexpected resulting path %s.\n", i, path);
743 static void test_PathCchAddBackslashEx(void)
745 WCHAR pathW[MAX_PATH];
746 SIZE_T remaining;
747 unsigned int i;
748 HRESULT hr;
749 WCHAR *ptrW;
751 if (!pPathCchAddBackslashEx)
753 win_skip("PathCchAddBackslashEx() is not available.\n");
754 return;
757 pathW[0] = 0;
758 hr = pPathCchAddBackslashEx(pathW, 0, NULL, NULL);
759 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "Unexpected hr %#x.\n", hr);
760 ok(pathW[0] == 0, "Unexpected path.\n");
762 pathW[0] = 0;
763 ptrW = (void *)0xdeadbeef;
764 remaining = 123;
765 hr = pPathCchAddBackslashEx(pathW, 1, &ptrW, &remaining);
766 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
767 ok(pathW[0] == 0, "Unexpected path.\n");
768 ok(ptrW == pathW, "Unexpected endptr %p.\n", ptrW);
769 ok(remaining == 1, "Unexpected remaining size.\n");
771 pathW[0] = 0;
772 hr = pPathCchAddBackslashEx(pathW, 2, NULL, NULL);
773 ok(hr == S_FALSE, "Unexpected hr %#x.\n", hr);
774 ok(pathW[0] == 0, "Unexpected path.\n");
776 for (i = 0; i < ARRAY_SIZE(addbackslash_tests); i++)
778 const struct addbackslash_test *test = &addbackslash_tests[i];
779 char path[MAX_PATH];
781 MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, ARRAY_SIZE(pathW));
782 hr = pPathCchAddBackslashEx(pathW, test->size, NULL, NULL);
783 ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr);
785 WideCharToMultiByte(CP_ACP, 0, pathW, -1, path, ARRAY_SIZE(path), NULL, NULL);
786 ok(!strcmp(path, test->result), "%u: unexpected resulting path %s.\n", i, path);
788 ptrW = (void *)0xdeadbeef;
789 remaining = 123;
790 MultiByteToWideChar(CP_ACP, 0, test->path, -1, pathW, ARRAY_SIZE(pathW));
791 hr = pPathCchAddBackslashEx(pathW, test->size, &ptrW, &remaining);
792 ok(hr == test->hr, "%u: unexpected return value %#x.\n", i, hr);
793 if (SUCCEEDED(hr))
795 ok(ptrW == (pathW + lstrlenW(pathW)), "%u: unexpected end pointer.\n", i);
796 ok(remaining == test->remaining, "%u: unexpected remaining buffer length.\n", i);
798 else
800 ok(ptrW == NULL, "%u: unexpected end pointer.\n", i);
801 ok(remaining == 0, "%u: unexpected remaining buffer length.\n", i);
806 struct addextension_test
808 const CHAR *path;
809 const CHAR *extension;
810 const CHAR *expected;
811 HRESULT hr;
814 static const struct addextension_test addextension_tests[] =
816 /* Normal */
817 {"", ".exe", ".exe", S_OK},
818 {"C:\\", "", "C:\\", S_OK},
819 {"C:", ".exe", "C:.exe", S_OK},
820 {"C:\\", ".exe", "C:\\.exe", S_OK},
821 {"\\", ".exe", "\\.exe", S_OK},
822 {"\\\\", ".exe", "\\\\.exe", S_OK},
823 {"\\\\?\\C:", ".exe", "\\\\?\\C:.exe", S_OK},
824 {"\\\\?\\C:\\", ".exe", "\\\\?\\C:\\.exe", S_OK},
825 {"\\\\?\\UNC\\", ".exe", "\\\\?\\UNC\\.exe", S_OK},
826 {"\\\\?\\UNC\\192.168.1.1\\", ".exe", "\\\\?\\UNC\\192.168.1.1\\.exe", S_OK},
827 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", ".exe",
828 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\.exe", S_OK},
829 {"C:\\", "exe", "C:\\.exe", S_OK},
830 {"C:\\", ".", "C:\\", S_OK},
831 {"C:\\1.exe", ".txt", "C:\\1.exe", S_FALSE},
833 /* Extension contains invalid characters but valid for PathCchAddExtension */
834 {"C:\\", "./", "C:\\./", S_OK},
835 {"C:\\", ".?", "C:\\.?", S_OK},
836 {"C:\\", ".%", "C:\\.%", S_OK},
837 {"C:\\", ".*", "C:\\.*", S_OK},
838 {"C:\\", ".:", "C:\\.:", S_OK},
839 {"C:\\", ".|", "C:\\.|", S_OK},
840 {"C:\\", ".\"", "C:\\.\"", S_OK},
841 {"C:\\", ".<", "C:\\.<", S_OK},
842 {"C:\\", ".>", "C:\\.>", S_OK},
844 /* Invalid argument for extension */
845 {"C:\\", " exe", NULL, E_INVALIDARG},
846 {"C:\\", ". exe", NULL, E_INVALIDARG},
847 {"C:\\", " ", NULL, E_INVALIDARG},
848 {"C:\\", "\\", NULL, E_INVALIDARG},
849 {"C:\\", "..", NULL, E_INVALIDARG},
850 {"C:\\", ". ", NULL, E_INVALIDARG},
851 {"C:\\", ".\\", NULL, E_INVALIDARG},
852 {"C:\\", ".a.", NULL, E_INVALIDARG},
853 {"C:\\", ".a ", NULL, E_INVALIDARG},
854 {"C:\\", ".a\\", NULL, E_INVALIDARG},
855 {"C:\\1.exe", " ", NULL, E_INVALIDARG}
858 struct append_test
860 const CHAR *path1;
861 const CHAR *path2;
862 const CHAR *result;
865 static const struct append_test append_tests[] =
867 /* normal paths */
868 {"C:\\", "a", "C:\\a"},
869 {"C:\\b", "..\\a", "C:\\a"},
870 {"C:", "a", "C:\\a"},
871 {"C:\\", ".", "C:\\"},
872 {"C:\\", "..", "C:\\"},
873 {"C:\\a", "", "C:\\a"},
875 /* normal UNC paths */
876 {"\\\\192.168.1.1\\test", "a", "\\\\192.168.1.1\\test\\a"},
877 {"\\\\192.168.1.1\\test", "..", "\\\\192.168.1.1"},
878 {"\\a", "b", "\\a\\b"},
879 {"\\", "a", "\\a"},
880 {"\\\\", "a", "\\\\a"},
881 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", "a",
882 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a"},
884 /* NT paths */
885 {"\\\\?\\C:\\", "a", "C:\\a"},
886 {"\\\\?\\C:\\", "..", "C:\\"},
887 {"\\\\?\\C:", "a", "C:\\a"},
889 /* NT UNC path */
890 {"\\\\?\\UNC\\", "a", "\\\\a"},
891 {"\\\\?\\UNC\\192.168.1.1\\test", "a", "\\\\192.168.1.1\\test\\a"},
892 {"\\\\?\\UNC\\192.168.1.1\\test", "..", "\\\\192.168.1.1"},
894 /* Second path begins with a single backslash */
895 {"C:a\\b", "\\1", "C:a\\b\\1"},
896 {"C:\\a\\b", "\\1", "C:\\a\\b\\1"},
897 {"\\a\\b", "\\1", "\\a\\b\\1"},
898 {"\\\\a\\b", "\\1", "\\\\a\\b\\1"},
899 {"\\\\a\\b\\c", "\\1", "\\\\a\\b\\c\\1"},
900 {"\\\\?\\UNC\\a", "\\1", "\\\\a\\1"},
901 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a", "\\1",
902 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\1"},
903 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", "\\1",
904 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\1"},
905 {"C:\\a\\b", "\\", "C:\\a\\b"},
907 /* Second path is fully qualified */
908 {"X:\\", "C:", "C:\\"},
909 {"X:\\", "C:\\", "C:\\"},
910 {"X:\\", "\\\\", "\\\\"},
911 {"X:\\", "\\\\?\\C:", "C:\\"},
912 {"X:\\", "\\\\?\\C:\\", "C:\\"},
913 {"X:\\", "\\\\?\\UNC\\", "\\\\"},
914 {"X:\\", "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
915 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\"},
917 /* Canonicalization */
918 {"C:\\a", ".\\b", "C:\\a\\b"},
919 {"C:\\a", "..\\b", "C:\\b"},
921 /* Other */
922 {"", "", "\\"},
923 {"a", "b", "a\\b"}
926 static void test_PathCchAppend(void)
928 WCHAR path1W[PATHCCH_MAX_CCH];
929 WCHAR path2W[PATHCCH_MAX_CCH];
930 CHAR path1A[PATHCCH_MAX_CCH];
931 HRESULT hr;
932 INT i;
934 if (!pPathCchAppend)
936 win_skip("PathCchAppend() is not available.\n");
937 return;
940 MultiByteToWideChar(CP_ACP, 0, "\\a", -1, path1W, ARRAY_SIZE(path1W));
941 MultiByteToWideChar(CP_ACP, 0, "\\b", -1, path2W, ARRAY_SIZE(path2W));
942 hr = pPathCchAppend(NULL, PATHCCH_MAX_CCH, path2W);
943 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
945 hr = pPathCchAppend(path1W, 0, path2W);
946 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
948 hr = pPathCchAppend(path1W, PATHCCH_MAX_CCH + 1, path2W);
949 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
951 hr = pPathCchAppend(path1W, PATHCCH_MAX_CCH, NULL);
952 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
953 WideCharToMultiByte(CP_ACP, 0, path1W, -1, path1A, ARRAY_SIZE(path1A), NULL, NULL);
954 ok(!lstrcmpA(path1A, "\\a"), "expect \\a, got %s\n", path1A);
956 for (i = 0; i < ARRAY_SIZE(append_tests); i++)
958 const struct append_test *t = append_tests + i;
960 MultiByteToWideChar(CP_ACP, 0, t->path1, -1, path1W, ARRAY_SIZE(path1W));
961 MultiByteToWideChar(CP_ACP, 0, t->path2, -1, path2W, ARRAY_SIZE(path2W));
962 hr = pPathCchAppend(path1W, PATHCCH_MAX_CCH, path2W);
963 ok(hr == S_OK, "append \"%s\" \"%s\" expect hr %#x, got %#x\n", t->path1, t->path2, S_OK, hr);
964 if (SUCCEEDED(hr))
966 WideCharToMultiByte(CP_ACP, 0, path1W, -1, path1A, ARRAY_SIZE(path1A), NULL, NULL);
967 ok(!lstrcmpA(path1A, t->result), "append \"%s\" \"%s\" expect result \"%s\", got \"%s\"\n", t->path1,
968 t->path2, t->result, path1A);
973 static void test_PathCchAppendEx(void)
975 WCHAR path1W[PATHCCH_MAX_CCH];
976 WCHAR path2W[PATHCCH_MAX_CCH];
977 CHAR path1A[PATHCCH_MAX_CCH];
978 HRESULT hr;
979 INT i;
981 if (!pPathCchAppendEx)
983 win_skip("PathCchAppendEx() is not available.\n");
984 return;
987 MultiByteToWideChar(CP_ACP, 0, "\\a", -1, path1W, ARRAY_SIZE(path1W));
988 MultiByteToWideChar(CP_ACP, 0, "\\b", -1, path2W, ARRAY_SIZE(path2W));
989 hr = pPathCchAppendEx(NULL, ARRAY_SIZE(path1W), path2W, 0);
990 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
992 hr = pPathCchAppendEx(path1W, 0, path2W, 0);
993 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
994 ok(path1W[0] == '\\', "expect path1 unchanged\n");
996 hr = pPathCchAppendEx(path1W, PATHCCH_MAX_CCH + 1, path2W, 0);
997 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
998 ok(path1W[0] == '\\', "expect path1 unchanged\n");
1000 hr = pPathCchAppendEx(path1W, ARRAY_SIZE(path1W), NULL, 0);
1001 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1002 WideCharToMultiByte(CP_ACP, 0, path1W, -1, path1A, ARRAY_SIZE(path1A), NULL, NULL);
1003 ok(!lstrcmpA(path1A, "\\a"), "expect \\a, got %s\n", path1A);
1005 hr = pPathCchAppendEx(path1W, PATHCCH_MAX_CCH, path2W, 0);
1006 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1008 for (i = 0; i < ARRAY_SIZE(append_tests); i++)
1010 const struct append_test *t = append_tests + i;
1012 MultiByteToWideChar(CP_ACP, 0, t->path1, -1, path1W, ARRAY_SIZE(path1W));
1013 MultiByteToWideChar(CP_ACP, 0, t->path2, -1, path2W, ARRAY_SIZE(path2W));
1014 hr = pPathCchAppendEx(path1W, PATHCCH_MAX_CCH, path2W, 0);
1015 ok(hr == S_OK, "append \"%s\" \"%s\" expect hr %#x, got %#x\n", t->path1, t->path2, S_OK, hr);
1016 if (SUCCEEDED(hr))
1018 WideCharToMultiByte(CP_ACP, 0, path1W, -1, path1A, ARRAY_SIZE(path1A), NULL, NULL);
1019 ok(!lstrcmpA(path1A, t->result), "append \"%s\" \"%s\" expect result \"%s\", got \"%s\"\n", t->path1,
1020 t->path2, t->result, path1A);
1025 static void test_PathCchAddExtension(void)
1027 WCHAR pathW[PATHCCH_MAX_CCH + 1];
1028 CHAR pathA[PATHCCH_MAX_CCH + 1];
1029 WCHAR extensionW[MAX_PATH];
1030 HRESULT hr;
1031 INT i;
1033 if (!pPathCchAddExtension)
1035 win_skip("PathCchAddExtension() is not available.\n");
1036 return;
1039 /* Arguments check */
1040 MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, pathW, ARRAY_SIZE(pathW));
1041 MultiByteToWideChar(CP_ACP, 0, ".exe", -1, extensionW, ARRAY_SIZE(extensionW));
1043 hr = pPathCchAddExtension(NULL, PATHCCH_MAX_CCH, extensionW);
1044 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1046 hr = pPathCchAddExtension(pathW, 0, extensionW);
1047 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1049 hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH, NULL);
1050 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1052 /* Path length check */
1053 hr = pPathCchAddExtension(pathW, ARRAY_SIZE("C:\\.exe") - 1, extensionW);
1054 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect result %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
1056 hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH + 1, extensionW);
1057 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1059 hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH, extensionW);
1060 ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr);
1062 for (i = 0; i < ARRAY_SIZE(addextension_tests); i++)
1064 const struct addextension_test *t = addextension_tests + i;
1065 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
1066 MultiByteToWideChar(CP_ACP, 0, t->extension, -1, extensionW, ARRAY_SIZE(extensionW));
1067 hr = pPathCchAddExtension(pathW, PATHCCH_MAX_CCH, extensionW);
1068 ok(hr == t->hr, "path %s extension %s expect result %#x, got %#x\n", t->path, t->extension, t->hr, hr);
1069 if (SUCCEEDED(hr))
1071 WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
1072 ok(!lstrcmpA(pathA, t->expected), "path %s extension %s expect output path %s, got %s\n", t->path,
1073 t->extension, t->expected, pathA);
1078 static void test_PathCchCanonicalize(void)
1080 WCHAR path_inW[MAX_PATH], path_outW[MAX_PATH];
1081 CHAR path_outA[MAX_PATH];
1082 HRESULT hr;
1083 INT i;
1085 if (!pPathCchCanonicalize)
1087 win_skip("PathCchCanonicalize() is not available.\n");
1088 return;
1091 /* No NULL check for path pointers on Windows */
1092 if (0)
1094 hr = pPathCchCanonicalize(NULL, ARRAY_SIZE(path_outW), path_inW);
1095 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1097 /* MSDN says NULL path_in result in a backslash added to path_out, but the fact is that it would crash */
1098 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), NULL);
1099 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1102 path_inW[0] = 0;
1103 hr = pPathCchCanonicalize(path_outW, 0, path_inW);
1104 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1106 /* Test path length */
1107 for (i = 0; i < MAX_PATH - 3; i++) path_inW[i] = 'a';
1108 path_inW[MAX_PATH - 3] = '\0';
1109 memset(path_outW, 0, sizeof(path_outW));
1110 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
1111 ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x %s\n",
1112 HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr, wine_dbgstr_w(path_outW));
1113 ok(!*path_outW, "got %d\n", lstrlenW(path_outW));
1115 path_inW[0] = 'C';
1116 path_inW[1] = ':';
1117 path_inW[2] = '\\';
1118 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
1119 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1121 path_inW[MAX_PATH - 4] = '\0';
1122 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
1123 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1125 /* Insufficient buffer size handling */
1126 hr = pPathCchCanonicalize(path_outW, 1, path_inW);
1127 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
1129 for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
1131 const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
1133 /* Skip testing X: path input, this case is different compared to PathAllocCanonicalize */
1134 /* Skip test cases where a flag is used */
1135 if (!lstrcmpA("C:", t->path_in) || t->flags) continue;
1137 MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
1138 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
1139 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
1140 if (SUCCEEDED(hr))
1142 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1143 ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
1144 t->path_out, path_outA);
1148 /* X: path input */
1149 /* Fill a \ at the end of X: if there is enough space */
1150 MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
1151 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
1152 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
1153 if (SUCCEEDED(hr))
1155 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1156 ok(!lstrcmpA(path_outA, "C:\\"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\",
1157 path_outA);
1160 /* Don't fill a \ at the end of X: if there isn't enough space */
1161 MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
1162 hr = pPathCchCanonicalize(path_outW, 3, path_inW);
1163 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
1164 if (SUCCEEDED(hr))
1166 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1167 ok(!lstrcmpA(path_outA, "C:"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\", path_outA);
1170 /* Don't fill a \ at the end of X: if there is character following X: */
1171 MultiByteToWideChar(CP_ACP, 0, "C:a", -1, path_inW, ARRAY_SIZE(path_inW));
1172 hr = pPathCchCanonicalize(path_outW, ARRAY_SIZE(path_outW), path_inW);
1173 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:a", S_OK, hr);
1174 if (SUCCEEDED(hr))
1176 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1177 ok(!lstrcmpA(path_outA, "C:a"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:a", "C:a", path_outA);
1181 static void test_PathCchCanonicalizeEx(void)
1183 WCHAR path_inW[PATHCCH_MAX_CCH + 1], path_outW[PATHCCH_MAX_CCH];
1184 CHAR path_outA[4096];
1185 BOOL skip_new_flags = TRUE;
1186 HRESULT hr;
1187 INT i;
1189 if (!pPathCchCanonicalizeEx)
1191 win_skip("PathCchCanonicalizeEx() is not available.\n");
1192 return;
1195 /* No NULL check for path pointers on Windows */
1196 if (0)
1198 hr = pPathCchCanonicalizeEx(NULL, ARRAY_SIZE(path_outW), path_inW, 0);
1199 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1201 /* MSDN says NULL path_in result in a backslash added to path_out, but the fact is that it would crash */
1202 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), NULL, 0);
1203 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1206 path_outW[0] = 0xff;
1207 hr = pPathCchCanonicalizeEx(path_outW, 0, path_inW, 0);
1208 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1209 ok(path_outW[0] = 0xff, "expect path_outW unchanged\n");
1211 /* Test path length */
1212 for (i = 0; i < ARRAY_SIZE(path_inW) - 1; i++) path_inW[i] = 'a';
1213 path_inW[PATHCCH_MAX_CCH] = '\0';
1214 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, PATHCCH_ALLOW_LONG_PATHS);
1215 ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
1216 HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
1218 path_inW[PATHCCH_MAX_CCH - 1] = '\0';
1219 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, PATHCCH_ALLOW_LONG_PATHS);
1220 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1222 hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, PATHCCH_ALLOW_LONG_PATHS);
1223 ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
1224 HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
1226 /* No root and path > MAX_PATH - 4, return HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE) */
1227 path_inW[MAX_PATH - 3] = '\0';
1228 hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
1229 ok(hr == HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), "expect hr %#x, got %#x\n",
1230 HRESULT_FROM_WIN32(ERROR_FILENAME_EXCED_RANGE), hr);
1232 /* Has root and path > MAX_PATH - 4 */
1233 path_inW[0] = 'C';
1234 path_inW[1] = ':';
1235 path_inW[2] = '\\';
1236 hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
1237 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
1239 path_inW[0] = '\\';
1240 path_inW[1] = path_inW[2] = 'a';
1241 hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
1242 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
1244 path_inW[0] = path_inW[1] = '\\';
1245 path_inW[2] = 'a';
1246 hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
1247 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
1249 /* path <= MAX_PATH - 4 */
1250 path_inW[0] = path_inW[1] = path_inW[2] = 'a';
1251 path_inW[MAX_PATH - 4] = '\0';
1252 hr = pPathCchCanonicalizeEx(path_outW, 1, path_inW, 0);
1253 ok(hr == STRSAFE_E_INSUFFICIENT_BUFFER, "expect hr %#x, got %#x\n", STRSAFE_E_INSUFFICIENT_BUFFER, hr);
1255 /* Check if flags added after Windows 10 1709 are supported */
1256 MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, path_inW, ARRAY_SIZE(path_inW));
1257 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS);
1258 if (hr == E_INVALIDARG) skip_new_flags = FALSE;
1260 for (i = 0; i < ARRAY_SIZE(alloccanonicalize_tests); i++)
1262 const struct alloccanonicalize_test *t = alloccanonicalize_tests + i;
1264 /* Skip testing X: path input, this case is different compared to PathAllocCanonicalize */
1265 if (!lstrcmpA("C:", t->path_in)) continue;
1267 if (((PATHCCH_FORCE_ENABLE_LONG_NAME_PROCESS | PATHCCH_FORCE_DISABLE_LONG_NAME_PROCESS
1268 | PATHCCH_DO_NOT_NORMALIZE_SEGMENTS | PATHCCH_ENSURE_IS_EXTENDED_LENGTH_PATH
1269 | PATHCCH_ENSURE_TRAILING_SLASH)
1270 & t->flags)
1271 && skip_new_flags)
1273 win_skip("Skip testing new flags added after Windows 10 1709\n");
1274 return;
1277 MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, path_inW, ARRAY_SIZE(path_inW));
1278 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, t->flags);
1279 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
1280 if (SUCCEEDED(hr))
1282 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1283 ok(!lstrcmpA(path_outA, t->path_out), "path \"%s\" expect output path \"%s\", got \"%s\"\n", t->path_in,
1284 t->path_out, path_outA);
1288 /* X: path input */
1289 /* Fill a \ at the end of X: if there is enough space */
1290 MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
1291 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, 0);
1292 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
1293 if (SUCCEEDED(hr))
1295 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1296 ok(!lstrcmpA(path_outA, "C:\\"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\",
1297 path_outA);
1300 /* Don't fill a \ at the end of X: if there isn't enough space */
1301 MultiByteToWideChar(CP_ACP, 0, "C:", -1, path_inW, ARRAY_SIZE(path_inW));
1302 hr = pPathCchCanonicalizeEx(path_outW, 3, path_inW, 0);
1303 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:", S_OK, hr);
1304 if (SUCCEEDED(hr))
1306 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1307 ok(!lstrcmpA(path_outA, "C:"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:", "C:\\", path_outA);
1310 /* Don't fill a \ at the end of X: if there is character following X: */
1311 MultiByteToWideChar(CP_ACP, 0, "C:a", -1, path_inW, ARRAY_SIZE(path_inW));
1312 hr = pPathCchCanonicalizeEx(path_outW, ARRAY_SIZE(path_outW), path_inW, 0);
1313 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", "C:a", S_OK, hr);
1314 if (SUCCEEDED(hr))
1316 WideCharToMultiByte(CP_ACP, 0, path_outW, -1, path_outA, ARRAY_SIZE(path_outA), NULL, NULL);
1317 ok(!lstrcmpA(path_outA, "C:a"), "path \"%s\" expect output path \"%s\", got \"%s\"\n", "C:a", "C:a", path_outA);
1321 struct findextension_test
1323 const CHAR *path;
1324 INT extension_offset;
1327 static const struct findextension_test findextension_tests[] =
1329 /* Normal */
1330 {"1.exe", 1},
1331 {"C:1.exe", 3},
1332 {"C:\\1.exe", 4},
1333 {"\\1.exe", 2},
1334 {"\\\\1.exe", 3},
1335 {"\\\\?\\C:1.exe", 7},
1336 {"\\\\?\\C:\\1.exe", 8},
1337 {"\\\\?\\UNC\\1.exe", 9},
1338 {"\\\\?\\UNC\\192.168.1.1\\1.exe", 21},
1339 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.exe", 50},
1341 /* Contains forward slash */
1342 {"C:\\a/1.exe", 6},
1343 {"/1.exe", 2},
1344 {"//1.exe", 3},
1345 {"C:\\a/b/1.exe", 8},
1346 {"/a/1.exe", 4},
1347 {"/a/1.exe", 4},
1349 /* Malformed */
1350 {"", 0},
1351 {" ", 1},
1352 {".", 0},
1353 {"..", 1},
1354 {"a", 1},
1355 {"a.", 1},
1356 {".a.b.", 4},
1357 {"a. ", 3},
1358 {"a.\\", 3},
1359 {"\\\\?\\UNC\\192.168.1.1", 17},
1360 {"\\\\?\\UNC\\192.168.1.1\\", 20},
1361 {"\\\\?\\UNC\\192.168.1.1\\a", 21}
1364 static void test_PathCchFindExtension(void)
1366 WCHAR pathW[PATHCCH_MAX_CCH + 1] = {0};
1367 const WCHAR *extension;
1368 HRESULT hr;
1369 INT i;
1371 if (!pPathCchFindExtension)
1373 win_skip("PathCchFindExtension() is not available.\n");
1374 return;
1377 /* Arguments check */
1378 extension = (const WCHAR *)0xdeadbeef;
1379 hr = pPathCchFindExtension(NULL, PATHCCH_MAX_CCH, &extension);
1380 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1381 ok(extension == NULL, "Expect extension null, got %p\n", extension);
1383 extension = (const WCHAR *)0xdeadbeef;
1384 hr = pPathCchFindExtension(pathW, 0, &extension);
1385 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1386 ok(extension == NULL, "Expect extension null, got %p\n", extension);
1388 /* Crashed on Windows */
1389 if (0)
1391 hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, NULL);
1392 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1395 /* Path length check */
1396 /* size == PATHCCH_MAX_CCH + 1 */
1397 MultiByteToWideChar(CP_ACP, 0, "C:\\1.exe", -1, pathW, ARRAY_SIZE(pathW));
1398 hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH + 1, &extension);
1399 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1401 /* Size == path length + 1*/
1402 hr = pPathCchFindExtension(pathW, ARRAY_SIZE("C:\\1.exe"), &extension);
1403 ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr);
1404 ok(*extension == '.', "wrong extension value\n");
1406 /* Size < path length + 1 */
1407 extension = (const WCHAR *)0xdeadbeef;
1408 hr = pPathCchFindExtension(pathW, ARRAY_SIZE("C:\\1.exe") - 1, &extension);
1409 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1410 ok(extension == NULL, "Expect extension null, got %p\n", extension);
1412 /* Size == PATHCCH_MAX_CCH */
1413 hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension);
1414 ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr);
1416 /* Path length + 1 > PATHCCH_MAX_CCH */
1417 for (i = 0; i < ARRAY_SIZE(pathW) - 1; i++) pathW[i] = 'a';
1418 pathW[PATHCCH_MAX_CCH] = 0;
1419 hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension);
1420 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1422 /* Path length + 1 == PATHCCH_MAX_CCH */
1423 pathW[PATHCCH_MAX_CCH - 1] = 0;
1424 hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension);
1425 ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr);
1427 for (i = 0; i < ARRAY_SIZE(findextension_tests); i++)
1429 const struct findextension_test *t = findextension_tests + i;
1430 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
1431 hr = pPathCchFindExtension(pathW, PATHCCH_MAX_CCH, &extension);
1432 ok(hr == S_OK, "path %s expect result %#x, got %#x\n", t->path, S_OK, hr);
1433 if (SUCCEEDED(hr))
1434 ok(extension - pathW == t->extension_offset, "path %s expect extension offset %d, got %ld\n", t->path,
1435 t->extension_offset, (UINT_PTR)(extension - pathW));
1439 struct isroot_test
1441 const CHAR *path;
1442 BOOL ret;
1445 static const struct isroot_test isroot_tests[] =
1447 {"", FALSE},
1448 {"a", FALSE},
1449 {"C:", FALSE},
1450 {"C:\\", TRUE},
1451 {"C:\\a", FALSE},
1452 {"\\\\?\\C:\\", TRUE},
1453 {"\\\\?\\C:", FALSE},
1454 {"\\\\?\\C:\\a", FALSE},
1455 {"\\", TRUE},
1456 {"\\a\\", FALSE},
1457 {"\\a\\b", FALSE},
1458 {"\\\\", TRUE},
1459 {"\\\\a", TRUE},
1460 {"\\\\a\\", FALSE},
1461 {"\\\\a\\b", TRUE},
1462 {"\\\\a\\b\\", FALSE},
1463 {"\\\\a\\b\\c", FALSE},
1464 {"\\\\?\\UNC\\", TRUE},
1465 {"\\\\?\\UNC\\a", TRUE},
1466 {"\\\\?\\UNC\\a\\", FALSE},
1467 {"\\\\?\\UNC\\a\\b", TRUE},
1468 {"\\\\?\\UNC\\a\\b\\", FALSE},
1469 {"\\\\?\\UNC\\a\\b\\c", FALSE},
1470 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", FALSE},
1471 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", TRUE},
1472 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", FALSE},
1473 {"..\\a", FALSE},
1475 /* Wrong MSDN examples */
1476 {"\\a", FALSE},
1477 {"X:", FALSE},
1478 {"\\server", FALSE}
1481 static void test_PathCchIsRoot(void)
1483 WCHAR pathW[MAX_PATH];
1484 BOOL ret;
1485 INT i;
1487 if (!pPathCchIsRoot)
1489 win_skip("PathCchIsRoot() is not available.\n");
1490 return;
1493 ret = pPathCchIsRoot(NULL);
1494 ok(ret == FALSE, "expect return FALSE\n");
1496 for (i = 0; i < ARRAY_SIZE(isroot_tests); i++)
1498 const struct isroot_test *t = isroot_tests + i;
1499 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
1500 ret = pPathCchIsRoot(pathW);
1501 ok(ret == t->ret, "path %s expect return %d, got %d\n", t->path, t->ret, ret);
1505 struct removebackslashex_test
1507 const CHAR *path_in;
1508 const CHAR *path_out;
1509 int end_offset;
1510 SIZE_T free_size;
1511 HRESULT hr;
1514 static const struct removebackslashex_test removebackslashex_tests [] =
1516 {"", "", 0, 1, S_FALSE},
1517 {"C", "C", 1, 1, S_FALSE},
1518 {"C\\", "C", 1, 2, S_OK},
1519 {"C:", "C:", 2, 1, S_FALSE},
1520 {"C:\\", "C:\\", 2, 2, S_FALSE},
1521 {"C:\\\\", "C:\\", 3, 2, S_OK},
1522 {"C:\\a\\", "C:\\a", 4, 2, S_OK},
1523 {"C:\\a\\\\", "C:\\a\\", 5, 2, S_OK},
1524 {"\\", "\\", 0, 2, S_FALSE},
1525 {"\\\\", "\\\\", 1, 2, S_FALSE},
1526 {"\\?\\", "\\?", 2, 2, S_OK},
1527 {"\\?\\\\", "\\?\\", 3, 2, S_OK},
1528 {"\\a\\", "\\a", 2, 2, S_OK},
1529 {"\\a\\\\", "\\a\\", 3, 2, S_OK},
1530 {"\\\\a\\", "\\\\a", 3, 2, S_OK},
1531 {"\\\\a\\b\\", "\\\\a\\b", 5, 2, S_OK},
1532 {"\\\\a\\\\", "\\\\a\\", 4, 2, S_OK},
1533 {"\\\\?\\", "\\\\?", 3, 2, S_OK},
1534 {"\\\\?\\\\", "\\\\?\\", 4, 2, S_OK},
1535 {"\\\\?\\C:", "\\\\?\\C:", 6, 1, S_FALSE},
1536 {"\\\\?\\C:\\", "\\\\?\\C:\\", 6, 2, S_FALSE},
1537 {"\\?\\UNC\\", "\\?\\UNC", 6, 2, S_OK},
1538 {"\\\\?\\UNC", "\\\\?\\UNC", 7, 1, S_FALSE},
1539 {"\\\\?\\UNC\\", "\\\\?\\UNC\\", 7, 2, S_FALSE},
1540 {"\\\\?\\UNC\\a", "\\\\?\\UNC\\a", 9, 1, S_FALSE},
1541 {"\\\\?\\UNC\\a\\", "\\\\?\\UNC\\a", 9, 2, S_OK},
1542 {"\\\\?\\UNC\\a\\b\\", "\\\\?\\UNC\\a\\b", 11, 2, S_OK},
1543 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}",
1544 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", 48, 1, S_FALSE},
1545 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
1546 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 48, 2, S_FALSE},
1547 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a",
1548 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 50, 1, S_FALSE},
1549 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\",
1550 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 50, 2, S_OK}
1553 static void test_PathCchRemoveBackslash(void)
1555 WCHAR pathW[PATHCCH_MAX_CCH];
1556 CHAR pathA[PATHCCH_MAX_CCH];
1557 HRESULT hr;
1558 SIZE_T path_size;
1559 INT i;
1561 if (!pPathCchRemoveBackslash)
1563 win_skip("PathCchRemoveBackslash() is not available.\n");
1564 return;
1567 /* No NULL check for path on Windows */
1568 if (0)
1570 hr = pPathCchRemoveBackslash(NULL, PATHCCH_MAX_CCH);
1571 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1574 MultiByteToWideChar(CP_ACP, 0, "C:\\a\\", -1, pathW, ARRAY_SIZE(pathW));
1575 hr = pPathCchRemoveBackslash(pathW, 0);
1576 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1578 hr = pPathCchRemoveBackslash(pathW, PATHCCH_MAX_CCH + 1);
1579 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1581 hr = pPathCchRemoveBackslash(pathW, PATHCCH_MAX_CCH);
1582 ok(hr == S_FALSE, "expect hr %#x, got %#x\n", S_FALSE, hr);
1584 for (i = 0; i < ARRAY_SIZE(removebackslashex_tests); i++)
1586 const struct removebackslashex_test *t = removebackslashex_tests + i;
1587 path_size = MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, pathW, ARRAY_SIZE(pathW));
1588 hr = pPathCchRemoveBackslash(pathW, path_size);
1589 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
1590 if (SUCCEEDED(hr))
1592 WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
1593 ok(!lstrcmpA(pathA, t->path_out), "path %s expect output path %s, got %s\n", t->path_in, t->path_out,
1594 pathA);
1599 static void test_PathCchRemoveBackslashEx(void)
1601 WCHAR pathW[PATHCCH_MAX_CCH];
1602 CHAR pathA[PATHCCH_MAX_CCH];
1603 WCHAR *path_end;
1604 SIZE_T path_size, free_size;
1605 HRESULT hr;
1606 INT i;
1608 if (!pPathCchRemoveBackslashEx)
1610 win_skip("PathCchRemoveBackslashEx() is not available.\n");
1611 return;
1614 /* No NULL check for path on Windows */
1615 if (0)
1617 hr = pPathCchRemoveBackslashEx(NULL, 0, &path_end, &path_size);
1618 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1621 path_size = MultiByteToWideChar(CP_ACP, 0, "C:\\a\\", -1, pathW, ARRAY_SIZE(pathW));
1622 hr = pPathCchRemoveBackslashEx(pathW, 0, &path_end, &path_size);
1623 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1625 free_size = 0xdeadbeef;
1626 hr = pPathCchRemoveBackslashEx(pathW, path_size, NULL, &free_size);
1627 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1628 ok(free_size == 0, "expect %d, got %lu\n", 0, free_size);
1630 path_end = (WCHAR *)0xdeadbeef;
1631 hr = pPathCchRemoveBackslashEx(pathW, path_size, &path_end, NULL);
1632 ok(hr == E_INVALIDARG, "expect hr %#x, got %#x\n", E_INVALIDARG, hr);
1633 ok(path_end == NULL, "expect null, got %p\n", path_end);
1635 hr = pPathCchRemoveBackslashEx(pathW, PATHCCH_MAX_CCH + 1, &path_end, &free_size);
1636 ok(hr == S_OK, "expect hr %#x, got %#x\n", S_OK, hr);
1638 hr = pPathCchRemoveBackslashEx(pathW, PATHCCH_MAX_CCH, &path_end, &free_size);
1639 ok(hr == S_FALSE, "expect hr %#x, got %#x\n", S_FALSE, hr);
1641 /* Size < original path length + 1, don't read beyond size */
1642 MultiByteToWideChar(CP_ACP, 0, "C:\\a", -1, pathW, ARRAY_SIZE(pathW));
1643 hr = pPathCchRemoveBackslashEx(pathW, ARRAY_SIZE("C:\\a") - 1, &path_end, &free_size);
1644 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1646 for (i = 0; i < ARRAY_SIZE(removebackslashex_tests); i++)
1648 const struct removebackslashex_test *t = removebackslashex_tests + i;
1649 path_size = MultiByteToWideChar(CP_ACP, 0, t->path_in, -1, pathW, ARRAY_SIZE(pathW));
1650 hr = pPathCchRemoveBackslashEx(pathW, path_size, &path_end, &free_size);
1651 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path_in, t->hr, hr);
1652 if (SUCCEEDED(hr))
1654 ok(path_end - pathW == t->end_offset, "path %s expect end offset %d, got %ld\n", t->path_in, t->end_offset,
1655 (INT_PTR)(path_end - pathW));
1656 ok(free_size == t->free_size, "path %s expect free size %lu, got %lu\n", t->path_in, t->free_size, free_size);
1657 WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
1658 ok(!lstrcmpA(pathA, t->path_out), "path %s expect output path %s, got %s\n", t->path_in, t->path_out,
1659 pathA);
1664 struct removeextension_test
1666 const CHAR *path;
1667 const CHAR *expected;
1668 HRESULT hr;
1671 static const struct removeextension_test removeextension_tests[] =
1673 {"1.exe", "1", S_OK},
1674 {"C:1.exe", "C:1", S_OK},
1675 {"C:\\1.exe", "C:\\1", S_OK},
1676 {"\\1.exe", "\\1", S_OK},
1677 {"\\\\1.exe", "\\\\1", S_OK},
1678 {"\\\\?\\C:1.exe", "\\\\?\\C:1", S_OK},
1679 {"\\\\?\\C:\\1.exe", "\\\\?\\C:\\1", S_OK},
1680 {"\\\\?\\UNC\\1.exe", "\\\\?\\UNC\\1", S_OK},
1681 {"\\\\?\\UNC\\192.168.1.1\\1.exe", "\\\\?\\UNC\\192.168.1.1\\1", S_OK},
1682 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.exe",
1683 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1", S_OK},
1685 /* Malformed */
1686 {"", "", S_FALSE},
1687 {" ", " ", S_FALSE},
1688 {".", "", S_OK},
1689 {"..", ".", S_OK},
1690 {"a", "a", S_FALSE},
1691 {"a.", "a", S_OK},
1692 {".a.b.", ".a.b", S_OK},
1693 {"a. ", "a. ", S_FALSE},
1694 {"a.\\", "a.\\", S_FALSE},
1695 {"\\\\?\\UNC\\192.168.1.1", "\\\\?\\UNC\\192.168.1", S_OK},
1696 {"\\\\?\\UNC\\192.168.1.1\\", "\\\\?\\UNC\\192.168.1.1\\", S_FALSE},
1697 {"\\\\?\\UNC\\192.168.1.1\\a", "\\\\?\\UNC\\192.168.1.1\\a", S_FALSE}
1700 static void test_PathCchRemoveExtension(void)
1702 WCHAR pathW[PATHCCH_MAX_CCH] = {0};
1703 CHAR pathA[PATHCCH_MAX_CCH];
1704 HRESULT hr;
1705 INT i;
1707 if (!pPathCchRemoveExtension)
1709 win_skip("PathCchRemoveExtension() is not available.\n");
1710 return;
1713 /* Arguments check */
1714 hr = pPathCchRemoveExtension(NULL, PATHCCH_MAX_CCH);
1715 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
1717 hr = pPathCchRemoveExtension(pathW, 0);
1718 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
1720 hr = pPathCchRemoveExtension(pathW, PATHCCH_MAX_CCH + 1);
1721 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
1723 hr = pPathCchRemoveExtension(pathW, PATHCCH_MAX_CCH);
1724 ok(hr == S_FALSE, "expect %#x, got %#x\n", S_FALSE, hr);
1726 /* Size < original path length + 1 */
1727 MultiByteToWideChar(CP_ACP, 0, "C:\\1.exe", -1, pathW, ARRAY_SIZE(pathW));
1728 hr = pPathCchRemoveExtension(pathW, ARRAY_SIZE("C:\\1.exe") - 1);
1729 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
1731 for (i = 0; i < ARRAY_SIZE(removeextension_tests); i++)
1733 const struct removeextension_test *t = removeextension_tests + i;
1735 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
1736 hr = pPathCchRemoveExtension(pathW, ARRAY_SIZE(pathW));
1737 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr);
1738 if (SUCCEEDED(hr))
1740 WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
1741 ok(!lstrcmpA(pathA, t->expected), "path %s expect stripped path %s, got %s\n", t->path, t->expected, pathA);
1746 struct removefilespec_test
1748 const CHAR *path;
1749 const CHAR *expected;
1750 HRESULT hr;
1751 SIZE_T size;
1754 static const struct removefilespec_test removefilespec_tests[] =
1756 {"", "", S_FALSE},
1757 {"a", "", S_OK},
1758 {"a\\", "a", S_OK},
1759 {"a\\b", "a", S_OK},
1761 {"\\", "\\", S_FALSE},
1762 {"\\a", "\\", S_OK},
1763 {"\\a\\", "\\a", S_OK},
1764 {"\\a\\b", "\\a", S_OK},
1766 {"\\\\", "\\\\", S_FALSE},
1767 {"\\\\a", "\\\\a", S_FALSE},
1768 {"\\\\a\\", "\\\\a", S_OK},
1769 {"\\\\a\\b", "\\\\a\\b", S_FALSE},
1770 {"\\\\a\\b\\", "\\\\a\\b", S_OK},
1771 {"\\\\a\\b\\c", "\\\\a\\b", S_OK},
1773 {"C:", "C:", S_FALSE},
1774 {"C:a", "C:", S_OK},
1775 {"C:a\\", "C:a", S_OK},
1776 {"C:a\\b", "C:a", S_OK},
1778 {"C:\\", "C:\\", S_FALSE},
1779 {"C:\\a", "C:\\", S_OK},
1780 {"C:\\a\\", "C:\\a", S_OK},
1781 {"C:\\a\\b", "C:\\a", S_OK},
1783 {"\\\\?\\", "\\\\?", S_OK},
1784 {"\\\\?\\a", "\\\\?", S_OK},
1785 {"\\\\?\\a\\", "\\\\?\\a", S_OK},
1786 {"\\\\?\\a\\b", "\\\\?\\a", S_OK},
1788 {"\\\\?\\C:", "\\\\?\\C:", S_FALSE},
1789 {"\\\\?\\C:a", "\\\\?\\C:", S_OK},
1790 {"\\\\?\\C:a\\", "\\\\?\\C:a", S_OK},
1791 {"\\\\?\\C:a\\b", "\\\\?\\C:a", S_OK},
1793 {"\\\\?\\C:\\", "\\\\?\\C:\\", S_FALSE},
1794 {"\\\\?\\C:\\a", "\\\\?\\C:\\", S_OK},
1795 {"\\\\?\\C:\\a\\", "\\\\?\\C:\\a", S_OK},
1796 {"\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", S_OK},
1798 {"\\\\?\\UNC\\", "\\\\?\\UNC\\", S_FALSE},
1799 {"\\\\?\\UNC\\a", "\\\\?\\UNC\\a", S_FALSE},
1800 {"\\\\?\\UNC\\a\\", "\\\\?\\UNC\\a", S_OK},
1801 {"\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b", S_FALSE},
1802 {"\\\\?\\UNC\\a\\b\\", "\\\\?\\UNC\\a\\b", S_OK},
1803 {"\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", S_OK},
1805 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}",
1806 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_FALSE},
1807 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a",
1808 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_OK},
1809 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\",
1810 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a", S_OK},
1811 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\b",
1812 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a", S_OK},
1814 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
1815 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_FALSE},
1816 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a",
1817 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_OK},
1818 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\",
1819 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", S_OK},
1820 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b",
1821 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", S_OK},
1823 /* Size tests */
1824 {"C:\\a", NULL, E_INVALIDARG, PATHCCH_MAX_CCH + 1},
1825 {"C:\\a", "C:\\", S_OK, PATHCCH_MAX_CCH},
1826 /* Size < original path length + 1, read beyond size */
1827 {"C:\\a", "C:\\", S_OK, ARRAY_SIZE("C:\\a") - 1},
1828 /* Size < result path length + 1 */
1829 {"C:\\a", NULL, E_INVALIDARG, ARRAY_SIZE("C:\\") - 1}
1832 static void test_PathCchRemoveFileSpec(void)
1834 WCHAR pathW[PATHCCH_MAX_CCH] = {0};
1835 CHAR pathA[PATHCCH_MAX_CCH];
1836 SIZE_T size;
1837 HRESULT hr;
1838 INT i;
1840 if (!pPathCchRemoveFileSpec)
1842 win_skip("PathCchRemoveFileSpec() is not available.\n");
1843 return;
1846 /* Null arguments */
1847 hr = pPathCchRemoveFileSpec(NULL, ARRAY_SIZE(pathW));
1848 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
1850 hr = pPathCchRemoveFileSpec(pathW, 0);
1851 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
1853 for (i = 0; i < ARRAY_SIZE(removefilespec_tests); i++)
1855 const struct removefilespec_test *t = removefilespec_tests + i;
1857 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
1858 size = t->size ? t->size : ARRAY_SIZE(pathW);
1859 hr = pPathCchRemoveFileSpec(pathW, size);
1860 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr);
1861 if (SUCCEEDED(hr))
1863 WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
1864 ok(!lstrcmpA(pathA, t->expected), "path %s expect stripped path %s, got %s\n", t->path, t->expected, pathA);
1869 struct renameextension_test
1871 const CHAR *path;
1872 const CHAR *extension;
1873 const CHAR *expected;
1876 static const struct renameextension_test renameextension_tests[] =
1878 {"1.exe", ".txt", "1.txt"},
1879 {"C:1.exe", ".txt", "C:1.txt"},
1880 {"C:\\1.exe", ".txt", "C:\\1.txt"},
1881 {"\\1.exe", ".txt", "\\1.txt"},
1882 {"\\\\1.exe", ".txt", "\\\\1.txt"},
1883 {"\\\\?\\C:1.exe", ".txt", "\\\\?\\C:1.txt"},
1884 {"\\\\?\\C:\\1.exe", ".txt", "\\\\?\\C:\\1.txt"},
1885 {"\\\\?\\UNC\\1.exe", ".txt", "\\\\?\\UNC\\1.txt"},
1886 {"\\\\?\\UNC\\192.168.1.1\\1.exe", ".txt", "\\\\?\\UNC\\192.168.1.1\\1.txt"},
1887 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.exe", ".txt",
1888 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\1.txt"},
1889 {"C:\\1.exe", "", "C:\\1"},
1890 {"C:\\1.exe", "txt", "C:\\1.txt"}
1893 static void test_PathCchRenameExtension(void)
1895 WCHAR pathW[PATHCCH_MAX_CCH + 1];
1896 CHAR pathA[PATHCCH_MAX_CCH + 1];
1897 WCHAR extensionW[MAX_PATH];
1898 HRESULT hr;
1899 INT i;
1901 if (!pPathCchRenameExtension)
1903 win_skip("PathCchRenameExtension() is not available.\n");
1904 return;
1907 /* Invalid arguments */
1908 MultiByteToWideChar(CP_ACP, 0, "C:\\1.txt", -1, pathW, ARRAY_SIZE(pathW));
1909 MultiByteToWideChar(CP_ACP, 0, ".exe", -1, extensionW, ARRAY_SIZE(extensionW));
1911 hr = pPathCchRenameExtension(NULL, PATHCCH_MAX_CCH, extensionW);
1912 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1914 hr = pPathCchRenameExtension(pathW, 0, extensionW);
1915 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1917 hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH, NULL);
1918 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1920 /* Path length */
1921 hr = pPathCchRenameExtension(pathW, ARRAY_SIZE("C:\\1.exe") - 1, extensionW);
1922 ok(E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1924 hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH + 1, extensionW);
1925 ok(hr == E_INVALIDARG, "expect result %#x, got %#x\n", E_INVALIDARG, hr);
1927 hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH, extensionW);
1928 ok(hr == S_OK, "expect result %#x, got %#x\n", S_OK, hr);
1930 for (i = 0; i < ARRAY_SIZE(renameextension_tests); i++)
1932 const struct renameextension_test *t = renameextension_tests + i;
1933 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
1934 MultiByteToWideChar(CP_ACP, 0, t->extension, -1, extensionW, ARRAY_SIZE(extensionW));
1935 hr = pPathCchRenameExtension(pathW, PATHCCH_MAX_CCH, extensionW);
1936 ok(hr == S_OK, "path %s extension %s expect result %#x, got %#x\n", t->path, t->extension, S_OK, hr);
1937 if (SUCCEEDED(hr))
1939 WideCharToMultiByte(CP_ACP, 0, pathW, -1, pathA, ARRAY_SIZE(pathA), NULL, NULL);
1940 ok(!lstrcmpA(pathA, t->expected), "path %s extension %s expect output path %s, got %s\n", t->path,
1941 t->extension, t->expected, pathA);
1946 struct skiproot_test
1948 const char *path;
1949 int root_offset;
1950 HRESULT hr;
1953 static const struct skiproot_test skiproot_tests [] =
1955 /* Basic combination */
1956 {"", 0, E_INVALIDARG},
1957 {"C:\\", 3, S_OK},
1958 {"\\", 1, S_OK},
1959 {"\\\\.\\", 4, S_OK},
1960 {"\\\\?\\UNC\\", 8, S_OK},
1961 {"\\\\?\\C:\\", 7, S_OK},
1963 /* Basic + \ */
1964 {"C:\\\\", 3, S_OK},
1965 {"\\\\", 2, S_OK},
1966 {"\\\\.\\\\", 4, S_OK},
1967 {"\\\\?\\UNC\\\\", 9, S_OK},
1968 {"\\\\?\\C:\\\\", 7, S_OK},
1970 /* Basic + a */
1971 {"a", 0, E_INVALIDARG},
1972 {"C:\\a", 3, S_OK},
1973 {"\\a", 1, S_OK},
1974 {"\\\\.\\a", 5, S_OK},
1975 {"\\\\?\\UNC\\a", 9, S_OK},
1977 /* Basic + \a */
1978 {"\\a", 1, S_OK},
1979 {"C:\\\\a", 3, S_OK},
1980 {"\\\\a", 3, S_OK},
1981 {"\\\\.\\\\a", 4, S_OK},
1982 {"\\\\?\\UNC\\\\a", 10, S_OK},
1983 {"\\\\?\\C:\\\\a", 7, S_OK},
1985 /* Basic + a\ */
1986 {"a\\", 0, E_INVALIDARG},
1987 {"C:\\a\\", 3, S_OK},
1988 {"\\a\\", 1, S_OK},
1989 {"\\\\.\\a\\", 6, S_OK},
1990 {"\\\\?\\UNC\\a\\", 10, S_OK},
1991 {"\\\\?\\C:\\a\\", 7, S_OK},
1993 /* Network share */
1994 {"\\\\\\\\", 3, S_OK},
1995 {"\\\\a\\", 4, S_OK},
1996 {"\\\\a\\b", 5, S_OK},
1997 {"\\\\a\\b\\", 6, S_OK},
1998 {"\\\\a\\b\\\\", 6, S_OK},
1999 {"\\\\a\\b\\\\c", 6, S_OK},
2000 {"\\\\a\\b\\c", 6, S_OK},
2001 {"\\\\a\\b\\c\\", 6, S_OK},
2002 {"\\\\a\\b\\c\\d", 6, S_OK},
2003 {"\\\\a\\\\b\\c\\", 4, S_OK},
2004 {"\\\\aa\\bb\\cc\\", 8, S_OK},
2006 /* UNC */
2007 {"\\\\?\\UNC\\\\", 9, S_OK},
2008 {"\\\\?\\UNC\\a\\b", 11, S_OK},
2009 {"\\\\?\\UNC\\a\\b", 11, S_OK},
2010 {"\\\\?\\UNC\\a\\b\\", 12, S_OK},
2011 {"\\\\?\\UNC\\a\\b\\c", 12, S_OK},
2012 {"\\\\?\\UNC\\a\\b\\c\\", 12, S_OK},
2013 {"\\\\?\\UNC\\a\\b\\c\\d", 12, S_OK},
2014 {"\\\\?\\C:", 6, S_OK},
2015 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", 48, S_OK},
2016 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 49, S_OK},
2017 {"\\\\?\\unc\\a\\b", 11, S_OK},
2018 {"\\\\?\\volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 49, S_OK},
2019 {"\\\\?\\volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a", 49, S_OK},
2021 /* Malformed */
2022 {"C:", 2, S_OK},
2023 {":", 0, E_INVALIDARG},
2024 {":\\", 0, E_INVALIDARG},
2025 {"C\\", 0, E_INVALIDARG},
2026 {"\\?", 1, S_OK},
2027 {"\\?\\UNC", 1, S_OK},
2028 {"\\\\?\\", 0, E_INVALIDARG},
2029 {"\\\\?\\UNC", 0, E_INVALIDARG},
2030 {"\\\\?\\::\\", 0, E_INVALIDARG},
2031 {"\\\\?\\Volume", 0, E_INVALIDARG},
2032 {"\\.", 1, S_OK},
2033 {"\\\\..", 4, S_OK},
2034 {"\\\\..a", 5, S_OK}
2037 static void test_PathCchSkipRoot(void)
2039 WCHAR pathW[MAX_PATH];
2040 const WCHAR *root_end;
2041 HRESULT hr;
2042 INT i;
2044 if (!pPathCchSkipRoot)
2046 win_skip("PathCchSkipRoot() is not available.\n");
2047 return;
2050 root_end = (const WCHAR *)0xdeadbeef;
2051 hr = pPathCchSkipRoot(NULL, &root_end);
2052 ok(hr == E_INVALIDARG, "Expect result %#x, got %#x\n", E_INVALIDARG, hr);
2053 ok(root_end == (const WCHAR *)0xdeadbeef, "Expect root_end 0xdeadbeef, got %p\n", root_end);
2055 MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, pathW, ARRAY_SIZE(pathW));
2056 hr = pPathCchSkipRoot(pathW, NULL);
2057 ok(hr == E_INVALIDARG, "Expect result %#x, got %#x\n", E_INVALIDARG, hr);
2059 for (i = 0; i < ARRAY_SIZE(skiproot_tests); i++)
2061 const struct skiproot_test *t = skiproot_tests + i;
2062 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
2063 hr = pPathCchSkipRoot(pathW, &root_end);
2064 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr);
2065 if (SUCCEEDED(hr))
2066 ok(root_end - pathW == t->root_offset, "path %s expect root offset %d, got %ld\n", t->path, t->root_offset,
2067 (INT_PTR)(root_end - pathW));
2071 struct stripprefix_test
2073 const CHAR *path;
2074 const CHAR *stripped_path;
2075 HRESULT hr;
2076 SIZE_T size;
2079 static const struct stripprefix_test stripprefix_tests[] =
2081 {"\\\\?\\UNC\\", "\\\\", S_OK},
2082 {"\\\\?\\UNC\\a", "\\\\a", S_OK},
2083 {"\\\\?\\C:", "C:", S_OK},
2084 {"\\\\?\\C:\\", "C:\\", S_OK},
2085 {"\\\\?\\C:\\a", "C:\\a", S_OK},
2086 {"\\\\?\\unc\\", "\\\\", S_OK},
2087 {"\\\\?\\c:\\", "c:\\", S_OK},
2089 {"\\", "\\", S_FALSE},
2090 {"\\\\", "\\\\", S_FALSE},
2091 {"\\\\a", "\\\\a", S_FALSE},
2092 {"\\\\a\\", "\\\\a\\", S_FALSE},
2093 {"\\\\?\\a", "\\\\?\\a", S_FALSE},
2094 {"\\\\?\\UNC", "\\\\?\\UNC", S_FALSE},
2095 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
2096 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_FALSE},
2098 /* Size Tests */
2099 {"C:\\", NULL, E_INVALIDARG, PATHCCH_MAX_CCH + 1},
2100 {"C:\\", "C:\\", S_FALSE, PATHCCH_MAX_CCH},
2101 /* Size < original path actual length + 1, read beyond size */
2102 {"\\\\?\\C:\\", "C:\\", S_OK, ARRAY_SIZE("\\\\?\\C:\\") - 1},
2103 /* Size < stripped path length + 1 */
2104 {"\\\\?\\C:\\", NULL, E_INVALIDARG, ARRAY_SIZE("C:\\") - 1},
2105 {"\\\\?\\UNC\\", NULL, E_INVALIDARG, ARRAY_SIZE("\\\\") - 1}
2108 static void test_PathCchStripPrefix(void)
2110 WCHAR pathW[PATHCCH_MAX_CCH + 1] = {0};
2111 CHAR stripped_pathA[PATHCCH_MAX_CCH];
2112 SIZE_T size;
2113 HRESULT hr;
2114 INT i;
2116 if (!pPathCchStripPrefix)
2118 win_skip("PathCchStripPrefix(() is not available.\n");
2119 return;
2122 /* Null arguments */
2123 hr = pPathCchStripPrefix(NULL, PATHCCH_MAX_CCH);
2124 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
2126 hr = pPathCchStripPrefix(pathW, 0);
2127 ok(hr == E_INVALIDARG, "expect %#x, got %#x\n", E_INVALIDARG, hr);
2129 for (i = 0; i < ARRAY_SIZE(stripprefix_tests); i++)
2131 const struct stripprefix_test *t = stripprefix_tests + i;
2133 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
2134 size = t->size ? t->size : PATHCCH_MAX_CCH;
2135 hr = pPathCchStripPrefix(pathW, size);
2136 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr);
2137 if (SUCCEEDED(hr))
2139 WideCharToMultiByte(CP_ACP, 0, pathW, -1, stripped_pathA, ARRAY_SIZE(stripped_pathA), NULL, NULL);
2140 ok(!lstrcmpA(stripped_pathA, t->stripped_path), "path %s expect stripped path %s, got %s\n", t->path,
2141 t->stripped_path, stripped_pathA);
2146 struct striptoroot_test
2148 const CHAR *path;
2149 const CHAR *root;
2150 HRESULT hr;
2151 SIZE_T size;
2154 static const struct striptoroot_test striptoroot_tests[] =
2156 /* Invalid */
2157 {"", "", E_INVALIDARG},
2158 {"C", NULL, E_INVALIDARG},
2159 {"\\\\?\\UNC", NULL, E_INVALIDARG},
2161 /* Size */
2162 {"C:\\", NULL, E_INVALIDARG, PATHCCH_MAX_CCH + 1},
2163 {"C:\\", "C:\\", S_FALSE, PATHCCH_MAX_CCH},
2164 /* Size < original path length + 1, read beyond size */
2165 {"C:\\a", "C:\\", S_OK, ARRAY_SIZE("C:\\a") - 1},
2166 /* Size < stripped path length + 1 */
2167 {"C:\\a", "C:\\", E_INVALIDARG, ARRAY_SIZE("C:\\") - 1},
2168 {"\\\\a\\b\\c", NULL, E_INVALIDARG, ARRAY_SIZE("\\\\a\\b") - 1},
2170 /* X: */
2171 {"C:", "C:", S_FALSE},
2172 {"C:a", "C:", S_OK},
2173 {"C:a\\b", "C:", S_OK},
2174 {"C:a\\b\\c", "C:", S_OK},
2176 /* X:\ */
2177 {"C:\\", "C:\\", S_FALSE},
2178 {"C:\\a", "C:\\", S_OK},
2179 {"C:\\a\\b", "C:\\", S_OK},
2180 {"C:\\a\\b\\c", "C:\\", S_OK},
2182 /* \ */
2183 {"\\", "\\", S_FALSE},
2184 {"\\a", "\\", S_OK},
2185 {"\\a\\b", "\\", S_OK},
2186 {"\\a\\b\\c", "\\", S_OK},
2188 /* \\ */
2189 {"\\\\", "\\\\", S_FALSE},
2190 {"\\\\a", "\\\\a", S_FALSE},
2191 {"\\\\a\\b", "\\\\a\\b", S_FALSE},
2192 {"\\\\a\\b\\c", "\\\\a\\b", S_OK},
2194 /* UNC */
2195 {"\\\\?\\UNC\\", "\\\\?\\UNC\\", S_FALSE},
2196 {"\\\\?\\UNC\\a", "\\\\?\\UNC\\a", S_FALSE},
2197 {"\\\\?\\UNC\\a\\b", "\\\\?\\UNC\\a\\b", S_FALSE},
2198 {"\\\\?\\UNC\\a\\b\\", "\\\\?\\UNC\\a\\b", S_OK},
2199 {"\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b", S_OK},
2201 /* Prefixed X: */
2202 {"\\\\?\\C:", "\\\\?\\C:", S_FALSE},
2203 {"\\\\?\\C:a", "\\\\?\\C:", S_OK},
2204 {"\\\\?\\C:a\\b", "\\\\?\\C:", S_OK},
2205 {"\\\\?\\C:a\\b\\c", "\\\\?\\C:", S_OK},
2207 /* Prefixed X:\ */
2208 {"\\\\?\\C:\\", "\\\\?\\C:\\", S_FALSE},
2209 {"\\\\?\\C:\\a", "\\\\?\\C:\\", S_OK},
2210 {"\\\\?\\C:\\a\\b", "\\\\?\\C:\\", S_OK},
2211 {"\\\\?\\C:\\a\\b\\c", "\\\\?\\C:\\", S_OK},
2213 /* UNC Volume */
2214 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}",
2215 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_FALSE},
2216 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a",
2217 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_OK},
2218 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\b",
2219 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_OK},
2220 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}a\\b\\c",
2221 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}", S_OK},
2223 /* UNC Volume with backslash */
2224 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\",
2225 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_FALSE},
2226 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a",
2227 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_OK},
2228 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b",
2229 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_OK},
2230 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\a\\b\\c",
2231 "\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", S_OK},
2234 static void test_PathCchStripToRoot(void)
2236 WCHAR pathW[PATHCCH_MAX_CCH];
2237 CHAR rootA[PATHCCH_MAX_CCH];
2238 SIZE_T size;
2239 HRESULT hr;
2240 INT i;
2242 if (!pPathCchStripToRoot)
2244 win_skip("PathCchStripToRoot() is not available.\n");
2245 return;
2248 /* Null arguments */
2249 hr = pPathCchStripToRoot(NULL, ARRAY_SIZE(pathW));
2250 ok(hr == E_INVALIDARG, "Expect result %#x, got %#x\n", E_INVALIDARG, hr);
2252 MultiByteToWideChar(CP_ACP, 0, "C:\\a", -1, pathW, ARRAY_SIZE(pathW));
2253 hr = pPathCchStripToRoot(pathW, 0);
2254 ok(hr == E_INVALIDARG, "Expect result %#x, got %#x\n", E_INVALIDARG, hr);
2256 for (i = 0; i < ARRAY_SIZE(striptoroot_tests); i++)
2258 const struct striptoroot_test *t = striptoroot_tests + i;
2259 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
2260 size = t->size ? t->size : ARRAY_SIZE(pathW);
2261 hr = pPathCchStripToRoot(pathW, size);
2262 ok(hr == t->hr, "path %s expect result %#x, got %#x\n", t->path, t->hr, hr);
2263 if (SUCCEEDED(hr))
2265 WideCharToMultiByte(CP_ACP, 0, pathW, -1, rootA, ARRAY_SIZE(rootA), NULL, NULL);
2266 ok(!lstrcmpA(rootA, t->root), "path %s expect stripped path %s, got %s\n", t->path, t->root, rootA);
2271 struct isuncex_test
2273 const CHAR *path;
2274 INT server_offset;
2275 BOOL ret;
2278 static const struct isuncex_test isuncex_tests[] =
2280 {"\\\\", 2, TRUE},
2281 {"\\\\a\\", 2, TRUE},
2282 {"\\\\.\\", 2, TRUE},
2283 {"\\\\?\\UNC\\", 8, TRUE},
2284 {"\\\\?\\UNC\\a", 8, TRUE},
2285 {"\\\\?\\unc\\", 8, TRUE},
2286 {"\\\\?\\unc\\a", 8, TRUE},
2288 {"", 0, FALSE},
2289 {"\\", 0, FALSE},
2290 {"C:\\", 0, FALSE},
2291 {"\\??\\", 0, FALSE},
2292 {"\\\\?\\", 0, FALSE},
2293 {"\\\\?\\UNC", 0, FALSE},
2294 {"\\\\?\\C:", 0, FALSE},
2295 {"\\\\?\\C:\\", 0, FALSE},
2296 {"\\\\?\\C:\\a", 0, FALSE},
2297 {"\\\\?\\Volume{e51a1864-6f2d-4019-b73d-f4e60e600c26}\\", 0, FALSE}
2300 static void test_PathIsUNCEx(void)
2302 WCHAR pathW[MAX_PATH];
2303 const WCHAR *server;
2304 BOOL ret;
2305 INT i;
2307 if (!pPathIsUNCEx)
2309 win_skip("PathIsUNCEx(() is not available.\n");
2310 return;
2313 /* No NULL check for path pointers on Windows */
2314 if (0)
2316 ret = pPathIsUNCEx(NULL, &server);
2317 ok(ret == FALSE, "expect FALSE\n");
2320 MultiByteToWideChar(CP_ACP, 0, "C:\\", -1, pathW, ARRAY_SIZE(pathW));
2321 ret = pPathIsUNCEx(pathW, NULL);
2322 ok(ret == FALSE, "expect FALSE\n");
2324 for (i = 0; i < ARRAY_SIZE(isuncex_tests); i++)
2326 const struct isuncex_test *t = isuncex_tests + i;
2328 MultiByteToWideChar(CP_ACP, 0, t->path, -1, pathW, ARRAY_SIZE(pathW));
2329 server = (const WCHAR *)0xdeadbeef;
2330 ret = pPathIsUNCEx(pathW, &server);
2331 ok(ret == t->ret, "path \"%s\" expect return %d, got %d\n", t->path, t->ret, ret);
2332 if (ret)
2333 ok(server == pathW + t->server_offset, "path \"%s\" expect server offset %d, got %ld\n", t->path,
2334 t->server_offset, (INT_PTR)(server - pathW));
2335 else
2336 ok(!server, "expect server is null, got %p\n", server);
2340 static void test_actctx(void)
2342 ACTCTX_SECTION_KEYED_DATA data = { sizeof(data) };
2343 WCHAR exe_path[MAX_PATH];
2344 char buf[1024];
2345 ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *info = (void *)buf;
2346 SIZE_T size;
2347 BOOL b;
2349 b = FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL, ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, L"testdll.dll", &data);
2350 ok(b, "FindActCtxSectionString failed: %u\n", GetLastError());
2352 b = QueryActCtxW(0, data.hActCtx, &data.ulAssemblyRosterIndex, AssemblyDetailedInformationInActivationContext, buf, sizeof(buf), &size);
2353 ok(b, "QueryActCtx failed: %u\n", GetLastError());
2355 GetModuleFileNameW(NULL, exe_path, ARRAY_SIZE(exe_path));
2356 ok(!lstrcmpW(info->lpAssemblyManifestPath, exe_path), "lpAssemblyManifestPath = %s expected %s\n", debugstr_w(info->lpAssemblyManifestPath), debugstr_w(exe_path));
2357 ok(!info->lpAssemblyDirectoryName, "lpAssemblyDirectoryName = %s\n", wine_dbgstr_w(info->lpAssemblyDirectoryName));
2360 START_TEST(path)
2362 HMODULE hmod = LoadLibraryA("kernelbase.dll");
2364 pPathAllocCanonicalize = (void *)GetProcAddress(hmod, "PathAllocCanonicalize");
2365 pPathAllocCombine = (void *)GetProcAddress(hmod, "PathAllocCombine");
2366 pPathCchAddBackslash = (void *)GetProcAddress(hmod, "PathCchAddBackslash");
2367 pPathCchAddBackslashEx = (void *)GetProcAddress(hmod, "PathCchAddBackslashEx");
2368 pPathCchAddExtension = (void *)GetProcAddress(hmod, "PathCchAddExtension");
2369 pPathCchAppend = (void *)GetProcAddress(hmod, "PathCchAppend");
2370 pPathCchAppendEx = (void *)GetProcAddress(hmod, "PathCchAppendEx");
2371 pPathCchCanonicalize = (void *)GetProcAddress(hmod, "PathCchCanonicalize");
2372 pPathCchCanonicalizeEx = (void *)GetProcAddress(hmod, "PathCchCanonicalizeEx");
2373 pPathCchCombine = (void *)GetProcAddress(hmod, "PathCchCombine");
2374 pPathCchCombineEx = (void *)GetProcAddress(hmod, "PathCchCombineEx");
2375 pPathCchFindExtension = (void *)GetProcAddress(hmod, "PathCchFindExtension");
2376 pPathCchIsRoot = (void *)GetProcAddress(hmod, "PathCchIsRoot");
2377 pPathCchRemoveBackslash = (void *)GetProcAddress(hmod, "PathCchRemoveBackslash");
2378 pPathCchRemoveBackslashEx = (void *)GetProcAddress(hmod, "PathCchRemoveBackslashEx");
2379 pPathCchRemoveExtension = (void *)GetProcAddress(hmod, "PathCchRemoveExtension");
2380 pPathCchRemoveFileSpec = (void *)GetProcAddress(hmod, "PathCchRemoveFileSpec");
2381 pPathCchRenameExtension = (void *)GetProcAddress(hmod, "PathCchRenameExtension");
2382 pPathCchSkipRoot = (void *)GetProcAddress(hmod, "PathCchSkipRoot");
2383 pPathCchStripPrefix = (void *)GetProcAddress(hmod, "PathCchStripPrefix");
2384 pPathCchStripToRoot = (void *)GetProcAddress(hmod, "PathCchStripToRoot");
2385 pPathIsUNCEx = (void *)GetProcAddress(hmod, "PathIsUNCEx");
2387 test_PathAllocCanonicalize();
2388 test_PathAllocCombine();
2389 test_PathCchAddBackslash();
2390 test_PathCchAddBackslashEx();
2391 test_PathCchAddExtension();
2392 test_PathCchAppend();
2393 test_PathCchAppendEx();
2394 test_PathCchCanonicalize();
2395 test_PathCchCanonicalizeEx();
2396 test_PathCchCombine();
2397 test_PathCchCombineEx();
2398 test_PathCchFindExtension();
2399 test_PathCchIsRoot();
2400 test_PathCchRemoveBackslash();
2401 test_PathCchRemoveBackslashEx();
2402 test_PathCchRemoveExtension();
2403 test_PathCchRemoveFileSpec();
2404 test_PathCchRenameExtension();
2405 test_PathCchSkipRoot();
2406 test_PathCchStripPrefix();
2407 test_PathCchStripToRoot();
2408 test_PathIsUNCEx();
2409 test_actctx();