gpt4 book ai didi

winapi -\??\和\\?\路径之间有区别吗?

转载 作者:行者123 更新时间:2023-12-04 10:50:44 25 4
gpt4 key购买 nike

MSDN文档Naming Files, Paths, and Namespaces讨论了\\?\前缀。报价:

For file I/O, the "\?\" prefix to a path string tells the Windows APIs to disable all string parsing and to send the string that follows it straight to the file system.



实验表明, \??\前缀具有相同的效果,既禁用路径解析( ..处理),又启用比 MAX_PATH长的路径。

MSDN将 \\?称为“Win32文件命名空间”,那么它是否仅由Win32用户模式API知道并转换为NT命名空间中的 \???而且无论如何,通过Winobj,我在NT namespace 中看到 GLOBAL??,而不是 ??

最佳答案

您问题的答案是,是的,将\\?\\??\传递给用户模式函数之间是有区别的。

在内部,NT始终使用\??\前缀表示路径。通常,当您使用诸如CreateDirectoryW之类的普通路径调用用户模式函数(例如C:\foo)时,用户模式函数会调用一个内部函数RtlDosPathNameToNtPathName_U,该函数会将其转换为前缀为\??\的NT样式路径。这种转换是使用固定大小的静态缓冲区完成的,这是著名的MAX_PATH限制所来自的地方。

当您调用指定\\?\前缀的用户模式函数(注意,仅一个?)时,RtlDosPathNameToNtPathName_U而不是。取而代之的是,第二个反斜杠变为?。字符和路径按原样使用。这就是当他们谈论\\?\关闭“...自动扩展路径字符串”时的意思。

但是,当您调用带有\??\前缀(记住是内部NT前缀)的用户模式函数时,此扩展仍会完成。

用户模式功能专门查找\\?\以禁用自动扩展过程,并且由于您未提供该功能,因此您的路径被视为非前缀路径,并被馈送到RtlDosPathNameToNtPathName_U。此函数足够聪明,不会在路径的开头添加额外的\??\前缀,但是仍然使用固定大小的静态缓冲区

这是关键的区别。当您将\??\作为前缀传递时,您的路径仍受MAX_PATH长度限制。

下面的示例程序对此进行了演示。 TestNestedDir函数只是尝试创建(然后删除)一个长度大于MAX_PATH字符的路径,一次增加一个级别。如果运行此代码,您将看到以下结果:

CreateDir, no prefix = 0
CreateDir, prefix \\?\ = 1
CreateDir, prefix \??\ = 0

只有使用\\?\前缀完成的创建才成功。
#include <stdio.h>
#include <tchar.h>
#include <string>
#include <assert.h>
#include <Windows.h>

const wchar_t* pszLongPath =
L"C:\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890\\"
L"12345678901234567890123456789012345678901234567890";

bool TestCreateNestedDir(LPCWSTR pszPath)
{
std::wstring strPath = pszPath;
std::wstring::size_type pos = 0, first = std::wstring::npos;
bool fDirs = false, fResult = false;

// step through each level in the path, but only try to start creating directories
// after seeing a : character
while ((pos = strPath.find_first_of(L'\\', pos)) != std::wstring::npos)
{
if (fDirs)
{
// get a substring for this level of the path
std::wstring strSub = strPath.substr(0, pos);

// check if the level already exists for some reason
DWORD dwAttr = ::GetFileAttributesW(strSub.c_str());
if (dwAttr != -1 && (dwAttr & FILE_ATTRIBUTE_DIRECTORY))
{
++pos;
continue;
}

// try to make the dir. if it exists, remember the first one we successfully made for later cleanup
if (!::CreateDirectoryW(strSub.c_str(), nullptr))
break;
if (first == std::wstring::npos) first = pos;
}
else
if (pos > 0 && strPath[pos - 1] == L':')
fDirs = true;

++pos;
}

if (pos == std::wstring::npos)
{
// try to create the last level of the path (we assume this one doesn't exist)
if (::CreateDirectoryW(pszPath, nullptr))
{
fResult = true;
::RemoveDirectoryW(pszPath);
}
}
else
--pos;

// now delete any dirs we successfully made
while ((pos = strPath.find_last_of(L'\\', pos)) != std::wstring::npos)
{
::RemoveDirectoryW(strPath.substr(0, pos).c_str());
if (pos == first) break;
--pos;
}
return fResult;
}


int _tmain(int argc, _TCHAR* argv[])
{
assert(wcslen(pszLongPath) > MAX_PATH);

printf("CreateDir, no prefix = %ld\n", TestCreateNestedDir(pszLongPath));

std::wstring strPrefix = L"\\\\?\\" + std::wstring(pszLongPath);
printf("CreateDir, prefix \\\\?\\ = %ld\n", TestCreateNestedDir(strPrefix.c_str()));

strPrefix[1] = L'?';
printf("CreateDir, prefix \\??\\ = %ld\n", TestCreateNestedDir(strPrefix.c_str()));
return 0;
}

关于winapi -\??\和\\?\路径之间有区别吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25090101/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com