2013-09-02 33 views
11

Trước tiên, hãy để tôi hỏi một câu hỏi hùng biện - Microsoft, tại sao chúng ta tạo đường dẫn trước với \\?\ để cho phép chúng dài 32.767 ký tự? Tại sao không chỉ sử dụng chúng như là-và mở rộng kích thước của bộ đệm nội bộ trên API? Xin lỗi, tôi chỉ trút sự thất vọng của tôi ...Cần làm rõ để chuyển đổi đường dẫn thành đường dẫn Unicode dài hoặc bắt đầu bằng \?

OK, bây giờ câu hỏi thực tế của tôi, nếu tôi có đường dẫn, làm cách nào để chuyển đổi sang định dạng chấp nhận độ dài ký tự 32,767? Lưu ý rằng tôi không biết gì về đường dẫn đó - nó có thể là đường dẫn tương đối, đường dẫn cục bộ tuyệt đối, chia sẻ mạng, v.v. Nói cách khác, nó có thể là bất kỳ định dạng đường dẫn nào mà Microsoft đã phát minh ra.

Lúc đầu, nó có vẻ giống như một mệnh đề đơn giản về việc thêm \\?\ ngay từ đầu, phải không? Vâng, nếu đường dẫn đó đã được chuyển đổi sang định dạng mở rộng thì sao? Tôi đã thử reading this và từ kích thước của trang đó và số lượng nhận xét ở dưới cùng, bạn có thể thấy rằng mọi thứ không đơn giản như nó có vẻ.

+2

Tôi khen bạn cho cả việc tìm kiếm và * đọc * bài viết bạn đã liên kết, cũng như thực hiện các hình thức thực sự phải được xem xét như là kết quả. Lời khuyên đơn giản duy nhất cho câu hỏi của bạn, "làm cách nào để chuyển đổi nó thành định dạng chấp nhận độ dài ký tự 32,767?" là: * cẩn thận *. Bản thân bạn đã chỉ ra rằng nó không đơn giản như vậy để tack một '\\? \' Ở phía trước và gọi nó là tốt, và các mảnh vụn của bài báo cũng không đưa ra những giả định như vậy, để chắc chắn. Nó không khó, nhưng nó là tẻ nhạt. – WhozCraig

+0

@WhozCraig: Tại thời điểm này tôi hỏi nếu có một API hệ thống thực hiện điều này. Và nếu không, như tôi nghi ngờ, tôi yêu cầu sự hợp tác để viết một chức năng như vậy. – c00000fd

+1

Tôi đặc biệt thích sự mâu thuẫn bất thường trong bài báo. Ở một nơi, "Đường dẫn tối đa 32.767 ký tự là gần đúng, bởi vì tiền tố" \\? \ "Có thể được mở rộng thành chuỗi dài hơn bởi hệ thống tại thời gian chạy và mở rộng này áp dụng cho tổng chiều dài.". Và sau đó, "Bởi vì nó tắt tự động mở rộng chuỗi đường dẫn, tiền tố" \\? \ "..." * thích điều đó *. – WhozCraig

Trả lời

4

OK . Điều này hóa ra không đơn giản như âm thanh. Các trở ngại (bên cạnh một tài liệu mờ và vô số các định dạng đường dẫn) là một số API thậm chí không hoạt động như quảng cáo trên tất cả các phiên bản của hệ điều hành.

Dù sao đây là những gì tôi nghĩ ra, có vẻ như hoạt động trên XP SP3, Vista, Windows 7 và 8. Hơi lớn, cũng được viết cho MFC, nhưng đó chỉ là quản lý chuỗi. Tôi không có thời gian để điều chỉnh nó:

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

Và dưới đây là cách tôi thử nghiệm nó:

_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"); 

Và đây là kết quả tôi nhận được:

\\?\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 
+0

Nếu bạn cần nó để làm việc trên một myrad khác nhau của các phiên bản hệ điều hành Windows sau đó lưu ý rằng UNCs chỉ được hỗ trợ với Windows 7 và phiên bản mới hơn, UNC hỗ trợ trên các phiên bản Windows Server tôi không rõ ràng nhưng tôi nghi ngờ UNCs không được hỗ trợ cho đến Windows Server 2008. –

+0

Bạn thậm chí có kiểm tra mã của tôi vì đầu ra của nó cũng giống như của bạn ... –

0

Dưới đây là ví dụ được chuyển đổi thành mã C++ chưa được kiểm tra từ một số mã .NET cũ của tôi.

#include <iostream> 
#include <string> 

// For PathIsRelative() & PathCombine() 
#include "Shlwapi.h" 
#pragma comment(lib, "Shlwapi.lib") 

// For _wgetcwd() 
#include <direct.h> 

std::wstring ConvertToWin32Path(std::wstring &filepath); 
std::wstring MakePathAbsolute(std::wstring &filepath); 

int main() 
{ 
    std::wstring filepath; 
    std::wcout << L"Enter absolute file path (ex. \"c:\\temp\\myfile.txt\"):"; 
    std::wcin >> filepath; 
    std::wcout << L"Converted file path: " << ConvertToWin32Path(filepath); 
    return 0; 
} 

// If file path is disk file path then prepend it with \\?\ 
// if file path is UNC prepend it with \\?\UNC\ and remove \\ prefix in unc path. 
std::wstring ConvertToWin32Path(std::wstring &filepath) 
{ 
    if (filepath.compare(0, 2, L"\\\\")) 
    { 
     // If the path is relative then we need to convert it to a absolute path 
     if (PathIsRelative(filepath.c_str())) 
      filepath = MakePathAbsolute(filepath); 

     filepath = std::wstring(L"\\\\?\\") + filepath; 
    } 
    else 
    { 
     // Is the path already converted, if so then return the same filepath 
     if (filepath.compare(0, 3, L"\\\\?")) 
      filepath = std::wstring(L"\\\\?\\UNC\\") + filepath.substr(2, filepath.length() - 2); 
    } 

    return filepath;  
} 

// Converts a relative path to a absolute one by adding the path of the executable 
std::wstring MakePathAbsolute(std::wstring &filepath) 
{ 
    // Convert from a relative to an absolute file path 
    const size_t maxCurrDirLen = 256; 
    wchar_t currentDir[maxCurrDirLen]; 
    _wgetcwd(currentDir, maxCurrDirLen - 1); 
    const size_t maxPathLen = 32767; 
    wchar_t fullPath[maxPathLen]; 
    PathCombine(fullPath, currentDir, filepath.c_str()); 
    return std::wstring(fullPath); 
} 

Cập nhật: "Cảm ơn bạn đã cố gắng, nhưng xin lỗi này không phải là đơn giản"

Bạn thậm chí kiểm tra mã của tôi trước khi kết luận rằng

? Tôi đã thêm đầu ra từ mã của tôi với đường dẫn nhập của bài đăng mới; bạn có thể vui lòng nêu rõ mã của tôi không thành công ở đâu? Theo tôi có thể thấy mã của tôi có đầu ra chính xác hơn mã (mã phức tạp hơn) của bạn. Vấn đề duy nhất tôi có thể thấy là con đường chia sẻ UNC cần phải có được \\share\folder\Desktop và không \\?\UNC\\share\folder\Desktop nhưng đó là một sửa chữa dễ dàng - nhưng sau đó lại mã riêng của bạn có lỗi tương tự ...

\\?\c:\dev\UNC_path_test 
\\?\C:\Ba*d\P|a?t<h>\Windows\Folder 
\\?\c:\dev\UNC_path_test\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 L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path 
\\?\UNC\server\share\Desktop\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\Very Long path\Very Long path\Very Long path\Very Long path\Very Long path\V 
ery Long path\Very Long path\Very Long path\Very Long path\Very Long path\Very L 
ong path\Very Long path\Very Long path\Very Long path\Very Long path\Very Long p 
ath\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 
\\?\\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 
+0

Cảm ơn bạn đã cố gắng nhưng xin lỗi. Đây không phải là đơn giản. Xem ví dụ của tôi trong một bài đăng khác. – c00000fd

+0

@ c00000fd Bạn có thể chỉ ra cho tôi loại đường dẫn nào sẽ không được hỗ trợ với giải pháp trên của tôi; Tôi đã xem bài đăng mới của bạn nhưng không thể thấy sự cố. –

+0

@Inge Nó không hoạt động cho đường dẫn tương đối. Đường dẫn tương đối được tuyên bố rõ ràng là một yêu cầu. Nó cũng sẽ thất bại đối với bất kỳ phần mở rộng nào trong tương lai mà Microsoft quyết định kết hợp. – IInspectable

2

Hôm nay là may mắn của bạn vì tôi chỉ đang làm việc về vấn đề cho chương trình của riêng tôi. Giải pháp rất đơn giản: chức năng PathCchCanonicalizeEx sẽ thêm dấu "\? \" Nếu cần. Nhưng chức năng này có một số minuses vì ​​nó đòi hỏi phải sử dụng Windows 8 như một nền tảng đích mà không phải là một thỏa thuận. Đó là cách tôi đã thực hiện chức năng của riêng tôi mà chấp nhận một chuỗi đường dẫn "bất thường" như là một đầu vào và đầu ra chuỗi chuẩn hóa đã sẵn sàng vượt quá giới hạn MAX_PATH.Nó sử dụng định nghĩa mới trong Win8 SDK:

// max # of characters we support using the "\\?\" syntax 
// (0x7FFF + 1 for NULL terminator) 
#define PATHCCH_MAX_CCH    0x8000 

Tờ khai chức năng là sau (không phải là nó đòi hỏi CString xác định và nó sử dụng SAL chú thích):

//Normalize path and prepend "\\?\" if it exceeds the MAX_PATH limit 
_Success_(return != false) //If the path was normalized and it exist (if bValidate == true) the return value is true and the normalized path is assigned to the sPath param 
bool NormalizePath(_Inout_ CString & sPath, //Set to the abnormal path (relative, UNC, absolute), it is also used to store the normal path 
    _In_ const CString sCurrentDir, //Set to the currend directory that will be used to resolve relative paths (used for security as GetCurrentDirectory function is thread-unsafe) 
    _Out_opt_ bool *bDir = NULL, //Set to a bool pointer that will be set to true if the path points to a directory 
    _In_ bool bValidate = false //If set the path existence is checked and the bDir argument is used 
    ); 

Và các định nghĩa (không có nhiều ý kiến):

// max # of characters we support using the "\\?\" syntax 
// (0x7FFF + 1 for NULL terminator) 
#define PATHCCH_MAX_CCH    0x8000 

#define LONG_PATH_ID    L"\\\\?\\" 
#define UNC_PREFIX     "\\\\" 
#define UNC_LONG_ID     L"\\\\?\\UNC\\" 
#define CUR_DIR_REL_PATH_ID   ".\\" 

#define WILDCAR_CHAR_ASTER   '*' 
#define WILDCAR_CHAR_QUEMARK  '?' 

#define DIR_DOWN     ".." 
#define DIR_UP      "." 

//Verify that a path exists and set bDir to true if the path points to an directory 
bool ValidatePath(_In_ const TCHAR *sPath, _Out_ bool & bDir) 
{ 
    //If the path contains a wildcards search test only the parent directory 

    const TCHAR * sLastElement = _tcsrchr(sPath, _T('\\')); //The last component in the path 

    bool bFoundWildCard = false; 

    if(sLastElement) 
    { 
     ++sLastElement; 
     if(_tcsrchr(sLastElement, _T(WILDCAR_CHAR_ASTER)) || _tcsrchr(sLastElement, _T(WILDCAR_CHAR_QUEMARK))) //If wilcard characters are contained in the last path component 
     { 
      bFoundWildCard = true; 
      --sLastElement; 
      const_cast<TCHAR *>(sLastElement)[0] = _T('\0'); 
     } 
    } 

    DWORD dwPathAttr = GetFileAttributes(sPath); 

    if(dwPathAttr == INVALID_FILE_ATTRIBUTES) 
    { 
     _com_error sErrorMsg(GetLastError()); 
     //CProgramError.Set(sErrorMsg.ErrorMessage()); 
     return false; 
    } 

    bDir = dwPathAttr & FILE_ATTRIBUTE_DIRECTORY; 

    if(bFoundWildCard) 
    { 
     const_cast<TCHAR *>(sLastElement)[0] = _T('\\'); 
    } 

    return true; 
} 

void RespondPathComponent(_In_ const TCHAR *pComponent, _Out_ std::vector<CString> & vPathComponents) 
{ 
    const TCHAR *pComponentLimiterR = _tcschr(pComponent, _T('\\')); 

    const TCHAR *pComponentLimiterL = _tcschr(pComponent, _T('/')); 

    const TCHAR *pComponentLimiter = NULL; 

    if(pComponentLimiterR && pComponentLimiterL) 
     pComponentLimiter = (pComponentLimiterR > pComponentLimiterL ? pComponentLimiterL : pComponentLimiterR); 
    else 
     pComponentLimiter = (pComponentLimiterR ? pComponentLimiterR : pComponentLimiterL); 

    if(pComponentLimiter) 
    { 
     size_t szComponent = pComponentLimiter - pComponent; 
     if(szComponent) 
     { 
      CString sTemp; 
      sTemp.SetString(pComponent, szComponent); 
      vPathComponents.push_back(sTemp); 
     } 
     ++pComponentLimiter; 
     RespondPathComponent(pComponentLimiter, vPathComponents); 
    } 
    else 
    { 
     size_t szLastComp = _tcslen(pComponent); 
     if(szLastComp) 
     { 
      CString sTemp; 
      sTemp.SetString(pComponent, szLastComp); 
      vPathComponents.push_back(sTemp); 
     } 
    } 
} 

size_t FixUpPathComponents(_Out_ std::vector<CString> & vPathComponents, _In_ const TCHAR *pPathComponents) 
{ 
    RespondPathComponent(pPathComponents, vPathComponents); 

    size_t szNumComponents = vPathComponents.size(); 

    for(size_t i(0); i < szNumComponents; ++i) //Check path components for special meanings 
    { 
     if(vPathComponents[i] == _T(DIR_DOWN)) 
     { 
      vPathComponents.erase(vPathComponents.begin() + i); //Remove the current component 
      --szNumComponents; 
      if(i > 0) 
      { 
       vPathComponents.erase(vPathComponents.begin() + i - 1); 
       --szNumComponents; 
      } 
     } 
     else if(vPathComponents[i] == _T(DIR_UP)) 
     { 
      if((i + 1) < szNumComponents) 
      { 
       vPathComponents.erase(vPathComponents.begin() + i + 1); 
       --szNumComponents; 
      } 
      vPathComponents.erase(vPathComponents.begin() + i); //Remove the current component 
      --szNumComponents; 
     } 
    } 

    return szNumComponents; 
} 

//Note that sCurrentDir is appended to all relative paths (nomatter the drive letter) - it needs to be a full path, not ending with '\\' 
bool ExpandAndFixUpPath(_Inout_ CString & sPath, _In_opt_ const CString sCurrentDir) 
{ 
    const size_t InPathStrSz = sPath.GetLength(); 

    if(!InPathStrSz) //Invalid path 
     return false; 

    //sPath.LockBuffer(); //Lock character buffer 

    const TCHAR *PathBuffer = sPath.GetString(); //Retrieve the buffer 

    if(InPathStrSz > 1) //To suppose the path is full it needs to have at lease 2 characters 
    { 
     if(_tcsstr(PathBuffer, _T(UNC_PREFIX)) == PathBuffer) //If the path begin with UNC_PREFIX 
     { 
      std::vector<CString> vPathComponents; 

      size_t nComponents; 

      if((nComponents = FixUpPathComponents(vPathComponents, &PathBuffer[2])) < 2) //A UNC path needs at leas two elements 
       return false; 

      sPath = _T('\\'); 

      for(size_t i(0); i < nComponents; ++i) 
      { 
       sPath += _T('\\'); 
       sPath += vPathComponents[i]; 
      } 

      return true; 
     } 
     else if(PathBuffer[1] == _T(':')) //If the path begin with a disk designator 
     { 
      std::vector<CString> vPathComponents; 

      if(FixUpPathComponents(vPathComponents, &PathBuffer[2])) 
      { 
       if(PathBuffer[2] == _T('\\') || PathBuffer[2] == _T('/')) 
       { 
        sPath.SetString(PathBuffer, 2); 

        for(size_t i(0); i < vPathComponents.size(); ++i) 
        { 
         sPath += _T('\\'); 
         sPath += vPathComponents[i]; 
        } 
       } 
       else 
       { 
        sPath = sCurrentDir; 

        for(size_t i(0); i < vPathComponents.size(); ++i) 
        { 
         sPath += _T('\\'); 
         sPath += vPathComponents[i]; 
        } 
       } 
      } 
      else 
      { 
       sPath.SetString(PathBuffer, 2); 
       sPath += _T('\\'); 
      } 
      return true; 
     } 
    } 

    std::vector<CString> vPathComponents; 

    const TCHAR *pComponentsBegin = (_tcsstr(PathBuffer, _T(CUR_DIR_REL_PATH_ID)) == PathBuffer ? &PathBuffer[((sizeof(_T(CUR_DIR_REL_PATH_ID))/sizeof(TCHAR)) - 1)] : PathBuffer); 

    FixUpPathComponents(vPathComponents, pComponentsBegin); 

    sPath = sCurrentDir; 

    for(size_t i(0); i < vPathComponents.size(); ++i) 
    { 
     sPath += _T('\\'); 
     sPath += vPathComponents[i]; 
    } 

    return true; 
} 

bool NormalizePath(_Inout_ CString & sPath, _In_ const CString sCurrentDir, _Out_opt_ bool *bDir = NULL, _In_ bool bValidate = false) 
{ 
    if(!ExpandAndFixUpPath(sPath, sCurrentDir)) //Extend the path to it's full form 
     return false; 

    size_t LongPathLen = sPath.GetLength(); 

    const TCHAR *pPathBuf = sPath.GetString(); 

#ifdef _UNICODE 

    if(LongPathLen <= (MAX_PATH - 1)) //If the path is longer in the range of MAX_PATH return it directly 
    { 
     if(bValidate) 
      if(!ValidatePath(pPathBuf, *bDir)) //Validate path before returning it 
       return false; 

     return true; 
    } 

    bool bIsUNCPath = _tcsstr(pPathBuf, _T(UNC_PREFIX)) == pPathBuf; 

    if(!bIsUNCPath) 
    { 
     if(LongPathLen > (PATHCCH_MAX_CCH - 1 - ((sizeof(LONG_PATH_ID)/sizeof(WCHAR)) - 1))) //If have no space to store the prefix fail 
     { 
      //CProgramError.Set(_T("Path too long!")); 
      return false; 
     } 


     CString sPathTmp = LONG_PATH_ID; 

     sPathTmp += pPathBuf; 

     if(bValidate) 
      if(!ValidatePath(sPathTmp.GetString(), *bDir)) //Validate path before returning it 
       return false; 

     sPath = sPathTmp; 

     return true; 
    } 
    else 
    { 
     if(LongPathLen > (PATHCCH_MAX_CCH - 1 - ((sizeof(UNC_LONG_ID)/sizeof(WCHAR)) - 1) + ((sizeof(_T(UNC_PREFIX))/sizeof(WCHAR)) - 1))) //If have no space to store the prefix fail 
     { 
      //CProgramError.Set(_T("Path too long!")); 
      return false; 
     } 


     CString sPathTmp = UNC_LONG_ID; 

     sPathTmp += &pPathBuf[2]; 

     if(bValidate) 
      if(!ValidatePath(sPathTmp.GetString(), *bDir)) //Validate path before returning it 
       return false; 

     sPath = sPathTmp; 

     return true; 
    } 

#else 

    if(bValidate) 
     if(!ValidatePath(pPathBuf, *bDir)) //Validate path before returning it 
      return false; 

    return true; 

#endif 
} 
+1

Cảm ơn. Trước tiên, cách "trực quan" để đặt tên cho API mới, 'PathCchCanonicalizeEx', Microsoft :) Thứ hai, tôi muốn bạn đăng nó sớm hơn một chút. Tôi thấy rằng bạn đang phân tích cú pháp tất cả các đường dẫn của riêng mình, điều này khiến tôi lo lắng vì phương pháp của tôi dựa trên các API Microsoft hiện có để thực hiện hầu hết các phân tích cú pháp . – c00000fd

+0

Tôi thích sử dụng các phương thức của riêng mình vì hàm GetFullPathName mà tôi đã sử dụng thay vì không phải là luồng an toàn. Nó không phải là cách thực hiện tốt nhất. Tôi thực sự hạnh phúc mặc dù Microsoft đã thêm một giá trị "MAX_PATH" mới để chúng tôi cuối cùng cũng có thể xử lý các đường dẫn dài. Tôi cũng mong rằng Windows Explorer tiếp theo cũng sẽ hỗ trợ chúng. –

+0

Với Shell là * lý do * cho giới hạn 'MAX_PATH', nó sẽ không bao giờ xảy ra với tôi để tìm kiếm giải pháp. Tuyệt vời tìm thấy. – IInspectable

Các vấn đề liên quan