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 <assert.h>
25 #include "wine/test.h"
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "winerror.h"
30 #include "winnls.h"
31 
32 #define HAS_TRAIL_SLASH_A(string) (string[lstrlenA(string)-1]=='\\')
33 
34 #define LONGFILE "Long File test.path"
35 #define SHORTFILE "pathtest.pth"
36 #define SHORTDIR "shortdir"
37 #define LONGDIR "Long Directory"
38 #define NONFILE_SHORT "noexist.pth"
39 #define NONFILE_LONG "NonExistent File"
40 #define NONDIR_SHORT "notadir"
41 #define NONDIR_LONG "NonExistent Directory"
42 
43 #define NOT_A_VALID_DRIVE '@'
44 
45 #ifdef __i386__
46 #define ARCH "x86"
47 #elif defined __x86_64__
48 #define ARCH "amd64"
49 #elif defined __arm__
50 #define ARCH "arm"
51 #elif defined __aarch64__
52 #define ARCH "arm64"
53 #else
54 #define ARCH "none"
55 #endif
56 
57 /* the following characters don't work well with GetFullPathNameA
58    in Win98.  I don't know if this is a FAT thing, or if it is an OS thing
59    but I don't test these characters now.
60    NOTE: Win2k allows GetFullPathNameA to work with them though
61       |<>"
62 */
63 static const CHAR funny_chars[]="!@#$%^&*()=+{}[],?'`";
64 static const CHAR is_char_ok[] ="11111110111111111011";
65 
66 static DWORD (WINAPI *pGetLongPathNameA)(LPCSTR,LPSTR,DWORD);
67 static DWORD (WINAPI *pGetLongPathNameW)(LPWSTR,LPWSTR,DWORD);
68 
69 /* Present in Win2003+ */
70 static BOOL  (WINAPI *pNeedCurrentDirectoryForExePathA)(LPCSTR);
71 static BOOL  (WINAPI *pNeedCurrentDirectoryForExePathW)(LPCWSTR);
72 
73 static DWORD (WINAPI *pSearchPathA)(LPCSTR,LPCSTR,LPCSTR,DWORD,LPSTR,LPSTR*);
74 static DWORD (WINAPI *pSearchPathW)(LPCWSTR,LPCWSTR,LPCWSTR,DWORD,LPWSTR,LPWSTR*);
75 static BOOL  (WINAPI *pSetSearchPathMode)(DWORD);
76 
77 static BOOL   (WINAPI *pActivateActCtx)(HANDLE,ULONG_PTR*);
78 static HANDLE (WINAPI *pCreateActCtxW)(PCACTCTXW);
79 static BOOL   (WINAPI *pDeactivateActCtx)(DWORD,ULONG_PTR);
80 static BOOL   (WINAPI *pGetCurrentActCtx)(HANDLE *);
81 static void   (WINAPI *pReleaseActCtx)(HANDLE);
82 
83 static BOOL (WINAPI *pCheckNameLegalDOS8Dot3W)(const WCHAR *, char *, DWORD, BOOL *, BOOL *);
84 static BOOL (WINAPI *pCheckNameLegalDOS8Dot3A)(const char *, char *, DWORD, BOOL *, BOOL *);
85 
86 /* a structure to deal with wine todos somewhat cleanly */
87 typedef struct {
88   DWORD shortlen;
89   DWORD shorterror;
90   DWORD s2llen;
91   DWORD s2lerror;
92   DWORD longlen;
93   DWORD longerror;
94 } SLpassfail;
95 
96 /* function that tests GetFullPathNameA, GetShortPathNameA,GetLongPathNameA */
97 /* NOTE: the passfail structure is used to allow customizable todo checking
98          for wine.  It is not very pretty, but it sure beats duplicating this
99          function lots of times
100 */
101 static void test_ValidPathA(const CHAR *curdir, const CHAR *subdir, const CHAR *filename,
102                          CHAR *shortstr, SLpassfail *passfail, const CHAR *errstr)
103 {
104   CHAR tmpstr[MAX_PATH],
105        fullpath[MAX_PATH],      /*full path to the file (not short/long) */
106        subpath[MAX_PATH],       /*relative path to the file */
107        fullpathshort[MAX_PATH], /*absolute path to the file (short format) */
108        fullpathlong[MAX_PATH],  /*absolute path to the file (long format) */
109        curdirshort[MAX_PATH],   /*absolute path to the current dir (short) */
110        curdirlong[MAX_PATH];    /*absolute path to the current dir (long) */
111   LPSTR strptr;                 /*ptr to the filename portion of the path */
112   DWORD len;
113 /* if passfail is NULL, we can perform all checks within this function,
114    otherwise, we will return the relevant data in the passfail struct, so
115    we must initialize it first
116 */
117   if(passfail!=NULL) {
118     passfail->shortlen=-1;passfail->s2llen=-1;passfail->longlen=-1;
119     passfail->shorterror=0;passfail->s2lerror=0;passfail->longerror=0;
120   }
121 /* GetLongPathNameA is only supported on Win2k+ and Win98+ */
122   if(pGetLongPathNameA) {
123     ok((len=pGetLongPathNameA(curdir,curdirlong,MAX_PATH)),
124        "%s: GetLongPathNameA failed\n",errstr);
125 /*GetLongPathNameA can return a trailing '\\' but shouldn't do so here */
126     ok(! HAS_TRAIL_SLASH_A(curdirlong),
127        "%s: GetLongPathNameA should not have a trailing \\\n",errstr);
128   }
129   ok((len=GetShortPathNameA(curdir,curdirshort,MAX_PATH)),
130      "%s: GetShortPathNameA failed\n",errstr);
131 /*GetShortPathNameA can return a trailing '\\' but shouldn't do so here */
132   ok(! HAS_TRAIL_SLASH_A(curdirshort),
133      "%s: GetShortPathNameA should not have a trailing \\\n",errstr);
134 /* build relative and absolute paths from inputs */
135   if(lstrlenA(subdir)) {
136     sprintf(subpath,"%s\\%s",subdir,filename);
137   } else {
138     lstrcpyA(subpath,filename);
139   }
140   sprintf(fullpath,"%s\\%s",curdir,subpath);
141   sprintf(fullpathshort,"%s\\%s",curdirshort,subpath);
142   sprintf(fullpathlong,"%s\\%s",curdirlong,subpath);
143 /* Test GetFullPathNameA functionality */
144   len=GetFullPathNameA(subpath,MAX_PATH,tmpstr,&strptr);
145   ok(len, "GetFullPathNameA failed for: '%s'\n",subpath);
146   if(HAS_TRAIL_SLASH_A(subpath)) {
147     ok(strptr==NULL,
148        "%s: GetFullPathNameA should not return a filename ptr\n",errstr);
149     ok(lstrcmpiA(fullpath,tmpstr)==0,
150        "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
151        errstr,tmpstr,fullpath);
152   } else {
153     ok(lstrcmpiA(strptr,filename)==0,
154        "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
155        errstr,strptr,filename);
156     ok(lstrcmpiA(fullpath,tmpstr)==0,
157        "%s: GetFullPathNameA returned '%s' instead of '%s'\n",
158        errstr,tmpstr,fullpath);
159   }
160 /* Test GetShortPathNameA functionality */
161   SetLastError(0);
162   len=GetShortPathNameA(fullpathshort,shortstr,MAX_PATH);
163   if(passfail==NULL) {
164     ok(len, "%s: GetShortPathNameA failed\n",errstr);
165   } else {
166     passfail->shortlen=len;
167     passfail->shorterror=GetLastError();
168   }
169 /* Test GetLongPathNameA functionality
170    We test both conversion from GetFullPathNameA and from GetShortPathNameA
171 */
172   if(pGetLongPathNameA) {
173     if(len!=0) {
174       SetLastError(0);
175       len=pGetLongPathNameA(shortstr,tmpstr,MAX_PATH);
176       if(passfail==NULL) {
177         ok(len,
178           "%s: GetLongPathNameA failed during Short->Long conversion\n", errstr);
179         ok(lstrcmpiA(fullpathlong,tmpstr)==0,
180            "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
181            errstr,tmpstr,fullpathlong);
182       } else {
183         passfail->s2llen=len;
184         passfail->s2lerror=GetLastError();
185       }
186     }
187     SetLastError(0);
188     len=pGetLongPathNameA(fullpath,tmpstr,MAX_PATH);
189     if(passfail==NULL) {
190       ok(len, "%s: GetLongPathNameA failed\n",errstr);
191       ok(!lstrcmpiA(fullpathlong, tmpstr), "%s: GetLongPathNameA returned '%s' instead of '%s'\n",
192          errstr, tmpstr, fullpathlong);
193     } else {
194       passfail->longlen=len;
195       passfail->longerror=GetLastError();
196     }
197   }
198 }
199 
200 /* split path into leading directory, and 8.3 filename */
201 static void test_SplitShortPathA(CHAR *path,CHAR *dir,CHAR *eight,CHAR *three) {
202   BOOL done = FALSE, error = FALSE;
203   int ext,fil;
204   int len,i;
205   len=lstrlenA(path);
206   ext=len;
207   fil=len;
208 /* walk backwards over path looking for '.' or '\\' separators */
209   for(i=len-1;(i>=0) && (!done);i--) {
210     if(path[i]=='.')
211       if(ext!=len) error=TRUE; else ext=i;
212     else if(path[i]=='\\') {
213       if(i==len-1) {
214         error=TRUE;
215       } else {
216         fil=i;
217         done=TRUE;
218       }
219     }
220   }
221 /* Check that we didn't find a trailing '\\' or multiple '.' */
222   ok(!error,"Illegal file found in 8.3 path '%s'\n",path);
223 /* Separate dir, root, and extension */
224   if(ext!=len) lstrcpyA(three,path+ext+1); else lstrcpyA(three,"");
225   if(fil!=len) {
226     lstrcpynA(eight,path+fil+1,ext-fil);
227     lstrcpynA(dir,path,fil+1);
228   } else {
229     lstrcpynA(eight,path,ext+1);
230     lstrcpyA(dir,"");
231   }
232 /* Validate that root and extension really are 8.3 */
233   ok(lstrlenA(eight)<=8 && lstrlenA(three)<=3,
234      "GetShortPathNAmeA did not return an 8.3 path\n");
235 }
236 
237 /* Check that GetShortPathNameA returns a valid 8.3 path */
238 static void test_LongtoShortA(CHAR *teststr,const CHAR *goodstr,
239                               const CHAR *ext,const CHAR *errstr) {
240   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
241 
242   test_SplitShortPathA(teststr,dir,eight,three);
243   ok(lstrcmpiA(dir,goodstr)==0,
244      "GetShortPathNameA returned '%s' instead of '%s'\n",dir,goodstr);
245   ok(lstrcmpiA(three,ext)==0,
246      "GetShortPathNameA returned '%s' with incorrect extension\n",three);
247 }
248 
249 /* Test that Get(Short|Long|Full)PathNameA work correctly with interesting
250    characters in the filename.
251      'valid' indicates whether this would be an allowed filename
252      'todo' indicates that wine doesn't get this right yet.
253    NOTE: We always call this routine with a nonexistent filename, so
254          Get(Short|Long)PathNameA should never pass, but GetFullPathNameA
255          should.
256 */
257 static void test_FunnyChars(CHAR *curdir,CHAR *curdir_short,CHAR *filename, INT valid,CHAR *errstr)
258 {
259   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
260   SLpassfail passfail;
261 
262   test_ValidPathA(curdir,"",filename,tmpstr,&passfail,errstr);
263   if(valid) {
264     sprintf(tmpstr1,"%s\\%s",curdir_short,filename);
265       ok((passfail.shortlen==0 &&
266           (passfail.shorterror==ERROR_FILE_NOT_FOUND || passfail.shorterror==ERROR_PATH_NOT_FOUND || !passfail.shorterror)) ||
267          (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
268          "%s: GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
269          errstr,passfail.shortlen,passfail.shorterror,tmpstr);
270   } else {
271       ok(passfail.shortlen==0 &&
272          (passfail.shorterror==ERROR_INVALID_NAME || passfail.shorterror==ERROR_FILE_NOT_FOUND || !passfail.shorterror),
273          "%s: GetShortPathA should have failed len=%d, error=%d\n",
274          errstr,passfail.shortlen,passfail.shorterror);
275   }
276   if(pGetLongPathNameA) {
277     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
278     if(valid) {
279       ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
280          "%s: GetLongPathA returned %d and not %d\n",
281          errstr,passfail.longerror,ERROR_FILE_NOT_FOUND);
282     } else {
283       ok(passfail.longerror==ERROR_INVALID_NAME ||
284          passfail.longerror==ERROR_FILE_NOT_FOUND,
285          "%s: GetLongPathA returned %d and not %d or %d'\n",
286          errstr, passfail.longerror,ERROR_INVALID_NAME,ERROR_FILE_NOT_FOUND);
287     }
288   }
289 }
290 
291 /* Routine to test that SetCurrentDirectory behaves as expected. */
292 static void test_setdir(CHAR *olddir,CHAR *newdir,
293                         CHAR *cmprstr, INT pass, const CHAR *errstr)
294 {
295   CHAR tmppath[MAX_PATH], *dirptr;
296   DWORD val,len,chklen;
297 
298   val=SetCurrentDirectoryA(newdir);
299   len=GetCurrentDirectoryA(MAX_PATH,tmppath);
300 /* if 'pass' then the SetDirectoryA was supposed to pass */
301   if(pass) {
302     dirptr=(cmprstr==NULL) ? newdir : cmprstr;
303     chklen=lstrlenA(dirptr);
304     ok(val,"%s: SetCurrentDirectoryA failed\n",errstr);
305     ok(len==chklen,
306        "%s: SetCurrentDirectory did not change the directory, though it passed\n",
307        errstr);
308     ok(lstrcmpiA(dirptr,tmppath)==0,
309        "%s: SetCurrentDirectory did not change the directory, though it passed\n",
310        errstr);
311     ok(SetCurrentDirectoryA(olddir),
312        "%s: Couldn't set directory to its original value\n",errstr);
313   } else {
314 /* else thest that it fails correctly */
315     chklen=lstrlenA(olddir);
316     ok(val==0,
317        "%s: SetCurrentDirectoryA passed when it should have failed\n",errstr);
318     ok(len==chklen,
319        "%s: SetCurrentDirectory changed the directory, though it failed\n",
320        errstr);
321     ok(lstrcmpiA(olddir,tmppath)==0,
322        "%s: SetCurrentDirectory changed the directory, though it failed\n",
323        errstr);
324   }
325 }
326 static void test_InitPathA(CHAR *newdir, CHAR *curDrive, CHAR *otherDrive)
327 {
328   CHAR tmppath[MAX_PATH], /*path to TEMP */
329        tmpstr[MAX_PATH],
330        tmpstr1[MAX_PATH],
331        invalid_dir[MAX_PATH];
332 
333   DWORD len,len1,drives;
334   INT id;
335   HANDLE hndl;
336   BOOL bRes;
337   UINT unique;
338 
339   *curDrive = *otherDrive = NOT_A_VALID_DRIVE;
340 
341 /* Get the current drive letter */
342   if( GetCurrentDirectoryA( MAX_PATH, tmpstr))
343     *curDrive = tmpstr[0];
344   else
345     trace( "Unable to discover current drive, some tests will not be conducted.\n");
346 
347 /* Test GetTempPathA */
348   len=GetTempPathA(MAX_PATH,tmppath);
349   ok(len!=0 && len < MAX_PATH,"GetTempPathA failed\n");
350   ok(HAS_TRAIL_SLASH_A(tmppath),
351      "GetTempPathA returned a path that did not end in '\\'\n");
352   lstrcpyA(tmpstr,"aaaaaaaa");
353   len1=GetTempPathA(len,tmpstr);
354   ok(len1==len+1 || broken(len1 == len), /* WinME */
355      "GetTempPathA should return string length %d instead of %d\n",len+1,len1);
356 
357 /* Test GetTmpFileNameA */
358   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
359   sprintf(tmpstr,"pat%.4x.tmp",id & 0xffff);
360   sprintf(tmpstr1,"pat%x.tmp",id & 0xffff);
361   ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
362      lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
363      "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
364      newdir,tmpstr,tmpstr1,id);
365   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
366 
367   id=GetTempFileNameA(tmppath,NULL,0,newdir);
368 /* Windows 95, 98 return 0==id, while Windows 2000, XP return 0!=id */
369   if (id)
370   {
371     sprintf(tmpstr,"%.4x.tmp",id & 0xffff);
372     sprintf(tmpstr1,"%x.tmp",id & 0xffff);
373     ok(lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr)==0 ||
374        lstrcmpiA(newdir+lstrlenA(tmppath),tmpstr1)==0,
375        "GetTempFileNameA returned '%s' which doesn't match '%s' or '%s'. id=%x\n",
376        newdir,tmpstr,tmpstr1,id);
377     ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
378   }
379 
380   for(unique=0;unique<3;unique++) {
381     /* Nonexistent path */
382     sprintf(invalid_dir, "%s\\%s",tmppath,"non_existent_dir_1jwj3y32nb3");
383     SetLastError(0xdeadbeef);
384     ok(!GetTempFileNameA(invalid_dir,"tfn",unique,newdir),"GetTempFileNameA should have failed\n");
385     ok(GetLastError()==ERROR_DIRECTORY || broken(GetLastError()==ERROR_PATH_NOT_FOUND)/*win98*/,
386     "got %d, expected ERROR_DIRECTORY\n", GetLastError());
387 
388     /* Check return value for unique !=0 */
389     if(unique) {
390       ok((GetTempFileNameA(tmppath,"tfn",unique,newdir) == unique),"GetTempFileNameA unexpectedly failed\n");
391       /* if unique != 0, the actual temp files are not created: */
392       ok(!DeleteFileA(newdir) && GetLastError() == ERROR_FILE_NOT_FOUND,"Deleted a file that shouldn't exist!\n");
393     }
394   }
395 
396 /* Find first valid drive letter that is neither newdir[0] nor curDrive */
397   drives = GetLogicalDrives() & ~(1<<(newdir[0]-'A'));
398   if( *curDrive != NOT_A_VALID_DRIVE)
399     drives &= ~(1<<(*curDrive-'A'));
400   if( drives)
401     for( *otherDrive='A'; (drives & 1) == 0; drives>>=1, (*otherDrive)++);
402   else
403     trace( "Could not find alternative drive, some tests will not be conducted.\n");
404 
405 /* Do some CreateDirectoryA tests */
406 /* It would be nice to do test the SECURITY_ATTRIBUTES, but I don't
407    really understand how they work.
408    More formal tests should be done along with CreateFile tests
409 */
410   ok((id=GetTempFileNameA(tmppath,"path",0,newdir)),"GetTempFileNameA failed\n");
411   ok(CreateDirectoryA(newdir,NULL)==0,
412      "CreateDirectoryA succeeded even though a file of the same name exists\n");
413   ok(DeleteFileA(newdir),"Couldn't delete the temporary file we just created\n");
414   ok(CreateDirectoryA(newdir,NULL),"CreateDirectoryA failed\n");
415 /* Create some files to test other functions.  Note, we will test CreateFileA
416    at some later point
417 */
418   sprintf(tmpstr,"%s\\%s",newdir,SHORTDIR);
419   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
420   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
421   ok(CreateDirectoryA(tmpstr,NULL),"CreateDirectoryA failed\n");
422   sprintf(tmpstr,"%c:", *curDrive);
423   bRes = CreateDirectoryA(tmpstr,NULL);
424   ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED  ||
425                GetLastError() == ERROR_ALREADY_EXISTS),
426      "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
427   sprintf(tmpstr,"%c:\\", *curDrive);
428   bRes = CreateDirectoryA(tmpstr,NULL);
429   ok(!bRes && (GetLastError() == ERROR_ACCESS_DENIED  ||
430                GetLastError() == ERROR_ALREADY_EXISTS),
431      "CreateDirectoryA(\"%s\" should have failed (%d)\n", tmpstr, GetLastError());
432   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,SHORTFILE);
433   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
434                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
435   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
436   ok(CloseHandle(hndl),"CloseHandle failed\n");
437   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,LONGFILE);
438   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
439                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
440   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
441   ok(CloseHandle(hndl),"CloseHandle failed\n");
442   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,SHORTFILE);
443   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
444                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
445   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
446   ok(CloseHandle(hndl),"CloseHandle failed\n");
447   sprintf(tmpstr,"%s\\%s\\%s",newdir,LONGDIR,LONGFILE);
448   hndl=CreateFileA(tmpstr,GENERIC_WRITE,0,NULL,
449                    CREATE_NEW,FILE_ATTRIBUTE_NORMAL,NULL);
450   ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed\n");
451   ok(CloseHandle(hndl),"CloseHandle failed\n");
452 }
453 
454 /* Test GetCurrentDirectory & SetCurrentDirectory */
455 static void test_CurrentDirectoryA(CHAR *origdir, CHAR *newdir)
456 {
457   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH];
458   char *buffer;
459   DWORD len,len1;
460 /* Save the original directory, so that we can return to it at the end
461    of the test
462 */
463   len=GetCurrentDirectoryA(MAX_PATH,origdir);
464   ok(len!=0 && len < MAX_PATH,"GetCurrentDirectoryA failed\n");
465 /* Make sure that CetCurrentDirectoryA doesn't overwrite the buffer when the
466    buffer size is too small to hold the current directory
467 */
468   lstrcpyA(tmpstr,"aaaaaaa");
469   len1=GetCurrentDirectoryA(len,tmpstr);
470   ok(len1==len+1, "GetCurrentDirectoryA returned %d instead of %d\n",len1,len+1);
471   ok(lstrcmpiA(tmpstr,"aaaaaaa")==0,
472      "GetCurrentDirectoryA should not have modified the buffer\n");
473 
474   buffer = HeapAlloc( GetProcessHeap(), 0, 2 * 65536 );
475   SetLastError( 0xdeadbeef );
476   strcpy( buffer, "foo" );
477   len = GetCurrentDirectoryA( 32767, buffer );
478   ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
479   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
480   SetLastError( 0xdeadbeef );
481   strcpy( buffer, "foo" );
482   len = GetCurrentDirectoryA( 32768, buffer );
483   ok( len != 0 && len < MAX_PATH, "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
484   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
485   SetLastError( 0xdeadbeef );
486   strcpy( buffer, "foo" );
487   len = GetCurrentDirectoryA( 65535, buffer );
488   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4, win2k, xp */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
489   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
490   SetLastError( 0xdeadbeef );
491   strcpy( buffer, "foo" );
492   len = GetCurrentDirectoryA( 65536, buffer );
493   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
494   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
495   SetLastError( 0xdeadbeef );
496   strcpy( buffer, "foo" );
497   len = GetCurrentDirectoryA( 2 * 65536, buffer );
498   ok( (len != 0 && len < MAX_PATH) || broken(!len), /* nt4 */ "GetCurrentDirectoryA failed %u err %u\n", len, GetLastError() );
499   if (len) ok( !strcmp( buffer, origdir ), "wrong result %s\n", buffer );
500   HeapFree( GetProcessHeap(), 0, buffer );
501 
502 /* Check for crash prevention on swapped args. Crashes all but Win9x.
503 */
504   if (0)
505   {
506       GetCurrentDirectoryA( 42, (LPSTR)(MAX_PATH + 42) );
507   }
508 
509 /* SetCurrentDirectoryA shouldn't care whether the string has a
510    trailing '\\' or not
511 */
512   sprintf(tmpstr,"%s\\",newdir);
513   test_setdir(origdir,tmpstr,newdir,1,"check 1");
514   test_setdir(origdir,newdir,NULL,1,"check 2");
515 /* Set the directory to the working area.  We just tested that this works,
516    so why check it again.
517 */
518   SetCurrentDirectoryA(newdir);
519 /* Check that SetCurrentDirectory fails when a nonexistent dir is specified */
520   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_SHORT);
521   test_setdir(newdir,tmpstr,NULL,0,"check 3");
522 /* Check that SetCurrentDirectory fails for a nonexistent lond directory */
523   sprintf(tmpstr,"%s\\%s\\%s",newdir,SHORTDIR,NONDIR_LONG);
524   test_setdir(newdir,tmpstr,NULL,0,"check 4");
525 /* Check that SetCurrentDirectory passes with a long directory */
526   sprintf(tmpstr,"%s\\%s",newdir,LONGDIR);
527   test_setdir(newdir,tmpstr,NULL,1,"check 5");
528 /* Check that SetCurrentDirectory passes with a short relative directory */
529   sprintf(tmpstr,"%s",SHORTDIR);
530   sprintf(tmpstr1,"%s\\%s",newdir,SHORTDIR);
531   test_setdir(newdir,tmpstr,tmpstr1,1,"check 6");
532 /* starting with a '.' */
533   sprintf(tmpstr,".\\%s",SHORTDIR);
534   test_setdir(newdir,tmpstr,tmpstr1,1,"check 7");
535 /* Check that SetCurrentDirectory passes with a short relative directory */
536   sprintf(tmpstr,"%s",LONGDIR);
537   sprintf(tmpstr1,"%s\\%s",newdir,LONGDIR);
538   test_setdir(newdir,tmpstr,tmpstr1,1,"check 8");
539 /* starting with a '.' */
540   sprintf(tmpstr,".\\%s",LONGDIR);
541   test_setdir(newdir,tmpstr,tmpstr1,1,"check 9");
542 /* change to root without a trailing backslash. The function call succeeds
543    but the directory is not changed.
544 */
545   sprintf(tmpstr, "%c:", newdir[0]);
546   test_setdir(newdir,tmpstr,newdir,1,"check 10");
547 /* works however with a trailing backslash */
548   sprintf(tmpstr, "%c:\\", newdir[0]);
549   test_setdir(newdir,tmpstr,NULL,1,"check 11");
550 }
551 
552 /* Cleanup the mess we made while executing these tests */
553 static void test_CleanupPathA(CHAR *origdir, CHAR *curdir)
554 {
555   CHAR tmpstr[MAX_PATH];
556   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
557   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
558   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,LONGFILE);
559   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
560   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,SHORTFILE);
561   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
562   sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
563   ok(DeleteFileA(tmpstr),"DeleteFileA failed\n");
564   sprintf(tmpstr,"%s\\%s",curdir,SHORTDIR);
565   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
566   sprintf(tmpstr,"%s\\%s",curdir,LONGDIR);
567   ok(RemoveDirectoryA(tmpstr),"RemoveDirectoryA failed\n");
568   ok(SetCurrentDirectoryA(origdir),"SetCurrentDirectoryA failed\n");
569   ok(RemoveDirectoryA(curdir),"RemoveDirectoryA failed\n");
570 }
571 
572 /* test that short path name functions work regardless of case */
573 static void test_ShortPathCase(const char *tmpdir, const char *dirname,
574                                const char *filename)
575 {
576     char buf[MAX_PATH], shortbuf[MAX_PATH];
577     HANDLE hndl;
578     size_t i;
579 
580     assert(strlen(tmpdir) + strlen(dirname) + strlen(filename) + 2 < sizeof(buf));
581     sprintf(buf,"%s\\%s\\%s",tmpdir,dirname,filename);
582     GetShortPathNameA(buf,shortbuf,sizeof(shortbuf));
583     hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
584     ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError());
585     CloseHandle(hndl);
586     /* Now for the real test */
587     for(i=0;i<strlen(shortbuf);i++)
588         if (i % 2)
589             shortbuf[i] = tolower(shortbuf[i]);
590     hndl = CreateFileA(shortbuf,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,0,NULL);
591     ok(hndl!=INVALID_HANDLE_VALUE,"CreateFileA failed (%d)\n",GetLastError());
592     CloseHandle(hndl);
593 }
594 
595 /* This routine will test Get(Full|Short|Long)PathNameA */
596 static void test_PathNameA(CHAR *curdir, CHAR curDrive, CHAR otherDrive)
597 {
598   CHAR curdir_short[MAX_PATH],
599        longdir_short[MAX_PATH];
600   CHAR tmpstr[MAX_PATH],tmpstr1[MAX_PATH],tmpstr2[MAX_PATH];
601   LPSTR strptr;                 /*ptr to the filename portion of the path */
602   DWORD len;
603   INT i;
604   CHAR dir[MAX_PATH],eight[MAX_PATH],three[MAX_PATH];
605   SLpassfail passfail;
606 
607 /* Get the short form of the current directory */
608   ok((len=GetShortPathNameA(curdir,curdir_short,MAX_PATH)),
609      "GetShortPathNameA failed\n");
610   ok(!HAS_TRAIL_SLASH_A(curdir_short),
611      "GetShortPathNameA should not have a trailing \\\n");
612 /* Get the short form of the absolute-path to LONGDIR */
613   sprintf(tmpstr,"%s\\%s",curdir_short,LONGDIR);
614   ok((len=GetShortPathNameA(tmpstr,longdir_short,MAX_PATH)),
615      "GetShortPathNameA failed\n");
616   ok(lstrcmpiA(longdir_short+(len-1),"\\")!=0,
617      "GetShortPathNameA should not have a trailing \\\n");
618 
619   if (pGetLongPathNameA) {
620     DWORD rc1,rc2;
621     sprintf(tmpstr,"%s\\%s\\%s",curdir,LONGDIR,LONGFILE);
622     rc1=(*pGetLongPathNameA)(tmpstr,NULL,0);
623     rc2=(*pGetLongPathNameA)(curdir,NULL,0);
624     ok((rc1-strlen(tmpstr))==(rc2-strlen(curdir)),
625        "GetLongPathNameA: wrong return code, %d instead of %d\n",
626        rc1, lstrlenA(tmpstr)+1);
627 
628     sprintf(dir,"%c:",curDrive);
629     rc1=(*pGetLongPathNameA)(dir,tmpstr,sizeof(tmpstr));
630     ok(strcmp(dir,tmpstr)==0,
631        "GetLongPathNameA: returned '%s' instead of '%s' (rc=%d)\n",
632        tmpstr,dir,rc1);
633   }
634 
635 /* Check the cases where both file and directory exist first */
636 /* Start with a 8.3 directory, 8.3 filename */
637   test_ValidPathA(curdir,SHORTDIR,SHORTFILE,tmpstr,NULL,"test1");
638   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,SHORTFILE);
639   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
640      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
641 /* Now try a 8.3 directory, long file name */
642   test_ValidPathA(curdir,SHORTDIR,LONGFILE,tmpstr,NULL,"test2");
643   sprintf(tmpstr1,"%s\\%s",curdir_short,SHORTDIR);
644   test_LongtoShortA(tmpstr,tmpstr1,"PAT","test2");
645 /* Next is a long directory, 8.3 file */
646   test_ValidPathA(curdir,LONGDIR,SHORTFILE,tmpstr,NULL,"test3");
647   sprintf(tmpstr1,"%s\\%s",longdir_short,SHORTFILE);
648   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
649      "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr,tmpstr1);
650 /*Lastly a long directory, long file */
651   test_ValidPathA(curdir,LONGDIR,LONGFILE,tmpstr,NULL,"test4");
652   test_LongtoShortA(tmpstr,longdir_short,"PAT","test4");
653 
654 /* Now check all of the invalid file w/ valid directory combinations */
655 /* Start with a 8.3 directory, 8.3 filename */
656   test_ValidPathA(curdir,SHORTDIR,NONFILE_SHORT,tmpstr,&passfail,"test5");
657   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,SHORTDIR,NONFILE_SHORT);
658   ok((passfail.shortlen==0 &&
659       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
660        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
661      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
662      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
663      passfail.shortlen,passfail.shorterror,tmpstr);
664   if(pGetLongPathNameA) {
665     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
666     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
667        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
668   }
669 /* Now try a 8.3 directory, long file name */
670   test_ValidPathA(curdir,SHORTDIR,NONFILE_LONG,tmpstr,&passfail,"test6");
671   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
672   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
673      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
674      !passfail.shorterror,
675      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
676   if(pGetLongPathNameA) {
677     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
678     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
679        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
680   }
681 /* Next is a long directory, 8.3 file */
682   test_ValidPathA(curdir,LONGDIR,NONFILE_SHORT,tmpstr,&passfail,"test7");
683   sprintf(tmpstr2,"%s\\%s",curdir_short,LONGDIR);
684   GetShortPathNameA(tmpstr2,tmpstr1,MAX_PATH);
685   strcat(tmpstr1,"\\" NONFILE_SHORT);
686   ok((passfail.shortlen==0 &&
687       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
688        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
689      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
690      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
691      passfail.shortlen,passfail.shorterror,tmpstr);
692   if(pGetLongPathNameA) {
693     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
694     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
695       "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
696   }
697 /*Lastly a long directory, long file */
698   test_ValidPathA(curdir,LONGDIR,NONFILE_LONG,tmpstr,&passfail,"test8");
699   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
700   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
701      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
702      !passfail.shorterror,
703      "GetShortPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
704   if(pGetLongPathNameA) {
705     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
706     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
707        "GetlongPathA should have returned 'ERROR_FILE_NOT_FOUND'\n");
708   }
709 /* Now try again with directories that don't exist */
710 /* 8.3 directory, 8.3 filename */
711   test_ValidPathA(curdir,NONDIR_SHORT,SHORTFILE,tmpstr,&passfail,"test9");
712   sprintf(tmpstr1,"%s\\%s\\%s",curdir_short,NONDIR_SHORT,SHORTFILE);
713   ok((passfail.shortlen==0 &&
714       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
715        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
716      (passfail.shortlen==strlen(tmpstr1) && lstrcmpiA(tmpstr,tmpstr1)==0),
717      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
718      passfail.shortlen,passfail.shorterror,tmpstr);
719   if(pGetLongPathNameA) {
720     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
721     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
722        passfail.longerror==ERROR_FILE_NOT_FOUND,
723        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
724        passfail.longerror);
725   }
726 /* Now try a 8.3 directory, long file name */
727   test_ValidPathA(curdir,NONDIR_SHORT,LONGFILE,tmpstr,&passfail,"test10");
728   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
729   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
730      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
731      !passfail.shorterror,
732      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
733       passfail.shorterror);
734   if(pGetLongPathNameA) {
735     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
736     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
737        passfail.longerror==ERROR_FILE_NOT_FOUND,
738        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
739        passfail.longerror);
740   }
741 /* Next is a long directory, 8.3 file */
742   test_ValidPathA(curdir,NONDIR_LONG,SHORTFILE,tmpstr,&passfail,"test11");
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_PATH_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_PATH_NOT_FOUND ||
752        passfail.longerror==ERROR_FILE_NOT_FOUND,
753        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
754        passfail.longerror);
755   }
756 /*Lastly a long directory, long file */
757   test_ValidPathA(curdir,NONDIR_LONG,LONGFILE,tmpstr,&passfail,"test12");
758   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
759   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
760      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
761      !passfail.shorterror,
762      "GetShortPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
763       passfail.shorterror);
764   if(pGetLongPathNameA) {
765     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
766     ok(passfail.longerror==ERROR_PATH_NOT_FOUND ||
767        passfail.longerror==ERROR_FILE_NOT_FOUND,
768        "GetLongPathA returned %d and not 'ERROR_PATH_NOT_FOUND'\n",
769        passfail.longerror);
770   }
771 /* Next try directories ending with '\\' */
772 /* Existing Directories */
773   sprintf(tmpstr,"%s\\",SHORTDIR);
774   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test13");
775   sprintf(tmpstr,"%s\\",LONGDIR);
776   test_ValidPathA(curdir,"",tmpstr,tmpstr1,NULL,"test14");
777 /* Nonexistent directories */
778   sprintf(tmpstr,"%s\\",NONDIR_SHORT);
779   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test15");
780   sprintf(tmpstr2,"%s\\%s",curdir_short,tmpstr);
781   ok((passfail.shortlen==0 &&
782       (passfail.shorterror==ERROR_PATH_NOT_FOUND ||
783        passfail.shorterror==ERROR_FILE_NOT_FOUND)) ||
784      (passfail.shortlen==strlen(tmpstr2) && lstrcmpiA(tmpstr1,tmpstr2)==0),
785      "GetShortPathNameA error: len=%d error=%d tmpstr=[%s]\n",
786      passfail.shortlen,passfail.shorterror,tmpstr);
787   if(pGetLongPathNameA) {
788     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
789     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
790        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
791        passfail.longerror);
792   }
793   sprintf(tmpstr,"%s\\",NONDIR_LONG);
794   test_ValidPathA(curdir,"",tmpstr,tmpstr1,&passfail,"test16");
795   ok(passfail.shortlen==0,"GetShortPathNameA passed when it shouldn't have\n");
796   ok(passfail.shorterror==ERROR_PATH_NOT_FOUND ||
797      passfail.shorterror==ERROR_FILE_NOT_FOUND ||
798      !passfail.shorterror,
799      "GetShortPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
800       passfail.shorterror);
801   if(pGetLongPathNameA) {
802     ok(passfail.longlen==0,"GetLongPathNameA passed when it shouldn't have\n");
803     ok(passfail.longerror==ERROR_FILE_NOT_FOUND,
804        "GetLongPathA returned %d and not 'ERROR_FILE_NOT_FOUND'\n",
805        passfail.longerror);
806   }
807 /* Test GetFullPathNameA with drive letters */
808   if( curDrive != NOT_A_VALID_DRIVE) {
809     sprintf(tmpstr,"%c:",curdir[0]);
810     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr2,&strptr),
811        "GetFullPathNameA(%c:) failed\n", curdir[0]);
812     GetCurrentDirectoryA(MAX_PATH,tmpstr);
813     sprintf(tmpstr1,"%s\\",tmpstr);
814     ok(lstrcmpiA(tmpstr,tmpstr2)==0 || lstrcmpiA(tmpstr1,tmpstr2)==0,
815        "GetFullPathNameA(%c:) returned '%s' instead of '%s' or '%s'\n",
816        curdir[0],tmpstr2,tmpstr,tmpstr1);
817 
818     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
819     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
820     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
821        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
822     ok(lstrcmpiA(SHORTFILE,strptr)==0,
823        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
824   }
825 /* Without a leading slash, insert the current directory if on the current drive */
826   sprintf(tmpstr,"%c:%s\\%s",curdir[0],SHORTDIR,SHORTFILE);
827   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
828   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
829   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
830       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
831   ok(lstrcmpiA(SHORTFILE,strptr)==0,
832       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
833 /* Otherwise insert the missing leading slash */
834   if( otherDrive != NOT_A_VALID_DRIVE) {
835     /* FIXME: this test assumes that current directory on other drive is root */
836     sprintf(tmpstr,"%c:%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
837     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed for %s\n", tmpstr);
838     sprintf(tmpstr,"%c:\\%s\\%s",otherDrive,SHORTDIR,SHORTFILE);
839     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
840        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
841     ok(lstrcmpiA(SHORTFILE,strptr)==0,
842        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
843   }
844 /* Xilinx tools like to mix Unix and DOS formats, which Windows handles fine.
845    So test for them. */
846   if( curDrive != NOT_A_VALID_DRIVE) {
847     sprintf(tmpstr,"%c:/%s\\%s",curDrive,SHORTDIR,SHORTFILE);
848     ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
849     sprintf(tmpstr,"%c:\\%s\\%s",curDrive,SHORTDIR,SHORTFILE);
850     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
851        "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
852     ok(lstrcmpiA(SHORTFILE,strptr)==0,
853        "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
854   }
855   /* Don't Starve relies on GetLongPathName returning the passed in filename,
856      even if the actual file on disk has a different case or separator */
857   if (pGetLongPathNameA) {
858     int len = lstrlenA(LONGDIR) + 1;
859     sprintf(tmpstr,"%s/%s",LONGDIR,LONGFILE);
860     ok(GetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
861     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
862        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
863     tmpstr[len] = tolower(tmpstr[len]);
864     ok(GetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
865     ok(lstrcmpA(tmpstr,tmpstr1)==0,
866        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
867     sprintf(tmpstr,"%s/%s",SHORTDIR,SHORTFILE);
868     ok(GetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
869     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
870        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
871     len = lstrlenA(SHORTDIR) + 1;
872     tmpstr[len] = toupper(tmpstr[len]);
873     ok(GetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
874     ok(lstrcmpiA(tmpstr,tmpstr1)==0 && lstrcmpA(tmpstr,tmpstr1) != 0,
875        "GetLongPathNameA returned '%s' instead of '%s/%s'\n",tmpstr1,SHORTDIR,SHORTFILE);
876   }
877   sprintf(tmpstr,"%s/%s",SHORTDIR,SHORTFILE);
878   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
879   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
880        "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
881 
882 /**/
883   sprintf(tmpstr,"%c:%s/%s",curdir[0],SHORTDIR,SHORTFILE);
884   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
885   sprintf(tmpstr,"%s\\%s\\%s",curdir,SHORTDIR,SHORTFILE);
886   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
887       "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
888   ok(lstrcmpiA(SHORTFILE,strptr)==0,
889       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
890 /* Windows will insert a drive letter in front of an absolute UNIX path */
891   sprintf(tmpstr,"/%s/%s",SHORTDIR,SHORTFILE);
892   ok(GetFullPathNameA(tmpstr,MAX_PATH,tmpstr1,&strptr),"GetFullPathNameA failed\n");
893   sprintf(tmpstr,"%c:\\%s\\%s",*tmpstr1,SHORTDIR,SHORTFILE);
894   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
895      "GetFullPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
896 /* This passes in Wine because it still contains the pointer from the previous test */
897   ok(lstrcmpiA(SHORTFILE,strptr)==0,
898       "GetFullPathNameA returned part '%s' instead of '%s'\n",strptr,SHORTFILE);
899 
900 /* Now try some relative paths */
901   ok(GetShortPathNameA(LONGDIR,tmpstr,MAX_PATH),"GetShortPathNameA failed\n");
902   test_SplitShortPathA(tmpstr,dir,eight,three);
903   if(pGetLongPathNameA) {
904     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
905     ok(lstrcmpiA(tmpstr1,LONGDIR)==0,
906        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,LONGDIR);
907   }
908   sprintf(tmpstr,".\\%s",LONGDIR);
909   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
910   test_SplitShortPathA(tmpstr1,dir,eight,three);
911   ok(lstrcmpiA(dir,".")==0 || dir[0]=='\0',
912      "GetShortPathNameA did not keep relative directory [%s]\n",tmpstr1);
913   if(pGetLongPathNameA) {
914     ok(pGetLongPathNameA(tmpstr1,tmpstr1,MAX_PATH),"GetLongPathNameA failed %s\n",
915        tmpstr);
916     ok(lstrcmpiA(tmpstr1,tmpstr)==0,
917        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
918   }
919 /* Check out Get*PathNameA on some funny characters */
920   for(i=0;i<lstrlenA(funny_chars);i++) {
921     INT valid;
922     valid=(is_char_ok[i]=='0') ? 0 : 1;
923     sprintf(tmpstr1,"check%d-1",i);
924     sprintf(tmpstr,"file%c000.ext",funny_chars[i]);
925     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
926     sprintf(tmpstr1,"check%d-2",i);
927     sprintf(tmpstr,"file000.e%ct",funny_chars[i]);
928     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
929     sprintf(tmpstr1,"check%d-3",i);
930     sprintf(tmpstr,"%cfile000.ext",funny_chars[i]);
931     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
932     sprintf(tmpstr1,"check%d-4",i);
933     sprintf(tmpstr,"file000%c.ext",funny_chars[i]);
934     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
935     sprintf(tmpstr1,"check%d-5",i);
936     sprintf(tmpstr,"Long %c File",funny_chars[i]);
937     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
938     sprintf(tmpstr1,"check%d-6",i);
939     sprintf(tmpstr,"%c Long File",funny_chars[i]);
940     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
941     sprintf(tmpstr1,"check%d-7",i);
942     sprintf(tmpstr,"Long File %c",funny_chars[i]);
943     test_FunnyChars(curdir,curdir_short,tmpstr,valid,tmpstr1);
944   }
945   /* Now try it on mixed case short names */
946   test_ShortPathCase(curdir,SHORTDIR,LONGFILE);
947   test_ShortPathCase(curdir,LONGDIR,SHORTFILE);
948   test_ShortPathCase(curdir,LONGDIR,LONGFILE);
949 
950   /* test double delimiters */
951   sprintf(tmpstr,"%s\\\\%s", SHORTDIR,SHORTFILE);
952   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
953   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
954        "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
955   sprintf(tmpstr,".\\\\%s\\\\%s", SHORTDIR,SHORTFILE);
956   ok(GetShortPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetShortPathNameA failed\n");
957   ok(lstrcmpiA(tmpstr,tmpstr1)==0,
958        "GetShortPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
959 
960   if (pGetLongPathNameA) {
961     sprintf(tmpstr,"%s\\\\%s",LONGDIR,LONGFILE);
962     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
963     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
964         "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
965 
966     sprintf(tmpstr,".\\\\%s\\\\%s",LONGDIR,LONGFILE);
967     ok(pGetLongPathNameA(tmpstr,tmpstr1,MAX_PATH),"GetLongPathNameA failed\n");
968     ok(lstrcmpiA(tmpstr,tmpstr1)==0,
969        "GetLongPathNameA returned '%s' instead of '%s'\n",tmpstr1,tmpstr);
970   }
971 }
972 
973 static void test_GetTempPathA(char* tmp_dir)
974 {
975     DWORD len, slen, len_with_null;
976     char buf[MAX_PATH];
977 
978     len_with_null = strlen(tmp_dir) + 1;
979 
980     lstrcpyA(buf, "foo");
981     len = GetTempPathA(MAX_PATH, buf);
982     ok(len <= MAX_PATH, "should fit into MAX_PATH\n");
983     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
984     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
985 
986     /* Some versions of Windows touch the buffer, some don't so we don't
987      * test that. Also, NT sometimes exaggerates the required buffer size
988      * so we cannot test for an exact match. Finally, the
989      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
990      * For instance in some cases Win98 returns len_with_null - 1 instead
991      * of len_with_null.
992      */
993     len = GetTempPathA(1, buf);
994     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
995 
996     len = GetTempPathA(0, NULL);
997     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
998 
999     /* The call above gave us the buffer size that Windows thinks is needed
1000      * so the next call should work
1001      */
1002     lstrcpyA(buf, "foo");
1003     len = GetTempPathA(len, buf);
1004     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
1005     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
1006 
1007     memset(buf, 'a', sizeof(buf));
1008     len = GetTempPathA(sizeof(buf), buf);
1009     ok(lstrcmpiA(buf, tmp_dir) == 0, "expected [%s], got [%s]\n",tmp_dir,buf);
1010     ok(len == strlen(buf), "returned length should be equal to the length of string\n");
1011     /* The rest of the buffer remains untouched */
1012     slen = len + 1;
1013     for(len++; len < sizeof(buf); len++)
1014         ok(buf[len] == 'a', "expected 'a' at [%d], got 0x%x\n", len, buf[len]);
1015 
1016     /* When the buffer is not long enough it remains untouched */
1017     memset(buf, 'a', sizeof(buf));
1018     len = GetTempPathA(slen / 2, buf);
1019     ok(len == slen || broken(len == slen + 1) /* read the big comment above */ ,
1020        "expected %d, got %d\n", slen, len);
1021     for(len = 0; len < sizeof(buf) / sizeof(buf[0]); len++)
1022         ok(buf[len] == 'a', "expected 'a' at [%d], got 0x%x\n", len, buf[len]);
1023 }
1024 
1025 static void test_GetTempPathW(char* tmp_dir)
1026 {
1027     DWORD len, slen, len_with_null;
1028     WCHAR buf[MAX_PATH], *long_buf;
1029     WCHAR tmp_dirW[MAX_PATH];
1030     static const WCHAR fooW[] = {'f','o','o',0};
1031 
1032     MultiByteToWideChar(CP_ACP,0,tmp_dir,-1,tmp_dirW,sizeof(tmp_dirW)/sizeof(*tmp_dirW));
1033     len_with_null = lstrlenW(tmp_dirW) + 1;
1034 
1035     /* This one is different from ANSI version: ANSI version doesn't
1036      * touch the buffer, unicode version usually truncates the buffer
1037      * to zero size. NT still exaggerates the required buffer size
1038      * sometimes so we cannot test for an exact match. Finally, the
1039      * 'len_with_null - 1' case is so buggy on Windows it's not testable.
1040      * For instance on NT4 it will sometimes return a path without the
1041      * trailing '\\' and sometimes return an error.
1042      */
1043 
1044     lstrcpyW(buf, fooW);
1045     len = GetTempPathW(MAX_PATH, buf);
1046     if (len == 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1047     {
1048         win_skip("GetTempPathW is not available\n");
1049         return;
1050     }
1051     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
1052     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
1053 
1054     lstrcpyW(buf, fooW);
1055     len = GetTempPathW(1, buf);
1056     ok(buf[0] == 0, "unicode version should truncate the buffer to zero size\n");
1057     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
1058 
1059     len = GetTempPathW(0, NULL);
1060     ok(len >= len_with_null, "Expected >= %u, got %u\n", len_with_null, len);
1061 
1062     lstrcpyW(buf, fooW);
1063     len = GetTempPathW(len, buf);
1064     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
1065     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
1066 
1067     for(len = 0; len < sizeof(buf) / sizeof(buf[0]); len++)
1068         buf[len] = 'a';
1069     len = GetTempPathW(len, buf);
1070     ok(lstrcmpiW(buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
1071     ok(len == lstrlenW(buf), "returned length should be equal to the length of string\n");
1072     /* The rest of the buffer must be zeroed */
1073     slen = len + 1;
1074     for(len++; len < sizeof(buf) / sizeof(buf[0]); len++)
1075         ok(buf[len] == '\0', "expected NULL at [%d], got 0x%x\n", len, buf[len]);
1076 
1077     /* When the buffer is not long enough the length passed is zeroed */
1078     for(len = 0; len < sizeof(buf) / sizeof(buf[0]); len++)
1079         buf[len] = 'a';
1080     len = GetTempPathW(slen / 2, buf);
1081     ok(len == slen || broken(len == slen + 1) /* read the big comment above */ ,
1082        "expected %d, got %d\n", slen, len);
1083 
1084     {
1085         /* In Windows 8 when TMP var points to a drive only (like C:) instead of a
1086         * full directory the behavior changes. It will start filling the path but
1087         * will later truncate the buffer before returning. So the generic test
1088         * below will fail for this Windows 8 corner case.
1089         */
1090         char tmp_var[64];
1091         DWORD version = GetVersion();
1092         GetEnvironmentVariableA("TMP", tmp_var, sizeof(tmp_var));
1093         if (strlen(tmp_var) == 2 && version >= 0x00060002)
1094             return;
1095     }
1096 
1097     for(len = 0; len < slen / 2; len++)
1098         ok(buf[len] == '\0', "expected NULL at [%d], got 0x%x\n", len, buf[len]);
1099     for(; len < sizeof(buf) / sizeof(buf[0]); len++)
1100         ok(buf[len] == 'a', "expected 'a' at [%d], got 0x%x\n", len, buf[len]);
1101 
1102     /* bogus application from bug 38220 passes the count value in sizeof(buffer)
1103      * instead the correct count of WCHAR, this test catches this case. */
1104     slen = 65534;
1105     long_buf = HeapAlloc(GetProcessHeap(), 0, slen * sizeof(WCHAR));
1106     if (!long_buf)
1107     {
1108         skip("Could not allocate memory for the test\n");
1109         return;
1110     }
1111     for(len = 0; len < slen; len++)
1112         long_buf[len] = 0xCC;
1113     len = GetTempPathW(slen, long_buf);
1114     ok(lstrcmpiW(long_buf, tmp_dirW) == 0, "GetTempPathW returned an incorrect temporary path\n");
1115     ok(len == lstrlenW(long_buf), "returned length should be equal to the length of string\n");
1116     /* the remaining buffer must be zeroed up to different values in different OS versions.
1117      * <= XP - 32766
1118      *  > XP - 32767
1119      * to simplify testing we will test only until XP.
1120      */
1121     for(; len < 32767; len++)
1122         ok(long_buf[len] == '\0', "expected NULL at [%d], got 0x%x\n", len, long_buf[len]);
1123     /* we will know skip the test that is in the middle of the OS difference by
1124      * incrementing len and then resume the test for the untouched part. */
1125     for(len++; len < slen; len++)
1126         ok(long_buf[len] == 0xcc, "expected 0xcc at [%d], got 0x%x\n", len, long_buf[len]);
1127 
1128     HeapFree(GetProcessHeap(), 0, long_buf);
1129 }
1130 
1131 static void test_GetTempPath(void)
1132 {
1133     char save_TMP[MAX_PATH];
1134     char windir[MAX_PATH];
1135     char buf[MAX_PATH];
1136     WCHAR curdir[MAX_PATH];
1137 
1138     if (!GetEnvironmentVariableA("TMP", save_TMP, sizeof(save_TMP))) save_TMP[0] = 0;
1139 
1140     /* test default configuration */
1141     trace("TMP=%s\n", save_TMP);
1142     if (save_TMP[0])
1143     {
1144         strcpy(buf,save_TMP);
1145         if (buf[strlen(buf)-1]!='\\')
1146             strcat(buf,"\\");
1147         test_GetTempPathA(buf);
1148         test_GetTempPathW(buf);
1149     }
1150 
1151     /* TMP=C:\WINDOWS */
1152     GetWindowsDirectoryA(windir, sizeof(windir));
1153     SetEnvironmentVariableA("TMP", windir);
1154     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1155     trace("TMP=%s\n", buf);
1156     strcat(windir,"\\");
1157     test_GetTempPathA(windir);
1158     test_GetTempPathW(windir);
1159 
1160     /* TMP=C:\ */
1161     GetWindowsDirectoryA(windir, sizeof(windir));
1162     windir[3] = 0;
1163     SetEnvironmentVariableA("TMP", windir);
1164     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1165     trace("TMP=%s\n", buf);
1166     test_GetTempPathA(windir);
1167     test_GetTempPathW(windir);
1168 
1169     GetCurrentDirectoryW(MAX_PATH, curdir);
1170     /* TMP=C: i.e. use current working directory of the specified drive */
1171     GetWindowsDirectoryA(windir, sizeof(windir));
1172     SetCurrentDirectoryA(windir);
1173     windir[2] = 0;
1174     SetEnvironmentVariableA("TMP", windir);
1175     GetEnvironmentVariableA("TMP", buf, sizeof(buf));
1176     trace("TMP=%s\n", buf);
1177     GetWindowsDirectoryA(windir, sizeof(windir));
1178     strcat(windir,"\\");
1179     test_GetTempPathA(windir);
1180     test_GetTempPathW(windir);
1181 
1182     SetEnvironmentVariableA("TMP", save_TMP);
1183     SetCurrentDirectoryW(curdir);
1184 }
1185 
1186 static void test_GetLongPathNameA(void)
1187 {
1188     DWORD length, explength, hostsize;
1189     char tempfile[MAX_PATH], *name;
1190     char longpath[MAX_PATH];
1191     char unc_prefix[MAX_PATH];
1192     char unc_short[MAX_PATH], unc_long[MAX_PATH];
1193     char temppath[MAX_PATH], temppath2[MAX_PATH];
1194     HANDLE file;
1195 
1196     if (!pGetLongPathNameA)
1197         return;
1198 
1199     GetTempPathA(MAX_PATH, tempfile);
1200     name = tempfile + strlen(tempfile);
1201 
1202     strcpy(name, "*");
1203     SetLastError(0xdeadbeef);
1204     length = pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1205     ok(!length, "GetLongPathNameA should fail\n");
1206     ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %d\n", GetLastError());
1207 
1208     strcpy(name, "longfilename.longext");
1209 
1210     file = CreateFileA(tempfile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1211     CloseHandle(file);
1212 
1213     /* Test a normal path with a small buffer size */
1214     memset(temppath, 0, MAX_PATH);
1215     length = pGetLongPathNameA(tempfile, temppath, 4);
1216     /* We have a failure so length should be the minimum plus the terminating '0'  */
1217     ok(length >= strlen(tempfile) + 1, "Wrong length\n");
1218     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1219 
1220     /* Some UNC syntax tests */
1221 
1222     memset(temppath, 0, MAX_PATH);
1223     memset(temppath2, 0, MAX_PATH);
1224     lstrcpyA(temppath2, "\\\\?\\");
1225     lstrcatA(temppath2, tempfile);
1226     explength = length + 4;
1227 
1228     SetLastError(0xdeadbeef);
1229     length = pGetLongPathNameA(temppath2, NULL, 0);
1230     if (length == 0 && GetLastError() == ERROR_BAD_NET_NAME)
1231     {
1232         win_skip("UNC syntax tests don't work on Win98/WinMe\n");
1233         DeleteFileA(tempfile);
1234         return;
1235     }
1236     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1237 
1238     length = pGetLongPathNameA(temppath2, NULL, MAX_PATH);
1239     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1240 
1241     length = pGetLongPathNameA(temppath2, temppath, 4);
1242     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1243     ok(temppath[0] == 0, "Buffer should not have been touched\n");
1244 
1245     /* Now an UNC path with the computername */
1246     lstrcpyA(unc_prefix, "\\\\");
1247     hostsize = sizeof(unc_prefix) - 2;
1248     GetComputerNameA(unc_prefix + 2, &hostsize);
1249     lstrcatA(unc_prefix, "\\");
1250 
1251     /* Create a short syntax for the whole unc path */
1252     memset(unc_short, 0, MAX_PATH);
1253     GetShortPathNameA(tempfile, temppath, MAX_PATH);
1254     lstrcpyA(unc_short, unc_prefix);
1255     unc_short[lstrlenA(unc_short)] = temppath[0];
1256     lstrcatA(unc_short, "$\\");
1257     lstrcatA(unc_short, strchr(temppath, '\\') + 1);
1258 
1259     /* Create a long syntax for reference */
1260     memset(longpath, 0, MAX_PATH);
1261     pGetLongPathNameA(tempfile, temppath, MAX_PATH);
1262     lstrcpyA(longpath, unc_prefix);
1263     longpath[lstrlenA(longpath)] = temppath[0];
1264     lstrcatA(longpath, "$\\");
1265     lstrcatA(longpath, strchr(temppath, '\\') + 1);
1266 
1267     /* NULL test */
1268     SetLastError(0xdeadbeef);
1269     length = pGetLongPathNameA(unc_short, NULL, 0);
1270     if (length == 0 && GetLastError() == ERROR_BAD_NETPATH)
1271     {
1272         /* Seen on Window XP Home */
1273         win_skip("UNC with computername is not supported\n");
1274         DeleteFileA(tempfile);
1275         return;
1276     }
1277     explength = lstrlenA(longpath) + 1;
1278     todo_wine
1279     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1280 
1281     length = pGetLongPathNameA(unc_short, NULL, MAX_PATH);
1282     todo_wine
1283     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1284 
1285     memset(unc_long, 0, MAX_PATH);
1286     length = pGetLongPathNameA(unc_short, unc_long, lstrlenA(unc_short));
1287     /* length will include terminating '0' on failure */
1288     todo_wine
1289     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1290     ok(unc_long[0] == 0, "Buffer should not have been touched\n");
1291 
1292     memset(unc_long, 0, MAX_PATH);
1293     length = pGetLongPathNameA(unc_short, unc_long, length);
1294     /* length doesn't include terminating '0' on success */
1295     explength--;
1296     todo_wine
1297     {
1298     ok(length == explength, "Wrong length %d, expected %d\n", length, explength);
1299     ok(!lstrcmpiA(unc_long, longpath), "Expected (%s), got (%s)\n", longpath, unc_long);
1300     }
1301 
1302     DeleteFileA(tempfile);
1303 }
1304 
1305 static void test_GetLongPathNameW(void)
1306 {
1307     DWORD length, expanded;
1308     BOOL ret;
1309     HANDLE file;
1310     WCHAR empty[MAX_PATH];
1311     WCHAR tempdir[MAX_PATH], name[200];
1312     WCHAR dirpath[4 + MAX_PATH + 200]; /* To ease removal */
1313     WCHAR shortpath[4 + MAX_PATH + 200 + 1 + 200];
1314     static const WCHAR prefix[] = { '\\','\\','?','\\', 0};
1315     static const WCHAR backslash[] = { '\\', 0};
1316     static const WCHAR letterX[] = { 'X', 0};
1317 
1318     if (!pGetLongPathNameW)
1319         return;
1320 
1321     SetLastError(0xdeadbeef);
1322     length = pGetLongPathNameW(NULL,NULL,0);
1323     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1324     {
1325         win_skip("GetLongPathNameW is not implemented\n");
1326         return;
1327     }
1328     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1329     ok(GetLastError()==ERROR_INVALID_PARAMETER,"GetLastError returned %d but expected ERROR_INVALID_PARAMETER\n",GetLastError());
1330 
1331     SetLastError(0xdeadbeef);
1332     empty[0]=0;
1333     length = pGetLongPathNameW(empty,NULL,0);
1334     ok(0==length,"GetLongPathNameW returned %d but expected 0\n",length);
1335     ok(GetLastError()==ERROR_PATH_NOT_FOUND,"GetLastError returned %d but expected ERROR_PATH_NOT_FOUND\n",GetLastError());
1336 
1337     /* Create a long path name. The path needs to exist for these tests to
1338      * succeed so we need the "\\?\" prefix when creating directories and
1339      * files.
1340      */
1341     name[0] = 0;
1342     while (lstrlenW(name) < (sizeof(name)/sizeof(WCHAR) - 1))
1343         lstrcatW(name, letterX);
1344 
1345     GetTempPathW(MAX_PATH, tempdir);
1346 
1347     lstrcpyW(shortpath, prefix);
1348     lstrcatW(shortpath, tempdir);
1349     lstrcatW(shortpath, name);
1350     lstrcpyW(dirpath, shortpath);
1351     ret = CreateDirectoryW(shortpath, NULL);
1352     ok(ret, "Could not create the temporary directory : %d\n", GetLastError());
1353     lstrcatW(shortpath, backslash);
1354     lstrcatW(shortpath, name);
1355 
1356     /* Path does not exist yet and we know it overruns MAX_PATH */
1357 
1358     /* No prefix */
1359     SetLastError(0xdeadbeef);
1360     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1361     ok(length == 0, "Expected 0, got %d\n", length);
1362     todo_wine
1363     ok(GetLastError() == ERROR_PATH_NOT_FOUND,
1364        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1365     /* With prefix */
1366     SetLastError(0xdeadbeef);
1367     length = pGetLongPathNameW(shortpath, NULL, 0);
1368     todo_wine
1369     {
1370     ok(length == 0, "Expected 0, got %d\n", length);
1371     ok(GetLastError() == ERROR_FILE_NOT_FOUND,
1372        "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1373     }
1374 
1375     file = CreateFileW(shortpath, GENERIC_READ|GENERIC_WRITE, 0, NULL,
1376                        CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1377     ok(file != INVALID_HANDLE_VALUE,
1378        "Could not create the temporary file : %d.\n", GetLastError());
1379     CloseHandle(file);
1380 
1381     /* Path exists */
1382 
1383     /* No prefix */
1384     SetLastError(0xdeadbeef);
1385     length = pGetLongPathNameW(shortpath + 4, NULL, 0);
1386     todo_wine
1387     {
1388     ok(length == 0, "Expected 0, got %d\n", length);
1389     ok(GetLastError() == ERROR_PATH_NOT_FOUND, "Expected ERROR_PATH_NOT_FOUND, got %d\n", GetLastError());
1390     }
1391     /* With prefix */
1392     expanded = 4 + (pGetLongPathNameW(tempdir, NULL, 0) - 1) + lstrlenW(name) + 1 + lstrlenW(name) + 1;
1393     SetLastError(0xdeadbeef);
1394     length = pGetLongPathNameW(shortpath, NULL, 0);
1395     ok(length == expanded, "Expected %d, got %d\n", expanded, length);
1396 
1397     /* NULL buffer with length crashes on Windows */
1398     if (0)
1399         pGetLongPathNameW(shortpath, NULL, 20);
1400 
1401     ok(DeleteFileW(shortpath), "Could not delete temporary file\n");
1402     ok(RemoveDirectoryW(dirpath), "Could not delete temporary directory\n");
1403 }
1404 
1405 static void test_GetShortPathNameW(void)
1406 {
1407     static const WCHAR extended_prefix[] = {'\\','\\','?','\\',0};
1408     static const WCHAR test_path[] = { 'L', 'o', 'n', 'g', 'D', 'i', 'r', 'e', 'c', 't', 'o', 'r', 'y', 'N', 'a', 'm', 'e',  0 };
1409     static const WCHAR name[] = { 't', 'e', 's', 't', 0 };
1410     static const WCHAR backSlash[] = { '\\', 0 };
1411     static const WCHAR a_bcdeW[] = {'a','.','b','c','d','e',0};
1412     static const WCHAR wildW[] = { '*',0 };
1413     WCHAR path[MAX_PATH], tmppath[MAX_PATH], *ptr;
1414     WCHAR short_path[MAX_PATH];
1415     DWORD length;
1416     HANDLE file;
1417     int ret;
1418 
1419     SetLastError(0xdeadbeef);
1420     GetTempPathW( MAX_PATH, tmppath );
1421     if (GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
1422     {
1423         win_skip("GetTempPathW is not implemented\n");
1424         return;
1425     }
1426 
1427     lstrcpyW( path, tmppath );
1428     lstrcatW( path, test_path );
1429     lstrcatW( path, backSlash );
1430     ret = CreateDirectoryW( path, NULL );
1431     ok( ret, "Directory was not created. LastError = %d\n", GetLastError() );
1432 
1433     /* Starting a main part of test */
1434 
1435     /* extended path \\?\C:\path\ */
1436     lstrcpyW( path, extended_prefix );
1437     lstrcatW( path, tmppath );
1438     lstrcatW( path, test_path );
1439     lstrcatW( path, backSlash );
1440     short_path[0] = 0;
1441     length = GetShortPathNameW( path, short_path, sizeof(short_path) / sizeof(*short_path) );
1442     ok( length, "GetShortPathNameW returned 0.\n" );
1443 
1444     lstrcpyW( path, tmppath );
1445     lstrcatW( path, test_path );
1446     lstrcatW( path, backSlash );
1447     length = GetShortPathNameW( path, short_path, 0 );
1448     ok( length, "GetShortPathNameW returned 0.\n" );
1449     ret = GetShortPathNameW( path, short_path, length );
1450     ok( ret && ret == length-1, "GetShortPathNameW returned 0.\n" );
1451 
1452     lstrcatW( short_path, name );
1453 
1454     /* GetShortPathName for a non-existent short file name should fail */
1455     SetLastError(0xdeadbeef);
1456     length = GetShortPathNameW( short_path, path, 0 );
1457     ok(!length, "GetShortPathNameW should fail\n");
1458     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "expected ERROR_FILE_NOT_FOUND, got %d\n", GetLastError());
1459 
1460     file = CreateFileW( short_path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1461     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1462     CloseHandle( file );
1463     ret = DeleteFileW( short_path );
1464     ok( ret, "Cannot delete file.\n" );
1465 
1466     ptr = path + lstrlenW(path);
1467     lstrcpyW( ptr, a_bcdeW);
1468     file = CreateFileW( path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
1469     ok( file != INVALID_HANDLE_VALUE, "File was not created.\n" );
1470     CloseHandle( file );
1471 
1472     length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) );
1473     ok( length, "GetShortPathNameW failed: %u.\n", GetLastError() );
1474 
1475     lstrcpyW(ptr, wildW);
1476     SetLastError(0xdeadbeef);
1477     length = GetShortPathNameW( path, short_path, sizeof(short_path)/sizeof(*short_path) );
1478     ok(!length, "GetShortPathNameW should fail\n");
1479     ok(GetLastError() == ERROR_INVALID_NAME, "wrong error %d\n", GetLastError());
1480 
1481     lstrcpyW(ptr, a_bcdeW);
1482     ret = DeleteFileW( path );
1483     ok( ret, "Cannot delete file.\n" );
1484     *ptr = 0;
1485 
1486     /* End test */
1487     ret = RemoveDirectoryW( path );
1488     ok( ret, "Cannot delete directory.\n" );
1489 }
1490 
1491 static void test_GetSystemDirectory(void)
1492 {
1493     CHAR    buffer[MAX_PATH + 4];
1494     DWORD   res;
1495     DWORD   total;
1496 
1497     SetLastError(0xdeadbeef);
1498     res = GetSystemDirectoryA(NULL, 0);
1499     /* res includes the terminating Zero */
1500     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1501 
1502     total = res;
1503 
1504     /* this crashes on XP */
1505     if (0)
1506         GetSystemDirectoryA(NULL, total);
1507 
1508     SetLastError(0xdeadbeef);
1509     res = GetSystemDirectoryA(NULL, total-1);
1510     /* 95+NT: total (includes the terminating Zero)
1511        98+ME: 0 with ERROR_INVALID_PARAMETER */
1512     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1513         "returned %d with %d (expected '%d' or: '0' with "
1514         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1515 
1516     if (total > MAX_PATH) return;
1517 
1518     buffer[0] = '\0';
1519     SetLastError(0xdeadbeef);
1520     res = GetSystemDirectoryA(buffer, total);
1521     /* res does not include the terminating Zero */
1522     ok( (res == (total-1)) && (buffer[0]),
1523         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1524         res, GetLastError(), buffer, total-1);
1525 
1526     buffer[0] = '\0';
1527     SetLastError(0xdeadbeef);
1528     res = GetSystemDirectoryA(buffer, total + 1);
1529     /* res does not include the terminating Zero */
1530     ok( (res == (total-1)) && (buffer[0]),
1531         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1532         res, GetLastError(), buffer, total-1);
1533 
1534     memset(buffer, '#', total + 1);
1535     buffer[total + 2] = '\0';
1536     SetLastError(0xdeadbeef);
1537     res = GetSystemDirectoryA(buffer, total-1);
1538     /* res includes the terminating Zero) */
1539     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1540         res, GetLastError(), buffer, total);
1541 
1542     memset(buffer, '#', total + 1);
1543     buffer[total + 2] = '\0';
1544     SetLastError(0xdeadbeef);
1545     res = GetSystemDirectoryA(buffer, total-2);
1546     /* res includes the terminating Zero) */
1547     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1548         res, GetLastError(), buffer, total);
1549 }
1550 
1551 static void test_GetWindowsDirectory(void)
1552 {
1553     CHAR    buffer[MAX_PATH + 4];
1554     DWORD   res;
1555     DWORD   total;
1556 
1557     SetLastError(0xdeadbeef);
1558     res = GetWindowsDirectoryA(NULL, 0);
1559     /* res includes the terminating Zero */
1560     ok(res > 0, "returned %d with %d (expected '>0')\n", res, GetLastError());
1561 
1562     total = res;
1563     /* this crashes on XP */
1564     if (0)
1565         GetWindowsDirectoryA(NULL, total);
1566 
1567     SetLastError(0xdeadbeef);
1568     res = GetWindowsDirectoryA(NULL, total-1);
1569     /* 95+NT: total (includes the terminating Zero)
1570        98+ME: 0 with ERROR_INVALID_PARAMETER */
1571     ok( (res == total) || (!res && (GetLastError() == ERROR_INVALID_PARAMETER)),
1572         "returned %d with %d (expected '%d' or: '0' with "
1573         "ERROR_INVALID_PARAMETER)\n", res, GetLastError(), total);
1574 
1575     if (total > MAX_PATH) return;
1576 
1577     buffer[0] = '\0';
1578     SetLastError(0xdeadbeef);
1579     res = GetWindowsDirectoryA(buffer, total);
1580     /* res does not include the terminating Zero */
1581     ok( (res == (total-1)) && (buffer[0]),
1582         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1583         res, GetLastError(), buffer, total-1);
1584 
1585     buffer[0] = '\0';
1586     SetLastError(0xdeadbeef);
1587     res = GetWindowsDirectoryA(buffer, total + 1);
1588     /* res does not include the terminating Zero */
1589     ok( (res == (total-1)) && (buffer[0]),
1590         "returned %d with %d and '%s' (expected '%d' and a string)\n",
1591         res, GetLastError(), buffer, total-1);
1592 
1593     memset(buffer, '#', total + 1);
1594     buffer[total + 2] = '\0';
1595     SetLastError(0xdeadbeef);
1596     res = GetWindowsDirectoryA(buffer, total-1);
1597     /* res includes the terminating Zero) */
1598     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1599         res, GetLastError(), buffer, total);
1600 
1601     memset(buffer, '#', total + 1);
1602     buffer[total + 2] = '\0';
1603     SetLastError(0xdeadbeef);
1604     res = GetWindowsDirectoryA(buffer, total-2);
1605     /* res includes the terminating Zero) */
1606     ok( res == total, "returned %d with %d and '%s' (expected '%d')\n",
1607         res, GetLastError(), buffer, total);
1608 }
1609 
1610 static void test_NeedCurrentDirectoryForExePathA(void)
1611 {
1612     if (!pNeedCurrentDirectoryForExePathA)
1613     {
1614         win_skip("NeedCurrentDirectoryForExePathA is not available\n");
1615         return;
1616     }
1617 
1618     /* Crashes in Windows */
1619     if (0)
1620         pNeedCurrentDirectoryForExePathA(NULL);
1621 
1622     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1623     ok(pNeedCurrentDirectoryForExePathA("."), "returned FALSE for \".\"\n");
1624     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1625     ok(pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned FALSE for \"cmd.exe\"\n");
1626 
1627     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1628     ok(!pNeedCurrentDirectoryForExePathA("."), "returned TRUE for \".\"\n");
1629     ok(pNeedCurrentDirectoryForExePathA("c:\\"), "returned FALSE for \"c:\\\"\n");
1630     ok(!pNeedCurrentDirectoryForExePathA("cmd.exe"), "returned TRUE for \"cmd.exe\"\n");
1631 }
1632 
1633 static void test_NeedCurrentDirectoryForExePathW(void)
1634 {
1635     const WCHAR thispath[] = {'.', 0};
1636     const WCHAR fullpath[] = {'c', ':', '\\', 0};
1637     const WCHAR cmdname[] = {'c', 'm', 'd', '.', 'e', 'x', 'e', 0};
1638 
1639     if (!pNeedCurrentDirectoryForExePathW)
1640     {
1641         win_skip("NeedCurrentDirectoryForExePathW is not available\n");
1642         return;
1643     }
1644 
1645     /* Crashes in Windows */
1646     if (0)
1647         pNeedCurrentDirectoryForExePathW(NULL);
1648 
1649     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", NULL);
1650     ok(pNeedCurrentDirectoryForExePathW(thispath), "returned FALSE for \".\"\n");
1651     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1652     ok(pNeedCurrentDirectoryForExePathW(cmdname), "returned FALSE for \"cmd.exe\"\n");
1653 
1654     SetEnvironmentVariableA("NoDefaultCurrentDirectoryInExePath", "nya");
1655     ok(!pNeedCurrentDirectoryForExePathW(thispath), "returned TRUE for \".\"\n");
1656     ok(pNeedCurrentDirectoryForExePathW(fullpath), "returned FALSE for \"c:\\\"\n");
1657     ok(!pNeedCurrentDirectoryForExePathW(cmdname), "returned TRUE for \"cmd.exe\"\n");
1658 }
1659 
1660 /* Call various path/file name retrieving APIs and check the case of
1661  * the returned drive letter. Some apps (for instance Adobe Photoshop CS3
1662  * installer) depend on the drive letter being in upper case.
1663  */
1664 static void test_drive_letter_case(void)
1665 {
1666     UINT ret;
1667     char buf[MAX_PATH];
1668 
1669 #define is_upper_case_letter(a) ((a) >= 'A' && (a) <= 'Z')
1670 
1671     memset(buf, 0, sizeof(buf));
1672     SetLastError(0xdeadbeef);
1673     ret = GetWindowsDirectoryA(buf, sizeof(buf));
1674     ok(ret, "GetWindowsDirectory error %u\n", GetLastError());
1675     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1676     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1677     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1678 
1679     /* re-use the buffer returned by GetFullPathName */
1680     buf[2] = '/';
1681     SetLastError(0xdeadbeef);
1682     ret = GetFullPathNameA(buf + 2, sizeof(buf), buf, NULL);
1683     ok(ret, "GetFullPathName error %u\n", GetLastError());
1684     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1685     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1686     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1687 
1688     memset(buf, 0, sizeof(buf));
1689     SetLastError(0xdeadbeef);
1690     ret = GetSystemDirectoryA(buf, sizeof(buf));
1691     ok(ret, "GetSystemDirectory error %u\n", GetLastError());
1692     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1693     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1694     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1695 
1696     memset(buf, 0, sizeof(buf));
1697     SetLastError(0xdeadbeef);
1698     ret = GetCurrentDirectoryA(sizeof(buf), buf);
1699     ok(ret, "GetCurrentDirectory error %u\n", GetLastError());
1700     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1701     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1702     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1703 
1704     /* TEMP is an environment variable, so it can't be tested for case-sensitivity */
1705     memset(buf, 0, sizeof(buf));
1706     SetLastError(0xdeadbeef);
1707     ret = GetTempPathA(sizeof(buf), buf);
1708     ok(ret, "GetTempPath error %u\n", GetLastError());
1709     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1710     if (buf[0])
1711     {
1712         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1713         ok(buf[strlen(buf)-1] == '\\', "Temporary path (%s) doesn't end in a slash\n", buf);
1714     }
1715 
1716     memset(buf, 0, sizeof(buf));
1717     SetLastError(0xdeadbeef);
1718     ret = GetFullPathNameA(".", sizeof(buf), buf, NULL);
1719     ok(ret, "GetFullPathName error %u\n", GetLastError());
1720     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1721     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1722     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1723 
1724     /* re-use the buffer returned by GetFullPathName */
1725     SetLastError(0xdeadbeef);
1726     ret = GetShortPathNameA(buf, buf, sizeof(buf));
1727     ok(ret, "GetShortPathName error %u\n", GetLastError());
1728     ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1729     ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1730     ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1731 
1732     if (pGetLongPathNameA)
1733     {
1734         /* re-use the buffer returned by GetShortPathName */
1735         SetLastError(0xdeadbeef);
1736         ret = pGetLongPathNameA(buf, buf, sizeof(buf));
1737         ok(ret, "GetLongPathNameA error %u\n", GetLastError());
1738         ok(ret < sizeof(buf), "buffer should be %u bytes\n", ret);
1739         ok(buf[1] == ':', "expected buf[1] == ':' got %c\n", buf[1]);
1740         ok(is_upper_case_letter(buf[0]), "expected buf[0] upper case letter got %c\n", buf[0]);
1741     }
1742 #undef is_upper_case_letter
1743 }
1744 
1745 static const char manifest_dep[] =
1746 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1747 "<assemblyIdentity version=\"1.2.3.4\"  name=\"testdep1\" type=\"win32\" processorArchitecture=\"" ARCH "\"/>"
1748 "    <file name=\"testdep.dll\" />"
1749 "    <file name=\"ole32\" />"
1750 "    <file name=\"kernel32.dll\" />"
1751 "</assembly>";
1752 
1753 static const char manifest_main[] =
1754 "<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
1755 "<assemblyIdentity version=\"1.2.3.4\" name=\"Wine.Test\" type=\"win32\" />"
1756 "<dependency>"
1757 " <dependentAssembly>"
1758 "  <assemblyIdentity type=\"win32\" name=\"testdep1\" version=\"1.2.3.4\" processorArchitecture=\"" ARCH "\" />"
1759 " </dependentAssembly>"
1760 "</dependency>"
1761 "</assembly>";
1762 
1763 static void create_manifest_file(const char *filename, const char *manifest)
1764 {
1765     WCHAR path[MAX_PATH], manifest_path[MAX_PATH];
1766     HANDLE file;
1767     DWORD size;
1768 
1769     MultiByteToWideChar( CP_ACP, 0, filename, -1, path, MAX_PATH );
1770 
1771     GetTempPathW(sizeof(manifest_path)/sizeof(WCHAR), manifest_path);
1772     lstrcatW(manifest_path, path);
1773 
1774     file = CreateFileW(manifest_path, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
1775     ok(file != INVALID_HANDLE_VALUE, "CreateFile failed: %u\n", GetLastError());
1776     WriteFile(file, manifest, strlen(manifest), &size, NULL);
1777     CloseHandle(file);
1778 }
1779 
1780 static void delete_manifest_file(const char *filename)
1781 {
1782     CHAR path[MAX_PATH];
1783 
1784     GetTempPathA(sizeof(path), path);
1785     strcat(path, filename);
1786     DeleteFileA(path);
1787 }
1788 
1789 static HANDLE test_create(const char *file)
1790 {
1791     WCHAR path[MAX_PATH], manifest_path[MAX_PATH];
1792     ACTCTXW actctx;
1793     HANDLE handle;
1794 
1795     MultiByteToWideChar(CP_ACP, 0, file, -1, path, MAX_PATH);
1796     GetTempPathW(sizeof(manifest_path)/sizeof(WCHAR), manifest_path);
1797     lstrcatW(manifest_path, path);
1798 
1799     memset(&actctx, 0, sizeof(ACTCTXW));
1800     actctx.cbSize = sizeof(ACTCTXW);
1801     actctx.lpSource = manifest_path;
1802 
1803     handle = pCreateActCtxW(&actctx);
1804     ok(handle != INVALID_HANDLE_VALUE, "failed to create context, error %u\n", GetLastError());
1805 
1806     ok(actctx.cbSize == sizeof(actctx), "cbSize=%d\n", actctx.cbSize);
1807     ok(actctx.dwFlags == 0, "dwFlags=%d\n", actctx.dwFlags);
1808     ok(actctx.lpSource == manifest_path, "lpSource=%p\n", actctx.lpSource);
1809     ok(actctx.wProcessorArchitecture == 0, "wProcessorArchitecture=%d\n", actctx.wProcessorArchitecture);
1810     ok(actctx.wLangId == 0, "wLangId=%d\n", actctx.wLangId);
1811     ok(actctx.lpAssemblyDirectory == NULL, "lpAssemblyDirectory=%p\n", actctx.lpAssemblyDirectory);
1812     ok(actctx.lpResourceName == NULL, "lpResourceName=%p\n", actctx.lpResourceName);
1813     ok(actctx.lpApplicationName == NULL, "lpApplicationName=%p\n", actctx.lpApplicationName);
1814     ok(actctx.hModule == NULL, "hModule=%p\n", actctx.hModule);
1815 
1816     return handle;
1817 }
1818 
1819 static void test_SearchPathA(void)
1820 {
1821     static const CHAR testdepA[] = "testdep.dll";
1822     static const CHAR testdeprelA[] = "./testdep.dll";
1823     static const CHAR kernel32A[] = "kernel32.dll";
1824     static const CHAR fileA[] = "";
1825     CHAR pathA[MAX_PATH], buffA[MAX_PATH], path2A[MAX_PATH], path3A[MAX_PATH], curdirA[MAX_PATH];
1826     CHAR tmpdirA[MAX_PATH], *ptrA = NULL;
1827     ULONG_PTR cookie;
1828     HANDLE handle;
1829     BOOL bret;
1830     DWORD ret;
1831 
1832     if (!pSearchPathA)
1833     {
1834         win_skip("SearchPathA isn't available\n");
1835         return;
1836     }
1837 
1838     GetWindowsDirectoryA(pathA, sizeof(pathA)/sizeof(CHAR));
1839 
1840     /* NULL filename */
1841     SetLastError(0xdeadbeef);
1842     ret = pSearchPathA(pathA, NULL, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1843     ok(ret == 0, "Expected failure, got %d\n", ret);
1844     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1845       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1846 
1847     /* empty filename */
1848     SetLastError(0xdeadbeef);
1849     ret = pSearchPathA(pathA, fileA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, &ptrA);
1850     ok(ret == 0, "Expected failure, got %d\n", ret);
1851     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1852       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1853 
1854     if (!pActivateActCtx)
1855         return;
1856 
1857     create_manifest_file("testdep1.manifest", manifest_dep);
1858     create_manifest_file("main.manifest", manifest_main);
1859 
1860     handle = test_create("main.manifest");
1861     delete_manifest_file("testdep1.manifest");
1862     delete_manifest_file("main.manifest");
1863 
1864     /* search fails without active context */
1865     ret = pSearchPathA(NULL, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1866     ok(ret == 0, "got %d\n", ret);
1867 
1868     ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(path2A)/sizeof(CHAR), path2A, NULL);
1869     ok(ret && ret == strlen(path2A), "got %d\n", ret);
1870 
1871     ret = pActivateActCtx(handle, &cookie);
1872     ok(ret, "failed to activate context, %u\n", GetLastError());
1873 
1874     /* works when activated */
1875     ret = pSearchPathA(NULL, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1876     ok(ret && ret == strlen(buffA), "got %d\n", ret);
1877 
1878     ret = pSearchPathA(NULL, "testdep.dll", ".ext", sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1879     ok(ret && ret == strlen(buffA), "got %d\n", ret);
1880 
1881     ret = pSearchPathA(NULL, "testdep", ".dll", sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1882     ok(ret && ret == strlen(buffA), "got %d\n", ret);
1883 
1884     ret = pSearchPathA(NULL, "testdep", ".ext", sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1885     ok(!ret, "got %d\n", ret);
1886 
1887     /* name contains path */
1888     ret = pSearchPathA(NULL, testdeprelA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1889     ok(!ret, "got %d\n", ret);
1890 
1891     /* fails with specified path that doesn't contain this file */
1892     ret = pSearchPathA(pathA, testdepA, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1893     ok(!ret, "got %d\n", ret);
1894 
1895     /* path is redirected for wellknown names too */
1896     ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(buffA)/sizeof(CHAR), buffA, NULL);
1897     ok(ret && ret == strlen(buffA), "got %d\n", ret);
1898     ok(strcmp(buffA, path2A), "got wrong path %s, %s\n", buffA, path2A);
1899 
1900     ret = pDeactivateActCtx(0, cookie);
1901     ok(ret, "failed to deactivate context, %u\n", GetLastError());
1902     pReleaseActCtx(handle);
1903 
1904     /* test the search path priority of the working directory */
1905     GetTempPathA(sizeof(tmpdirA), tmpdirA);
1906     ret = GetCurrentDirectoryA(MAX_PATH, curdirA);
1907     ok(ret, "failed to obtain working directory.\n");
1908     sprintf(pathA, "%s\\%s", tmpdirA, kernel32A);
1909     ret = pSearchPathA(NULL, kernel32A, NULL, sizeof(path2A)/sizeof(CHAR), path2A, NULL);
1910     ok(ret && ret == strlen(path2A), "got %d\n", ret);
1911     bret = CopyFileA(path2A, pathA, FALSE);
1912     ok(bret != 0, "failed to copy test executable to temp directory, %u\n", GetLastError());
1913     sprintf(path3A, "%s%s%s", curdirA, curdirA[strlen(curdirA)-1] != '\\' ? "\\" : "", kernel32A);
1914     bret = CopyFileA(path2A, path3A, FALSE);
1915     ok(bret != 0, "failed to copy test executable to launch directory, %u\n", GetLastError());
1916     bret = SetCurrentDirectoryA(tmpdirA);
1917     ok(bret, "failed to change working directory\n");
1918     ret = pSearchPathA(NULL, kernel32A, ".exe", sizeof(buffA), buffA, NULL);
1919     ok(ret && ret == strlen(buffA), "got %d\n", ret);
1920     ok(strcmp(buffA, path3A) == 0, "expected %s, got %s\n", path3A, buffA);
1921     bret = SetCurrentDirectoryA(curdirA);
1922     ok(bret, "failed to reset working directory\n");
1923     DeleteFileA(path3A);
1924     DeleteFileA(pathA);
1925 }
1926 
1927 static void test_SearchPathW(void)
1928 {
1929     static const WCHAR testdeprelW[] = {'.','/','t','e','s','t','d','e','p','.','d','l','l',0};
1930     static const WCHAR testdepW[] = {'t','e','s','t','d','e','p','.','d','l','l',0};
1931     static const WCHAR testdep1W[] = {'t','e','s','t','d','e','p',0};
1932     static const WCHAR kernel32dllW[] = {'k','e','r','n','e','l','3','2','.','d','l','l',0};
1933     static const WCHAR kernel32W[] = {'k','e','r','n','e','l','3','2',0};
1934     static const WCHAR ole32W[] = {'o','l','e','3','2',0};
1935     static const WCHAR extW[] = {'.','e','x','t',0};
1936     static const WCHAR dllW[] = {'.','d','l','l',0};
1937     static const WCHAR fileW[] = { 0 };
1938     WCHAR pathW[MAX_PATH], buffW[MAX_PATH], path2W[MAX_PATH];
1939     WCHAR *ptrW = NULL;
1940     ULONG_PTR cookie;
1941     HANDLE handle;
1942     DWORD ret;
1943 
1944     if (!pSearchPathW)
1945     {
1946         win_skip("SearchPathW isn't available\n");
1947         return;
1948     }
1949 
1950 if (0)
1951 {
1952     /* NULL filename, crashes on nt4 */
1953     pSearchPathW(pathW, NULL, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1954 }
1955 
1956     GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1957 
1958     /* empty filename */
1959     SetLastError(0xdeadbeef);
1960     ret = pSearchPathW(pathW, fileW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, &ptrW);
1961     ok(ret == 0, "Expected failure, got %d\n", ret);
1962     ok(GetLastError() == ERROR_INVALID_PARAMETER,
1963       "Expected ERROR_INVALID_PARAMETER, got %x\n", GetLastError());
1964 
1965     if (!pActivateActCtx)
1966         return;
1967 
1968     create_manifest_file("testdep1.manifest", manifest_dep);
1969     create_manifest_file("main.manifest", manifest_main);
1970 
1971     handle = test_create("main.manifest");
1972     delete_manifest_file("testdep1.manifest");
1973     delete_manifest_file("main.manifest");
1974 
1975     /* search fails without active context */
1976     ret = pSearchPathW(NULL, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
1977     ok(ret == 0, "got %d\n", ret);
1978 
1979     ret = pSearchPathW(NULL, kernel32dllW, NULL, sizeof(path2W)/sizeof(WCHAR), path2W, NULL);
1980     ok(ret && ret == lstrlenW(path2W), "got %d\n", ret);
1981 
1982     /* full path, name without 'dll' extension */
1983     GetSystemDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1984     ret = pSearchPathW(pathW, kernel32W, NULL, sizeof(path2W)/sizeof(WCHAR), path2W, NULL);
1985     ok(ret == 0, "got %d\n", ret);
1986 
1987     GetWindowsDirectoryW(pathW, sizeof(pathW)/sizeof(WCHAR));
1988 
1989     ret = pActivateActCtx(handle, &cookie);
1990     ok(ret, "failed to activate context, %u\n", GetLastError());
1991 
1992     /* works when activated */
1993     ret = pSearchPathW(NULL, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
1994     ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
1995 
1996     ret = pSearchPathW(NULL, testdepW, extW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
1997     ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
1998 
1999     ret = pSearchPathW(NULL, testdep1W, dllW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
2000     ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
2001 
2002     ret = pSearchPathW(NULL, testdep1W, extW, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
2003     ok(!ret, "got %d\n", ret);
2004 
2005     /* name contains path */
2006     ret = pSearchPathW(NULL, testdeprelW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
2007     ok(!ret, "got %d\n", ret);
2008 
2009     /* fails with specified path that doesn't contain this file */
2010     ret = pSearchPathW(pathW, testdepW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
2011     ok(!ret, "got %d\n", ret);
2012 
2013     /* path is redirected for wellknown names too, meaning it takes precedence over normal search order */
2014     ret = pSearchPathW(NULL, kernel32dllW, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
2015     ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
2016     ok(lstrcmpW(buffW, path2W), "got wrong path %s, %s\n", wine_dbgstr_w(buffW), wine_dbgstr_w(path2W));
2017 
2018     /* path is built using on manifest file name */
2019     ret = pSearchPathW(NULL, ole32W, NULL, sizeof(buffW)/sizeof(WCHAR), buffW, NULL);
2020     ok(ret && ret == lstrlenW(buffW), "got %d\n", ret);
2021 
2022     ret = pDeactivateActCtx(0, cookie);
2023     ok(ret, "failed to deactivate context, %u\n", GetLastError());
2024     pReleaseActCtx(handle);
2025 }
2026 
2027 static void test_GetFullPathNameA(void)
2028 {
2029     char output[MAX_PATH], *filepart;
2030     DWORD ret;
2031     int i;
2032     UINT acp;
2033 
2034     const struct
2035     {
2036         LPCSTR name;
2037         DWORD len;
2038         LPSTR buffer;
2039         LPSTR *lastpart;
2040     } invalid_parameters[] =
2041     {
2042         {NULL, 0,        NULL,   NULL},
2043         {NULL, MAX_PATH, NULL,   NULL},
2044         {NULL, MAX_PATH, output, NULL},
2045         {NULL, MAX_PATH, output, &filepart},
2046         {"",   0,        NULL,   NULL},
2047         {"",   MAX_PATH, NULL,   NULL},
2048         {"",   MAX_PATH, output, NULL},
2049         {"",   MAX_PATH, output, &filepart},
2050     };
2051 
2052     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
2053     {
2054         SetLastError(0xdeadbeef);
2055         strcpy(output, "deadbeef");
2056         filepart = (char *)0xdeadbeef;
2057         ret = GetFullPathNameA(invalid_parameters[i].name,
2058                                invalid_parameters[i].len,
2059                                invalid_parameters[i].buffer,
2060                                invalid_parameters[i].lastpart);
2061         ok(!ret, "[%d] Expected GetFullPathNameA to return 0, got %u\n", i, ret);
2062         ok(!strcmp(output, "deadbeef"), "[%d] Expected the output buffer to be unchanged, got \"%s\"\n", i, output);
2063         ok(filepart == (char *)0xdeadbeef, "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
2064         ok(GetLastError() == 0xdeadbeef ||
2065            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
2066            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
2067            i, GetLastError());
2068     }
2069 
2070     acp = GetACP();
2071     if (acp != 932)
2072         skip("Skipping DBCS(Japanese) GetFullPathNameA test in this codepage (%d)\n", acp);
2073     else {
2074         const struct dbcs_case {
2075             const char *input;
2076             const char *expected;
2077         } testset[] = {
2078             { "c:\\a\\\x95\x5c\x97\xa0.txt", "\x95\x5c\x97\xa0.txt" },
2079             { "c:\\\x83\x8f\x83\x43\x83\x93\\wine.c", "wine.c" },
2080             { "c:\\demo\\\x97\xa0\x95\x5c", "\x97\xa0\x95\x5c" }
2081         };
2082         for (i = 0; i < sizeof(testset)/sizeof(testset[0]); i++) {
2083             ret = GetFullPathNameA(testset[i].input, sizeof(output),
2084                                    output, &filepart);
2085             ok(ret, "[%d] GetFullPathName error %u\n", i, GetLastError());
2086             ok(!lstrcmpA(filepart, testset[i].expected),
2087                "[%d] expected %s got %s\n", i, testset[i].expected, filepart);
2088         }
2089     }
2090 }
2091 
2092 static void test_GetFullPathNameW(void)
2093 {
2094     static const WCHAR emptyW[] = {0};
2095     static const WCHAR deadbeefW[] = {'d','e','a','d','b','e','e','f',0};
2096 
2097     WCHAR output[MAX_PATH], *filepart;
2098     DWORD ret;
2099     int i;
2100 
2101     const struct
2102     {
2103         LPCWSTR name;
2104         DWORD len;
2105         LPWSTR buffer;
2106         LPWSTR *lastpart;
2107         int win7_expect;
2108     } invalid_parameters[] =
2109     {
2110         {NULL,   0,        NULL,   NULL},
2111         {NULL,   0,        NULL,   &filepart, 1},
2112         {NULL,   MAX_PATH, NULL,   NULL},
2113         {NULL,   MAX_PATH, output, NULL},
2114         {NULL,   MAX_PATH, output, &filepart, 1},
2115         {emptyW, 0,        NULL,   NULL},
2116         {emptyW, 0,        NULL,   &filepart, 1},
2117         {emptyW, MAX_PATH, NULL,   NULL},
2118         {emptyW, MAX_PATH, output, NULL},
2119         {emptyW, MAX_PATH, output, &filepart, 1},
2120     };
2121 
2122     SetLastError(0xdeadbeef);
2123     ret = GetFullPathNameW(NULL, 0, NULL, NULL);
2124     if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
2125     {
2126         win_skip("GetFullPathNameW is not available\n");
2127         return;
2128     }
2129 
2130     for (i = 0; i < sizeof(invalid_parameters)/sizeof(invalid_parameters[0]); i++)
2131     {
2132         SetLastError(0xdeadbeef);
2133         lstrcpyW(output, deadbeefW);
2134         filepart = (WCHAR *)0xdeadbeef;
2135         ret = GetFullPathNameW(invalid_parameters[i].name,
2136                                invalid_parameters[i].len,
2137                                invalid_parameters[i].buffer,
2138                                invalid_parameters[i].lastpart);
2139         ok(!ret, "[%d] Expected GetFullPathNameW to return 0, got %u\n", i, ret);
2140         ok(!lstrcmpW(output, deadbeefW), "[%d] Expected the output buffer to be unchanged, got %s\n", i, wine_dbgstr_w(output));
2141         ok(filepart == (WCHAR *)0xdeadbeef ||
2142            (invalid_parameters[i].win7_expect && filepart == NULL),
2143            "[%d] Expected output file part pointer to be untouched, got %p\n", i, filepart);
2144         ok(GetLastError() == 0xdeadbeef ||
2145            GetLastError() == ERROR_INVALID_NAME, /* Win7 */
2146            "[%d] Expected GetLastError() to return 0xdeadbeef, got %u\n",
2147            i, GetLastError());
2148     }
2149 }
2150 
2151 static void init_pointers(void)
2152 {
2153     HMODULE hKernel32 = GetModuleHandleA("kernel32.dll");
2154 
2155 #define MAKEFUNC(f) (p##f = (void*)GetProcAddress(hKernel32, #f))
2156     MAKEFUNC(GetLongPathNameA);
2157     MAKEFUNC(GetLongPathNameW);
2158     MAKEFUNC(NeedCurrentDirectoryForExePathA);
2159     MAKEFUNC(NeedCurrentDirectoryForExePathW);
2160     MAKEFUNC(SearchPathA);
2161     MAKEFUNC(SearchPathW);
2162     MAKEFUNC(SetSearchPathMode);
2163     MAKEFUNC(ActivateActCtx);
2164     MAKEFUNC(CreateActCtxW);
2165     MAKEFUNC(DeactivateActCtx);
2166     MAKEFUNC(GetCurrentActCtx);
2167     MAKEFUNC(ReleaseActCtx);
2168     MAKEFUNC(CheckNameLegalDOS8Dot3W);
2169     MAKEFUNC(CheckNameLegalDOS8Dot3A);
2170 #undef MAKEFUNC
2171 }
2172 
2173 static void test_relative_path(void)
2174 {
2175     char path[MAX_PATH], buf[MAX_PATH];
2176     HANDLE file;
2177     int ret;
2178     WCHAR curdir[MAX_PATH];
2179 
2180     if (!pGetLongPathNameA) return;
2181 
2182     GetCurrentDirectoryW(MAX_PATH, curdir);
2183     GetTempPathA(MAX_PATH, path);
2184     ret = SetCurrentDirectoryA(path);
2185     ok(ret, "SetCurrentDirectory error %d\n", GetLastError());
2186 
2187     ret = CreateDirectoryA("foo", NULL);
2188     ok(ret, "CreateDirectory error %d\n", GetLastError());
2189     file = CreateFileA("foo\\file", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0);
2190     ok(file != INVALID_HANDLE_VALUE, "failed to create temp file\n");
2191     CloseHandle(file);
2192     ret = CreateDirectoryA("bar", NULL);
2193     ok(ret, "CreateDirectory error %d\n", GetLastError());
2194     ret = SetCurrentDirectoryA("bar");
2195     ok(ret, "SetCurrentDirectory error %d\n", GetLastError());
2196 
2197     ret = GetFileAttributesA("..\\foo\\file");
2198     ok(ret != INVALID_FILE_ATTRIBUTES, "GetFileAttributes error %d\n", GetLastError());
2199 
2200     strcpy(buf, "deadbeef");
2201     ret = pGetLongPathNameA(".", buf, MAX_PATH);
2202     ok(ret, "GetLongPathName error %d\n", GetLastError());
2203     ok(!strcmp(buf, "."), "expected ., got %s\n", buf);
2204     strcpy(buf, "deadbeef");
2205     ret = GetShortPathNameA(".", buf, MAX_PATH);
2206     ok(ret, "GetShortPathName error %d\n", GetLastError());
2207     ok(!strcmp(buf, "."), "expected ., got %s\n", buf);
2208 
2209     strcpy(buf, "deadbeef");
2210     ret = pGetLongPathNameA("..", buf, MAX_PATH);
2211     ok(ret, "GetLongPathName error %d\n", GetLastError());
2212     ok(!strcmp(buf, ".."), "expected .., got %s\n", buf);
2213     strcpy(buf, "deadbeef");
2214     ret = GetShortPathNameA("..", buf, MAX_PATH);
2215     ok(ret, "GetShortPathName error %d\n", GetLastError());
2216     ok(!strcmp(buf, ".."), "expected .., got %s\n", buf);
2217 
2218     strcpy(buf, "deadbeef");
2219     ret = pGetLongPathNameA("..\\foo\\file", buf, MAX_PATH);
2220     ok(ret, "GetLongPathName error %d\n", GetLastError());
2221     ok(!strcmp(buf, "..\\foo\\file"), "expected ..\\foo\\file, got %s\n", buf);
2222     strcpy(buf, "deadbeef");
2223     ret = GetShortPathNameA("..\\foo\\file", buf, MAX_PATH);
2224     ok(ret, "GetShortPathName error %d\n", GetLastError());
2225     ok(!strcmp(buf, "..\\foo\\file"), "expected ..\\foo\\file, got %s\n", buf);
2226 
2227     strcpy(buf, "deadbeef");
2228     ret = pGetLongPathNameA(".\\..\\foo\\file", buf, MAX_PATH);
2229     ok(ret, "GetLongPathName error %d\n", GetLastError());
2230     ok(!strcmp(buf, ".\\..\\foo\\file"), "expected .\\..\\foo\\file, got %s\n", buf);
2231     strcpy(buf, "deadbeef");
2232     ret = GetShortPathNameA(".\\..\\foo\\file", buf, MAX_PATH);
2233     ok(ret, "GetShortPathName error %d\n", GetLastError());
2234     ok(!strcmp(buf, ".\\..\\foo\\file"), "expected .\\..\\foo\\file, got %s\n", buf);
2235 
2236     /* test double delimiters */
2237     strcpy(buf, "deadbeef");
2238     ret = pGetLongPathNameA("..\\\\foo\\file", buf, MAX_PATH);
2239     ok(ret, "GetLongPathName error %d\n", GetLastError());
2240     ok(!strcmp(buf, "..\\\\foo\\file"), "expected ..\\\\foo\\file, got %s\n", buf);
2241     strcpy(buf, "deadbeef");
2242     ret = GetShortPathNameA("..\\\\foo\\file", buf, MAX_PATH);
2243     ok(ret, "GetShortPathName error %d\n", GetLastError());
2244     ok(!strcmp(buf, "..\\\\foo\\file"), "expected ..\\\\foo\\file, got %s\n", buf);
2245 
2246     SetCurrentDirectoryA("..");
2247     DeleteFileA("foo\\file");
2248     RemoveDirectoryA("foo");
2249     RemoveDirectoryA("bar");
2250     SetCurrentDirectoryW(curdir);
2251 }
2252 
2253 static void test_CheckNameLegalDOS8Dot3(void)
2254 {
2255     static const WCHAR has_driveW[] = {'C',':','\\','a','.','t','x','t',0};
2256     static const WCHAR has_pathW[] = {'b','\\','a','.','t','x','t',0};
2257     static const WCHAR too_longW[] = {'a','l','o','n','g','f','i','l','e','n','a','m','e','.','t','x','t',0};
2258     static const WCHAR twodotsW[] = {'t','e','s','t','.','e','s','t','.','t','x','t',0};
2259     static const WCHAR longextW[] = {'t','e','s','t','.','t','x','t','t','x','t',0};
2260     static const WCHAR emptyW[] = {0};
2261     static const WCHAR funnycharsW[] = {'!','#','$','%','&','\'','(',')','.','-','@','^',0};
2262     static const WCHAR length8W[] = {'t','e','s','t','t','e','s','t','.','t','x','t',0};
2263     static const WCHAR length1W[] = {'t',0};
2264     static const WCHAR withspaceW[] = {'t','e','s','t',' ','e','s','t','.','t','x','t',0};
2265 
2266     static const struct {
2267         const WCHAR *name;
2268         BOOL should_be_legal, has_space;
2269     } cases[] = {
2270         {has_driveW, FALSE, FALSE},
2271         {has_pathW, FALSE, FALSE},
2272         {too_longW, FALSE, FALSE},
2273         {twodotsW, FALSE, FALSE},
2274         {longextW, FALSE, FALSE},
2275         {emptyW, TRUE /* ! */, FALSE},
2276         {funnycharsW, TRUE, FALSE},
2277         {length8W, TRUE, FALSE},
2278         {length1W, TRUE, FALSE},
2279         {withspaceW, TRUE, TRUE},
2280     };
2281 
2282     BOOL br, is_legal, has_space;
2283     char astr[64];
2284     DWORD i;
2285 
2286     if(!pCheckNameLegalDOS8Dot3W){
2287         win_skip("Missing CheckNameLegalDOS8Dot3, skipping tests\n");
2288         return;
2289     }
2290 
2291     br = pCheckNameLegalDOS8Dot3W(NULL, NULL, 0, NULL, &is_legal);
2292     ok(br == FALSE, "CheckNameLegalDOS8Dot3W should have failed\n");
2293 
2294     br = pCheckNameLegalDOS8Dot3A(NULL, NULL, 0, NULL, &is_legal);
2295     ok(br == FALSE, "CheckNameLegalDOS8Dot3A should have failed\n");
2296 
2297     br = pCheckNameLegalDOS8Dot3W(length8W, NULL, 0, NULL, NULL);
2298     ok(br == FALSE, "CheckNameLegalDOS8Dot3W should have failed\n");
2299 
2300     br = pCheckNameLegalDOS8Dot3A("testtest.txt", NULL, 0, NULL, NULL);
2301     ok(br == FALSE, "CheckNameLegalDOS8Dot3A should have failed\n");
2302 
2303     for(i = 0; i < sizeof(cases)/sizeof(*cases); ++i){
2304         br = pCheckNameLegalDOS8Dot3W(cases[i].name, NULL, 0, &has_space, &is_legal);
2305         ok(br == TRUE, "CheckNameLegalDOS8Dot3W failed for %s\n", wine_dbgstr_w(cases[i].name));
2306         ok(is_legal == cases[i].should_be_legal, "Got wrong legality for %s\n", wine_dbgstr_w(cases[i].name));
2307         if(is_legal)
2308             ok(has_space == cases[i].has_space, "Got wrong space for %s\n", wine_dbgstr_w(cases[i].name));
2309 
2310         WideCharToMultiByte(CP_ACP, 0, cases[i].name, -1, astr, sizeof(astr), NULL, NULL);
2311 
2312         br = pCheckNameLegalDOS8Dot3A(astr, NULL, 0, &has_space, &is_legal);
2313         ok(br == TRUE, "CheckNameLegalDOS8Dot3W failed for %s\n", astr);
2314         ok(is_legal == cases[i].should_be_legal, "Got wrong legality for %s\n", astr);
2315         if(is_legal)
2316             ok(has_space == cases[i].has_space, "Got wrong space for %s\n", wine_dbgstr_w(cases[i].name));
2317     }
2318 }
2319 
2320 static void test_SetSearchPathMode(void)
2321 {
2322     BOOL ret;
2323     char orig[MAX_PATH], buf[MAX_PATH], dir[MAX_PATH], expect[MAX_PATH];
2324     HANDLE handle;
2325 
2326     if (!pSetSearchPathMode)
2327     {
2328         win_skip( "SetSearchPathMode isn't available\n" );
2329         return;
2330     }
2331     GetCurrentDirectoryA( MAX_PATH, orig );
2332     GetTempPathA( MAX_PATH, buf );
2333     GetTempFileNameA( buf, "path", 0, dir );
2334     DeleteFileA( dir );
2335     CreateDirectoryA( dir, NULL );
2336     ret = SetCurrentDirectoryA( dir );
2337     ok( ret, "failed to switch to %s\n", dir );
2338     if (!ret)
2339     {
2340         RemoveDirectoryA( dir );
2341         return;
2342     }
2343 
2344     handle = CreateFileA( "kernel32.dll", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0 );
2345     CloseHandle( handle );
2346 
2347     SetLastError( 0xdeadbeef );
2348     ret = pSetSearchPathMode( 0 );
2349     ok( !ret, "SetSearchPathMode succeeded\n" );
2350     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2351 
2352     SetLastError( 0xdeadbeef );
2353     ret = pSetSearchPathMode( 0x80 );
2354     ok( !ret, "SetSearchPathMode succeeded\n" );
2355     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2356 
2357     SetLastError( 0xdeadbeef );
2358     ret = pSetSearchPathMode( BASE_SEARCH_PATH_PERMANENT );
2359     ok( !ret, "SetSearchPathMode succeeded\n" );
2360     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2361 
2362     SetLastError( 0xdeadbeef );
2363     ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL );
2364     ok( ret, "SearchPathA failed err %u\n", GetLastError() );
2365     GetCurrentDirectoryA( MAX_PATH, expect );
2366     strcat( expect, "\\kernel32.dll" );
2367     ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect );
2368 
2369     SetLastError( 0xdeadbeef );
2370     ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE );
2371     ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() );
2372 
2373     SetLastError( 0xdeadbeef );
2374     ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL );
2375     ok( ret, "SearchPathA failed err %u\n", GetLastError() );
2376     GetSystemDirectoryA( expect, MAX_PATH );
2377     strcat( expect, "\\kernel32.dll" );
2378     ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect );
2379 
2380     SetLastError( 0xdeadbeef );
2381     ret = pSetSearchPathMode( BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE );
2382     ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() );
2383 
2384     SetLastError( 0xdeadbeef );
2385     ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL );
2386     ok( ret, "SearchPathA failed err %u\n", GetLastError() );
2387     GetCurrentDirectoryA( MAX_PATH, expect );
2388     strcat( expect, "\\kernel32.dll" );
2389     ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect );
2390 
2391     SetLastError( 0xdeadbeef );
2392     ret = pSetSearchPathMode( BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT );
2393     ok( !ret, "SetSearchPathMode succeeded\n" );
2394     ok( GetLastError() == ERROR_INVALID_PARAMETER, "wrong error %u\n", GetLastError() );
2395 
2396     SetLastError( 0xdeadbeef );
2397     ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT );
2398     ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() );
2399 
2400     SetLastError( 0xdeadbeef );
2401     ret = pSetSearchPathMode( BASE_SEARCH_PATH_DISABLE_SAFE_SEARCHMODE );
2402     ok( !ret, "SetSearchPathMode succeeded\n" );
2403     ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() );
2404 
2405     SetLastError( 0xdeadbeef );
2406     ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE );
2407     ok( !ret, "SetSearchPathMode succeeded\n" );
2408     ok( GetLastError() == ERROR_ACCESS_DENIED, "wrong error %u\n", GetLastError() );
2409 
2410     SetLastError( 0xdeadbeef );
2411     ret = pSetSearchPathMode( BASE_SEARCH_PATH_ENABLE_SAFE_SEARCHMODE | BASE_SEARCH_PATH_PERMANENT );
2412     ok( ret, "SetSearchPathMode failed err %u\n", GetLastError() );
2413 
2414     SetLastError( 0xdeadbeef );
2415     ret = SearchPathA( NULL, "kernel32.dll", NULL, MAX_PATH, buf, NULL );
2416     ok( ret, "SearchPathA failed err %u\n", GetLastError() );
2417     GetSystemDirectoryA( expect, MAX_PATH );
2418     strcat( expect, "\\kernel32.dll" );
2419     ok( !lstrcmpiA( buf, expect ), "found %s expected %s\n", buf, expect );
2420 
2421     DeleteFileA( "kernel32.dll" );
2422     SetCurrentDirectoryA( orig );
2423     RemoveDirectoryA( dir );
2424 }
2425 
2426 START_TEST(path)
2427 {
2428     CHAR origdir[MAX_PATH],curdir[MAX_PATH], curDrive, otherDrive;
2429 
2430     init_pointers();
2431 
2432     /* Report only once */
2433     if (!pGetLongPathNameA)
2434         win_skip("GetLongPathNameA is not available\n");
2435     if (!pGetLongPathNameW)
2436         win_skip("GetLongPathNameW is not available\n");
2437     if (!pActivateActCtx)
2438         win_skip("Activation contexts not supported, some tests will be skipped\n");
2439 
2440     test_relative_path();
2441     test_InitPathA(curdir, &curDrive, &otherDrive);
2442     test_CurrentDirectoryA(origdir,curdir);
2443     test_PathNameA(curdir, curDrive, otherDrive);
2444     test_CleanupPathA(origdir,curdir);
2445     test_GetTempPath();
2446     test_GetLongPathNameA();
2447     test_GetLongPathNameW();
2448     test_GetShortPathNameW();
2449     test_GetSystemDirectory();
2450     test_GetWindowsDirectory();
2451     test_NeedCurrentDirectoryForExePathA();
2452     test_NeedCurrentDirectoryForExePathW();
2453     test_drive_letter_case();
2454     test_SearchPathA();
2455     test_SearchPathW();
2456     test_GetFullPathNameA();
2457     test_GetFullPathNameW();
2458     test_CheckNameLegalDOS8Dot3();
2459     test_SetSearchPathMode();
2460 }
2461