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