oleaut32: Rewrite RollUdate to be easier to change and to support more conversions.
[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 /* SetCurrentDirectoryA shouldn't care whether the string has a
471    trailing '\\' or not
472 */
473   sprintf(tmpstr,"%s\\",newdir);
474   test_setdir(origdir,tmpstr,newdir,1,"check 1");
475   test_setdir(origdir,newdir,NULL,1,"check 2");
476 /* Set the directory to the working area.  We just tested that this works,
477    so why check it again.
478 */
479   SetCurrentDirectoryA(newdir);
480 /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
481   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
482   test_setdir(newdir,tmpstr,NULL,0,"check 3");
483 /* Check that SetCurrentDirectory fails for a nonexistent lond directory */
484   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
485   test_setdir(newdir,tmpstr,NULL,0,"check 4");
486 /* Check that SetCurrentDirectory passes with a long directory */
487   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
488   test_setdir(newdir,tmpstr,NULL,1,"check 5");
489 /* Check that SetCurrentDirectory passes with a short relative directory */
490   sprintf(tmpstr,"%s",SHORTDIR);
491   sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
492   test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
493 /* starting with a '.' */
494   sprintf(tmpstr,".\\%s",SHORTDIR);
495   test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
496 /* Check that SetCurrentDirectory passes with a short relative directory */
497   sprintf(tmpstr,"%s",LONGDIR);
498   sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
499   test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
500 /* starting with a '.' */
501   sprintf(tmpstr,".\\%s",LONGDIR);
502   test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
503 /* change to root without a trailing backslash. The function call succeeds
504    but the directory is not changed.
505 */
506   sprintf(tmpstr, "%c:", newdir[0]);
507   test_setdir(newdir,tmpstr,newdir,1,"check 10");
508 /* works however with a trailing backslash */
509   sprintf(tmpstr, "%c:\\", newdir[0]);
510   test_setdir(newdir,tmpstr,NULL,1,"check 11");
511 }
512
513 /* Cleanup the mess we made while executing these tests */
514 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
515 {
516   CHAR tmpstr[MAX_PATH];
517   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
518   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
519   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
520   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
521   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
522   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
523   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
524   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
525   sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
526   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
527   sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
528   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
529   ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
530   ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
531 }
532
533 /* This routine will test Get(Full|Short|Long)PathNameA */
534 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
535 {
536   CHAR curdir_short[MAX_PATH],
537        longdir_short[MAX_PATH];
538   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
539   LPSTR strptr;                 /*ptr to the filename portion of the path */
540   DWORD len;
541   INT i;
542   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
543   SLpassfail passfail;
544
545 /* Get the short form of the current directory */
546   ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
547      "GetShortPathNameA failed\n");
548   ok(!HAS_TRAIL_SLASH_A(curdir_short),
549      "GetShortPathNameA should not have a trailing \\\n");
550 /* Get the short form of the absolute-path to LONGDIR */
551   sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
552   ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
553      "GetShortPathNameA failed\n");
554   ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
555      "GetShortPathNameA should not have a trailing \\\n");
556
557   if (pGetLongPathNameA) {
558     DWORD rc1,rc2;
559     sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
560     rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
561     rc2=(*pGetLongPathNameA)(curdir,NULL,0);
562     ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
563        "GetLongPathNameA: wrong return code, %d instead of %d\n",
564        rc1, lstrlenA(tmpstr)+1);
565
566     sprintf(dir,"%c:",curDrive);
567     rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
568     ok(strcmp(dir,tmpstr)==0,
569        "GetLongPathNameA: returned '%s' instead of '%s' (rc=%d)\n",
570        tmpstr,dir,rc1);
571   }
572
573 /* Check the cases where both file and directory exist first */
574 /* Start with a 8.3 directory, 8.3 filename */
575   test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
576   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
577   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
578      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
579 /* Now try a 8.3 directory, long file name */
580   test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
581   sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
582   test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
583 /* Next is a long directory, 8.3 file */
584   test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
585   sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
586   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
587      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
588 /*Lastly a long directory, long file */
589   test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
590   test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
591
592 /* Now check all of the invalid file w/ valid directory combinations */
593 /* Start with a 8.3 directory, 8.3 filename */
594   test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
595   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
596   ok((passfail.shortlen==0 &&
597       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
598        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
599      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
600      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
601      passfail.shortlen,passfail.shorterror,tmpstr);
602   if(pGetLongPathNameA) {
603     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
604     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
605        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
606   }
607 /* Now try a 8.3 directory, long file name */
608   test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
609   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
610   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
611      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
612      !passfail.shorterror,
613      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
614   if(pGetLongPathNameA) {
615     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
616     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
617        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
618   }
619 /* Next is a long directory, 8.3 file */
620   test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
621   sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
622   GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
623   strcat(tmpstr1,"\\" NONFILE_SHORT);
624   ok((passfail.shortlen==0 &&
625       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
626        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
627      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
628      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
629      passfail.shortlen,passfail.shorterror,tmpstr);
630   if(pGetLongPathNameA) {
631     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
632     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
633       "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
634   }
635 /*Lastly a long directory, long file */
636   test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
637   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
638   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
639      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
640      !passfail.shorterror,
641      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
642   if(pGetLongPathNameA) {
643     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
644     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
645        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
646   }
647 /* Now try again with directories that don't exist */
648 /* 8.3 directory, 8.3 filename */
649   test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
650   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
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_PATH_NOT_FOUND ||
660        passfail.longerror==ERROR_FILE_NOT_FOUND,
661        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
662        passfail.longerror);
663   }
664 /* Now try a 8.3 directory, long file name */
665   test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
666   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
667   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
668      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
669      !passfail.shorterror,
670      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
671       passfail.shorterror);
672   if(pGetLongPathNameA) {
673     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
674     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
675        passfail.longerror==ERROR_FILE_NOT_FOUND,
676        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
677        passfail.longerror);
678   }
679 /* Next is a long directory, 8.3 file */
680   test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
681   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
682   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
683      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
684      !passfail.shorterror,
685      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
686       passfail.shorterror);
687   if(pGetLongPathNameA) {
688     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
689     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
690        passfail.longerror==ERROR_FILE_NOT_FOUND,
691        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
692        passfail.longerror);
693   }
694 /*Lastly a long directory, long file */
695   test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
696   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
697   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
698      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
699      !passfail.shorterror,
700      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
701       passfail.shorterror);
702   if(pGetLongPathNameA) {
703     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
704     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
705        passfail.longerror==ERROR_FILE_NOT_FOUND,
706        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
707        passfail.longerror);
708   }
709 /* Next try directories ending with '\\' */
710 /* Existing Directories */
711   sprintf(tmpstr,"%s\\",SHORTDIR);
712   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
713   sprintf(tmpstr,"%s\\",LONGDIR);
714   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
715 /* Nonexistent directories */
716   sprintf(tmpstr,"%s\\",NONDIR_SHORT);
717   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
718   sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
719   ok((passfail.shortlen==0 &&
720       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
721        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
722      (passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
723      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
724      passfail.shortlen,passfail.shorterror,tmpstr);
725   if(pGetLongPathNameA) {
726     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
727     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
728        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
729        passfail.longerror);
730   }
731   sprintf(tmpstr,"%s\\",NONDIR_LONG);
732   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
733   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
734   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
735      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
736      !passfail.shorterror,
737      "GetShortPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
738       passfail.shorterror);
739   if(pGetLongPathNameA) {
740     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
741     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
742        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
743        passfail.longerror);
744   }
745 /* Test GetFullPathNameA with drive letters */
746   if( curDrive != NOT_A_VALID_DRIVE) {
747     sprintf(tmpstr,"%c:",curdir[0]);
748     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
749        "GetFullPathNameA(%c:) failed\n", curdir[0]);
750     GetCurrentDirectoryA(MAX_PATH,tmpstr);
751     sprintf(tmpstr1,"%s\\",tmpstr);
752     ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
753        "GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
754        curdir[0],tmpstr2,tmpstr,tmpstr1);
755
756     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
757     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
758     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
759        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
760     ok(lstrcmpiA(SHORTFILE,strptr)==0,
761        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
762   }
763 /* Without a leading slash, insert the current directory if on the current drive */
764   sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
765   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
766   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
767   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
768       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
769   ok(lstrcmpiA(SHORTFILE,strptr)==0,
770       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
771 /* Otherwise insert the missing leading slash */
772   if( otherDrive != NOT_A_VALID_DRIVE) {
773     /* FIXME: this test assumes that current directory on other drive is root */
774     sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
775     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
776     sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,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   }
782 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
783    So test for them. */
784   if( curDrive != NOT_A_VALID_DRIVE) {
785     sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
786     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
787     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
788     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
789        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
790     ok(lstrcmpiA(SHORTFILE,strptr)==0,
791        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
792   }
793 /**/
794   sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
795   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
796   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
797   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
798       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
799   ok(lstrcmpiA(SHORTFILE,strptr)==0,
800       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
801 /* Windows will insert a drive letter in front of an absolute UNIX path */
802   sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
803   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
804   sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
805   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
806      "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
807 /* This passes in Wine because it still contains the pointer from the previous test */
808   ok(lstrcmpiA(SHORTFILE,strptr)==0,
809       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
810
811 /* Now try some relative paths */
812   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
813   test_SplitShortPathA(tmpstr,dir,eight,three);
814   if(pGetLongPathNameA) {
815     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
816     ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
817        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
818   }
819   sprintf(tmpstr,".\\%s",LONGDIR);
820   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
821   test_SplitShortPathA(tmpstr1,dir,eight,three);
822   ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
823      "GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
824   if(pGetLongPathNameA) {
825     ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
826        tmpstr);
827     ok(lstrcmpiA(tmpstr1,tmpstr)==0,
828        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
829   }
830 /* Check out Get*PathNameA on some funny characters */
831   for(i=0;i<lstrlenA(funny_chars);i++) {
832     INT valid;
833     valid=(is_char_ok[i]=='0') ? 0 : 1;
834     sprintf(tmpstr1,"check%d-1",i);
835     sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
836     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
837     sprintf(tmpstr1,"check%d-2",i);
838     sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
839     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
840     sprintf(tmpstr1,"check%d-3",i);
841     sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
842     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
843     sprintf(tmpstr1,"check%d-4",i);
844     sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
845     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
846     sprintf(tmpstr1,"check%d-5",i);
847     sprintf(tmpstr,"Long %c File",funny_chars[i]);
848     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
849     sprintf(tmpstr1,"check%d-6",i);
850     sprintf(tmpstr,"%c Long File",funny_chars[i]);
851     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
852     sprintf(tmpstr1,"check%d-7",i);
853     sprintf(tmpstr,"Long File %c",funny_chars[i]);
854     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
855   }
856 }
857
858 static void test_GetTempPathA(char* tmp_dir)
859 {
860     DWORD len, len_with_null;
861     char buf[MAX_PATH];
862
863     len_with_null = strlen(tmp_dir) + 1;
864
865     lstrcpyA(buf, "foo");
866     len = GetTempPathA(MAX_PATH, buf);
867     ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
868     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
869     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
870
871     /* Some versions of Windows touch the buffer, some don't so we don't
872      * test that. Also, NT sometimes exaggerates the required buffer size
873      * so we cannot test for an exact match. Finally, the
874      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
875      * For instance in some cases Win98 returns len_with_null - 1 instead
876      * of len_with_null.
877      */
878     len = GetTempPathA(1, buf);
879     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
880
881     len = GetTempPathA(0, NULL);
882     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
883
884     /* The call above gave us the buffer size that Windows thinks is needed
885      * so the next call should work
886      */
887     lstrcpyA(buf, "foo");
888     len = GetTempPathA(len, buf);
889     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
890     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
891 }
892
893 static void test_GetTempPathW(char* tmp_dir)
894 {
895     DWORD len, len_with_null;
896     WCHAR buf[MAX_PATH];
897     WCHAR tmp_dirW[MAX_PATH];
898     static const WCHAR fooW[] = {'f','o','o',0};
899
900     MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
901     len_with_null = lstrlenW(tmp_dirW) + 1;
902
903     /* This one is different from ANSI version: ANSI version doesn't
904      * touch the buffer, unicode version usually truncates the buffer
905      * to zero size. NT still exaggerates the required buffer size
906      * sometimes so we cannot test for an exact match. Finally, the
907      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
908      * For instance on NT4 it will sometimes return a path without the
909      * trailing '\\' and sometimes return an error.
910      */
911
912     lstrcpyW(buf, fooW);
913     len = GetTempPathW(MAX_PATH, buf);
914     if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
915     {
916         win_skip("GetTempPathW is not available\n");
917         return;
918     }
919     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
920     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
921
922     lstrcpyW(buf, fooW);
923     len = GetTempPathW(1, buf);
924     ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
925     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
926
927     len = GetTempPathW(0, NULL);
928     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
929
930     lstrcpyW(buf, fooW);
931     len = GetTempPathW(len, buf);
932     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
933     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
934 }
935
936 static void test_GetTempPath(void)
937 {
938     char save_TMP[MAX_PATH];
939     char windir[MAX_PATH];
940     char buf[MAX_PATH];
941
942     if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0;
943
944     /* test default configuration */
945     trace("TMP=%s\n", save_TMP);
946     if (save_TMP[0])
947     {
948         strcpy(buf,save_TMP);
949         if (buf[strlen(buf)-1]!='\\')
950             strcat(buf,"\\");
951         test_GetTempPathA(buf);
952         test_GetTempPathW(buf);
953     }
954
955     /* TMP=C:\WINDOWS */
956     GetWindowsDirectoryA(windir, sizeof(windir));
957     SetEnvironmentVariableA("TMP", windir);
958     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
959     trace("TMP=%s\n", buf);
960     strcat(windir,"\\");
961     test_GetTempPathA(windir);
962     test_GetTempPathW(windir);
963
964     /* TMP=C:\ */
965     GetWindowsDirectoryA(windir, sizeof(windir));
966     windir[3] = 0;
967     SetEnvironmentVariableA("TMP", windir);
968     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
969     trace("TMP=%s\n", buf);
970     test_GetTempPathA(windir);
971     test_GetTempPathW(windir);
972
973     /* TMP=C: i.e. use current working directory of the specified drive */
974     GetWindowsDirectoryA(windir, sizeof(windir));
975     SetCurrentDirectoryA(windir);
976     windir[2] = 0;
977     SetEnvironmentVariableA("TMP", windir);
978     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
979     trace("TMP=%s\n", buf);
980     GetWindowsDirectoryA(windir, sizeof(windir));
981     strcat(windir,"\\");
982     test_GetTempPathA(windir);
983     test_GetTempPathW(windir);
984
985     SetEnvironmentVariableA("TMP", save_TMP);
986 }
987
988 static void test_GetLongPathNameA(void)
989 {
990     DWORD length, explength, hostsize;
991     char tempfile[MAX_PATH];
992     char longpath[MAX_PATH];
993     char unc_prefix[MAX_PATH];
994     char unc_short[MAX_PATH], unc_long[MAX_PATH];
995     char temppath[MAX_PATH], temppath2[MAX_PATH];
996     HANDLE file;
997
998     if (!pGetLongPathNameA)
999         return;
1000
1001     GetTempPathA(MAX_PATH, tempfile);
1002     lstrcatA(tempfile, "longfilename.longext");
1003
1004     file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1005     CloseHandle(file);
1006
1007     /* Test a normal path with a small buffer size */
1008     memset(temppath, 0, MAX_PATH);
1009     length = pGetLongPathNameA(tempfile, temppath, 4);
1010     /* We have a failure so length should be the minumum plus the terminating '0'  */
1011     ok(length >= lstrlen(tempfile) + 1, "Wrong length\n");
1012     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1013
1014     /* Some UNC syntax tests */
1015
1016     memset(temppath, 0, MAX_PATH);
1017     memset(temppath2, 0, MAX_PATH);
1018     lstrcpyA(temppath2, "\\\\?\\");
1019     lstrcatA(temppath2, tempfile);
1020     explength = length + 4;
1021
1022     SetLastError(0xdeadbeef);
1023     length = pGetLongPathNameA(temppath2, NULL, 0);
1024     if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME)
1025     {
1026         win_skip("UNC syntax tests don't work on Win98/WinMe\n");
1027         DeleteFileA(tempfile);
1028         return;
1029     }
1030     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1031
1032     length = pGetLongPathNameA(temppath2, NULL, MAX_PATH);
1033     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1034
1035     length = pGetLongPathNameA(temppath2, temppath, 4);
1036     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1037     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1038
1039     /* Now an UNC path with the computername */
1040     lstrcpyA(unc_prefix, "\\\\");
1041     hostsize = sizeof(unc_prefix) - 2;
1042     GetComputerName(unc_prefix + 2, &hostsize);
1043     lstrcatA(unc_prefix, "\\");
1044
1045     /* Create a short syntax for the whole unc path */
1046     memset(unc_short, 0, MAX_PATH);
1047     GetShortPathNameA(tempfile, temppath, MAX_PATH);
1048     lstrcpyA(unc_short, unc_prefix);
1049     unc_short[lstrlenA(unc_short)] = temppath[0];
1050     lstrcatA(unc_short, "$\\");
1051     lstrcatA(unc_short, strchr(temppath, '\\') + 1);
1052
1053     /* Create a long syntax for reference */
1054     memset(longpath, 0, MAX_PATH);
1055     pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1056     lstrcpyA(longpath, unc_prefix);
1057     longpath[lstrlenA(longpath)] = temppath[0];
1058     lstrcatA(longpath, "$\\");
1059     lstrcatA(longpath, strchr(temppath, '\\') + 1);
1060
1061     /* NULL test */
1062     SetLastError(0xdeadbeef);
1063     length = pGetLongPathNameA(unc_short, NULL, 0);
1064     if (length == 0 && GetLastError() == ERROR_BAD_NETPATH)
1065     {
1066         /* Seen on Window XP Home */
1067         win_skip("UNC with computername is not supported\n");
1068         DeleteFileA(tempfile);
1069         return;
1070     }
1071     explength = lstrlenA(longpath) + 1;
1072     todo_wine
1073     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1074
1075     length = pGetLongPathNameA(unc_short, NULL, MAX_PATH);
1076     todo_wine
1077     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1078
1079     memset(unc_long, 0, MAX_PATH);
1080     length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short));
1081     /* length will include terminating '0' on failure */
1082     todo_wine
1083     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1084     ok(unc_long[0] == 0, "Buffer should not have been touched\n");
1085
1086     memset(unc_long, 0, MAX_PATH);
1087     length = pGetLongPathNameA(unc_short, unc_long, length);
1088     /* length doesn't include terminating '0' on success */
1089     explength--;
1090     todo_wine
1091     {
1092     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1093     ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long);
1094     }
1095
1096     DeleteFileA(tempfile);
1097 }
1098
1099 static void test_GetLongPathNameW(void)
1100 {
1101     DWORD length, expanded;
1102     BOOL ret;
1103     HANDLE file;
1104     WCHAR empty[MAX_PATH];
1105     WCHAR tempdir[MAX_PATH], name[200];
1106     WCHAR dirpath[4 + MAX_PATH + 200]; /* To ease removal */
1107     WCHAR shortpath[4 + MAX_PATH + 200 + 1 + 200];
1108     static const WCHAR prefix[] = { '\\','\\','?','\\', 0};
1109     static const WCHAR backslash[] = { '\\', 0};
1110     static const WCHAR letterX[] = { 'X', 0};
1111
1112     if (!pGetLongPathNameW)
1113         return;
1114
1115     SetLastError(0xdeadbeef); 
1116     length = pGetLongPathNameW(NULL,NULL,0);
1117     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1118     {
1119         win_skip("GetLongPathNameW is not implemented\n");
1120         return;
1121     }
1122     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1123     ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError());
1124
1125     SetLastError(0xdeadbeef); 
1126     empty[0]=0;
1127     length = pGetLongPathNameW(empty,NULL,0);
1128     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1129     ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError());
1130
1131     /* Create a long path name. The path needs to exist for these tests to
1132      * succeed so we need the "\\?\" prefix when creating directories and
1133      * files.
1134      */
1135     name[0] = 0;
1136     while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1))
1137         lstrcatW(name, letterX);
1138
1139     GetTempPathW(MAX_PATH, tempdir);
1140
1141     lstrcpyW(shortpath, prefix);
1142     lstrcatW(shortpath, tempdir);
1143     lstrcatW(shortpath, name);
1144     lstrcpyW(dirpath, shortpath);
1145     ret = CreateDirectoryW(shortpath, NULL);
1146     ok(ret, "Could not create the temporary directory : %d\n", GetLastError());
1147     lstrcatW(shortpath, backslash);
1148     lstrcatW(shortpath, name);
1149
1150     /* Path does not exist yet and we know it overruns MAX_PATH */
1151
1152     /* No prefix */
1153     SetLastError(0xdeadbeef);
1154     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1155     ok(length == 0, "Expected 0, got %d\n", length);
1156     todo_wine
1157     ok(GetLastError() == ERROR_PATH_NOT_FOUND,
1158        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1159     /* With prefix */
1160     SetLastError(0xdeadbeef);
1161     length = pGetLongPathNameW(shortpath, NULL, 0);
1162     todo_wine
1163     {
1164     ok(length == 0, "Expected 0, got %d\n", length);
1165     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1166        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1167     }
1168
1169     file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1170                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1171     ok(file != INVALID_HANDLE_VALUE,
1172        "Could not create the temporary file : %d.\n", GetLastError());
1173     CloseHandle(file);
1174
1175     /* Path exists */
1176
1177     /* No prefix */
1178     SetLastError(0xdeadbeef);
1179     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1180     todo_wine
1181     {
1182     ok(length == 0, "Expected 0, got %d\n", length);
1183     ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1184     }
1185     /* With prefix */
1186     expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1;
1187     SetLastError(0xdeadbeef);
1188     length = pGetLongPathNameW(shortpath, NULL, 0);
1189     ok(length == expanded, "Expected %d, got %d\n", expanded, length);
1190
1191     /* NULL buffer with length crashes on Windows */
1192     if (0)
1193     length = pGetLongPathNameW(shortpath, NULL, 20);
1194
1195     ok(DeleteFileW(shortpath), "Could not delete temporary file\n");
1196     ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n");
1197 }
1198
1199 static void test_GetShortPathNameW(void)
1200 {
1201     WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e',  0 };
1202     WCHAR path[MAX_PATH];
1203     WCHAR short_path[MAX_PATH];
1204     DWORD length;
1205     HANDLE file;
1206     int ret;
1207     WCHAR name[] = { 't', 'e', 's', 't', 0 };
1208     WCHAR backSlash[] = { '\\', 0 };
1209
1210     SetLastError(0xdeadbeef);
1211     GetTempPathW( MAX_PATH, path );
1212     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1213     {
1214         win_skip("GetTempPathW is not implemented\n");
1215         return;
1216     }
1217
1218     lstrcatW( path, test_path );
1219     lstrcatW( path, backSlash );
1220     ret = CreateDirectoryW( path, NULL );
1221     ok( ret, "Directory was not created. LastError = %d\n", GetLastError() );
1222
1223     /* Starting a main part of test */
1224     length = GetShortPathNameW( path, short_path, 0 );
1225     ok( length, "GetShortPathNameW returned 0.\n" );
1226     ret = GetShortPathNameW( path, short_path, length );
1227     ok( ret, "GetShortPathNameW returned 0.\n" );
1228     lstrcatW( short_path, name );
1229     file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1230     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1231
1232     /* End test */
1233     CloseHandle( file );
1234     ret = DeleteFileW( short_path );
1235     ok( ret, "Cannot delete file.\n" );
1236     ret = RemoveDirectoryW( path );
1237     ok( ret, "Cannot delete directory.\n" );
1238 }
1239
1240 static void test_GetSystemDirectory(void)
1241 {
1242     CHAR    buffer[MAX_PATH + 4];
1243     DWORD   res;
1244     DWORD   total;
1245
1246     SetLastError(0xdeadbeef);
1247     res = GetSystemDirectory(NULL, 0);
1248     /* res includes the terminating Zero */
1249     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1250
1251     total = res;
1252
1253     /* this crashes on XP */
1254     if (0) res = GetSystemDirectory(NULL, total);
1255
1256     SetLastError(0xdeadbeef);
1257     res = GetSystemDirectory(NULL, total-1);
1258     /* 95+NT: total (includes the terminating Zero)
1259        98+ME: 0 with ERROR_INVALID_PARAMETER */
1260     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1261         "returned %d with %d (expected '%d' or: '0' with "
1262         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1263
1264     if (total > MAX_PATH) return;
1265
1266     buffer[0] = '\0';
1267     SetLastError(0xdeadbeef);
1268     res = GetSystemDirectory(buffer, total);
1269     /* res does not include the terminating Zero */
1270     ok( (res == (total-1)) && (buffer[0]),
1271         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1272         res, GetLastError(), buffer, total-1);
1273
1274     buffer[0] = '\0';
1275     SetLastError(0xdeadbeef);
1276     res = GetSystemDirectory(buffer, total + 1);
1277     /* res does not include the terminating Zero */
1278     ok( (res == (total-1)) && (buffer[0]),
1279         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1280         res, GetLastError(), buffer, total-1);
1281
1282     memset(buffer, '#', total + 1);
1283     buffer[total + 2] = '\0';
1284     SetLastError(0xdeadbeef);
1285     res = GetSystemDirectory(buffer, total-1);
1286     /* res includes the terminating Zero) */
1287     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1288         res, GetLastError(), buffer, total);
1289
1290     memset(buffer, '#', total + 1);
1291     buffer[total + 2] = '\0';
1292     SetLastError(0xdeadbeef);
1293     res = GetSystemDirectory(buffer, total-2);
1294     /* res includes the terminating Zero) */
1295     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1296         res, GetLastError(), buffer, total);
1297 }
1298
1299 static void test_GetWindowsDirectory(void)
1300 {
1301     CHAR    buffer[MAX_PATH + 4];
1302     DWORD   res;
1303     DWORD   total;
1304
1305     SetLastError(0xdeadbeef);
1306     res = GetWindowsDirectory(NULL, 0);
1307     /* res includes the terminating Zero */
1308     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1309
1310     total = res;
1311     /* this crashes on XP */
1312     if (0) res = GetWindowsDirectory(NULL, total);
1313
1314     SetLastError(0xdeadbeef);
1315     res = GetWindowsDirectory(NULL, total-1);
1316     /* 95+NT: total (includes the terminating Zero)
1317        98+ME: 0 with ERROR_INVALID_PARAMETER */
1318     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1319         "returned %d with %d (expected '%d' or: '0' with "
1320         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1321
1322     if (total > MAX_PATH) return;
1323
1324     buffer[0] = '\0';
1325     SetLastError(0xdeadbeef);
1326     res = GetWindowsDirectory(buffer, total);
1327     /* res does not include the terminating Zero */
1328     ok( (res == (total-1)) && (buffer[0]),
1329         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1330         res, GetLastError(), buffer, total-1);
1331
1332     buffer[0] = '\0';
1333     SetLastError(0xdeadbeef);
1334     res = GetWindowsDirectory(buffer, total + 1);
1335     /* res does not include the terminating Zero */
1336     ok( (res == (total-1)) && (buffer[0]),
1337         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1338         res, GetLastError(), buffer, total-1);
1339
1340     memset(buffer, '#', total + 1);
1341     buffer[total + 2] = '\0';
1342     SetLastError(0xdeadbeef);
1343     res = GetWindowsDirectory(buffer, total-1);
1344     /* res includes the terminating Zero) */
1345     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1346         res, GetLastError(), buffer, total);
1347
1348     memset(buffer, '#', total + 1);
1349     buffer[total + 2] = '\0';
1350     SetLastError(0xdeadbeef);
1351     res = GetWindowsDirectory(buffer, total-2);
1352     /* res includes the terminating Zero) */
1353     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1354         res, GetLastError(), buffer, total);
1355 }
1356
1357 static void test_NeedCurrentDirectoryForExePathA(void)
1358 {
1359     if (!pNeedCurrentDirectoryForExePathA)
1360     {
1361         win_skip("NeedCurrentDirectoryForExePathA is not available\n");
1362         return;
1363     }
1364
1365     /* Crashes in Windows */
1366     if (0)
1367         ok(pNeedCurrentDirectoryForExePathA(NULL), "returned FALSE for NULL\n");
1368
1369     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1370     ok(pNeedCurrentDirectoryForExePathA("."), "returned FALSE for \".\"\n");
1371     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1372     ok(pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned FALSE for \"cmd.exe\"\n");
1373
1374     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1375     ok(!pNeedCurrentDirectoryForExePathA("."), "returned TRUE for \".\"\n");
1376     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1377     ok(!pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned TRUE for \"cmd.exe\"\n");
1378 }
1379
1380 static void test_NeedCurrentDirectoryForExePathW(void)
1381 {
1382     const WCHAR thispath[] = {'.', 0};
1383     const WCHAR fullpath[] = {'c', ':', '\\', 0};
1384     const WCHAR cmdname[] = {'c', 'm', 'd', '.', 'e', 'x', 'e', 0};
1385
1386     if (!pNeedCurrentDirectoryForExePathW)
1387     {
1388         win_skip("NeedCurrentDirectoryForExePathW is not available\n");
1389         return;
1390     }
1391
1392     /* Crashes in Windows */
1393     if (0)
1394         ok(pNeedCurrentDirectoryForExePathW(NULL), "returned FALSE for NULL\n");
1395
1396     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1397     ok(pNeedCurrentDirectoryForExePathW(thispath), "returned FALSE for \".\"\n");
1398     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1399     ok(pNeedCurrentDirectoryForExePathW(cmdname), "returned FALSE for \"cmd.exe\"\n");
1400
1401     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1402     ok(!pNeedCurrentDirectoryForExePathW(thispath), "returned TRUE for \".\"\n");
1403     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1404     ok(!pNeedCurrentDirectoryForExePathW(cmdname), "returned TRUE for \"cmd.exe\"\n");
1405 }
1406
1407 /* Call various path/file name retrieving APIs and check the case of
1408  * the returned drive letter. Some apps (for instance Adobe Photoshop CS3
1409  * installer) depend on the drive letter being in upper case.
1410  */
1411 static void test_drive_letter_case(void)
1412 {
1413     UINT ret;
1414     char buf[MAX_PATH];
1415
1416 #define is_upper_case_letter(a) ((a) >= 'A' && (a) <= 'Z')
1417
1418     memset(buf, 0, sizeof(buf));
1419     SetLastError(0xdeadbeef);
1420     ret = GetWindowsDirectory(buf, sizeof(buf));
1421     ok(ret, "GetWindowsDirectory error %u\n", GetLastError());
1422     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1423     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1424     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1425
1426     /* re-use the buffer returned by GetFullPathName */
1427     buf[2] = '/';
1428     SetLastError(0xdeadbeef);
1429     ret = GetFullPathName(buf + 2, sizeof(buf), buf, NULL);
1430     ok(ret, "GetFullPathName error %u\n", GetLastError());
1431     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1432     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1433     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1434
1435     memset(buf, 0, sizeof(buf));
1436     SetLastError(0xdeadbeef);
1437     ret = GetSystemDirectory(buf, sizeof(buf));
1438     ok(ret, "GetSystemDirectory error %u\n", GetLastError());
1439     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1440     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1441     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1442
1443     memset(buf, 0, sizeof(buf));
1444     SetLastError(0xdeadbeef);
1445     ret = GetCurrentDirectory(sizeof(buf), buf);
1446     ok(ret, "GetCurrentDirectory error %u\n", GetLastError());
1447     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1448     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1449     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1450
1451     /* TEMP is an environment variable, so it can't be tested for case-sensitivity */
1452     memset(buf, 0, sizeof(buf));
1453     SetLastError(0xdeadbeef);
1454     ret = GetTempPath(sizeof(buf), buf);
1455     ok(ret, "GetTempPath error %u\n", GetLastError());
1456     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1457     if (buf[0])
1458     {
1459         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1460         ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf);
1461     }
1462
1463     memset(buf, 0, sizeof(buf));
1464     SetLastError(0xdeadbeef);
1465     ret = GetFullPathName(".", sizeof(buf), buf, NULL);
1466     ok(ret, "GetFullPathName error %u\n", GetLastError());
1467     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1468     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1469     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1470
1471     /* re-use the buffer returned by GetFullPathName */
1472     SetLastError(0xdeadbeef);
1473     ret = GetShortPathName(buf, buf, sizeof(buf));
1474     ok(ret, "GetShortPathName error %u\n", GetLastError());
1475     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1476     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1477     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1478
1479     if (pGetLongPathNameA)
1480     {
1481         /* re-use the buffer returned by GetShortPathName */
1482         SetLastError(0xdeadbeef);
1483         ret = pGetLongPathNameA(buf, buf, sizeof(buf));
1484         ok(ret, "GetLongPathNameA 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 #undef is_upper_case_letter
1490 }
1491
1492 static void test_SearchPathA(void)
1493 {
1494     CHAR pathA[MAX_PATH], fileA[] = "", buffA[MAX_PATH];
1495     CHAR *ptrA = NULL;
1496     DWORD ret;
1497
1498     if (!pSearchPathA)
1499     {
1500         win_skip("SearchPathA isn't available\n");
1501         return;
1502     }
1503
1504     GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR));
1505
1506     /* NULL filename */
1507     SetLastError(0xdeadbeef);
1508     ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1509     ok(ret == 0, "Expected failure, got %d\n", ret);
1510     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1511       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1512
1513     /* empty filename */
1514     SetLastError(0xdeadbeef);
1515     ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1516     ok(ret == 0, "Expected failure, got %d\n", ret);
1517     ok(GetLastError() == ERROR_INVALID_PARAMETER ||
1518        broken(GetLastError() == ERROR_FILE_NOT_FOUND) /* win9x */,
1519       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1520 }
1521
1522 static void test_SearchPathW(void)
1523 {
1524     WCHAR pathW[MAX_PATH], fileW[] = { 0 }, buffW[MAX_PATH];
1525     WCHAR *ptrW = NULL;
1526     DWORD ret;
1527
1528     if (!pSearchPathW)
1529     {
1530         win_skip("SearchPathW isn't available\n");
1531         return;
1532     }
1533
1534     /* SearchPathW is a stub on win9x and doesn't return sane error,
1535        so quess if it's implemented indirectly */
1536     SetLastError(0xdeadbeef);
1537     GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1538     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1539     {
1540         win_skip("SearchPathW not implemented\n");
1541         return;
1542     }
1543
1544 if (0)
1545 {
1546     /* NULL filename, crashes on nt4 */
1547     SetLastError(0xdeadbeef);
1548     ret = pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1549     ok(ret == 0, "Expected failure, got %d\n", ret);
1550     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1551        "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1552 }
1553
1554     /* empty filename */
1555     SetLastError(0xdeadbeef);
1556     ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1557     ok(ret == 0, "Expected failure, got %d\n", ret);
1558     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1559       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1560 }
1561
1562 static void init_pointers(void)
1563 {
1564     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
1565
1566 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f))
1567     MAKEFUNC(GetLongPathNameA);
1568     MAKEFUNC(GetLongPathNameW);
1569     MAKEFUNC(NeedCurrentDirectoryForExePathA);
1570     MAKEFUNC(NeedCurrentDirectoryForExePathW);
1571     MAKEFUNC(SearchPathA);
1572     MAKEFUNC(SearchPathW);
1573 #undef MAKEFUNC
1574 }
1575
1576 START_TEST(path)
1577 {
1578     CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
1579
1580     init_pointers();
1581
1582     /* Report only once */
1583     if (!pGetLongPathNameA)
1584         win_skip("GetLongPathNameA is not available\n");
1585     if (!pGetLongPathNameW)
1586         win_skip("GetLongPathNameW is not available\n");
1587
1588     test_InitPathA(curdir, &curDrive, &otherDrive);
1589     test_CurrentDirectoryA(origdir,curdir);
1590     test_PathNameA(curdir, curDrive, otherDrive);
1591     test_CleanupPathA(origdir,curdir);
1592     test_GetTempPath();
1593     test_GetLongPathNameA();
1594     test_GetLongPathNameW();
1595     test_GetShortPathNameW();
1596     test_GetSystemDirectory();
1597     test_GetWindowsDirectory();
1598     test_NeedCurrentDirectoryForExePathA();
1599     test_NeedCurrentDirectoryForExePathW();
1600     test_drive_letter_case();
1601     test_SearchPathA();
1602     test_SearchPathW();
1603 }