GetFullPathNameW and Long Windows File Paths

In the version of my current personal Windows project, I want to support extended file length paths . As a result, I'm a little confused about how to use the GetFullPathNameW API to resolve the full name of the long file path.

According to MSDN (regarding the lpFileName parameter):

In the ANSI version of this function, the name is limited to MAX_PATH characters. To extend this limit to 32,767 wide characters, call the Unicode function version and add "\? \" To the path. For more information, see the "File Naming" section.

If I understand this correctly, to use a path of length with a length of GetFullPathNameW , I need to specify the path with the prefix \\?\ GetFullPathNameW . Since the prefix \\?\ valid only up to volume letters or UNC paths, this means that the API is not applicable for resolving the full path name relative to the current directory.

If so, is there another API that I can use to resolve the full path name of a file, such as ..\somedir\somefile.txt , if the resulting name length exceeds MAX_PATH ? If not, can I combine GetCurrentDirectory with the relative path to the file ( \\?\C:\my\cwd\..\somedir\somefile.txt ) and use it with GetFullPathNameW , or will I need to handle all permissions along the path to file yourself?

+7
source share
2 answers
  1. GetFullPathNameA limited to GetFullPathNameA characters because it pre-converts the ANSI name to UNICODE using the hard-coded buffer MAX_PATH -sized (in characters) UNICODE . If the conversion does not fail due to length restrictions, GetFullPathNameW (or the direct GetFullPathName_U[Ex] ) is called, and the resulting UNICODE name is converted to ANSI.

  2. GetFullPathNameW very thin shell over GetFullPathName_U . It is limited by the length of MAXSHORT (0x7fff) in WCHAR, regardless of the \\?\ File prefix. Even without \\?\ , This will work for long (> MAX_PATH ) relative names. However, if the lpFileName parameter lpFileName not start with the \\?\ Prefix, the result name in the lpBuffer parameter also will not start with \\?\ .

  3. if you use lpBuffer with functions such as CreateFileW , this function internally converts Win32Name to NtName . and the result will depend on the type of neck ( RTL_PATH_TYPE ). if the name does not start with the prefix \\?\ , the conversion will fail because RtlDosPathNameToRelativeNtPathName_U[_WithStatus] will fail (because if the path does not start with \\?\ , it will be called internally by GetFullPathName_U (the same function that GetFullPathNameW calls ) with nBufferLength hardcoded to MAX_PATH (exactly 2*MAX_PATH in bytes - NTDLL functions use the size of the buffer in bytes rather than in WCHAR s.) If the name starts with the prefix \\?\ , another case is RtlDosPathNameToRelativeNtPathName_U[_WithStatus] in RtlDosPathNameToRelativeNtPathName_U[_WithStatus] RtlpWin32NtNameToNtPathName , which replaces \\?\ RtlpWin32NtNameToNtPathName \??\ and has no MAX_PATH restriction

So the solution might look like this:

 if(ULONG len = GetFullPathNameW(FileName, 0, 0, 0)) { PWSTR buf = (PWSTR)_alloca((4 + len) * sizeof(WCHAR)); buf[0] = L'\\', buf[1] = L'\\', buf[2] = L'?', buf[3] = L'\\'; if (len - 1 == GetFullPathName(FileName, len, buf + 4, &c)) { CreateFile(buf, ...); } } 

So, we need to specify the path with the prefix \\?\ Attached, but not before GetFullPathName - after!

For more information, read this - Complete Guide to Converting a Win32 Path to NT

+10
source

Just to update the current state:

Starting with Windows 10 version 1607, MAX_PATH restrictions have been removed from the common Win32 file and directory functions. However, you must subscribe to the new behavior. To enable the new long-path behavior, both of the following conditions must be met: ...

For the rest, see my answer here: fooobar.com/questions/3827294 / ...

-1
source

All Articles