问题
In the Windows version of my current personal project, I'm looking to support extended length filepaths. As a result, I'm a little confused with how to use the GetFullPathNameW API to resolve the full name of a long filepath.
According to the MSDN (with regards to 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 version of the function and prepend "\?\" to the path. For more information, see Naming a File.
If I'm understanding this correctly, in order to use an extended length filepath with GetFullPathNameW
, I need to specify a path with the \\?\
prefix attached. Since the \\?\
prefix is only valid before volume letters or UNC paths, this would mean that the API is unusable for resolving the full name of a path relative to the current directory.
If that's the case, is there another API I can use to resolve the full name of a filepath like ..\somedir\somefile.txt
if the resulting name's length exceeds MAX_PATH
? If not, would I be able to combine GetCurrentDirectory
with the relative filepath (\\?\C:\my\cwd\..\somedir\somefile.txt
) and use it with GetFullPathNameW
, or would I need to handle all of the filepath resolution on my own?
回答1:
GetFullPathNameA
is limited toMAX_PATH
characters, because it converts the ANSI name to aUNICODE
name beforehand using a hardcodedMAX_PATH
-sized (in chars)UNICODE
buffer. If the conversion doesn't fail due to the length restrictions, thenGetFullPathNameW
(or directGetFullPathName_U[Ex]
) is called and the resultingUNICODE
name is converted to ANSI.GetFullPathNameW
is a very thin shell overGetFullPathName_U
. It is limited toMAXSHORT (0x7fff)
length in WCHARs, independent of the\\?\
file prefix. Even without\\?\
, it will be work for long (>MAX_PATH
) relative names. However, if thelpFileName
parameter does not begin with the\\?\
prefix, the result name in thelpBuffer
parameter will not begin with\\?\
either.if you will be use
lpBuffer
with functions likeCreateFileW
- this function internally convertWin32Name
toNtName
. and result will be depended from nape type (RTL_PATH_TYPE
). if the name does not begin with\\?\
prefix, the conversion fails becauseRtlDosPathNameToRelativeNtPathName_U[_WithStatus]
fails (because if the path not begin with\\?\
it will be internally callGetFullPathName_U
(same function called byGetFullPathNameW
) withnBufferLength
hardcoded to MAX_PATH (exactly2*MAX_PATH
in bytes – NTDLL functions use buffer size in bytes, not inWCHAR
s). If name begin with\\?\
prefix, another case inRtlDosPathNameToRelativeNtPathName_U[_WithStatus]
is executed –RtlpWin32NtNameToNtPathName
, which replaces\\?\
with\??\
and has noMAX_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
回答2:
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
来源:https://stackoverflow.com/questions/38036943/getfullpathnamew-and-long-windows-file-paths