* Convert path to canonical long path. * This function converts given path to canonical long form. For example * foldenames with ~ short names are expanded. Also environment strings are * expanded if @p bExpandEnvs is true. If path does not exist, make canonical * the part that does exist, and leave the rest as is. Result, if a directory, * usually does not have a trailing backslash. * @para
| 198 | * @return Converted path. |
| 199 | */ |
| 200 | String GetLongPath(const String& szPath, bool bExpandEnvs) |
| 201 | { |
| 202 | String sPath = szPath; |
| 203 | size_t len = sPath.length(); |
| 204 | if (len < 1) |
| 205 | return sPath; |
| 206 | |
| 207 | tchar_t fullPath[MAX_PATH_FULL] = {0}; |
| 208 | tchar_t *pFullPath = &fullPath[0]; |
| 209 | tchar_t *lpPart; |
| 210 | |
| 211 | // GetFullPathName GetLongPathName |
| 212 | // Convert to fully qualified form Yes No |
| 213 | // (Including .) |
| 214 | // Convert /, //, \/, ... to \ Yes No |
| 215 | // Handle ., .., ..\..\.. Yes No |
| 216 | // Convert 8.3 names to long names No Yes |
| 217 | // Fail when file/directory does not exist No Yes |
| 218 | // |
| 219 | // Fully qualify/normalize name using GetFullPathName. |
| 220 | |
| 221 | // Expand environment variables: |
| 222 | // Convert "%userprofile%\My Documents" to "C:\Documents and Settings\username\My Documents" |
| 223 | tchar_t expandedPath[MAX_PATH_FULL]; |
| 224 | const tchar_t *lpcszPath = sPath.c_str(); |
| 225 | if (bExpandEnvs && tc::tcschr(lpcszPath, '%') != nullptr) |
| 226 | { |
| 227 | DWORD dwLen = ExpandEnvironmentStrings(lpcszPath, expandedPath, MAX_PATH_FULL); |
| 228 | if (dwLen > 0 && dwLen < MAX_PATH_FULL) |
| 229 | lpcszPath = expandedPath; |
| 230 | } |
| 231 | |
| 232 | String tPath = TFile(String(lpcszPath)).wpath(); |
| 233 | DWORD dwLen = GetFullPathName(tPath.c_str(), MAX_PATH_FULL, pFullPath, &lpPart); |
| 234 | if (dwLen == 0 || dwLen >= MAX_PATH_FULL) |
| 235 | tc::tcslcpy(pFullPath, MAX_PATH_FULL, tPath.c_str()); |
| 236 | |
| 237 | // We are done if this is not a short name. |
| 238 | if (tc::tcschr(pFullPath, _T('~')) == nullptr) |
| 239 | return pFullPath; |
| 240 | |
| 241 | // We have to do it the hard way because GetLongPathName is not |
| 242 | // available on Win9x and some WinNT 4 |
| 243 | |
| 244 | // The file/directory does not exist, use as much long name as we can |
| 245 | // and leave the invalid stuff at the end. |
| 246 | String sLong; |
| 247 | tchar_t *ptr = pFullPath; |
| 248 | tchar_t *end = nullptr; |
| 249 | |
| 250 | // Skip to \ position d:\abcd or \\host\share\abcd |
| 251 | // indicated by ^ ^ ^ |
| 252 | if (tc::tcslen(ptr) > 2) |
| 253 | end = tc::tcschr(pFullPath+2, _T('\\')); |
| 254 | if (end != nullptr && !tc::tcsncmp(pFullPath, _T("\\\\"),2)) |
| 255 | end = tc::tcschr(end+1, _T('\\')); |
| 256 | |
| 257 | if (end == nullptr) |