GetFullPathNameW 和长 Windows 文件路径
GetFullPathNameW and long Windows file paths
在我当前个人项目的 Windows 版本中,我希望支持 extended length filepaths. As a result, I'm a little confused with how to use the GetFullPathNameW API 来解析长文件路径的全名。
根据 MSDN(关于 lpFileName 参数):
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.
如果我理解正确,为了在 GetFullPathNameW
中使用扩展长度的文件路径,我需要指定一个附加了 \?\
前缀的路径。由于 \?\
前缀仅在卷号或 UNC 路径之前有效,这意味着 API 无法用于解析相对于当前目录的路径的全名。
如果是这样,如果结果名称的长度超过 MAX_PATH
,是否还有另一个 API 我可以用来解析文件路径的全名,例如 ..\somedir\somefile.txt
?如果没有,我是否能够将 GetCurrentDirectory
与相对文件路径 (\?\C:\my\cwd\..\somedir\somefile.txt
) 结合使用并与 GetFullPathNameW
一起使用,还是我需要自己处理所有文件路径解析?
GetFullPathNameA
限制为 MAX_PATH
个字符,因为它事先使用硬编码的 MAX_PATH
大小将 ANSI 名称转换为 UNICODE
名称(以字符为单位)UNICODE
缓冲区。如果转换没有因长度限制而失败,则调用 GetFullPathNameW
(或直接 GetFullPathName_U[Ex]
)并将生成的 UNICODE
名称转换为 ANSI。
GetFullPathNameW
比 GetFullPathName_U
更薄 shell。它在 WCHAR 中限制为 MAXSHORT (0x7fff)
长度,与 \?\
文件前缀无关。即使没有 \?\
,它也适用于长 (> MAX_PATH
) 的相对名称。但是,如果 lpFileName
参数不以 \?\
前缀开头,则 lpBuffer
参数中的结果名称也不会以 \?\
开头。
如果您将 lpBuffer
与 CreateFileW
等函数一起使用 - 此函数在内部将 Win32Name
转换为 NtName
。结果将取决于颈背类型 (RTL_PATH_TYPE
)。如果名称不以 \?\
前缀开头,则转换失败,因为 RtlDosPathNameToRelativeNtPathName_U[_WithStatus]
失败(因为如果路径不以 \?\
开头,它将在内部调用 GetFullPathName_U
(相同的功能由 GetFullPathNameW
调用),nBufferLength
硬编码为 MAX_PATH(恰好 2*MAX_PATH
字节 – NTDLL 函数使用缓冲区大小,而不是 WCHAR
s)。如果名称以 \?\
前缀开头,执行 RtlDosPathNameToRelativeNtPathName_U[_WithStatus]
中的另一种情况 – RtlpWin32NtNameToNtPathName
,它将 \?\
替换为 \??\
并且没有 MAX_PATH
限制
所以解决方案可能如下所示:
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, ...);
}
}
所以我们需要指定一个带有 \?\
前缀的路径,但不是在 GetFullPathName 之前 - 之后!
有关详细信息,请阅读此 - The Definitive Guide on Win32 to NT Path Conversion
仅更新当前状态:
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: ...
其他的请看我的回答:
在我当前个人项目的 Windows 版本中,我希望支持 extended length filepaths. As a result, I'm a little confused with how to use the GetFullPathNameW API 来解析长文件路径的全名。
根据 MSDN(关于 lpFileName 参数):
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.
如果我理解正确,为了在 GetFullPathNameW
中使用扩展长度的文件路径,我需要指定一个附加了 \?\
前缀的路径。由于 \?\
前缀仅在卷号或 UNC 路径之前有效,这意味着 API 无法用于解析相对于当前目录的路径的全名。
如果是这样,如果结果名称的长度超过 MAX_PATH
,是否还有另一个 API 我可以用来解析文件路径的全名,例如 ..\somedir\somefile.txt
?如果没有,我是否能够将 GetCurrentDirectory
与相对文件路径 (\?\C:\my\cwd\..\somedir\somefile.txt
) 结合使用并与 GetFullPathNameW
一起使用,还是我需要自己处理所有文件路径解析?
GetFullPathNameA
限制为MAX_PATH
个字符,因为它事先使用硬编码的MAX_PATH
大小将 ANSI 名称转换为UNICODE
名称(以字符为单位)UNICODE
缓冲区。如果转换没有因长度限制而失败,则调用GetFullPathNameW
(或直接GetFullPathName_U[Ex]
)并将生成的UNICODE
名称转换为 ANSI。GetFullPathNameW
比GetFullPathName_U
更薄 shell。它在 WCHAR 中限制为MAXSHORT (0x7fff)
长度,与\?\
文件前缀无关。即使没有\?\
,它也适用于长 (>MAX_PATH
) 的相对名称。但是,如果lpFileName
参数不以\?\
前缀开头,则lpBuffer
参数中的结果名称也不会以\?\
开头。如果您将
lpBuffer
与CreateFileW
等函数一起使用 - 此函数在内部将Win32Name
转换为NtName
。结果将取决于颈背类型 (RTL_PATH_TYPE
)。如果名称不以\?\
前缀开头,则转换失败,因为RtlDosPathNameToRelativeNtPathName_U[_WithStatus]
失败(因为如果路径不以\?\
开头,它将在内部调用GetFullPathName_U
(相同的功能由GetFullPathNameW
调用),nBufferLength
硬编码为 MAX_PATH(恰好2*MAX_PATH
字节 – NTDLL 函数使用缓冲区大小,而不是WCHAR
s)。如果名称以\?\
前缀开头,执行RtlDosPathNameToRelativeNtPathName_U[_WithStatus]
中的另一种情况 –RtlpWin32NtNameToNtPathName
,它将\?\
替换为\??\
并且没有MAX_PATH
限制
所以解决方案可能如下所示:
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, ...);
}
}
所以我们需要指定一个带有 \?\
前缀的路径,但不是在 GetFullPathName 之前 - 之后!
有关详细信息,请阅读此 - The Definitive Guide on Win32 to NT Path Conversion
仅更新当前状态:
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: ...
其他的请看我的回答: