kernel32: Don't use HIWORD to check for swapped args in GetCurrentDirectoryA.
[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   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 minumum 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 }