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