jscript: Added VBArray.dimensions() implementation.
[wine] / dlls / kernel32 / tests / 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        invalid_dir[MAX_PATH];
315
316   DWORD len,len1,drives;
317   INT id;
318   HANDLE hndl;
319   BOOL bRes;
320   UINT unique;
321
322   *curDrive = *otherDrive = NOT_A_VALID_DRIVE;
323
324 /* Get the current drive letter */
325   if( GetCurrentDirectoryA( MAX_PATH, tmpstr))
326     *curDrive = tmpstr[0];
327   else
328     trace( "Unable to discover current drive, some tests will not be conducted.\n");
329
330 /* Test GetTempPathA */
331   len=GetTempPathA(MAX_PATH,tmppath);
332   ok(len!=0 && len < MAX_PATH,"GetTempPathA failed\n");
333   ok(HAS_TRAIL_SLASH_A(tmppath),
334      "GetTempPathA returned a path that did not end in '\\'\n");
335   lstrcpyA(tmpstr,"aaaaaaaa");
336   len1=GetTempPathA(len,tmpstr);
337   ok(len1==len+1 || broken(len1 == len), /* WinME */
338      "GetTempPathA should return string length %d instead of %d\n",len+1,len1);
339
340 /* Test GetTmpFileNameA */
341   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
342   sprintf(tmpstr,"pat%.4x.tmp",id & 0xffff);
343   sprintf(tmpstr1,"pat%x.tmp",id & 0xffff);
344   ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
345      lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
346      "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
347      newdir,tmpstr,tmpstr1,id);
348   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");     
349
350   id=GetTempFileNameA(tmppath,NULL,0,newdir);
351 /* Windows 95, 98 return 0==id, while Windows 2000, XP return 0!=id */
352   if (id)
353   {
354     sprintf(tmpstr,"%.4x.tmp",id & 0xffff);
355     sprintf(tmpstr1,"%x.tmp",id & 0xffff);
356     ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
357        lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
358        "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
359        newdir,tmpstr,tmpstr1,id);
360     ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
361   }
362
363   for(unique=0;unique<3;unique++) {
364     /* Non-existent path */
365     sprintf(invalid_dir, "%s\%s",tmppath,"non_existent_dir_1jwj3y32nb3");
366     SetLastError(0xdeadbeef);
367     todo_wine
368     ok(!GetTempFileNameA(invalid_dir,"tfn",unique,newdir),"GetTempFileNameA should have failed\n");
369     todo_wine
370     ok(GetLastError()==ERROR_DIRECTORY || broken(GetLastError()==ERROR_PATH_NOT_FOUND)/*win98*/,
371     "got %d, expected ERROR_DIRECTORY\n", GetLastError());
372
373     /* Check return value for unique !=0 */
374     if(unique) {
375       ok((GetTempFileNameA(tmppath,"tfn",unique,newdir) == unique),"GetTempFileNameA unexpectedly failed\n");
376       /* if unique != 0, the actual temp files are not created: */
377       ok(!DeleteFileA(newdir) && GetLastError() == ERROR_FILE_NOT_FOUND,"Deleted a file that shouldn't exist!\n");
378     }
379   }
380
381 /* Find first valid drive letter that is neither newdir[0] nor curDrive */
382   drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
383   if( *curDrive != NOT_A_VALID_DRIVE)
384     drives &= ~(1<<(*curDrive-'A'));
385   if( drives)
386     for( *otherDrive='A'; (drives & 1) == 0; drives>>=1, (*otherDrive)++);
387   else
388     trace( "Could not find alternative drive, some tests will not be conducted.\n");
389
390 /* Do some CreateDirectoryA tests */
391 /* It would be nice to do test the SECURITY_ATTRIBUTES, but I don't
392    really understand how they work.
393    More formal tests should be done along with CreateFile tests
394 */
395   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
396   ok(CreateDirectoryA(newdir,NULL)==0,
397      "CreateDirectoryA succeeded even though a file of the same name exists\n");
398   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
399   ok(CreateDirectoryA(newdir,NULL),"CreateDirectoryA failed\n");
400 /* Create some files to test other functions.  Note, we will test CreateFileA
401    at some later point
402 */
403   sprintf(tmpstr,"%s\\%s",newdir,SHORTDIR);
404   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
405   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
406   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
407   sprintf(tmpstr,"%c:", *curDrive);
408   bRes = CreateDirectoryA(tmpstr,NULL);
409   ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED  ||
410                GetLastError() == ERROR_ALREADY_EXISTS),
411      "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
412   sprintf(tmpstr,"%c:\\", *curDrive);
413   bRes = CreateDirectoryA(tmpstr,NULL);
414   ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED  ||
415                GetLastError() == ERROR_ALREADY_EXISTS),
416      "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
417   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
418   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
419                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
420   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
421   ok(CloseHandle(hndl),"CloseHandle failed\n");
422   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,LONGFILE);
423   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
424                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
425   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
426   ok(CloseHandle(hndl),"CloseHandle failed\n");
427   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,SHORTFILE);
428   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
429                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
430   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
431   ok(CloseHandle(hndl),"CloseHandle failed\n");
432   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,LONGFILE);
433   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
434                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
435   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
436   ok(CloseHandle(hndl),"CloseHandle failed\n");
437 }
438
439 /* Test GetCurrentDirectory & SetCurrentDirectory */
440 static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir)
441 {
442   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
443   char *buffer;
444   DWORD len,len1;
445 /* Save the original directory, so that we can return to it at the end
446    of the test
447 */
448   len=GetCurrentDirectoryA(MAX_PATH,origdir);
449   ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed\n");
450 /* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
451    buffer size is too small to hold the current directory
452 */
453   lstrcpyA(tmpstr,"aaaaaaa");
454   len1=GetCurrentDirectoryA(len,tmpstr);
455   ok(len1==len+1, "GetCurrentDirectoryA returned %d instead of %d\n",len1,len+1);
456   ok(lstrcmpiA(tmpstr,"aaaaaaa")==0,
457      "GetCurrentDirectoryA should not have modified the buffer\n");
458
459   buffer = HeapAlloc( GetProcessHeap(), 0, 2 * 65536 );
460   SetLastError( 0xdeadbeef );
461   strcpy( buffer, "foo" );
462   len = GetCurrentDirectoryA( 32767, buffer );
463   ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
464   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
465   SetLastError( 0xdeadbeef );
466   strcpy( buffer, "foo" );
467   len = GetCurrentDirectoryA( 32768, buffer );
468   ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
469   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
470   SetLastError( 0xdeadbeef );
471   strcpy( buffer, "foo" );
472   len = GetCurrentDirectoryA( 65535, buffer );
473   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4, win2k, xp */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
474   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
475   SetLastError( 0xdeadbeef );
476   strcpy( buffer, "foo" );
477   len = GetCurrentDirectoryA( 65536, buffer );
478   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
479   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
480   SetLastError( 0xdeadbeef );
481   strcpy( buffer, "foo" );
482   len = GetCurrentDirectoryA( 2 * 65536, buffer );
483   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
484   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
485   HeapFree( GetProcessHeap(), 0, buffer );
486
487 /* Check for crash prevention on swapped args. Crashes all but Win9x.
488 */
489   if (0)
490   {
491     SetLastError( 0xdeadbeef );
492     len = GetCurrentDirectoryA( 42, (LPSTR)(MAX_PATH + 42) );
493     ok( len == 0 && GetLastError() == ERROR_INVALID_PARAMETER,
494         "GetCurrentDirectoryA failed to fail %u err %u\n", len, GetLastError() );
495   }
496
497 /* SetCurrentDirectoryA shouldn't care whether the string has a
498    trailing '\\' or not
499 */
500   sprintf(tmpstr,"%s\\",newdir);
501   test_setdir(origdir,tmpstr,newdir,1,"check 1");
502   test_setdir(origdir,newdir,NULL,1,"check 2");
503 /* Set the directory to the working area.  We just tested that this works,
504    so why check it again.
505 */
506   SetCurrentDirectoryA(newdir);
507 /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
508   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
509   test_setdir(newdir,tmpstr,NULL,0,"check 3");
510 /* Check that SetCurrentDirectory fails for a nonexistent lond directory */
511   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
512   test_setdir(newdir,tmpstr,NULL,0,"check 4");
513 /* Check that SetCurrentDirectory passes with a long directory */
514   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
515   test_setdir(newdir,tmpstr,NULL,1,"check 5");
516 /* Check that SetCurrentDirectory passes with a short relative directory */
517   sprintf(tmpstr,"%s",SHORTDIR);
518   sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
519   test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
520 /* starting with a '.' */
521   sprintf(tmpstr,".\\%s",SHORTDIR);
522   test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
523 /* Check that SetCurrentDirectory passes with a short relative directory */
524   sprintf(tmpstr,"%s",LONGDIR);
525   sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
526   test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
527 /* starting with a '.' */
528   sprintf(tmpstr,".\\%s",LONGDIR);
529   test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
530 /* change to root without a trailing backslash. The function call succeeds
531    but the directory is not changed.
532 */
533   sprintf(tmpstr, "%c:", newdir[0]);
534   test_setdir(newdir,tmpstr,newdir,1,"check 10");
535 /* works however with a trailing backslash */
536   sprintf(tmpstr, "%c:\\", newdir[0]);
537   test_setdir(newdir,tmpstr,NULL,1,"check 11");
538 }
539
540 /* Cleanup the mess we made while executing these tests */
541 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
542 {
543   CHAR tmpstr[MAX_PATH];
544   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
545   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
546   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
547   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
548   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
549   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
550   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
551   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
552   sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
553   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
554   sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
555   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
556   ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
557   ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
558 }
559
560 /* This routine will test Get(Full|Short|Long)PathNameA */
561 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
562 {
563   CHAR curdir_short[MAX_PATH],
564        longdir_short[MAX_PATH];
565   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
566   LPSTR strptr;                 /*ptr to the filename portion of the path */
567   DWORD len;
568   INT i;
569   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
570   SLpassfail passfail;
571
572 /* Get the short form of the current directory */
573   ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
574      "GetShortPathNameA failed\n");
575   ok(!HAS_TRAIL_SLASH_A(curdir_short),
576      "GetShortPathNameA should not have a trailing \\\n");
577 /* Get the short form of the absolute-path to LONGDIR */
578   sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
579   ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
580      "GetShortPathNameA failed\n");
581   ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
582      "GetShortPathNameA should not have a trailing \\\n");
583
584   if (pGetLongPathNameA) {
585     DWORD rc1,rc2;
586     sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
587     rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
588     rc2=(*pGetLongPathNameA)(curdir,NULL,0);
589     ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
590        "GetLongPathNameA: wrong return code, %d instead of %d\n",
591        rc1, lstrlenA(tmpstr)+1);
592
593     sprintf(dir,"%c:",curDrive);
594     rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
595     ok(strcmp(dir,tmpstr)==0,
596        "GetLongPathNameA: returned '%s' instead of '%s' (rc=%d)\n",
597        tmpstr,dir,rc1);
598   }
599
600 /* Check the cases where both file and directory exist first */
601 /* Start with a 8.3 directory, 8.3 filename */
602   test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
603   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
604   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
605      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
606 /* Now try a 8.3 directory, long file name */
607   test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
608   sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
609   test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
610 /* Next is a long directory, 8.3 file */
611   test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
612   sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
613   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
614      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
615 /*Lastly a long directory, long file */
616   test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
617   test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
618
619 /* Now check all of the invalid file w/ valid directory combinations */
620 /* Start with a 8.3 directory, 8.3 filename */
621   test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
622   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
623   ok((passfail.shortlen==0 &&
624       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
625        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
626      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
627      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
628      passfail.shortlen,passfail.shorterror,tmpstr);
629   if(pGetLongPathNameA) {
630     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
631     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
632        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
633   }
634 /* Now try a 8.3 directory, long file name */
635   test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
636   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
637   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
638      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
639      !passfail.shorterror,
640      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
641   if(pGetLongPathNameA) {
642     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
643     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
644        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
645   }
646 /* Next is a long directory, 8.3 file */
647   test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
648   sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
649   GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
650   strcat(tmpstr1,"\\" NONFILE_SHORT);
651   ok((passfail.shortlen==0 &&
652       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
653        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
654      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
655      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
656      passfail.shortlen,passfail.shorterror,tmpstr);
657   if(pGetLongPathNameA) {
658     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
659     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
660       "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
661   }
662 /*Lastly a long directory, long file */
663   test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
664   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
665   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
666      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
667      !passfail.shorterror,
668      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
669   if(pGetLongPathNameA) {
670     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
671     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
672        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
673   }
674 /* Now try again with directories that don't exist */
675 /* 8.3 directory, 8.3 filename */
676   test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
677   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
678   ok((passfail.shortlen==0 &&
679       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
680        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
681      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
682      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
683      passfail.shortlen,passfail.shorterror,tmpstr);
684   if(pGetLongPathNameA) {
685     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
686     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
687        passfail.longerror==ERROR_FILE_NOT_FOUND,
688        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
689        passfail.longerror);
690   }
691 /* Now try a 8.3 directory, long file name */
692   test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
693   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
694   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
695      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
696      !passfail.shorterror,
697      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
698       passfail.shorterror);
699   if(pGetLongPathNameA) {
700     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
701     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
702        passfail.longerror==ERROR_FILE_NOT_FOUND,
703        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
704        passfail.longerror);
705   }
706 /* Next is a long directory, 8.3 file */
707   test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
708   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
709   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
710      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
711      !passfail.shorterror,
712      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
713       passfail.shorterror);
714   if(pGetLongPathNameA) {
715     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
716     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
717        passfail.longerror==ERROR_FILE_NOT_FOUND,
718        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
719        passfail.longerror);
720   }
721 /*Lastly a long directory, long file */
722   test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
723   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
724   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
725      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
726      !passfail.shorterror,
727      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
728       passfail.shorterror);
729   if(pGetLongPathNameA) {
730     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
731     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
732        passfail.longerror==ERROR_FILE_NOT_FOUND,
733        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
734        passfail.longerror);
735   }
736 /* Next try directories ending with '\\' */
737 /* Existing Directories */
738   sprintf(tmpstr,"%s\\",SHORTDIR);
739   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
740   sprintf(tmpstr,"%s\\",LONGDIR);
741   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
742 /* Nonexistent directories */
743   sprintf(tmpstr,"%s\\",NONDIR_SHORT);
744   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
745   sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
746   ok((passfail.shortlen==0 &&
747       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
748        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
749      (passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
750      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
751      passfail.shortlen,passfail.shorterror,tmpstr);
752   if(pGetLongPathNameA) {
753     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
754     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
755        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
756        passfail.longerror);
757   }
758   sprintf(tmpstr,"%s\\",NONDIR_LONG);
759   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
760   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
761   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
762      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
763      !passfail.shorterror,
764      "GetShortPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
765       passfail.shorterror);
766   if(pGetLongPathNameA) {
767     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
768     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
769        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
770        passfail.longerror);
771   }
772 /* Test GetFullPathNameA with drive letters */
773   if( curDrive != NOT_A_VALID_DRIVE) {
774     sprintf(tmpstr,"%c:",curdir[0]);
775     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
776        "GetFullPathNameA(%c:) failed\n", curdir[0]);
777     GetCurrentDirectoryA(MAX_PATH,tmpstr);
778     sprintf(tmpstr1,"%s\\",tmpstr);
779     ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
780        "GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
781        curdir[0],tmpstr2,tmpstr,tmpstr1);
782
783     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
784     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
785     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
786        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
787     ok(lstrcmpiA(SHORTFILE,strptr)==0,
788        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
789   }
790 /* Without a leading slash, insert the current directory if on the current drive */
791   sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
792   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
793   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
794   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
795       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
796   ok(lstrcmpiA(SHORTFILE,strptr)==0,
797       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
798 /* Otherwise insert the missing leading slash */
799   if( otherDrive != NOT_A_VALID_DRIVE) {
800     /* FIXME: this test assumes that current directory on other drive is root */
801     sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
802     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
803     sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
804     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
805        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
806     ok(lstrcmpiA(SHORTFILE,strptr)==0,
807        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
808   }
809 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
810    So test for them. */
811   if( curDrive != NOT_A_VALID_DRIVE) {
812     sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
813     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
814     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
815     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
816        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
817     ok(lstrcmpiA(SHORTFILE,strptr)==0,
818        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
819   }
820 /**/
821   sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
822   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
823   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
824   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
825       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
826   ok(lstrcmpiA(SHORTFILE,strptr)==0,
827       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
828 /* Windows will insert a drive letter in front of an absolute UNIX path */
829   sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
830   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
831   sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
832   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
833      "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
834 /* This passes in Wine because it still contains the pointer from the previous test */
835   ok(lstrcmpiA(SHORTFILE,strptr)==0,
836       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
837
838 /* Now try some relative paths */
839   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
840   test_SplitShortPathA(tmpstr,dir,eight,three);
841   if(pGetLongPathNameA) {
842     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
843     ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
844        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
845   }
846   sprintf(tmpstr,".\\%s",LONGDIR);
847   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
848   test_SplitShortPathA(tmpstr1,dir,eight,three);
849   ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
850      "GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
851   if(pGetLongPathNameA) {
852     ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
853        tmpstr);
854     ok(lstrcmpiA(tmpstr1,tmpstr)==0,
855        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
856   }
857 /* Check out Get*PathNameA on some funny characters */
858   for(i=0;i<lstrlenA(funny_chars);i++) {
859     INT valid;
860     valid=(is_char_ok[i]=='0') ? 0 : 1;
861     sprintf(tmpstr1,"check%d-1",i);
862     sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
863     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
864     sprintf(tmpstr1,"check%d-2",i);
865     sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
866     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
867     sprintf(tmpstr1,"check%d-3",i);
868     sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
869     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
870     sprintf(tmpstr1,"check%d-4",i);
871     sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
872     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
873     sprintf(tmpstr1,"check%d-5",i);
874     sprintf(tmpstr,"Long %c File",funny_chars[i]);
875     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
876     sprintf(tmpstr1,"check%d-6",i);
877     sprintf(tmpstr,"%c Long File",funny_chars[i]);
878     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
879     sprintf(tmpstr1,"check%d-7",i);
880     sprintf(tmpstr,"Long File %c",funny_chars[i]);
881     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
882   }
883 }
884
885 static void test_GetTempPathA(char* tmp_dir)
886 {
887     DWORD len, len_with_null;
888     char buf[MAX_PATH];
889
890     len_with_null = strlen(tmp_dir) + 1;
891
892     lstrcpyA(buf, "foo");
893     len = GetTempPathA(MAX_PATH, buf);
894     ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
895     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
896     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
897
898     /* Some versions of Windows touch the buffer, some don't so we don't
899      * test that. Also, NT sometimes exaggerates the required buffer size
900      * so we cannot test for an exact match. Finally, the
901      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
902      * For instance in some cases Win98 returns len_with_null - 1 instead
903      * of len_with_null.
904      */
905     len = GetTempPathA(1, buf);
906     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
907
908     len = GetTempPathA(0, NULL);
909     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
910
911     /* The call above gave us the buffer size that Windows thinks is needed
912      * so the next call should work
913      */
914     lstrcpyA(buf, "foo");
915     len = GetTempPathA(len, buf);
916     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
917     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
918 }
919
920 static void test_GetTempPathW(char* tmp_dir)
921 {
922     DWORD len, len_with_null;
923     WCHAR buf[MAX_PATH];
924     WCHAR tmp_dirW[MAX_PATH];
925     static const WCHAR fooW[] = {'f','o','o',0};
926
927     MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
928     len_with_null = lstrlenW(tmp_dirW) + 1;
929
930     /* This one is different from ANSI version: ANSI version doesn't
931      * touch the buffer, unicode version usually truncates the buffer
932      * to zero size. NT still exaggerates the required buffer size
933      * sometimes so we cannot test for an exact match. Finally, the
934      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
935      * For instance on NT4 it will sometimes return a path without the
936      * trailing '\\' and sometimes return an error.
937      */
938
939     lstrcpyW(buf, fooW);
940     len = GetTempPathW(MAX_PATH, buf);
941     if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
942     {
943         win_skip("GetTempPathW is not available\n");
944         return;
945     }
946     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
947     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
948
949     lstrcpyW(buf, fooW);
950     len = GetTempPathW(1, buf);
951     ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
952     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
953
954     len = GetTempPathW(0, NULL);
955     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
956
957     lstrcpyW(buf, fooW);
958     len = GetTempPathW(len, buf);
959     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
960     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
961 }
962
963 static void test_GetTempPath(void)
964 {
965     char save_TMP[MAX_PATH];
966     char windir[MAX_PATH];
967     char buf[MAX_PATH];
968
969     if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0;
970
971     /* test default configuration */
972     trace("TMP=%s\n", save_TMP);
973     if (save_TMP[0])
974     {
975         strcpy(buf,save_TMP);
976         if (buf[strlen(buf)-1]!='\\')
977             strcat(buf,"\\");
978         test_GetTempPathA(buf);
979         test_GetTempPathW(buf);
980     }
981
982     /* TMP=C:\WINDOWS */
983     GetWindowsDirectoryA(windir, sizeof(windir));
984     SetEnvironmentVariableA("TMP", windir);
985     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
986     trace("TMP=%s\n", buf);
987     strcat(windir,"\\");
988     test_GetTempPathA(windir);
989     test_GetTempPathW(windir);
990
991     /* TMP=C:\ */
992     GetWindowsDirectoryA(windir, sizeof(windir));
993     windir[3] = 0;
994     SetEnvironmentVariableA("TMP", windir);
995     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
996     trace("TMP=%s\n", buf);
997     test_GetTempPathA(windir);
998     test_GetTempPathW(windir);
999
1000     /* TMP=C: i.e. use current working directory of the specified drive */
1001     GetWindowsDirectoryA(windir, sizeof(windir));
1002     SetCurrentDirectoryA(windir);
1003     windir[2] = 0;
1004     SetEnvironmentVariableA("TMP", windir);
1005     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1006     trace("TMP=%s\n", buf);
1007     GetWindowsDirectoryA(windir, sizeof(windir));
1008     strcat(windir,"\\");
1009     test_GetTempPathA(windir);
1010     test_GetTempPathW(windir);
1011
1012     SetEnvironmentVariableA("TMP", save_TMP);
1013 }
1014
1015 static void test_GetLongPathNameA(void)
1016 {
1017     DWORD length, explength, hostsize;
1018     char tempfile[MAX_PATH];
1019     char longpath[MAX_PATH];
1020     char unc_prefix[MAX_PATH];
1021     char unc_short[MAX_PATH], unc_long[MAX_PATH];
1022     char temppath[MAX_PATH], temppath2[MAX_PATH];
1023     HANDLE file;
1024
1025     if (!pGetLongPathNameA)
1026         return;
1027
1028     GetTempPathA(MAX_PATH, tempfile);
1029     lstrcatA(tempfile, "longfilename.longext");
1030
1031     file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1032     CloseHandle(file);
1033
1034     /* Test a normal path with a small buffer size */
1035     memset(temppath, 0, MAX_PATH);
1036     length = pGetLongPathNameA(tempfile, temppath, 4);
1037     /* We have a failure so length should be the minimum plus the terminating '0'  */
1038     ok(length >= lstrlen(tempfile) + 1, "Wrong length\n");
1039     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1040
1041     /* Some UNC syntax tests */
1042
1043     memset(temppath, 0, MAX_PATH);
1044     memset(temppath2, 0, MAX_PATH);
1045     lstrcpyA(temppath2, "\\\\?\\");
1046     lstrcatA(temppath2, tempfile);
1047     explength = length + 4;
1048
1049     SetLastError(0xdeadbeef);
1050     length = pGetLongPathNameA(temppath2, NULL, 0);
1051     if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME)
1052     {
1053         win_skip("UNC syntax tests don't work on Win98/WinMe\n");
1054         DeleteFileA(tempfile);
1055         return;
1056     }
1057     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1058
1059     length = pGetLongPathNameA(temppath2, NULL, MAX_PATH);
1060     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1061
1062     length = pGetLongPathNameA(temppath2, temppath, 4);
1063     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1064     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1065
1066     /* Now an UNC path with the computername */
1067     lstrcpyA(unc_prefix, "\\\\");
1068     hostsize = sizeof(unc_prefix) - 2;
1069     GetComputerName(unc_prefix + 2, &hostsize);
1070     lstrcatA(unc_prefix, "\\");
1071
1072     /* Create a short syntax for the whole unc path */
1073     memset(unc_short, 0, MAX_PATH);
1074     GetShortPathNameA(tempfile, temppath, MAX_PATH);
1075     lstrcpyA(unc_short, unc_prefix);
1076     unc_short[lstrlenA(unc_short)] = temppath[0];
1077     lstrcatA(unc_short, "$\\");
1078     lstrcatA(unc_short, strchr(temppath, '\\') + 1);
1079
1080     /* Create a long syntax for reference */
1081     memset(longpath, 0, MAX_PATH);
1082     pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1083     lstrcpyA(longpath, unc_prefix);
1084     longpath[lstrlenA(longpath)] = temppath[0];
1085     lstrcatA(longpath, "$\\");
1086     lstrcatA(longpath, strchr(temppath, '\\') + 1);
1087
1088     /* NULL test */
1089     SetLastError(0xdeadbeef);
1090     length = pGetLongPathNameA(unc_short, NULL, 0);
1091     if (length == 0 && GetLastError() == ERROR_BAD_NETPATH)
1092     {
1093         /* Seen on Window XP Home */
1094         win_skip("UNC with computername is not supported\n");
1095         DeleteFileA(tempfile);
1096         return;
1097     }
1098     explength = lstrlenA(longpath) + 1;
1099     todo_wine
1100     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1101
1102     length = pGetLongPathNameA(unc_short, NULL, MAX_PATH);
1103     todo_wine
1104     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1105
1106     memset(unc_long, 0, MAX_PATH);
1107     length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short));
1108     /* length will include terminating '0' on failure */
1109     todo_wine
1110     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1111     ok(unc_long[0] == 0, "Buffer should not have been touched\n");
1112
1113     memset(unc_long, 0, MAX_PATH);
1114     length = pGetLongPathNameA(unc_short, unc_long, length);
1115     /* length doesn't include terminating '0' on success */
1116     explength--;
1117     todo_wine
1118     {
1119     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1120     ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long);
1121     }
1122
1123     DeleteFileA(tempfile);
1124 }
1125
1126 static void test_GetLongPathNameW(void)
1127 {
1128     DWORD length, expanded;
1129     BOOL ret;
1130     HANDLE file;
1131     WCHAR empty[MAX_PATH];
1132     WCHAR tempdir[MAX_PATH], name[200];
1133     WCHAR dirpath[4 + MAX_PATH + 200]; /* To ease removal */
1134     WCHAR shortpath[4 + MAX_PATH + 200 + 1 + 200];
1135     static const WCHAR prefix[] = { '\\','\\','?','\\', 0};
1136     static const WCHAR backslash[] = { '\\', 0};
1137     static const WCHAR letterX[] = { 'X', 0};
1138
1139     if (!pGetLongPathNameW)
1140         return;
1141
1142     SetLastError(0xdeadbeef); 
1143     length = pGetLongPathNameW(NULL,NULL,0);
1144     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1145     {
1146         win_skip("GetLongPathNameW is not implemented\n");
1147         return;
1148     }
1149     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1150     ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError());
1151
1152     SetLastError(0xdeadbeef); 
1153     empty[0]=0;
1154     length = pGetLongPathNameW(empty,NULL,0);
1155     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1156     ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError());
1157
1158     /* Create a long path name. The path needs to exist for these tests to
1159      * succeed so we need the "\\?\" prefix when creating directories and
1160      * files.
1161      */
1162     name[0] = 0;
1163     while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1))
1164         lstrcatW(name, letterX);
1165
1166     GetTempPathW(MAX_PATH, tempdir);
1167
1168     lstrcpyW(shortpath, prefix);
1169     lstrcatW(shortpath, tempdir);
1170     lstrcatW(shortpath, name);
1171     lstrcpyW(dirpath, shortpath);
1172     ret = CreateDirectoryW(shortpath, NULL);
1173     ok(ret, "Could not create the temporary directory : %d\n", GetLastError());
1174     lstrcatW(shortpath, backslash);
1175     lstrcatW(shortpath, name);
1176
1177     /* Path does not exist yet and we know it overruns MAX_PATH */
1178
1179     /* No prefix */
1180     SetLastError(0xdeadbeef);
1181     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1182     ok(length == 0, "Expected 0, got %d\n", length);
1183     todo_wine
1184     ok(GetLastError() == ERROR_PATH_NOT_FOUND,
1185        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1186     /* With prefix */
1187     SetLastError(0xdeadbeef);
1188     length = pGetLongPathNameW(shortpath, NULL, 0);
1189     todo_wine
1190     {
1191     ok(length == 0, "Expected 0, got %d\n", length);
1192     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1193        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1194     }
1195
1196     file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1197                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1198     ok(file != INVALID_HANDLE_VALUE,
1199        "Could not create the temporary file : %d.\n", GetLastError());
1200     CloseHandle(file);
1201
1202     /* Path exists */
1203
1204     /* No prefix */
1205     SetLastError(0xdeadbeef);
1206     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1207     todo_wine
1208     {
1209     ok(length == 0, "Expected 0, got %d\n", length);
1210     ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1211     }
1212     /* With prefix */
1213     expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1;
1214     SetLastError(0xdeadbeef);
1215     length = pGetLongPathNameW(shortpath, NULL, 0);
1216     ok(length == expanded, "Expected %d, got %d\n", expanded, length);
1217
1218     /* NULL buffer with length crashes on Windows */
1219     if (0)
1220     length = pGetLongPathNameW(shortpath, NULL, 20);
1221
1222     ok(DeleteFileW(shortpath), "Could not delete temporary file\n");
1223     ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n");
1224 }
1225
1226 static void test_GetShortPathNameW(void)
1227 {
1228     WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e',  0 };
1229     WCHAR path[MAX_PATH];
1230     WCHAR short_path[MAX_PATH];
1231     DWORD length;
1232     HANDLE file;
1233     int ret;
1234     WCHAR name[] = { 't', 'e', 's', 't', 0 };
1235     WCHAR backSlash[] = { '\\', 0 };
1236
1237     SetLastError(0xdeadbeef);
1238     GetTempPathW( MAX_PATH, path );
1239     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1240     {
1241         win_skip("GetTempPathW is not implemented\n");
1242         return;
1243     }
1244
1245     lstrcatW( path, test_path );
1246     lstrcatW( path, backSlash );
1247     ret = CreateDirectoryW( path, NULL );
1248     ok( ret, "Directory was not created. LastError = %d\n", GetLastError() );
1249
1250     /* Starting a main part of test */
1251     length = GetShortPathNameW( path, short_path, 0 );
1252     ok( length, "GetShortPathNameW returned 0.\n" );
1253     ret = GetShortPathNameW( path, short_path, length );
1254     ok( ret, "GetShortPathNameW returned 0.\n" );
1255     lstrcatW( short_path, name );
1256     file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1257     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1258
1259     /* End test */
1260     CloseHandle( file );
1261     ret = DeleteFileW( short_path );
1262     ok( ret, "Cannot delete file.\n" );
1263     ret = RemoveDirectoryW( path );
1264     ok( ret, "Cannot delete directory.\n" );
1265 }
1266
1267 static void test_GetSystemDirectory(void)
1268 {
1269     CHAR    buffer[MAX_PATH + 4];
1270     DWORD   res;
1271     DWORD   total;
1272
1273     SetLastError(0xdeadbeef);
1274     res = GetSystemDirectory(NULL, 0);
1275     /* res includes the terminating Zero */
1276     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1277
1278     total = res;
1279
1280     /* this crashes on XP */
1281     if (0) res = GetSystemDirectory(NULL, total);
1282
1283     SetLastError(0xdeadbeef);
1284     res = GetSystemDirectory(NULL, total-1);
1285     /* 95+NT: total (includes the terminating Zero)
1286        98+ME: 0 with ERROR_INVALID_PARAMETER */
1287     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1288         "returned %d with %d (expected '%d' or: '0' with "
1289         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1290
1291     if (total > MAX_PATH) return;
1292
1293     buffer[0] = '\0';
1294     SetLastError(0xdeadbeef);
1295     res = GetSystemDirectory(buffer, total);
1296     /* res does not include the terminating Zero */
1297     ok( (res == (total-1)) && (buffer[0]),
1298         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1299         res, GetLastError(), buffer, total-1);
1300
1301     buffer[0] = '\0';
1302     SetLastError(0xdeadbeef);
1303     res = GetSystemDirectory(buffer, total + 1);
1304     /* res does not include the terminating Zero */
1305     ok( (res == (total-1)) && (buffer[0]),
1306         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1307         res, GetLastError(), buffer, total-1);
1308
1309     memset(buffer, '#', total + 1);
1310     buffer[total + 2] = '\0';
1311     SetLastError(0xdeadbeef);
1312     res = GetSystemDirectory(buffer, total-1);
1313     /* res includes the terminating Zero) */
1314     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1315         res, GetLastError(), buffer, total);
1316
1317     memset(buffer, '#', total + 1);
1318     buffer[total + 2] = '\0';
1319     SetLastError(0xdeadbeef);
1320     res = GetSystemDirectory(buffer, total-2);
1321     /* res includes the terminating Zero) */
1322     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1323         res, GetLastError(), buffer, total);
1324 }
1325
1326 static void test_GetWindowsDirectory(void)
1327 {
1328     CHAR    buffer[MAX_PATH + 4];
1329     DWORD   res;
1330     DWORD   total;
1331
1332     SetLastError(0xdeadbeef);
1333     res = GetWindowsDirectory(NULL, 0);
1334     /* res includes the terminating Zero */
1335     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1336
1337     total = res;
1338     /* this crashes on XP */
1339     if (0) res = GetWindowsDirectory(NULL, total);
1340
1341     SetLastError(0xdeadbeef);
1342     res = GetWindowsDirectory(NULL, total-1);
1343     /* 95+NT: total (includes the terminating Zero)
1344        98+ME: 0 with ERROR_INVALID_PARAMETER */
1345     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1346         "returned %d with %d (expected '%d' or: '0' with "
1347         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1348
1349     if (total > MAX_PATH) return;
1350
1351     buffer[0] = '\0';
1352     SetLastError(0xdeadbeef);
1353     res = GetWindowsDirectory(buffer, total);
1354     /* res does not include the terminating Zero */
1355     ok( (res == (total-1)) && (buffer[0]),
1356         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1357         res, GetLastError(), buffer, total-1);
1358
1359     buffer[0] = '\0';
1360     SetLastError(0xdeadbeef);
1361     res = GetWindowsDirectory(buffer, total + 1);
1362     /* res does not include the terminating Zero */
1363     ok( (res == (total-1)) && (buffer[0]),
1364         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1365         res, GetLastError(), buffer, total-1);
1366
1367     memset(buffer, '#', total + 1);
1368     buffer[total + 2] = '\0';
1369     SetLastError(0xdeadbeef);
1370     res = GetWindowsDirectory(buffer, total-1);
1371     /* res includes the terminating Zero) */
1372     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1373         res, GetLastError(), buffer, total);
1374
1375     memset(buffer, '#', total + 1);
1376     buffer[total + 2] = '\0';
1377     SetLastError(0xdeadbeef);
1378     res = GetWindowsDirectory(buffer, total-2);
1379     /* res includes the terminating Zero) */
1380     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1381         res, GetLastError(), buffer, total);
1382 }
1383
1384 static void test_NeedCurrentDirectoryForExePathA(void)
1385 {
1386     if (!pNeedCurrentDirectoryForExePathA)
1387     {
1388         win_skip("NeedCurrentDirectoryForExePathA is not available\n");
1389         return;
1390     }
1391
1392     /* Crashes in Windows */
1393     if (0)
1394         ok(pNeedCurrentDirectoryForExePathA(NULL), "returned FALSE for NULL\n");
1395
1396     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1397     ok(pNeedCurrentDirectoryForExePathA("."), "returned FALSE for \".\"\n");
1398     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1399     ok(pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned FALSE for \"cmd.exe\"\n");
1400
1401     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1402     ok(!pNeedCurrentDirectoryForExePathA("."), "returned TRUE for \".\"\n");
1403     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1404     ok(!pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned TRUE for \"cmd.exe\"\n");
1405 }
1406
1407 static void test_NeedCurrentDirectoryForExePathW(void)
1408 {
1409     const WCHAR thispath[] = {'.', 0};
1410     const WCHAR fullpath[] = {'c', ':', '\\', 0};
1411     const WCHAR cmdname[] = {'c', 'm', 'd', '.', 'e', 'x', 'e', 0};
1412
1413     if (!pNeedCurrentDirectoryForExePathW)
1414     {
1415         win_skip("NeedCurrentDirectoryForExePathW is not available\n");
1416         return;
1417     }
1418
1419     /* Crashes in Windows */
1420     if (0)
1421         ok(pNeedCurrentDirectoryForExePathW(NULL), "returned FALSE for NULL\n");
1422
1423     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1424     ok(pNeedCurrentDirectoryForExePathW(thispath), "returned FALSE for \".\"\n");
1425     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1426     ok(pNeedCurrentDirectoryForExePathW(cmdname), "returned FALSE for \"cmd.exe\"\n");
1427
1428     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1429     ok(!pNeedCurrentDirectoryForExePathW(thispath), "returned TRUE for \".\"\n");
1430     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1431     ok(!pNeedCurrentDirectoryForExePathW(cmdname), "returned TRUE for \"cmd.exe\"\n");
1432 }
1433
1434 /* Call various path/file name retrieving APIs and check the case of
1435  * the returned drive letter. Some apps (for instance Adobe Photoshop CS3
1436  * installer) depend on the drive letter being in upper case.
1437  */
1438 static void test_drive_letter_case(void)
1439 {
1440     UINT ret;
1441     char buf[MAX_PATH];
1442
1443 #define is_upper_case_letter(a) ((a) >= 'A' && (a) <= 'Z')
1444
1445     memset(buf, 0, sizeof(buf));
1446     SetLastError(0xdeadbeef);
1447     ret = GetWindowsDirectory(buf, sizeof(buf));
1448     ok(ret, "GetWindowsDirectory 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     /* re-use the buffer returned by GetFullPathName */
1454     buf[2] = '/';
1455     SetLastError(0xdeadbeef);
1456     ret = GetFullPathName(buf + 2, sizeof(buf), buf, NULL);
1457     ok(ret, "GetFullPathName error %u\n", GetLastError());
1458     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1459     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1460     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1461
1462     memset(buf, 0, sizeof(buf));
1463     SetLastError(0xdeadbeef);
1464     ret = GetSystemDirectory(buf, sizeof(buf));
1465     ok(ret, "GetSystemDirectory error %u\n", GetLastError());
1466     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1467     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1468     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1469
1470     memset(buf, 0, sizeof(buf));
1471     SetLastError(0xdeadbeef);
1472     ret = GetCurrentDirectory(sizeof(buf), buf);
1473     ok(ret, "GetCurrentDirectory error %u\n", GetLastError());
1474     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1475     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1476     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1477
1478     /* TEMP is an environment variable, so it can't be tested for case-sensitivity */
1479     memset(buf, 0, sizeof(buf));
1480     SetLastError(0xdeadbeef);
1481     ret = GetTempPath(sizeof(buf), buf);
1482     ok(ret, "GetTempPath error %u\n", GetLastError());
1483     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1484     if (buf[0])
1485     {
1486         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1487         ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf);
1488     }
1489
1490     memset(buf, 0, sizeof(buf));
1491     SetLastError(0xdeadbeef);
1492     ret = GetFullPathName(".", sizeof(buf), buf, NULL);
1493     ok(ret, "GetFullPathName error %u\n", GetLastError());
1494     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1495     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1496     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1497
1498     /* re-use the buffer returned by GetFullPathName */
1499     SetLastError(0xdeadbeef);
1500     ret = GetShortPathName(buf, buf, sizeof(buf));
1501     ok(ret, "GetShortPathName error %u\n", GetLastError());
1502     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1503     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1504     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1505
1506     if (pGetLongPathNameA)
1507     {
1508         /* re-use the buffer returned by GetShortPathName */
1509         SetLastError(0xdeadbeef);
1510         ret = pGetLongPathNameA(buf, buf, sizeof(buf));
1511         ok(ret, "GetLongPathNameA error %u\n", GetLastError());
1512         ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1513         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1514         ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1515     }
1516 #undef is_upper_case_letter
1517 }
1518
1519 static void test_SearchPathA(void)
1520 {
1521     CHAR pathA[MAX_PATH], fileA[] = "", buffA[MAX_PATH];
1522     CHAR *ptrA = NULL;
1523     DWORD ret;
1524
1525     if (!pSearchPathA)
1526     {
1527         win_skip("SearchPathA isn't available\n");
1528         return;
1529     }
1530
1531     GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR));
1532
1533     /* NULL filename */
1534     SetLastError(0xdeadbeef);
1535     ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1536     ok(ret == 0, "Expected failure, got %d\n", ret);
1537     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1538       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1539
1540     /* empty filename */
1541     SetLastError(0xdeadbeef);
1542     ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1543     ok(ret == 0, "Expected failure, got %d\n", ret);
1544     ok(GetLastError() == ERROR_INVALID_PARAMETER ||
1545        broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* win9x */,
1546       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1547 }
1548
1549 static void test_SearchPathW(void)
1550 {
1551     WCHAR pathW[MAX_PATH], fileW[] = { 0 }, buffW[MAX_PATH];
1552     WCHAR *ptrW = NULL;
1553     DWORD ret;
1554
1555     if (!pSearchPathW)
1556     {
1557         win_skip("SearchPathW isn't available\n");
1558         return;
1559     }
1560
1561     /* SearchPathW is a stub on win9x and doesn't return sane error,
1562        so quess if it's implemented indirectly */
1563     SetLastError(0xdeadbeef);
1564     GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1565     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1566     {
1567         win_skip("SearchPathW not implemented\n");
1568         return;
1569     }
1570
1571 if (0)
1572 {
1573     /* NULL filename, crashes on nt4 */
1574     SetLastError(0xdeadbeef);
1575     ret = pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1576     ok(ret == 0, "Expected failure, got %d\n", ret);
1577     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1578        "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1579 }
1580
1581     /* empty filename */
1582     SetLastError(0xdeadbeef);
1583     ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1584     ok(ret == 0, "Expected failure, got %d\n", ret);
1585     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1586       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1587 }
1588
1589 static void test_GetFullPathNameA(void)
1590 {
1591     char output[MAX_PATH], *filepart;
1592     DWORD ret;
1593     int is_win9x, i;
1594
1595     const struct
1596     {
1597         LPCSTR name;
1598         DWORD len;
1599         LPSTR buffer;
1600         LPSTR *lastpart;
1601         int win9x_crash;
1602     } invalid_parameters[] =
1603     {
1604         {NULL, 0,        NULL,   NULL,      1},
1605         {NULL, MAX_PATH, NULL,   NULL,      1},
1606         {NULL, MAX_PATH, output, NULL,      1},
1607         {NULL, MAX_PATH, output, &filepart, 1},
1608         {"",   0,        NULL,   NULL},
1609         {"",   MAX_PATH, NULL,   NULL},
1610         {"",   MAX_PATH, output, NULL},
1611         {"",   MAX_PATH, output, &filepart},
1612     };
1613
1614     SetLastError(0xdeadbeef);
1615     ret = GetFullPathNameW(NULL, 0, NULL, NULL);
1616     is_win9x = !ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED;
1617
1618     if (is_win9x)
1619         win_skip("Skipping some tests that cause GetFullPathNameA to crash on Win9x\n");
1620
1621     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
1622     {
1623         if (is_win9x && invalid_parameters[i].win9x_crash)
1624             continue;
1625
1626         SetLastError(0xdeadbeef);
1627         strcpy(output, "deadbeef");
1628         filepart = (char *)0xdeadbeef;
1629         ret = GetFullPathNameA(invalid_parameters[i].name,
1630                                invalid_parameters[i].len,
1631                                invalid_parameters[i].buffer,
1632                                invalid_parameters[i].lastpart);
1633         ok(!ret, "[%d] Expected GetFullPathNameA to return 0, got %u\n", i, ret);
1634         ok(!strcmp(output, "deadbeef"), "[%d] Expected the output buffer to be unchanged, got \"%s\"\n", i, output);
1635         ok(filepart == (char *)0xdeadbeef, "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
1636         ok(GetLastError() == 0xdeadbeef ||
1637            GetLastError() == ERROR_BAD_PATHNAME || /* Win9x */
1638            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
1639            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
1640            i, GetLastError());
1641     }
1642 }
1643
1644 static void test_GetFullPathNameW(void)
1645 {
1646     static const WCHAR emptyW[] = {0};
1647     static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
1648
1649     WCHAR output[MAX_PATH], *filepart;
1650     DWORD ret;
1651     int i;
1652
1653     const struct
1654     {
1655         LPCWSTR name;
1656         DWORD len;
1657         LPWSTR buffer;
1658         LPWSTR *lastpart;
1659         int win7_expect;
1660     } invalid_parameters[] =
1661     {
1662         {NULL,   0,        NULL,   NULL},
1663         {NULL,   0,        NULL,   &filepart, 1},
1664         {NULL,   MAX_PATH, NULL,   NULL},
1665         {NULL,   MAX_PATH, output, NULL},
1666         {NULL,   MAX_PATH, output, &filepart, 1},
1667         {emptyW, 0,        NULL,   NULL},
1668         {emptyW, 0,        NULL,   &filepart, 1},
1669         {emptyW, MAX_PATH, NULL,   NULL},
1670         {emptyW, MAX_PATH, output, NULL},
1671         {emptyW, MAX_PATH, output, &filepart, 1},
1672     };
1673
1674     SetLastError(0xdeadbeef);
1675     ret = GetFullPathNameW(NULL, 0, NULL, NULL);
1676     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1677     {
1678         win_skip("GetFullPathNameW is not available\n");
1679         return;
1680     }
1681
1682     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
1683     {
1684         SetLastError(0xdeadbeef);
1685         lstrcpyW(output, deadbeefW);
1686         filepart = (WCHAR *)0xdeadbeef;
1687         ret = GetFullPathNameW(invalid_parameters[i].name,
1688                                invalid_parameters[i].len,
1689                                invalid_parameters[i].buffer,
1690                                invalid_parameters[i].lastpart);
1691         ok(!ret, "[%d] Expected GetFullPathNameW to return 0, got %u\n", i, ret);
1692         ok(!lstrcmpW(output, deadbeefW), "[%d] Expected the output buffer to be unchanged, got %s\n", i, wine_dbgstr_w(output));
1693         ok(filepart == (WCHAR *)0xdeadbeef ||
1694            (invalid_parameters[i].win7_expect && filepart == NULL),
1695            "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
1696         ok(GetLastError() == 0xdeadbeef ||
1697            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
1698            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
1699            i, GetLastError());
1700     }
1701 }
1702
1703 static void init_pointers(void)
1704 {
1705     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
1706
1707 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f))
1708     MAKEFUNC(GetLongPathNameA);
1709     MAKEFUNC(GetLongPathNameW);
1710     MAKEFUNC(NeedCurrentDirectoryForExePathA);
1711     MAKEFUNC(NeedCurrentDirectoryForExePathW);
1712     MAKEFUNC(SearchPathA);
1713     MAKEFUNC(SearchPathW);
1714 #undef MAKEFUNC
1715 }
1716
1717 START_TEST(path)
1718 {
1719     CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
1720
1721     init_pointers();
1722
1723     /* Report only once */
1724     if (!pGetLongPathNameA)
1725         win_skip("GetLongPathNameA is not available\n");
1726     if (!pGetLongPathNameW)
1727         win_skip("GetLongPathNameW is not available\n");
1728
1729     test_InitPathA(curdir, &curDrive, &otherDrive);
1730     test_CurrentDirectoryA(origdir,curdir);
1731     test_PathNameA(curdir, curDrive, otherDrive);
1732     test_CleanupPathA(origdir,curdir);
1733     test_GetTempPath();
1734     test_GetLongPathNameA();
1735     test_GetLongPathNameW();
1736     test_GetShortPathNameW();
1737     test_GetSystemDirectory();
1738     test_GetWindowsDirectory();
1739     test_NeedCurrentDirectoryForExePathA();
1740     test_NeedCurrentDirectoryForExePathW();
1741     test_drive_letter_case();
1742     test_SearchPathA();
1743     test_SearchPathW();
1744     test_GetFullPathNameA();
1745     test_GetFullPathNameW();
1746 }