需要澄清将路径转换为长Unicode路径或以\\?\开头的路径

c00*_*0fd 11 c++ windows unicode winapi path

首先,让我问一个修辞问题 - 微软,为什么\\?\要让我们在前面添加路径以允许它们长达32,767个字符?为什么不直接使用它们并扩展API上内部缓冲区的大小?对不起,我只是在发泄我的沮丧......

好的,现在我的实际问题,如果我有一条路径,如何将其转换为接受32,767个字符长度的格式?请注意,我对该路径一无所知 - 它可以是相对路径,绝对本地路径,网络共享等.换句话说,它可以是Microsoft发明的众多路径格式中的任何一种.

起初,它似乎是一个直接的命题,\\?\在开头添加,对吧?那么,如果该路径已经转换为扩展格式怎么办?我尝试阅读这个,从该页面的大小和底部的评论数量,你可以看到事情并不像看起来那么简单.

c00*_*0fd 5

好的。事实证明这并不像听起来那么简单。绊脚石(除了模糊的文档和无数的路径格式)是,某些 API 甚至无法在所有版本的操作系统上都像宣传的那样工作。

无论如何,这就是我想出的,它似乎适用于 XP SP3、Vista、Windows 7 和 8。有点大,也是为 MFC 编写的,但这仅用于字符串管理。我没有时间调整它:

enum PATH_PREFIX_TYPE
{
    PPT_UNKNOWN,
    PPT_ABSOLUTE,           //Found absolute path that is none of the other types
    PPT_UNC,                //Found \\server\share\ prefix
    PPT_LONG_UNICODE,       //Found \\?\ prefix
    PPT_LONG_UNICODE_UNC,   //Found \\?\UNC\ prefix
};

CString MakeUnicodeLargePath(LPCTSTR pPath)
{
    //Convert path from 'pPath' into a larger Unicode path, that allows up to 32,767 character length
    //RETURN:
    //      = Resulting path
    CString strPath;

    if(pPath &&
        pPath[0] != 0)
    {
        //Determine the type of the existing prefix
        PATH_PREFIX_TYPE ppt;
        GetOffsetAfterPathRoot(pPath, &ppt);

        //Assume path to be without change
        strPath = pPath;

        switch(ppt)
        {
        case PPT_ABSOLUTE:
            {
                //First we need to check if its an absolute path relative to the root
                BOOL bOK2AddPrefix = TRUE;
                if(strPath.GetLength() >= 1 &&
                    (strPath[0] == L'\\' || strPath[0] == L'/'))
                {
                    bOK2AddPrefix = FALSE;

                    //Get current root path
                    TCHAR chDummy[1];
                    DWORD dwLnSz = GetCurrentDirectory(0, chDummy);
                    if(dwLnSz)
                    {
                        TCHAR* pBuff = new (std::nothrow) TCHAR[dwLnSz];
                        if(pBuff)
                        {
                            if(GetCurrentDirectory(dwLnSz, pBuff) == dwLnSz - 1)
                            {
                                int nIndFollowing = GetOffsetAfterPathRoot(pBuff);
                                if(nIndFollowing > 0)
                                {
                                    bOK2AddPrefix = TRUE;
                                    CString strRoot = pBuff;
                                    strPath = strRoot.Left(nIndFollowing) + strPath.Right(strPath.GetLength() - 1);
                                }
                            }

                            delete[] pBuff;
                            pBuff = NULL;
                        }
                    }
                }

                if(bOK2AddPrefix)
                {
                    //Add \\?\ prefix
                    strPath = L"\\\\?\\" + strPath;
                }
            }
            break;

        case PPT_UNC:
            {
                //First we need to remove the opening slashes for UNC share
                if(strPath.GetLength() >= 2 &&
                    (strPath[0] == L'\\' || strPath[0] == L'/') &&
                    (strPath[1] == L'\\' || strPath[1] == L'/')
                    )
                {
                    strPath = strPath.Right(strPath.GetLength() - 2);
                }

                //Add \\?\UNC\ prefix
                strPath = L"\\\\?\\UNC\\" + strPath;
            }
            break;
        }
    }

    return strPath;
}

LPCTSTR PathSkipRoot_CorrectedForMicrosoftStupidity(LPCTSTR pszPath)
{
    //Correction for PathSkipRoot API
    CString strPath = pszPath;

    //Replace all /'s with \'s because PathSkipRoot can't handle /'s
    strPath.Replace(L'/', L'\\');

    //Now call the API
    LPCTSTR pResBuff = PathSkipRoot(strPath.GetString());

    return pResBuff ? pszPath + (UINT)(pResBuff - strPath.GetString()) : NULL;
}

BOOL PathIsRelative_CorrectedForMicrosoftStupidity(LPCTSTR pszPath)
{
    //Correction for PathIsRelative API
    CString strPath = pszPath;

    //Replace all /'s with \'s because PathIsRelative can't handle /'s
    strPath.Replace(L'/', L'\\');

    //Now call the API
    return PathIsRelative(strPath);
}

int GetOffsetAfterPathRoot(LPCTSTR pPath, PATH_PREFIX_TYPE* pOutPrefixType)
{
    //Checks if 'pPath' begins with the drive, share, prefix, etc
    //EXAMPLES:
    //   Path                          Return:   Points at:                 PrefixType:
    //  Relative\Folder\File.txt        0         Relative\Folder\File.txt   PPT_UNKNOWN
    //  \RelativeToRoot\Folder          1         RelativeToRoot\Folder      PPT_ABSOLUTE
    //  C:\Windows\Folder               3         Windows\Folder             PPT_ABSOLUTE
    //  \\server\share\Desktop          15        Desktop                    PPT_UNC
    //  \\?\C:\Windows\Folder           7         Windows\Folder             PPT_LONG_UNICODE
    //  \\?\UNC\server\share\Desktop    21        Desktop                    PPT_LONG_UNICODE_UNC
    //RETURN:
    //      = Index in 'pPath' after the root, or
    //      = 0 if no root was found
    int nRetInd = 0;
    PATH_PREFIX_TYPE ppt = PPT_UNKNOWN;

    if(pPath &&
        pPath[0] != 0)
    {
        int nLen = lstrlen(pPath);

        //Determine version of Windows
        OSVERSIONINFO osi;
        osi.dwOSVersionInfoSize = sizeof(osi);
        BOOL bWinXPOnly = GetVersionEx(&osi) && osi.dwMajorVersion <= 5;

        //The PathSkipRoot() API doesn't work correctly on Windows XP
        if(!bWinXPOnly)
        {
            //Works since Vista and up, but still needs correction :)
            LPCTSTR pPath2 = PathSkipRoot_CorrectedForMicrosoftStupidity(pPath);
            if(pPath2 &&
                pPath2 >= pPath)
            {
                nRetInd = pPath2 - pPath;
            }
        }

        //Now determine the type of prefix
        int nIndCheckUNC = -1;

        if(nLen >= 8 &&
            (pPath[0] == L'\\' || pPath[0] == L'/') &&
            (pPath[1] == L'\\' || pPath[1] == L'/') &&
            pPath[2] == L'?' &&
            (pPath[3] == L'\\' || pPath[3] == L'/') &&
            (pPath[4] == L'U' || pPath[4] == L'u') &&
            (pPath[5] == L'N' || pPath[5] == L'n') &&
            (pPath[6] == L'C' || pPath[6] == L'c') &&
            (pPath[7] == L'\\' || pPath[7] == L'/')
            )
        {
            //Found \\?\UNC\ prefix
            ppt = PPT_LONG_UNICODE_UNC;

            if(bWinXPOnly)
            {
                //For older OS
                nRetInd += 8;
            }

            //Check for UNC share later
            nIndCheckUNC = 8;
        }
        else if(nLen >= 4 &&
            (pPath[0] == L'\\' || pPath[0] == L'/') &&
            (pPath[1] == L'\\' || pPath[1] == L'/') &&
            pPath[2] == L'?' &&
            (pPath[3] == L'\\' || pPath[3] == L'/')
            )
        {
            //Found \\?\ prefix
            ppt = PPT_LONG_UNICODE;

            if(bWinXPOnly)
            {
                //For older OS
                nRetInd += 4;
            }
        }
        else if(nLen >= 2 &&
            (pPath[0] == L'\\' || pPath[0] == L'/') &&
            (pPath[1] == L'\\' || pPath[1] == L'/')
            )
        {
            //Check for UNC share later
            nIndCheckUNC = 2;
        }

        if(nIndCheckUNC >= 0)
        {
            //Check for UNC, i.e. \\server\share\ part
            int i = nIndCheckUNC;
            for(int nSkipSlashes = 2; nSkipSlashes > 0; nSkipSlashes--)
            {
                for(; i < nLen; i++)
                {
                    TCHAR z = pPath[i];
                    if(z == L'\\' ||
                        z == L'/' ||
                        i + 1 >= nLen)
                    {
                        i++;
                        if(nSkipSlashes == 1)
                        {
                            if(ppt == PPT_UNKNOWN)
                                ppt = PPT_UNC;

                            if(bWinXPOnly)
                            {
                                //For older OS
                                nRetInd = i;
                            }
                        }

                        break;
                    }
                }
            }
        }

        if(bWinXPOnly)
        {
            //Only if we didn't determine any other type
            if(ppt == PPT_UNKNOWN)
            {
                if(!PathIsRelative_CorrectedForMicrosoftStupidity(pPath + nRetInd))
                {
                    ppt = PPT_ABSOLUTE;
                }
            }

            //For older OS only
            LPCTSTR pPath2 = PathSkipRoot_CorrectedForMicrosoftStupidity(pPath + nRetInd);
            if(pPath2 &&
                pPath2 >= pPath)
            {
                nRetInd = pPath2 - pPath;
            }

        }
        else
        {
            //Only if we didn't determine any other type
            if(ppt == PPT_UNKNOWN)
            {
                if(!PathIsRelative_CorrectedForMicrosoftStupidity(pPath))
                {
                    ppt = PPT_ABSOLUTE;
                }
            }
        }
    }

    if(pOutPrefixType)
        *pOutPrefixType = ppt;

    return nRetInd;
}
Run Code Online (Sandbox Code Playgroud)

这是我测试它的方法:

_tprintf(MakeUnicodeLargePath(L""));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"C:\\Ba*d\\P|a?t<h>\\Windows\\Folder"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"Relative\\Folder\\File.txt"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"C:\\Windows\\Folder"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\?\\C:\\Windows\\Folder"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\?\\UNC\\server\\share\\Desktop"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\?\\unC\\server\\share\\Desktop\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\server\\share\\Desktop\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"C:\\Desktop\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\AbsoluteToRoot\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path\\Very Long path"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\server\\share\\Desktop"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\?\\UNC\\\\share\\folder\\Desktop"));
_tprintf(L"\n");
_tprintf(MakeUnicodeLargePath(L"\\\\server\\share"));
_tprintf(L"\n");
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出:

\\?\C:\Ba*d\P|a?t<h>\Windows\Folder
Relative\Folder\File.txt
\\?\C:\Windows\Folder
\\?\C:\Windows\Folder
\\?\UNC\server\share\Desktop
\\?\unC\server\share\Desktop\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path
\\?\UNC\server\share\Desktop\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path
\\?\C:\Desktop\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path
\\?\C:\AbsoluteToRoot\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path
\\?\UNC\server\share\Desktop
\\?\UNC\\share\folder\Desktop
\\?\UNC\server\share
Run Code Online (Sandbox Code Playgroud)