[KERNEL32]
[reactos.git] / rostests / winetests / kernel32 / path.c
1 /*
2 * Unit test suite for various Path and Directory Functions
3 *
4 * Copyright 2002 Geoffrey Hausheer
5 * Copyright 2006 Detlef Riekenberg
6 *
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.
11 *
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.
16 *
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
20 */
21
22 #include <stdarg.h>
23 #include <stdio.h>
24 #include "wine/test.h"
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winuser.h"
28 #include "winerror.h"
29 #include "winnls.h"
30
31 #define HAS_TRAIL_SLASH_A(string) (string[lstrlenA(string)-1]=='\\')
32
33 #define LONGFILE "Long File test.path"
34 #define SHORTFILE "pathtest.pth"
35 #define SHORTDIR "shortdir"
36 #define LONGDIR "Long Directory"
37 #define NONFILE_SHORT "noexist.pth"
38 #define NONFILE_LONG "NonExistent File"
39 #define NONDIR_SHORT "notadir"
40 #define NONDIR_LONG "NonExistent Directory"
41
42 #define NOT_A_VALID_DRIVE '@'
43
44 /* the following characters don't work well with GetFullPathNameA
45 in Win98. I don't know if this is a FAT thing, or if it is an OS thing
46 but I don't test these characters now.
47 NOTE: Win2k allows GetFullPathNameA to work with them though
48 |<>"
49 */
50 static const CHAR funny_chars[]="!@#$%^&*()=+{}[],?'`";
51 static const CHAR is_char_ok[] ="11111110111111111011";
52
53 static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR,LPSTR,DWORD);
54 static DWORD (WINAPI *pGetLongPathNameW)(LPWSTR,LPWSTR,DWORD);
55
56 /* Present in Win2003+ */
57 static BOOL (WINAPI *pNeedCurrentDirectoryForExePathA)(LPCSTR);
58 static BOOL (WINAPI *pNeedCurrentDirectoryForExePathW)(LPCWSTR);
59
60 static DWORD (WINAPI *pSearchPathA)(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*);
61 static DWORD (WINAPI *pSearchPathW)(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPWSTR,LPWSTR*);
62
63 /* a structure to deal with wine todos somewhat cleanly */
64 typedef struct {
65 DWORD shortlen;
66 DWORD shorterror;
67 DWORD s2llen;
68 DWORD s2lerror;
69 DWORD longlen;
70 DWORD longerror;
71 } SLpassfail;
72
73 /* function that tests GetFullPathNameA, GetShortPathNameA,GetLongPathNameA */
74 /* NOTE: the passfail structure is used to allow customizable todo checking
75 for wine. It is not very pretty, but it sure beats duplicating this
76 function lots of times
77 */
78 static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR *filename,
79 CHAR *shortstr, SLpassfail *passfail, const CHAR *errstr)
80 {
81 CHAR tmpstr[MAX_PATH],
82 fullpath[MAX_PATH], /*full path to the file (not short/long) */
83 subpath[MAX_PATH], /*relative path to the file */
84 fullpathshort[MAX_PATH], /*absolute path to the file (short format) */
85 fullpathlong[MAX_PATH], /*absolute path to the file (long format) */
86 curdirshort[MAX_PATH], /*absolute path to the current dir (short) */
87 curdirlong[MAX_PATH]; /*absolute path to the current dir (long) */
88 LPSTR strptr; /*ptr to the filename portion of the path */
89 DWORD len;
90 /* if passfail is NULL, we can perform all checks within this function,
91 otherwise, we will return the relevant data in the passfail struct, so
92 we must initialize it first
93 */
94 if(passfail!=NULL) {
95 passfail->shortlen=-1;passfail->s2llen=-1;passfail->longlen=-1;
96 passfail->shorterror=0;passfail->s2lerror=0;passfail->longerror=0;
97 }
98 /* GetLongPathNameA is only supported on Win2k+ and Win98+ */
99 if(pGetLongPathNameA) {
100 ok((len=pGetLongPathNameA(curdir,curdirlong,MAX_PATH)),
101 "%s: GetLongPathNameA failed\n",errstr);
102 /*GetLongPathNameA can return a trailing '\\' but shouldn't do so here */
103 ok(! HAS_TRAIL_SLASH_A(curdirlong),
104 "%s: GetLongPathNameA should not have a trailing \\\n",errstr);
105 }
106 ok((len=GetShortPathNameA(curdir,curdirshort,MAX_PATH)),
107 "%s: GetShortPathNameA failed\n",errstr);
108 /*GetShortPathNameA can return a trailing '\\' but shouldn't do so here */
109 ok(! HAS_TRAIL_SLASH_A(curdirshort),
110 "%s: GetShortPathNameA should not have a trailing \\\n",errstr);
111 /* build relative and absolute paths from inputs */
112 if(lstrlenA(subdir)) {
113 sprintf(subpath,"%s\\%s",subdir,filename);
114 } else {
115 lstrcpyA(subpath,filename);
116 }
117 sprintf(fullpath,"%s\\%s",curdir,subpath);
118 sprintf(fullpathshort,"%s\\%s",curdirshort,subpath);
119 sprintf(fullpathlong,"%s\\%s",curdirlong,subpath);
120 /* Test GetFullPathNameA functionality */
121 len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr);
122 ok(len, "GetFullPathNameA failed for: '%s'\n",subpath);
123 if(HAS_TRAIL_SLASH_A(subpath)) {
124 ok(strptr==NULL,
125 "%s: GetFullPathNameA should not return a filename ptr\n",errstr);
126 ok(lstrcmpiA(fullpath,tmpstr)==0,
127 "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
128 errstr,tmpstr,fullpath);
129 } else {
130 ok(lstrcmpiA(strptr,filename)==0,
131 "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
132 errstr,strptr,filename);
133 ok(lstrcmpiA(fullpath,tmpstr)==0,
134 "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
135 errstr,tmpstr,fullpath);
136 }
137 /* Test GetShortPathNameA functionality */
138 SetLastError(0);
139 len=GetShortPathNameA(fullpathshort,shortstr,MAX_PATH);
140 if(passfail==NULL) {
141 ok(len, "%s: GetShortPathNameA failed\n",errstr);
142 } else {
143 passfail->shortlen=len;
144 passfail->shorterror=GetLastError();
145 }
146 /* Test GetLongPathNameA functionality
147 We test both conversion from GetFullPathNameA and from GetShortPathNameA
148 */
149 if(pGetLongPathNameA) {
150 if(len!=0) {
151 SetLastError(0);
152 len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH);
153 if(passfail==NULL) {
154 ok(len,
155 "%s: GetLongPathNameA failed during Short->Long conversion\n", errstr);
156 ok(lstrcmpiA(fullpathlong,tmpstr)==0,
157 "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
158 errstr,tmpstr,fullpathlong);
159 } else {
160 passfail->s2llen=len;
161 passfail->s2lerror=GetLastError();
162 }
163 }
164 SetLastError(0);
165 len=pGetLongPathNameA(fullpath,tmpstr,MAX_PATH);
166 if(passfail==NULL) {
167 ok(len, "%s: GetLongPathNameA failed\n",errstr);
168 if(HAS_TRAIL_SLASH_A(fullpath)) {
169 ok(lstrcmpiA(fullpathlong,tmpstr)==0,
170 "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
171 errstr,tmpstr,fullpathlong);
172 } else {
173 ok(lstrcmpiA(fullpathlong,tmpstr)==0,
174 "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
175 errstr,tmpstr,fullpathlong);
176 }
177 } else {
178 passfail->longlen=len;
179 passfail->longerror=GetLastError();
180 }
181 }
182 }
183
184 /* split path into leading directory, and 8.3 filename */
185 static void test_SplitShortPathA(CHAR *path,CHAR *dir,CHAR *eight,CHAR *three) {
186 int done,error;
187 int ext,fil;
188 int len,i;
189 len=lstrlenA(path);
190 ext=len; fil=len; done=0; error=0;
191 /* walk backwards over path looking for '.' or '\\' separators */
192 for(i=len-1;(i>=0) && (!done);i--) {
193 if(path[i]=='.')
194 if(ext!=len) error=1; else ext=i;
195 else if(path[i]=='\\') {
196 if(i==len-1) {
197 error=1;
198 } else {
199 fil=i;
200 done=1;
201 }
202 }
203 }
204 /* Check that we didn't find a trailing '\\' or multiple '.' */
205 ok(!error,"Illegal file found in 8.3 path '%s'\n",path);
206 /* Separate dir, root, and extension */
207 if(ext!=len) lstrcpyA(three,path+ext+1); else lstrcpyA(three,"");
208 if(fil!=len) {
209 lstrcpynA(eight,path+fil+1,ext-fil);
210 lstrcpynA(dir,path,fil+1);
211 } else {
212 lstrcpynA(eight,path,ext+1);
213 lstrcpyA(dir,"");
214 }
215 /* Validate that root and extension really are 8.3 */
216 ok(lstrlenA(eight)<=8 && lstrlenA(three)<=3,
217 "GetShortPathNAmeA did not return an 8.3 path\n");
218 }
219
220 /* Check that GetShortPathNameA returns a valid 8.3 path */
221 static void test_LongtoShortA(CHAR *teststr,const CHAR *goodstr,
222 const CHAR *ext,const CHAR *errstr) {
223 CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
224
225 test_SplitShortPathA(teststr,dir,eight,three);
226 ok(lstrcmpiA(dir,goodstr)==0,
227 "GetShortPathNameA returned '%s' instead of '%s'\n",dir,goodstr);
228 ok(lstrcmpiA(three,ext)==0,
229 "GetShortPathNameA returned '%s' with incorrect extension\n",three);
230 }
231
232 /* Test that Get(Short|Long|Full)PathNameA work correctly with interesting
233 characters in the filename.
234 'valid' indicates whether this would be an allowed filename
235 'todo' indicates that wine doesn't get this right yet.
236 NOTE: We always call this routine with a nonexistent filename, so
237 Get(Short|Long)PathNameA should never pass, but GetFullPathNameA
238 should.
239 */
240 static void test_FunnyChars(CHAR *curdir,CHAR *curdir_short,CHAR *filename, INT valid,CHAR *errstr)
241 {
242 CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
243 SLpassfail passfail;
244
245 test_ValidPathA(curdir,"",filename,tmpstr,&passfail,errstr);
246 if(valid) {
247 sprintf(tmpstr1,"%s\\%s",curdir_short,filename);
248 ok((passfail.shortlen==0 &&
249 (passfail.shorterror==ERROR_FILE_NOT_FOUND || passfail.shorterror==ERROR_PATH_NOT_FOUND || !passfail.shorterror)) ||
250 (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
251 "%s: GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
252 errstr,passfail.shortlen,passfail.shorterror,tmpstr);
253 } else {
254 ok(passfail.shortlen==0 &&
255 (passfail.shorterror==ERROR_INVALID_NAME || passfail.shorterror==ERROR_FILE_NOT_FOUND || !passfail.shorterror),
256 "%s: GetShortPathA should have failed len=%d, error=%d\n",
257 errstr,passfail.shortlen,passfail.shorterror);
258 }
259 if(pGetLongPathNameA) {
260 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
261 if(valid) {
262 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
263 "%s: GetLongPathA returned %d and not %d\n",
264 errstr,passfail.longerror,ERROR_FILE_NOT_FOUND);
265 } else {
266 ok(passfail.longerror==ERROR_INVALID_NAME ||
267 passfail.longerror==ERROR_FILE_NOT_FOUND,
268 "%s: GetLongPathA returned %d and not %d or %d'\n",
269 errstr, passfail.longerror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
270 }
271 }
272 }
273
274 /* Routine to test that SetCurrentDirectory behaves as expected. */
275 static void test_setdir(CHAR *olddir,CHAR *newdir,
276 CHAR *cmprstr, INT pass, const CHAR *errstr)
277 {
278 CHAR tmppath[MAX_PATH], *dirptr;
279 DWORD val,len,chklen;
280
281 val=SetCurrentDirectoryA(newdir);
282 len=GetCurrentDirectoryA(MAX_PATH,tmppath);
283 /* if 'pass' then the SetDirectoryA was supposed to pass */
284 if(pass) {
285 dirptr=(cmprstr==NULL) ? newdir : cmprstr;
286 chklen=lstrlenA(dirptr);
287 ok(val,"%s: SetCurrentDirectoryA failed\n",errstr);
288 ok(len==chklen,
289 "%s: SetCurrentDirectory did not change the directory, though it passed\n",
290 errstr);
291 ok(lstrcmpiA(dirptr,tmppath)==0,
292 "%s: SetCurrentDirectory did not change the directory, though it passed\n",
293 errstr);
294 ok(SetCurrentDirectoryA(olddir),
295 "%s: Couldn't set directory to it's original value\n",errstr);
296 } else {
297 /* else thest that it fails correctly */
298 chklen=lstrlenA(olddir);
299 ok(val==0,
300 "%s: SetCurrentDirectoryA passed when it should have failed\n",errstr);
301 ok(len==chklen,
302 "%s: SetCurrentDirectory changed the directory, though it failed\n",
303 errstr);
304 ok(lstrcmpiA(olddir,tmppath)==0,
305 "%s: SetCurrentDirectory changed the directory, though it failed\n",
306 errstr);
307 }
308 }
309 static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive)
310 {
311 CHAR tmppath[MAX_PATH], /*path to TEMP */
312 tmpstr[MAX_PATH],
313 tmpstr1[MAX_PATH];
314 DWORD len,len1,drives;
315 INT id;
316 HANDLE hndl;
317 BOOL bRes;
318
319 *curDrive = *otherDrive = NOT_A_VALID_DRIVE;
320
321 /* Get the current drive letter */
322 if( GetCurrentDirectoryA( MAX_PATH, tmpstr))
323 *curDrive = tmpstr[0];
324 else
325 trace( "Unable to discover current drive, some tests will not be conducted.\n");
326
327 /* Test GetTempPathA */
328 len=GetTempPathA(MAX_PATH,tmppath);
329 ok(len!=0 && len < MAX_PATH,"GetTempPathA failed\n");
330 ok(HAS_TRAIL_SLASH_A(tmppath),
331 "GetTempPathA returned a path that did not end in '\\'\n");
332 lstrcpyA(tmpstr,"aaaaaaaa");
333 len1=GetTempPathA(len,tmpstr);
334 ok(len1==len+1 || broken(len1 == len), /* WinME */
335 "GetTempPathA should return string length %d instead of %d\n",len+1,len1);
336
337 /* Test GetTmpFileNameA
338 The only test we do here is whether GetTempFileNameA passes or not.
339 We do not thoroughly test this function yet (specifically, whether
340 it behaves correctly when 'unique' is non zero)
341 */
342 ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
343 sprintf(tmpstr,"pat%.4x.tmp",id & 0xffff);
344 sprintf(tmpstr1,"pat%x.tmp",id & 0xffff);
345 ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
346 lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
347 "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
348 newdir,tmpstr,tmpstr1,id);
349 ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
350
351 id=GetTempFileNameA(tmppath,NULL,0,newdir);
352 /* Windows 95, 98 return 0==id, while Windows 2000, XP return 0!=id */
353 if (id)
354 {
355 sprintf(tmpstr,"%.4x.tmp",id & 0xffff);
356 sprintf(tmpstr1,"%x.tmp",id & 0xffff);
357 ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
358 lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
359 "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
360 newdir,tmpstr,tmpstr1,id);
361 ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
362 }
363
364 /* Find first valid drive letter that is neither newdir[0] nor curDrive */
365 drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
366 if( *curDrive != NOT_A_VALID_DRIVE)
367 drives &= ~(1<<(*curDrive-'A'));
368 if( drives)
369 for( *otherDrive='A'; (drives & 1) == 0; drives>>=1, (*otherDrive)++);
370 else
371 trace( "Could not find alternative drive, some tests will not be conducted.\n");
372
373 /* Do some CreateDirectoryA tests */
374 /* It would be nice to do test the SECURITY_ATTRIBUTES, but I don't
375 really understand how they work.
376 More formal tests should be done along with CreateFile tests
377 */
378 ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
379 ok(CreateDirectoryA(newdir,NULL)==0,
380 "CreateDirectoryA succeeded even though a file of the same name exists\n");
381 ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
382 ok(CreateDirectoryA(newdir,NULL),"CreateDirectoryA failed\n");
383 /* Create some files to test other functions. Note, we will test CreateFileA
384 at some later point
385 */
386 sprintf(tmpstr,"%s\\%s",newdir,SHORTDIR);
387 ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
388 sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
389 ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
390 sprintf(tmpstr,"%c:", *curDrive);
391 bRes = CreateDirectoryA(tmpstr,NULL);
392 ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED ||
393 GetLastError() == ERROR_ALREADY_EXISTS),
394 "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
395 sprintf(tmpstr,"%c:\\", *curDrive);
396 bRes = CreateDirectoryA(tmpstr,NULL);
397 ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED ||
398 GetLastError() == ERROR_ALREADY_EXISTS),
399 "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
400 sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
401 hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
402 CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
403 ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
404 ok(CloseHandle(hndl),"CloseHandle failed\n");
405 sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,LONGFILE);
406 hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
407 CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
408 ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
409 ok(CloseHandle(hndl),"CloseHandle failed\n");
410 sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,SHORTFILE);
411 hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
412 CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
413 ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
414 ok(CloseHandle(hndl),"CloseHandle failed\n");
415 sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,LONGFILE);
416 hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
417 CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
418 ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
419 ok(CloseHandle(hndl),"CloseHandle failed\n");
420 }
421
422 /* Test GetCurrentDirectory & SetCurrentDirectory */
423 static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir)
424 {
425 CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
426 char *buffer;
427 DWORD len,len1;
428 /* Save the original directory, so that we can return to it at the end
429 of the test
430 */
431 len=GetCurrentDirectoryA(MAX_PATH,origdir);
432 ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed\n");
433 /* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
434 buffer size is too small to hold the current directory
435 */
436 lstrcpyA(tmpstr,"aaaaaaa");
437 len1=GetCurrentDirectoryA(len,tmpstr);
438 ok(len1==len+1, "GetCurrentDirectoryA returned %d instead of %d\n",len1,len+1);
439 ok(lstrcmpiA(tmpstr,"aaaaaaa")==0,
440 "GetCurrentDirectoryA should not have modified the buffer\n");
441
442 buffer = HeapAlloc( GetProcessHeap(), 0, 2 * 65536 );
443 SetLastError( 0xdeadbeef );
444 strcpy( buffer, "foo" );
445 len = GetCurrentDirectoryA( 32767, buffer );
446 ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
447 if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
448 SetLastError( 0xdeadbeef );
449 strcpy( buffer, "foo" );
450 len = GetCurrentDirectoryA( 32768, buffer );
451 ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
452 if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
453 SetLastError( 0xdeadbeef );
454 strcpy( buffer, "foo" );
455 len = GetCurrentDirectoryA( 65535, buffer );
456 ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4, win2k, xp */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
457 if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
458 SetLastError( 0xdeadbeef );
459 strcpy( buffer, "foo" );
460 len = GetCurrentDirectoryA( 65536, buffer );
461 ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
462 if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
463 SetLastError( 0xdeadbeef );
464 strcpy( buffer, "foo" );
465 len = GetCurrentDirectoryA( 2 * 65536, buffer );
466 ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
467 if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
468 HeapFree( GetProcessHeap(), 0, buffer );
469
470 /* Check for crash prevention on swapped args. Crashes all but Win9x.
471 */
472 if (0)
473 {
474 SetLastError( 0xdeadbeef );
475 len = GetCurrentDirectoryA( 42, (LPSTR)(MAX_PATH + 42) );
476 ok( len == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
477 "GetCurrentDirectoryA failed to fail %u err %u\n", len, GetLastError() );
478 }
479
480 /* SetCurrentDirectoryA shouldn't care whether the string has a
481 trailing '\\' or not
482 */
483 sprintf(tmpstr,"%s\\",newdir);
484 test_setdir(origdir,tmpstr,newdir,1,"check 1");
485 test_setdir(origdir,newdir,NULL,1,"check 2");
486 /* Set the directory to the working area. We just tested that this works,
487 so why check it again.
488 */
489 SetCurrentDirectoryA(newdir);
490 /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
491 sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
492 test_setdir(newdir,tmpstr,NULL,0,"check 3");
493 /* Check that SetCurrentDirectory fails for a nonexistent lond directory */
494 sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
495 test_setdir(newdir,tmpstr,NULL,0,"check 4");
496 /* Check that SetCurrentDirectory passes with a long directory */
497 sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
498 test_setdir(newdir,tmpstr,NULL,1,"check 5");
499 /* Check that SetCurrentDirectory passes with a short relative directory */
500 sprintf(tmpstr,"%s",SHORTDIR);
501 sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
502 test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
503 /* starting with a '.' */
504 sprintf(tmpstr,".\\%s",SHORTDIR);
505 test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
506 /* Check that SetCurrentDirectory passes with a short relative directory */
507 sprintf(tmpstr,"%s",LONGDIR);
508 sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
509 test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
510 /* starting with a '.' */
511 sprintf(tmpstr,".\\%s",LONGDIR);
512 test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
513 /* change to root without a trailing backslash. The function call succeeds
514 but the directory is not changed.
515 */
516 sprintf(tmpstr, "%c:", newdir[0]);
517 test_setdir(newdir,tmpstr,newdir,1,"check 10");
518 /* works however with a trailing backslash */
519 sprintf(tmpstr, "%c:\\", newdir[0]);
520 test_setdir(newdir,tmpstr,NULL,1,"check 11");
521 }
522
523 /* Cleanup the mess we made while executing these tests */
524 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
525 {
526 CHAR tmpstr[MAX_PATH];
527 sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
528 ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
529 sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
530 ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
531 sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
532 ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
533 sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
534 ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
535 sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
536 ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
537 sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
538 ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
539 ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
540 ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
541 }
542
543 /* This routine will test Get(Full|Short|Long)PathNameA */
544 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
545 {
546 CHAR curdir_short[MAX_PATH],
547 longdir_short[MAX_PATH];
548 CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
549 LPSTR strptr; /*ptr to the filename portion of the path */
550 DWORD len;
551 INT i;
552 CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
553 SLpassfail passfail;
554
555 /* Get the short form of the current directory */
556 ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
557 "GetShortPathNameA failed\n");
558 ok(!HAS_TRAIL_SLASH_A(curdir_short),
559 "GetShortPathNameA should not have a trailing \\\n");
560 /* Get the short form of the absolute-path to LONGDIR */
561 sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
562 ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
563 "GetShortPathNameA failed\n");
564 ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
565 "GetShortPathNameA should not have a trailing \\\n");
566
567 if (pGetLongPathNameA) {
568 DWORD rc1,rc2;
569 sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
570 rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
571 rc2=(*pGetLongPathNameA)(curdir,NULL,0);
572 ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
573 "GetLongPathNameA: wrong return code, %d instead of %d\n",
574 rc1, lstrlenA(tmpstr)+1);
575
576 sprintf(dir,"%c:",curDrive);
577 rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
578 ok(strcmp(dir,tmpstr)==0,
579 "GetLongPathNameA: returned '%s' instead of '%s' (rc=%d)\n",
580 tmpstr,dir,rc1);
581 }
582
583 /* Check the cases where both file and directory exist first */
584 /* Start with a 8.3 directory, 8.3 filename */
585 test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
586 sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
587 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
588 "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
589 /* Now try a 8.3 directory, long file name */
590 test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
591 sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
592 test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
593 /* Next is a long directory, 8.3 file */
594 test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
595 sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
596 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
597 "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
598 /*Lastly a long directory, long file */
599 test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
600 test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
601
602 /* Now check all of the invalid file w/ valid directory combinations */
603 /* Start with a 8.3 directory, 8.3 filename */
604 test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
605 sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
606 ok((passfail.shortlen==0 &&
607 (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
608 passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
609 (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
610 "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
611 passfail.shortlen,passfail.shorterror,tmpstr);
612 if(pGetLongPathNameA) {
613 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
614 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
615 "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
616 }
617 /* Now try a 8.3 directory, long file name */
618 test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
619 ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
620 ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
621 passfail.shorterror==ERROR_FILE_NOT_FOUND ||
622 !passfail.shorterror,
623 "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
624 if(pGetLongPathNameA) {
625 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
626 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
627 "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
628 }
629 /* Next is a long directory, 8.3 file */
630 test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
631 sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
632 GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
633 strcat(tmpstr1,"\\" NONFILE_SHORT);
634 ok((passfail.shortlen==0 &&
635 (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
636 passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
637 (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
638 "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
639 passfail.shortlen,passfail.shorterror,tmpstr);
640 if(pGetLongPathNameA) {
641 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
642 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
643 "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
644 }
645 /*Lastly a long directory, long file */
646 test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
647 ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
648 ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
649 passfail.shorterror==ERROR_FILE_NOT_FOUND ||
650 !passfail.shorterror,
651 "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
652 if(pGetLongPathNameA) {
653 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
654 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
655 "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
656 }
657 /* Now try again with directories that don't exist */
658 /* 8.3 directory, 8.3 filename */
659 test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
660 sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
661 ok((passfail.shortlen==0 &&
662 (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
663 passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
664 (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
665 "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
666 passfail.shortlen,passfail.shorterror,tmpstr);
667 if(pGetLongPathNameA) {
668 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
669 ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
670 passfail.longerror==ERROR_FILE_NOT_FOUND,
671 "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
672 passfail.longerror);
673 }
674 /* Now try a 8.3 directory, long file name */
675 test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
676 ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
677 ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
678 passfail.shorterror==ERROR_FILE_NOT_FOUND ||
679 !passfail.shorterror,
680 "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
681 passfail.shorterror);
682 if(pGetLongPathNameA) {
683 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
684 ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
685 passfail.longerror==ERROR_FILE_NOT_FOUND,
686 "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
687 passfail.longerror);
688 }
689 /* Next is a long directory, 8.3 file */
690 test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
691 ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
692 ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
693 passfail.shorterror==ERROR_FILE_NOT_FOUND ||
694 !passfail.shorterror,
695 "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
696 passfail.shorterror);
697 if(pGetLongPathNameA) {
698 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
699 ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
700 passfail.longerror==ERROR_FILE_NOT_FOUND,
701 "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
702 passfail.longerror);
703 }
704 /*Lastly a long directory, long file */
705 test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
706 ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
707 ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
708 passfail.shorterror==ERROR_FILE_NOT_FOUND ||
709 !passfail.shorterror,
710 "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
711 passfail.shorterror);
712 if(pGetLongPathNameA) {
713 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
714 ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
715 passfail.longerror==ERROR_FILE_NOT_FOUND,
716 "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
717 passfail.longerror);
718 }
719 /* Next try directories ending with '\\' */
720 /* Existing Directories */
721 sprintf(tmpstr,"%s\\",SHORTDIR);
722 test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
723 sprintf(tmpstr,"%s\\",LONGDIR);
724 test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
725 /* Nonexistent directories */
726 sprintf(tmpstr,"%s\\",NONDIR_SHORT);
727 test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
728 sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
729 ok((passfail.shortlen==0 &&
730 (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
731 passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
732 (passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
733 "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
734 passfail.shortlen,passfail.shorterror,tmpstr);
735 if(pGetLongPathNameA) {
736 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
737 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
738 "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
739 passfail.longerror);
740 }
741 sprintf(tmpstr,"%s\\",NONDIR_LONG);
742 test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
743 ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
744 ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
745 passfail.shorterror==ERROR_FILE_NOT_FOUND ||
746 !passfail.shorterror,
747 "GetShortPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
748 passfail.shorterror);
749 if(pGetLongPathNameA) {
750 ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
751 ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
752 "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
753 passfail.longerror);
754 }
755 /* Test GetFullPathNameA with drive letters */
756 if( curDrive != NOT_A_VALID_DRIVE) {
757 sprintf(tmpstr,"%c:",curdir[0]);
758 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
759 "GetFullPathNameA(%c:) failed\n", curdir[0]);
760 GetCurrentDirectoryA(MAX_PATH,tmpstr);
761 sprintf(tmpstr1,"%s\\",tmpstr);
762 ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
763 "GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
764 curdir[0],tmpstr2,tmpstr,tmpstr1);
765
766 sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
767 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
768 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
769 "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
770 ok(lstrcmpiA(SHORTFILE,strptr)==0,
771 "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
772 }
773 /* Without a leading slash, insert the current directory if on the current drive */
774 sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
775 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
776 sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
777 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
778 "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
779 ok(lstrcmpiA(SHORTFILE,strptr)==0,
780 "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
781 /* Otherwise insert the missing leading slash */
782 if( otherDrive != NOT_A_VALID_DRIVE) {
783 /* FIXME: this test assumes that current directory on other drive is root */
784 sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
785 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
786 sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
787 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
788 "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
789 ok(lstrcmpiA(SHORTFILE,strptr)==0,
790 "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
791 }
792 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
793 So test for them. */
794 if( curDrive != NOT_A_VALID_DRIVE) {
795 sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
796 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
797 sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
798 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
799 "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
800 ok(lstrcmpiA(SHORTFILE,strptr)==0,
801 "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
802 }
803 /**/
804 sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
805 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
806 sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
807 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
808 "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
809 ok(lstrcmpiA(SHORTFILE,strptr)==0,
810 "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
811 /* Windows will insert a drive letter in front of an absolute UNIX path */
812 sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
813 ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
814 sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
815 ok(lstrcmpiA(tmpstr,tmpstr1)==0,
816 "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
817 /* This passes in Wine because it still contains the pointer from the previous test */
818 ok(lstrcmpiA(SHORTFILE,strptr)==0,
819 "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
820
821 /* Now try some relative paths */
822 ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
823 test_SplitShortPathA(tmpstr,dir,eight,three);
824 if(pGetLongPathNameA) {
825 ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
826 ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
827 "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
828 }
829 sprintf(tmpstr,".\\%s",LONGDIR);
830 ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
831 test_SplitShortPathA(tmpstr1,dir,eight,three);
832 ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
833 "GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
834 if(pGetLongPathNameA) {
835 ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
836 tmpstr);
837 ok(lstrcmpiA(tmpstr1,tmpstr)==0,
838 "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
839 }
840 /* Check out Get*PathNameA on some funny characters */
841 for(i=0;i<lstrlenA(funny_chars);i++) {
842 INT valid;
843 valid=(is_char_ok[i]=='0') ? 0 : 1;
844 sprintf(tmpstr1,"check%d-1",i);
845 sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
846 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
847 sprintf(tmpstr1,"check%d-2",i);
848 sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
849 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
850 sprintf(tmpstr1,"check%d-3",i);
851 sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
852 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
853 sprintf(tmpstr1,"check%d-4",i);
854 sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
855 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
856 sprintf(tmpstr1,"check%d-5",i);
857 sprintf(tmpstr,"Long %c File",funny_chars[i]);
858 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
859 sprintf(tmpstr1,"check%d-6",i);
860 sprintf(tmpstr,"%c Long File",funny_chars[i]);
861 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
862 sprintf(tmpstr1,"check%d-7",i);
863 sprintf(tmpstr,"Long File %c",funny_chars[i]);
864 test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
865 }
866 }
867
868 static void test_GetTempPathA(char* tmp_dir)
869 {
870 DWORD len, len_with_null;
871 char buf[MAX_PATH];
872
873 len_with_null = strlen(tmp_dir) + 1;
874
875 lstrcpyA(buf, "foo");
876 len = GetTempPathA(MAX_PATH, buf);
877 ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
878 ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
879 ok(len == strlen(buf), "returned length should be equal to the length of string\n");
880
881 /* Some versions of Windows touch the buffer, some don't so we don't
882 * test that. Also, NT sometimes exaggerates the required buffer size
883 * so we cannot test for an exact match. Finally, the
884 * 'len_with_null - 1' case is so buggy on Windows it's not testable.
885 * For instance in some cases Win98 returns len_with_null - 1 instead
886 * of len_with_null.
887 */
888 len = GetTempPathA(1, buf);
889 ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
890
891 len = GetTempPathA(0, NULL);
892 ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
893
894 /* The call above gave us the buffer size that Windows thinks is needed
895 * so the next call should work
896 */
897 lstrcpyA(buf, "foo");
898 len = GetTempPathA(len, buf);
899 ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
900 ok(len == strlen(buf), "returned length should be equal to the length of string\n");
901 }
902
903 static void test_GetTempPathW(char* tmp_dir)
904 {
905 DWORD len, len_with_null;
906 WCHAR buf[MAX_PATH];
907 WCHAR tmp_dirW[MAX_PATH];
908 static const WCHAR fooW[] = {'f','o','o',0};
909
910 MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
911 len_with_null = lstrlenW(tmp_dirW) + 1;
912
913 /* This one is different from ANSI version: ANSI version doesn't
914 * touch the buffer, unicode version usually truncates the buffer
915 * to zero size. NT still exaggerates the required buffer size
916 * sometimes so we cannot test for an exact match. Finally, the
917 * 'len_with_null - 1' case is so buggy on Windows it's not testable.
918 * For instance on NT4 it will sometimes return a path without the
919 * trailing '\\' and sometimes return an error.
920 */
921
922 lstrcpyW(buf, fooW);
923 len = GetTempPathW(MAX_PATH, buf);
924 if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
925 {
926 win_skip("GetTempPathW is not available\n");
927 return;
928 }
929 ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
930 ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
931
932 lstrcpyW(buf, fooW);
933 len = GetTempPathW(1, buf);
934 ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
935 ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
936
937 len = GetTempPathW(0, NULL);
938 ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
939
940 lstrcpyW(buf, fooW);
941 len = GetTempPathW(len, buf);
942 ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
943 ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
944 }
945
946 static void test_GetTempPath(void)
947 {
948 char save_TMP[MAX_PATH];
949 char windir[MAX_PATH];
950 char buf[MAX_PATH];
951
952 if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0;
953
954 /* test default configuration */
955 trace("TMP=%s\n", save_TMP);
956 if (save_TMP[0])
957 {
958 strcpy(buf,save_TMP);
959 if (buf[strlen(buf)-1]!='\\')
960 strcat(buf,"\\");
961 test_GetTempPathA(buf);
962 test_GetTempPathW(buf);
963 }
964
965 /* TMP=C:\WINDOWS */
966 GetWindowsDirectoryA(windir, sizeof(windir));
967 SetEnvironmentVariableA("TMP", windir);
968 GetEnvironmentVariableA("TMP", buf, sizeof(buf));
969 trace("TMP=%s\n", buf);
970 strcat(windir,"\\");
971 test_GetTempPathA(windir);
972 test_GetTempPathW(windir);
973
974 /* TMP=C:\ */
975 GetWindowsDirectoryA(windir, sizeof(windir));
976 windir[3] = 0;
977 SetEnvironmentVariableA("TMP", windir);
978 GetEnvironmentVariableA("TMP", buf, sizeof(buf));
979 trace("TMP=%s\n", buf);
980 test_GetTempPathA(windir);
981 test_GetTempPathW(windir);
982
983 /* TMP=C: i.e. use current working directory of the specified drive */
984 GetWindowsDirectoryA(windir, sizeof(windir));
985 SetCurrentDirectoryA(windir);
986 windir[2] = 0;
987 SetEnvironmentVariableA("TMP", windir);
988 GetEnvironmentVariableA("TMP", buf, sizeof(buf));
989 trace("TMP=%s\n", buf);
990 GetWindowsDirectoryA(windir, sizeof(windir));
991 strcat(windir,"\\");
992 test_GetTempPathA(windir);
993 test_GetTempPathW(windir);
994
995 SetEnvironmentVariableA("TMP", save_TMP);
996 }
997
998 static void test_GetLongPathNameA(void)
999 {
1000 DWORD length, explength, hostsize;
1001 char tempfile[MAX_PATH];
1002 char longpath[MAX_PATH];
1003 char unc_prefix[MAX_PATH];
1004 char unc_short[MAX_PATH], unc_long[MAX_PATH];
1005 char temppath[MAX_PATH], temppath2[MAX_PATH];
1006 HANDLE file;
1007
1008 if (!pGetLongPathNameA)
1009 return;
1010
1011 GetTempPathA(MAX_PATH, tempfile);
1012 lstrcatA(tempfile, "longfilename.longext");
1013
1014 file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1015 CloseHandle(file);
1016
1017 /* Test a normal path with a small buffer size */
1018 memset(temppath, 0, MAX_PATH);
1019 length = pGetLongPathNameA(tempfile, temppath, 4);
1020 /* We have a failure so length should be the minimum plus the terminating '0' */
1021 ok(length >= lstrlen(tempfile) + 1, "Wrong length\n");
1022 ok(temppath[0] == 0, "Buffer should not have been touched\n");
1023
1024 /* Some UNC syntax tests */
1025
1026 memset(temppath, 0, MAX_PATH);
1027 memset(temppath2, 0, MAX_PATH);
1028 lstrcpyA(temppath2, "\\\\?\\");
1029 lstrcatA(temppath2, tempfile);
1030 explength = length + 4;
1031
1032 SetLastError(0xdeadbeef);
1033 length = pGetLongPathNameA(temppath2, NULL, 0);
1034 if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME)
1035 {
1036 win_skip("UNC syntax tests don't work on Win98/WinMe\n");
1037 DeleteFileA(tempfile);
1038 return;
1039 }
1040 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1041
1042 length = pGetLongPathNameA(temppath2, NULL, MAX_PATH);
1043 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1044
1045 length = pGetLongPathNameA(temppath2, temppath, 4);
1046 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1047 ok(temppath[0] == 0, "Buffer should not have been touched\n");
1048
1049 /* Now an UNC path with the computername */
1050 lstrcpyA(unc_prefix, "\\\\");
1051 hostsize = sizeof(unc_prefix) - 2;
1052 GetComputerName(unc_prefix + 2, &hostsize);
1053 lstrcatA(unc_prefix, "\\");
1054
1055 /* Create a short syntax for the whole unc path */
1056 memset(unc_short, 0, MAX_PATH);
1057 GetShortPathNameA(tempfile, temppath, MAX_PATH);
1058 lstrcpyA(unc_short, unc_prefix);
1059 unc_short[lstrlenA(unc_short)] = temppath[0];
1060 lstrcatA(unc_short, "$\\");
1061 lstrcatA(unc_short, strchr(temppath, '\\') + 1);
1062
1063 /* Create a long syntax for reference */
1064 memset(longpath, 0, MAX_PATH);
1065 pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1066 lstrcpyA(longpath, unc_prefix);
1067 longpath[lstrlenA(longpath)] = temppath[0];
1068 lstrcatA(longpath, "$\\");
1069 lstrcatA(longpath, strchr(temppath, '\\') + 1);
1070
1071 /* NULL test */
1072 SetLastError(0xdeadbeef);
1073 length = pGetLongPathNameA(unc_short, NULL, 0);
1074 if (length == 0 && GetLastError() == ERROR_BAD_NETPATH)
1075 {
1076 /* Seen on Window XP Home */
1077 win_skip("UNC with computername is not supported\n");
1078 DeleteFileA(tempfile);
1079 return;
1080 }
1081 explength = lstrlenA(longpath) + 1;
1082 todo_wine
1083 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1084
1085 length = pGetLongPathNameA(unc_short, NULL, MAX_PATH);
1086 todo_wine
1087 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1088
1089 memset(unc_long, 0, MAX_PATH);
1090 length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short));
1091 /* length will include terminating '0' on failure */
1092 todo_wine
1093 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1094 ok(unc_long[0] == 0, "Buffer should not have been touched\n");
1095
1096 memset(unc_long, 0, MAX_PATH);
1097 length = pGetLongPathNameA(unc_short, unc_long, length);
1098 /* length doesn't include terminating '0' on success */
1099 explength--;
1100 todo_wine
1101 {
1102 ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1103 ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long);
1104 }
1105
1106 DeleteFileA(tempfile);
1107 }
1108
1109 static void test_GetLongPathNameW(void)
1110 {
1111 DWORD length, expanded;
1112 BOOL ret;
1113 HANDLE file;
1114 WCHAR empty[MAX_PATH];
1115 WCHAR tempdir[MAX_PATH], name[200];
1116 WCHAR dirpath[4 + MAX_PATH + 200]; /* To ease removal */
1117 WCHAR shortpath[4 + MAX_PATH + 200 + 1 + 200];
1118 static const WCHAR prefix[] = { '\\','\\','?','\\', 0};
1119 static const WCHAR backslash[] = { '\\', 0};
1120 static const WCHAR letterX[] = { 'X', 0};
1121
1122 if (!pGetLongPathNameW)
1123 return;
1124
1125 SetLastError(0xdeadbeef);
1126 length = pGetLongPathNameW(NULL,NULL,0);
1127 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1128 {
1129 win_skip("GetLongPathNameW is not implemented\n");
1130 return;
1131 }
1132 ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1133 ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError());
1134
1135 SetLastError(0xdeadbeef);
1136 empty[0]=0;
1137 length = pGetLongPathNameW(empty,NULL,0);
1138 ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1139 ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError());
1140
1141 /* Create a long path name. The path needs to exist for these tests to
1142 * succeed so we need the "\\?\" prefix when creating directories and
1143 * files.
1144 */
1145 name[0] = 0;
1146 while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1))
1147 lstrcatW(name, letterX);
1148
1149 GetTempPathW(MAX_PATH, tempdir);
1150
1151 lstrcpyW(shortpath, prefix);
1152 lstrcatW(shortpath, tempdir);
1153 lstrcatW(shortpath, name);
1154 lstrcpyW(dirpath, shortpath);
1155 ret = CreateDirectoryW(shortpath, NULL);
1156 ok(ret, "Could not create the temporary directory : %d\n", GetLastError());
1157 lstrcatW(shortpath, backslash);
1158 lstrcatW(shortpath, name);
1159
1160 /* Path does not exist yet and we know it overruns MAX_PATH */
1161
1162 /* No prefix */
1163 SetLastError(0xdeadbeef);
1164 length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1165 ok(length == 0, "Expected 0, got %d\n", length);
1166 todo_wine
1167 ok(GetLastError() == ERROR_PATH_NOT_FOUND,
1168 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1169 /* With prefix */
1170 SetLastError(0xdeadbeef);
1171 length = pGetLongPathNameW(shortpath, NULL, 0);
1172 todo_wine
1173 {
1174 ok(length == 0, "Expected 0, got %d\n", length);
1175 ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1176 "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1177 }
1178
1179 file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1180 CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1181 ok(file != INVALID_HANDLE_VALUE,
1182 "Could not create the temporary file : %d.\n", GetLastError());
1183 CloseHandle(file);
1184
1185 /* Path exists */
1186
1187 /* No prefix */
1188 SetLastError(0xdeadbeef);
1189 length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1190 todo_wine
1191 {
1192 ok(length == 0, "Expected 0, got %d\n", length);
1193 ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1194 }
1195 /* With prefix */
1196 expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1;
1197 SetLastError(0xdeadbeef);
1198 length = pGetLongPathNameW(shortpath, NULL, 0);
1199 ok(length == expanded, "Expected %d, got %d\n", expanded, length);
1200
1201 /* NULL buffer with length crashes on Windows */
1202 if (0)
1203 length = pGetLongPathNameW(shortpath, NULL, 20);
1204
1205 ok(DeleteFileW(shortpath), "Could not delete temporary file\n");
1206 ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n");
1207 }
1208
1209 static void test_GetShortPathNameW(void)
1210 {
1211 WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e', 0 };
1212 WCHAR path[MAX_PATH];
1213 WCHAR short_path[MAX_PATH];
1214 DWORD length;
1215 HANDLE file;
1216 int ret;
1217 WCHAR name[] = { 't', 'e', 's', 't', 0 };
1218 WCHAR backSlash[] = { '\\', 0 };
1219
1220 SetLastError(0xdeadbeef);
1221 GetTempPathW( MAX_PATH, path );
1222 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1223 {
1224 win_skip("GetTempPathW is not implemented\n");
1225 return;
1226 }
1227
1228 lstrcatW( path, test_path );
1229 lstrcatW( path, backSlash );
1230 ret = CreateDirectoryW( path, NULL );
1231 ok( ret, "Directory was not created. LastError = %d\n", GetLastError() );
1232
1233 /* Starting a main part of test */
1234 length = GetShortPathNameW( path, short_path, 0 );
1235 ok( length, "GetShortPathNameW returned 0.\n" );
1236 ret = GetShortPathNameW( path, short_path, length );
1237 ok( ret, "GetShortPathNameW returned 0.\n" );
1238 lstrcatW( short_path, name );
1239 file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1240 ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1241
1242 /* End test */
1243 CloseHandle( file );
1244 ret = DeleteFileW( short_path );
1245 ok( ret, "Cannot delete file.\n" );
1246 ret = RemoveDirectoryW( path );
1247 ok( ret, "Cannot delete directory.\n" );
1248 }
1249
1250 static void test_GetSystemDirectory(void)
1251 {
1252 CHAR buffer[MAX_PATH + 4];
1253 DWORD res;
1254 DWORD total;
1255
1256 SetLastError(0xdeadbeef);
1257 res = GetSystemDirectory(NULL, 0);
1258 /* res includes the terminating Zero */
1259 ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1260
1261 total = res;
1262
1263 /* this crashes on XP */
1264 if (0) res = GetSystemDirectory(NULL, total);
1265
1266 SetLastError(0xdeadbeef);
1267 res = GetSystemDirectory(NULL, total-1);
1268 /* 95+NT: total (includes the terminating Zero)
1269 98+ME: 0 with ERROR_INVALID_PARAMETER */
1270 ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1271 "returned %d with %d (expected '%d' or: '0' with "
1272 "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1273
1274 if (total > MAX_PATH) return;
1275
1276 buffer[0] = '\0';
1277 SetLastError(0xdeadbeef);
1278 res = GetSystemDirectory(buffer, total);
1279 /* res does not include the terminating Zero */
1280 ok( (res == (total-1)) && (buffer[0]),
1281 "returned %d with %d and '%s' (expected '%d' and a string)\n",
1282 res, GetLastError(), buffer, total-1);
1283
1284 buffer[0] = '\0';
1285 SetLastError(0xdeadbeef);
1286 res = GetSystemDirectory(buffer, total + 1);
1287 /* res does not include the terminating Zero */
1288 ok( (res == (total-1)) && (buffer[0]),
1289 "returned %d with %d and '%s' (expected '%d' and a string)\n",
1290 res, GetLastError(), buffer, total-1);
1291
1292 memset(buffer, '#', total + 1);
1293 buffer[total + 2] = '\0';
1294 SetLastError(0xdeadbeef);
1295 res = GetSystemDirectory(buffer, total-1);
1296 /* res includes the terminating Zero) */
1297 ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1298 res, GetLastError(), buffer, total);
1299
1300 memset(buffer, '#', total + 1);
1301 buffer[total + 2] = '\0';
1302 SetLastError(0xdeadbeef);
1303 res = GetSystemDirectory(buffer, total-2);
1304 /* res includes the terminating Zero) */
1305 ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1306 res, GetLastError(), buffer, total);
1307 }
1308
1309 static void test_GetWindowsDirectory(void)
1310 {
1311 CHAR buffer[MAX_PATH + 4];
1312 DWORD res;
1313 DWORD total;
1314
1315 SetLastError(0xdeadbeef);
1316 res = GetWindowsDirectory(NULL, 0);
1317 /* res includes the terminating Zero */
1318 ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1319
1320 total = res;
1321 /* this crashes on XP */
1322 if (0) res = GetWindowsDirectory(NULL, total);
1323
1324 SetLastError(0xdeadbeef);
1325 res = GetWindowsDirectory(NULL, total-1);
1326 /* 95+NT: total (includes the terminating Zero)
1327 98+ME: 0 with ERROR_INVALID_PARAMETER */
1328 ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1329 "returned %d with %d (expected '%d' or: '0' with "
1330 "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1331
1332 if (total > MAX_PATH) return;
1333
1334 buffer[0] = '\0';
1335 SetLastError(0xdeadbeef);
1336 res = GetWindowsDirectory(buffer, total);
1337 /* res does not include the terminating Zero */
1338 ok( (res == (total-1)) && (buffer[0]),
1339 "returned %d with %d and '%s' (expected '%d' and a string)\n",
1340 res, GetLastError(), buffer, total-1);
1341
1342 buffer[0] = '\0';
1343 SetLastError(0xdeadbeef);
1344 res = GetWindowsDirectory(buffer, total + 1);
1345 /* res does not include the terminating Zero */
1346 ok( (res == (total-1)) && (buffer[0]),
1347 "returned %d with %d and '%s' (expected '%d' and a string)\n",
1348 res, GetLastError(), buffer, total-1);
1349
1350 memset(buffer, '#', total + 1);
1351 buffer[total + 2] = '\0';
1352 SetLastError(0xdeadbeef);
1353 res = GetWindowsDirectory(buffer, total-1);
1354 /* res includes the terminating Zero) */
1355 ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1356 res, GetLastError(), buffer, total);
1357
1358 memset(buffer, '#', total + 1);
1359 buffer[total + 2] = '\0';
1360 SetLastError(0xdeadbeef);
1361 res = GetWindowsDirectory(buffer, total-2);
1362 /* res includes the terminating Zero) */
1363 ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1364 res, GetLastError(), buffer, total);
1365 }
1366
1367 static void test_NeedCurrentDirectoryForExePathA(void)
1368 {
1369 if (!pNeedCurrentDirectoryForExePathA)
1370 {
1371 win_skip("NeedCurrentDirectoryForExePathA is not available\n");
1372 return;
1373 }
1374
1375 /* Crashes in Windows */
1376 if (0)
1377 ok(pNeedCurrentDirectoryForExePathA(NULL), "returned FALSE for NULL\n");
1378
1379 SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1380 ok(pNeedCurrentDirectoryForExePathA("."), "returned FALSE for \".\"\n");
1381 ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1382 ok(pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned FALSE for \"cmd.exe\"\n");
1383
1384 SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1385 ok(!pNeedCurrentDirectoryForExePathA("."), "returned TRUE for \".\"\n");
1386 ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1387 ok(!pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned TRUE for \"cmd.exe\"\n");
1388 }
1389
1390 static void test_NeedCurrentDirectoryForExePathW(void)
1391 {
1392 const WCHAR thispath[] = {'.', 0};
1393 const WCHAR fullpath[] = {'c', ':', '\\', 0};
1394 const WCHAR cmdname[] = {'c', 'm', 'd', '.', 'e', 'x', 'e', 0};
1395
1396 if (!pNeedCurrentDirectoryForExePathW)
1397 {
1398 win_skip("NeedCurrentDirectoryForExePathW is not available\n");
1399 return;
1400 }
1401
1402 /* Crashes in Windows */
1403 if (0)
1404 ok(pNeedCurrentDirectoryForExePathW(NULL), "returned FALSE for NULL\n");
1405
1406 SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1407 ok(pNeedCurrentDirectoryForExePathW(thispath), "returned FALSE for \".\"\n");
1408 ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1409 ok(pNeedCurrentDirectoryForExePathW(cmdname), "returned FALSE for \"cmd.exe\"\n");
1410
1411 SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1412 ok(!pNeedCurrentDirectoryForExePathW(thispath), "returned TRUE for \".\"\n");
1413 ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1414 ok(!pNeedCurrentDirectoryForExePathW(cmdname), "returned TRUE for \"cmd.exe\"\n");
1415 }
1416
1417 /* Call various path/file name retrieving APIs and check the case of
1418 * the returned drive letter. Some apps (for instance Adobe Photoshop CS3
1419 * installer) depend on the drive letter being in upper case.
1420 */
1421 static void test_drive_letter_case(void)
1422 {
1423 UINT ret;
1424 char buf[MAX_PATH];
1425
1426 #define is_upper_case_letter(a) ((a) >= 'A' && (a) <= 'Z')
1427
1428 memset(buf, 0, sizeof(buf));
1429 SetLastError(0xdeadbeef);
1430 ret = GetWindowsDirectory(buf, sizeof(buf));
1431 ok(ret, "GetWindowsDirectory error %u\n", GetLastError());
1432 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1433 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1434 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1435
1436 /* re-use the buffer returned by GetFullPathName */
1437 buf[2] = '/';
1438 SetLastError(0xdeadbeef);
1439 ret = GetFullPathName(buf + 2, sizeof(buf), buf, NULL);
1440 ok(ret, "GetFullPathName error %u\n", GetLastError());
1441 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1442 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1443 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1444
1445 memset(buf, 0, sizeof(buf));
1446 SetLastError(0xdeadbeef);
1447 ret = GetSystemDirectory(buf, sizeof(buf));
1448 ok(ret, "GetSystemDirectory error %u\n", GetLastError());
1449 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1450 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1451 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1452
1453 memset(buf, 0, sizeof(buf));
1454 SetLastError(0xdeadbeef);
1455 ret = GetCurrentDirectory(sizeof(buf), buf);
1456 ok(ret, "GetCurrentDirectory error %u\n", GetLastError());
1457 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1458 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1459 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1460
1461 /* TEMP is an environment variable, so it can't be tested for case-sensitivity */
1462 memset(buf, 0, sizeof(buf));
1463 SetLastError(0xdeadbeef);
1464 ret = GetTempPath(sizeof(buf), buf);
1465 ok(ret, "GetTempPath error %u\n", GetLastError());
1466 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1467 if (buf[0])
1468 {
1469 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1470 ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf);
1471 }
1472
1473 memset(buf, 0, sizeof(buf));
1474 SetLastError(0xdeadbeef);
1475 ret = GetFullPathName(".", sizeof(buf), buf, NULL);
1476 ok(ret, "GetFullPathName error %u\n", GetLastError());
1477 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1478 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1479 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1480
1481 /* re-use the buffer returned by GetFullPathName */
1482 SetLastError(0xdeadbeef);
1483 ret = GetShortPathName(buf, buf, sizeof(buf));
1484 ok(ret, "GetShortPathName error %u\n", GetLastError());
1485 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1486 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1487 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1488
1489 if (pGetLongPathNameA)
1490 {
1491 /* re-use the buffer returned by GetShortPathName */
1492 SetLastError(0xdeadbeef);
1493 ret = pGetLongPathNameA(buf, buf, sizeof(buf));
1494 ok(ret, "GetLongPathNameA error %u\n", GetLastError());
1495 ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1496 ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1497 ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1498 }
1499 #undef is_upper_case_letter
1500 }
1501
1502 static void test_SearchPathA(void)
1503 {
1504 CHAR pathA[MAX_PATH], fileA[] = "", buffA[MAX_PATH];
1505 CHAR *ptrA = NULL;
1506 DWORD ret;
1507
1508 if (!pSearchPathA)
1509 {
1510 win_skip("SearchPathA isn't available\n");
1511 return;
1512 }
1513
1514 GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR));
1515
1516 /* NULL filename */
1517 SetLastError(0xdeadbeef);
1518 ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1519 ok(ret == 0, "Expected failure, got %d\n", ret);
1520 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1521 "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1522
1523 /* empty filename */
1524 SetLastError(0xdeadbeef);
1525 ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1526 ok(ret == 0, "Expected failure, got %d\n", ret);
1527 ok(GetLastError() == ERROR_INVALID_PARAMETER ||
1528 broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* win9x */,
1529 "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1530 }
1531
1532 static void test_SearchPathW(void)
1533 {
1534 WCHAR pathW[MAX_PATH], fileW[] = { 0 }, buffW[MAX_PATH];
1535 WCHAR *ptrW = NULL;
1536 DWORD ret;
1537
1538 if (!pSearchPathW)
1539 {
1540 win_skip("SearchPathW isn't available\n");
1541 return;
1542 }
1543
1544 /* SearchPathW is a stub on win9x and doesn't return sane error,
1545 so quess if it's implemented indirectly */
1546 SetLastError(0xdeadbeef);
1547 GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1548 if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1549 {
1550 win_skip("SearchPathW not implemented\n");
1551 return;
1552 }
1553
1554 if (0)
1555 {
1556 /* NULL filename, crashes on nt4 */
1557 SetLastError(0xdeadbeef);
1558 ret = pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1559 ok(ret == 0, "Expected failure, got %d\n", ret);
1560 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1561 "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1562 }
1563
1564 /* empty filename */
1565 SetLastError(0xdeadbeef);
1566 ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1567 ok(ret == 0, "Expected failure, got %d\n", ret);
1568 ok(GetLastError() == ERROR_INVALID_PARAMETER,
1569 "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1570 }
1571
1572 static void init_pointers(void)
1573 {
1574 HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
1575
1576 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f))
1577 MAKEFUNC(GetLongPathNameA);
1578 MAKEFUNC(GetLongPathNameW);
1579 MAKEFUNC(NeedCurrentDirectoryForExePathA);
1580 MAKEFUNC(NeedCurrentDirectoryForExePathW);
1581 MAKEFUNC(SearchPathA);
1582 MAKEFUNC(SearchPathW);
1583 #undef MAKEFUNC
1584 }
1585
1586 START_TEST(path)
1587 {
1588 CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
1589
1590 init_pointers();
1591
1592 /* Report only once */
1593 if (!pGetLongPathNameA)
1594 win_skip("GetLongPathNameA is not available\n");
1595 if (!pGetLongPathNameW)
1596 win_skip("GetLongPathNameW is not available\n");
1597
1598 test_InitPathA(curdir, &curDrive, &otherDrive);
1599 test_CurrentDirectoryA(origdir,curdir);
1600 test_PathNameA(curdir, curDrive, otherDrive);
1601 test_CleanupPathA(origdir,curdir);
1602 test_GetTempPath();
1603 test_GetLongPathNameA();
1604 test_GetLongPathNameW();
1605 test_GetShortPathNameW();
1606 test_GetSystemDirectory();
1607 test_GetWindowsDirectory();
1608 test_NeedCurrentDirectoryForExePathA();
1609 test_NeedCurrentDirectoryForExePathW();
1610 test_drive_letter_case();
1611 test_SearchPathA();
1612 test_SearchPathW();
1613 }