GetFullPathNameW and long Windows file paths GetFullPathNameW and long Windows file paths windows windows

GetFullPathNameW and long Windows file paths


  1. GetFullPathNameA is limited to MAX_PATH characters, because it converts the ANSI name to a UNICODE name beforehand using a hardcoded MAX_PATH-sized (in chars) UNICODE buffer. If the conversion doesn't fail due to the length restrictions, then GetFullPathNameW (or direct GetFullPathName_U[Ex]) is called and the resulting UNICODE name is converted to ANSI.

  2. GetFullPathNameW is a very thin shell over GetFullPathName_U. It is limited to MAXSHORT (0x7fff) length in WCHARs, independent of the \\?\ file prefix. Even without \\?\, it will be work for long (> MAX_PATH) relative names. However, if the lpFileName parameter does not begin with the \\?\ prefix, the result name in the lpBuffer parameter will not begin with \\?\ either.

  3. if you will be use lpBuffer with functions like CreateFileW - this function internally convert Win32Name to NtName. and result will be depended from nape type (RTL_PATH_TYPE). if the name does not begin with \\?\ prefix, the conversion fails because RtlDosPathNameToRelativeNtPathName_U[_WithStatus] fails (because if the path not begin with \\?\ it will be internally call GetFullPathName_U (same function called by GetFullPathNameW) with nBufferLength hardcoded to MAX_PATH (exactly 2*MAX_PATH in bytes – NTDLL functions use buffer size in bytes, not in WCHARs). If name begin with \\?\ prefix, another case in RtlDosPathNameToRelativeNtPathName_U[_WithStatus] is executed – RtlpWin32NtNameToNtPathName, which replaces \\?\ with \??\ and has no MAX_PATH limitation

So the solution may 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 a path with the \\?\ prefix attached, but not before GetFullPathName - after!

For more info, read this - The Definitive Guide on Win32 to NT Path Conversion


Just to update with the current state:

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

For the rest, please see my answer here: https://stackoverflow.com/a/57624626/3736444