Ответ 1
OK. Это оказывается не таким простым, как кажется. Камнем преткновения (помимо нечеткой документации и несметным количеством форматов пути) является то, что некоторые 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 / with \ 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 / with \ 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;
}
И вот как я его тестирую:
_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");
И это результат, который я получаю:
\\?\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