没有前缀 '\\?\' 的 GetFinalPathNameByHandle() 结果
GetFinalPathNameByHandle() result without prepended '\\?\'
这是我的代码片段:
char existingTarget[MAX_PATH];
HANDLE hFile = CreateFile(linkPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
GetFinalPathNameByHandle(hFile, existingTarget, MAX_PATH, FILE_NAME_OPENED);
CloseHandle(hFile);
}
然而,existingTarget
即将成为 \?\C:\mydir\etc
。我怎样才能 return 只是 C:\mydir\etc
?
注意:我不想检查字符串 \?\
而只是 memmove
它,对于这个程序。
how can I get it to return just C:\mydir\etc
你不能。 VOLUME_NAME_DOS
和 VOLUME_NAME_GUID
始终 使用该格式,并记录如下:
The string that is returned by this function uses the \?\
syntax.
请参阅documentation 的“社区添加”部分中的示例结果。
Note: I don't want to check for the string \?\
and just memmove it, its a bit too hackish of a solution for this program.
这是最简单的解决方案。否则,您必须使用其他 API 将返回的路径转换为更易于阅读的路径。比如用VOLUME_NAME_NT
的结果和QueryDosDevice()
, or using the result of VOLUME_NAME_GUID
with GetVolumePathNamesForVolumeName()
.
我知道,您不想检查 \?\
并将其删除,但正如雷米在他的 , that's the easiest solution. However, you should be careful, because local paths and network paths have different prefixes. As you know, a local path starts with \?\
, but a network path starts with \?\UNC\
(as described here 中解释的那样,例如:
\?\UNC\My server\My share\Directory
因此,根据您的代码,我去除前缀的解决方案如下:
char existingTarget[MAX_PATH];
HANDLE hFile = CreateFileA(linkPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
DWORD ret = GetFinalPathNameByHandleA(hFile, existingTarget, MAX_PATH, FILE_NAME_OPENED);
CloseHandle(hFile);
// Check whether existingTarget is large enough to hold the final path.
if (ret < MAX_PATH)
{
// The local path prefix is also a prefix of the network path prefix.
// Therefore, look for the network path prefix first.
// Please note that backslashes have to be escaped.
std::string targetPath(existingTarget);
if (targetPath.substr(0, 8).compare("\\?\UNC\") == 0)
{
// In case of a network path, replace `\?\UNC\` with `\`.
targetPath = "\" + targetPath.substr(7);
}
else if (targetPath.substr(0, 4).compare("\\?\") == 0)
{
// In case of a local path, crop `\?\`.
targetPath = targetPath.substr(4);
}
}
}
如果需要,您仍然可以使用 memmove()
将 targetPath
复制到另一个变量中。
如果您不想进行解析,还有其他一些方法:
std::filesystem
可以处理它(至少使用 MSVC,没有在 MinGW 或 Cygwin 上检查 GCC),如果你不介意 std::string
:
#include <filesystem>
#include <string>
...
std::string cleanerPath = std::filesystem::canonical(existingTarget).string();
// use weakly_canonical instead if the file might not exist.
如果您将 VOLUME_NAME_NONE
传递给 GetFinalPathNameByHandle
,它将去除前缀 和 驱动器号,它最终会给你一条以 \
开头的无驱动路径,根据情况可能有用也可能没用,但是...
如果你传递了VOLUME_NAME_NONE
但你也知道该文件与当前工作目录在同一个驱动器上,那么std::filesystem
和GetFullPathName
都可以重新- 为您完成路径:
...
// result will not include drive letter component
GetFinalPathNameByHandle(hFile, existingTarget, MAX_PATH,
FILE_NAME_OPENED | VOLUME_NAME_NONE);
...
{
// with std::filesystem into an std::string:
std::string cleanerPath = std::filesystem::absolute(existingTarget).string();
}
...
{
// or with win api:
char cleanerPath[MAX_PATH];
GetFullPathNameA(existingTarget, sizeof(cleanerPath), cleanerPath, nullptr);
}
您也可以使用 GetFileInformationByHandleEx
而不是 GetFinalPathNameByHandle
,但代价是 API(并且没有 ANSI 版本)。 (待办事项:示例;现在没有更多时间)
当然,您可以保留 是 Windows 上的有效路径的前缀,即使它有点不常见。
这是我的代码片段:
char existingTarget[MAX_PATH];
HANDLE hFile = CreateFile(linkPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
GetFinalPathNameByHandle(hFile, existingTarget, MAX_PATH, FILE_NAME_OPENED);
CloseHandle(hFile);
}
然而,existingTarget
即将成为 \?\C:\mydir\etc
。我怎样才能 return 只是 C:\mydir\etc
?
注意:我不想检查字符串 \?\
而只是 memmove
它,对于这个程序。
how can I get it to return just C:\mydir\etc
你不能。 VOLUME_NAME_DOS
和 VOLUME_NAME_GUID
始终 使用该格式,并记录如下:
The string that is returned by this function uses the
\?\
syntax.
请参阅documentation 的“社区添加”部分中的示例结果。
Note: I don't want to check for the string
\?\
and just memmove it, its a bit too hackish of a solution for this program.
这是最简单的解决方案。否则,您必须使用其他 API 将返回的路径转换为更易于阅读的路径。比如用VOLUME_NAME_NT
的结果和QueryDosDevice()
, or using the result of VOLUME_NAME_GUID
with GetVolumePathNamesForVolumeName()
.
我知道,您不想检查 \?\
并将其删除,但正如雷米在他的 \?\
, but a network path starts with \?\UNC\
(as described here 中解释的那样,例如:
\?\UNC\My server\My share\Directory
因此,根据您的代码,我去除前缀的解决方案如下:
char existingTarget[MAX_PATH];
HANDLE hFile = CreateFileA(linkPath.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (INVALID_HANDLE_VALUE != hFile)
{
DWORD ret = GetFinalPathNameByHandleA(hFile, existingTarget, MAX_PATH, FILE_NAME_OPENED);
CloseHandle(hFile);
// Check whether existingTarget is large enough to hold the final path.
if (ret < MAX_PATH)
{
// The local path prefix is also a prefix of the network path prefix.
// Therefore, look for the network path prefix first.
// Please note that backslashes have to be escaped.
std::string targetPath(existingTarget);
if (targetPath.substr(0, 8).compare("\\?\UNC\") == 0)
{
// In case of a network path, replace `\?\UNC\` with `\`.
targetPath = "\" + targetPath.substr(7);
}
else if (targetPath.substr(0, 4).compare("\\?\") == 0)
{
// In case of a local path, crop `\?\`.
targetPath = targetPath.substr(4);
}
}
}
如果需要,您仍然可以使用 memmove()
将 targetPath
复制到另一个变量中。
如果您不想进行解析,还有其他一些方法:
std::filesystem
可以处理它(至少使用 MSVC,没有在 MinGW 或 Cygwin 上检查 GCC),如果你不介意std::string
:#include <filesystem> #include <string> ... std::string cleanerPath = std::filesystem::canonical(existingTarget).string(); // use weakly_canonical instead if the file might not exist.
如果您将
VOLUME_NAME_NONE
传递给GetFinalPathNameByHandle
,它将去除前缀 和 驱动器号,它最终会给你一条以\
开头的无驱动路径,根据情况可能有用也可能没用,但是...如果你传递了
VOLUME_NAME_NONE
但你也知道该文件与当前工作目录在同一个驱动器上,那么std::filesystem
和GetFullPathName
都可以重新- 为您完成路径:... // result will not include drive letter component GetFinalPathNameByHandle(hFile, existingTarget, MAX_PATH, FILE_NAME_OPENED | VOLUME_NAME_NONE); ... { // with std::filesystem into an std::string: std::string cleanerPath = std::filesystem::absolute(existingTarget).string(); } ... { // or with win api: char cleanerPath[MAX_PATH]; GetFullPathNameA(existingTarget, sizeof(cleanerPath), cleanerPath, nullptr); }
您也可以使用
GetFileInformationByHandleEx
而不是GetFinalPathNameByHandle
,但代价是 API(并且没有 ANSI 版本)。 (待办事项:示例;现在没有更多时间)
当然,您可以保留 是 Windows 上的有效路径的前缀,即使它有点不常见。