GetFinalPathNameByHandle() 结果不带前缀 '\?\'

问题描述 投票:0回答:4

这是我的代码片段:

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
。我怎样才能让它返回
C:\mydir\etc

注意:我不想检查字符串

\\?\
,只是检查
memmove
,这个程序的解决方案有点太老套了。

c++ winapi file-management
4个回答
5
投票

我怎样才能让它只返回 C:\mydir tc

你不能。

VOLUME_NAME_DOS
VOLUME_NAME_GUID
always 使用该格式,并记录如下:

此函数返回的字符串使用

\\?\
语法。

请参阅文档的社区添加部分中的示例结果

注意:我不想检查字符串

\\?\
并只是 memmove 它,对于这个程序来说,它的解决方案有点太老套了。

这是最简单的解决方案。否则,您必须使用其他 API 将返回的路径转换为更易于理解的路径。例如将

VOLUME_NAME_NT
的结果与
QueryDosDevice()
一起使用,或者将
VOLUME_NAME_GUID
的结果与
GetVolumePathNamesForVolumeName()
一起使用。


1
投票

我知道,您不想检查

\\?\
并将其删除,但正如 Remy 在他的 answer 中解释的那样,这是最简单的解决方案。但是,您应该小心,因为本地路径和网络路径具有不同的前缀。如您所知,本地路径以
\\?\
开头,但网络路径以
\\?\UNC\
开头(如此处所述),例如:

\\?\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
复制到另一个变量中。


0
投票

从 Windows 8 开始,您只需调用 PathCchStripPrefix 即可删除

\\?\
\\?\UNC
前缀。


-1
投票

如果您不想进行解析,还有其他一些方法:

  • 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 上的有效路径,即使它有点不常见。

© www.soinside.com 2019 - 2024. All rights reserved.