Winapi \??\和\\?\路径之间有区别吗?
MSDN文档讨论了Winapi \??\和\\?\路径之间有区别吗?,winapi,internals,Winapi,Internals,MSDN文档讨论了\\?\前缀。引述: 对于文件I/O,路径字符串的“\?\”前缀告诉Windows API禁用所有字符串解析,并将其后的字符串直接发送到文件系统 实验表明,\??\前缀具有相同的效果,既可以禁用路径解析(。处理),也可以启用长度超过MAX\u path的路径 MSDN将\\?称为“Win32文件名称空间”,那么它是否纯粹由Win32 usermode API所知,并在NT名称空间中转换为\???无论如何,通过Winobj,我在NT名称空间中看到了GLOBAL???,而不是?,您
\\?\
前缀。引述:
对于文件I/O,路径字符串的“\?\”前缀告诉Windows API禁用所有字符串解析,并将其后的字符串直接发送到文件系统
实验表明,\??\
前缀具有相同的效果,既可以禁用路径解析(。
处理),也可以启用长度超过MAX\u path
的路径
MSDN将
\\?
称为“Win32文件名称空间”,那么它是否纯粹由Win32 usermode API所知,并在NT名称空间中转换为\??
?无论如何,通过Winobj,我在NT名称空间中看到了GLOBAL???
,而不是?
,您的问题的答案是,将\\?\
和\??
传递给用户模式函数是有区别的
在内部,NT总是以\??\
前缀表示路径。通常,当您使用正常路径(如C:\foo
)调用用户模式函数(例如CreateDirectoryW
)时,用户模式函数调用名为rtldospathname tontpathname\U
的内部函数,该函数将此路径转换为前缀为\??\
的NT样式路径。这种转换是通过一个固定大小的静态缓冲区完成的,这就是著名的MAX\u路径
限制的来源
当您调用指定\?\
前缀的用户模式函数(注意,只有一个?
)时,rtldospathnametpathname\U
不会被调用。相反,第二个反斜杠变成了?字符和路径被逐字使用。这就是文档在谈论关闭“…自动扩展路径字符串”时的意思
但是,当您使用\??\
前缀调用用户模式函数时(记住该前缀是内部NT前缀),此扩展仍然完成
用户模式功能专门查找\\?\
以禁用自动扩展过程,由于您不提供自动扩展过程,因此您的路径将被视为非前缀路径,并馈送至rtldospathnametpathname\U
。此函数足够智能,不会在路径的开头添加额外的\??\
前缀,但是仍然使用固定大小的静态缓冲区
这是关键区别。当您将\??\
作为前缀传递时,您的路径仍受最大路径
长度限制的约束
下面的示例程序演示了这一点。TestNestedDir
函数只是尝试创建(然后删除)长度大于MAX\u 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;
}
#包括
#包括
#包括
#包括
#包括
常量wchar_t*pszLongPath=
L“C:\\”
L“12345678901213456789012345678901234567890123456789012345678901234567890\\”
L“12345678901213456789012345678901234567890123456789012345678901234567890\\”
L“12345678901213456789012345678901234567890123456789012345678901234567890\\”
L“12345678901213456789012345678901234567890123456789012345678901234567890\\”
L“12345678901213456789012345678901234567890123456789012345678901234567890\\”
L“12345678901213456789012345678901234567890123456789012345678901234567890”;
bool TestCreateNestedDir(LPCWSTR pszPath)
{
std::wstring strPath=pszPath;
std::wstring::size_type pos=0,first=std::wstring::npos;
bool-fDirs=false,fResult=false;
//逐步浏览路径中的每个级别,但仅尝试开始创建目录
//看完一个:角色
while((pos=strPath.find_first_of(L'\\',pos))!=std::wstring::npos)
{
如果(联邦国税局)
{
//获取此级别路径的子字符串
std::wstring strSub=strPath.substr(0,位置);
//检查该级别是否因某种原因已存在
DWORD dwAttr=::GetFileAttributesW(strSub.c_str());
if(dwAttr!=-1&(dwAttr&FILE\u属性\u目录))
{
++pos;
继续;
}
//尝试创建目录。如果它存在,请记住我们成功创建的第一个目录,以便以后进行清理
if(!::CreateDirectoryW(strSub.c_str(),nullptr))
打破
if(first==std::wstring::npos)first=pos;
}
其他的
如果(pos>0&&strPath[pos-1]==L':')
fDirs=真;
++pos;
}
if(pos==std::wstring::npos)
{
//尝试创建路径的最后一级(我们假设这一级不存在)
if(::CreateDirectoryW(pszPath,nullptr))
{
fResult=真;
::RemoveDirectoryW(pszPath);
}
}
其他的
--pos;
//现在删除我们成功创建的所有目录
while((pos=strPath.find_last_of(L'\\',pos))!=std::wstring::npos)
{
::RemoveDirectoryW(strPath.substr(0,pos.c_str());
如果(位置==首次)中断;
--pos;
}
返回fResult;
}
int _tmain(int argc,_TCHAR*argv[]
{
断言(wcslen(pszLongPath)>最大路径);
printf(“CreateDir,无前缀=%ld\n”,TestCreateNestedDir(pszLongPath));
std::wstring strPrefix=L“\\\\\?\\”+std::wstring(pszLongPath);
printf(“CreateDir,前缀\\\\?\\=%ld\n”,TestCreateNestedDir(strPrefix.c_str());
strPrefix[1]=L'?';
printf(“CreateDir,前缀\??\=%ld\n”,TestCreateNestedDir(strPrefix.c_str());
返回0;
}
实际路径和带有转义反斜杠的C样式字符串文字混淆在一起。没有\\\.\
前缀“\\\\.\\”
是如何在C字符串文本中编写\\.\
前缀的。\.\
前缀在同一MSDN页面的“Win32 Device Namespaces”部分中进行了描述,可能与我删除的\\.\n问题完全相同。集中我的问题