Is there a difference between \ ?? \ and \\? \ Roads?

The MSDN document Naming Files, Paths, and Namespaces discusses the prefix \\?\. Quote:

For file input / output, the prefix "\? \" To the path line tells the Windows API to turn off all parsing of the line and send the line that follows it directly to the file system.

The experiment showed me that the prefix \??\has the same effect as disabling path parsing ( ..processing) and enabling paths longer than MAX_PATH.

MSDN refers to \\?both as the "Win32 file namespace" and is it known only by the Win32 API and translates to \??in the NT namespace? And in general, through Winobj I see GLOBAL??in the NT namespace, not ??.

+4
source share
1 answer

The answer to your question: yes, there is a difference between the transfer \\?\and \??\user mode functions.

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;
}
+8

All Articles