#pragma once #include #include #include #include #include #include #include #include #include "strcmp.h" #include "version.h" #include "module.h" typedef version S_VERSION; template constexpr T Max (T l, T r) { return l > r ? l : r; } template constexpr T Max (T l, T m, T r) { return Max (Max (l, r), m); } template constexpr T Max (T l, T ml, T mr, T r) { return Max (Max (l, ml), Max (mr, r)); } template std::basic_string replace_substring ( const std::basic_string &str, const std::basic_string &from, const std::basic_string &to ) { if (from.empty ()) return str; std::basic_string result; size_t pos = 0; size_t start_pos; while ((start_pos = str.find (from, pos)) != std::basic_string::npos) { result.append (str, pos, start_pos - pos); result.append (to); pos = start_pos + from.length (); } result.append (str, pos, str.length () - pos); return result; } std::string GetProgramRootDirectoryA (HMODULE hModule hModule_DefaultParam) { char path [MAX_PATH]; if (GetModuleFileNameA (hModule, path, MAX_PATH)) { std::string dir (path); size_t pos = dir.find_last_of ("\\/"); if (pos != std::string::npos) { dir = dir.substr (0, pos); } return dir; } return ""; } std::wstring GetProgramRootDirectoryW (HMODULE hModule hModule_DefaultParam) { wchar_t path [MAX_PATH]; if (GetModuleFileNameW (hModule, path, MAX_PATH)) { std::wstring dir (path); size_t pos = dir.find_last_of (L"\\/"); if (pos != std::wstring::npos) { dir = dir.substr (0, pos); } return dir; } return L""; } std::string EnsureTrailingSlash (const std::string &path) { if (path.empty ()) return path; // 空路径直接返回 char lastChar = path.back (); if (lastChar == '\\' || lastChar == '/') return path; // 已有分隔符,直接返回 // 根据系统或原路径格式添加适当的分隔符 char separator = (path.find ('/') != std::string::npos) ? '/' : '\\'; return path + separator; } std::wstring EnsureTrailingSlash (const std::wstring &path) { if (path.empty ()) return path; wchar_t lastChar = path.back (); if (lastChar == L'\\' || lastChar == L'/') return path; wchar_t separator = (path.find (L'/') != std::wstring::npos) ? L'/' : L'\\'; return path + separator; } bool IsFileExistsW (LPCWSTR filename) { DWORD dwAttrib = GetFileAttributesW (filename); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } bool IsFileExistsA (LPCSTR filename) { DWORD dwAttrib = GetFileAttributesA (filename); return (dwAttrib != INVALID_FILE_ATTRIBUTES && !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY)); } bool IsFileExists (LPWSTR filePath) { return IsFileExistsW (filePath); } bool IsFileExists (LPCSTR filePath) { return IsFileExistsA (filePath); } bool IsFileExists (const std::string &filePath) { return IsFileExistsA (filePath.c_str ()); } bool IsFileExists (const std::wstring &filePath) { return IsFileExistsW (filePath.c_str ()); } bool IsDirectoryExistsA (LPCSTR path) { DWORD attributes = GetFileAttributesA (path); return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY)); } bool IsDirectoryExistsW (LPCWSTR path) { DWORD attributes = GetFileAttributesW (path); return (attributes != INVALID_FILE_ATTRIBUTES && (attributes & FILE_ATTRIBUTE_DIRECTORY)); } bool IsDirectoryExists (const std::string &path) { return IsDirectoryExistsA (path.c_str ()); } bool IsDirectoryExists (const std::wstring &path) { return IsDirectoryExistsW (path.c_str ()); } bool IsDirectoryExists (LPCSTR path) { return IsDirectoryExistsA (path); } bool IsDirectoryExists (LPCWSTR path) { return IsDirectoryExistsW (path); } bool IsPathExistsW (LPCWSTR filename) { DWORD dwAttrib = GetFileAttributesW (filename); return (dwAttrib != INVALID_FILE_ATTRIBUTES); } bool IsPathExistsA (LPCSTR filename) { DWORD dwAttrib = GetFileAttributesA (filename); return (dwAttrib != INVALID_FILE_ATTRIBUTES); } bool IsPathExists (const std::string &path) { return IsPathExistsA (path.c_str ()); } bool IsPathExists (const std::wstring &path) { return IsPathExistsW (path.c_str ()); } bool IsPathExists (LPCSTR path) { return IsPathExistsA (path); } bool IsPathExists (LPCWSTR path) { return IsPathExistsW (path); } std::string NormalizePath (const std::string &path) { if (!path.empty () && path.back () == '\\') return path.substr (0, path.size () - 1); return path.c_str (); } std::wstring NormalizePath (const std::wstring &path) { if (!path.empty () && path.back () == L'\\') return path.substr (0, path.size () - 1); return path.c_str (); } std::vector EnumSubdirectories (const std::string &directory, bool includeParentPath) { std::vector subdirs; std::string normPath = NormalizePath (directory); std::string searchPath = normPath + "\\*"; WIN32_FIND_DATAA findData; HANDLE hFind = FindFirstFileA (searchPath.c_str (), &findData); if (hFind == INVALID_HANDLE_VALUE) return subdirs; do { // 过滤 "." 和 ".." if (strcmp (findData.cFileName, ".") == 0 || strcmp (findData.cFileName, "..") == 0) continue; // 判断是否为目录 if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (includeParentPath) subdirs.push_back (normPath + "\\" + findData.cFileName); else subdirs.push_back (findData.cFileName); } } while (FindNextFileA (hFind, &findData)); FindClose (hFind); return subdirs; } std::vector EnumSubdirectories (const std::wstring &directory, bool includeParentPath) { std::vector subdirs; std::wstring normPath = NormalizePath (directory); std::wstring searchPath = normPath + L"\\*"; WIN32_FIND_DATAW findData; HANDLE hFind = FindFirstFileW (searchPath.c_str (), &findData); if (hFind == INVALID_HANDLE_VALUE) return subdirs; do { if (wcscmp (findData.cFileName, L".") == 0 || wcscmp (findData.cFileName, L"..") == 0) continue; if (findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { if (includeParentPath) subdirs.push_back (normPath + L"\\" + findData.cFileName); else subdirs.push_back (findData.cFileName); } } while (FindNextFileW (hFind, &findData)); FindClose (hFind); return subdirs; } std::string GetCurrentProgramPathA (HMODULE hModule hModule_DefaultParam) { std::vector buf (Max (MAX_PATH, GetModuleFileNameA (hModule, nullptr, 0)) + 1); GetModuleFileNameA (hModule, buf.data (), buf.capacity ()); return buf.data (); } std::wstring GetCurrentProgramPathW (HMODULE hModule hModule_DefaultParam) { std::vector buf (Max (MAX_PATH, GetModuleFileNameW (hModule, nullptr, 0)) + 1); GetModuleFileNameW (hModule, buf.data (), buf.capacity ()); return buf.data (); } std::string GetCurrentProgramNameA (HMODULE hModule hModule_DefaultParam) { return PathFindFileNameA (GetCurrentProgramPathA (hModule).c_str ()); } std::wstring GetCurrentProgramNameW (HMODULE hModule hModule_DefaultParam) { return PathFindFileNameW (GetCurrentProgramPathW (hModule).c_str ()); } S_VERSION GetExeFileVersion (LPCSTR lpszFilePath) { S_VERSION ver (0); DWORD dummy; DWORD size = GetFileVersionInfoSizeA (lpszFilePath, &dummy); std::vector pVersionInfo (size); if (!GetFileVersionInfoA (lpszFilePath, 0, size, pVersionInfo.data ())) { return ver; } VS_FIXEDFILEINFO* pFileInfo = nullptr; UINT len = 0; if (!VerQueryValueA (pVersionInfo.data (), "\\", (LPVOID *)&pFileInfo, &len)) { return ver; } if (len == 0 || pFileInfo == nullptr) { return ver; } ver = S_VERSION ( HIWORD (pFileInfo->dwFileVersionMS), LOWORD (pFileInfo->dwFileVersionMS), HIWORD (pFileInfo->dwFileVersionLS), LOWORD (pFileInfo->dwFileVersionLS) ); return ver; } S_VERSION GetExeFileVersion (LPCWSTR lpswFilePath) { S_VERSION ver (0); DWORD dummy; DWORD size = GetFileVersionInfoSizeW (lpswFilePath, &dummy); std::vector pVersionInfo (size); if (!GetFileVersionInfoW (lpswFilePath, 0, size, pVersionInfo.data ())) { return ver; } VS_FIXEDFILEINFO* pFileInfo = nullptr; UINT len = 0; if (!VerQueryValueA (pVersionInfo.data (), "\\", (LPVOID *)&pFileInfo, &len)) { return ver; } if (len == 0 || pFileInfo == nullptr) { return ver; } ver = S_VERSION ( HIWORD (pFileInfo->dwFileVersionMS), LOWORD (pFileInfo->dwFileVersionMS), HIWORD (pFileInfo->dwFileVersionLS), LOWORD (pFileInfo->dwFileVersionLS) ); return ver; } S_VERSION GetExeFileVersion (std::wstring objswFilePath) { return GetExeFileVersion (objswFilePath.c_str ()); } S_VERSION GetExeFileVersion (std::string objszFilePath) { return GetExeFileVersion (objszFilePath.c_str ()); } // 设置当前进程的环境变量RunPath和ProgramPath void SetupInstanceEnvironment (HMODULE hModule hModule_DefaultParam) { // 设置RunPath为当前工作目录(无结尾反斜杠) std::vector currentDir (Max (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1); DWORD len = GetCurrentDirectoryW (currentDir.capacity (), currentDir.data ()); if (len > 0) { std::wstring runPath (currentDir.data ()); if (!runPath.empty () && (runPath.back () == L'\\' || runPath.back () == L'/')) { runPath.pop_back (); } SetEnvironmentVariableW (L"RunPath", runPath.c_str ()); } // 设置ProgramPath为程序所在目录(无结尾反斜杠) std::vector modulePath (Max (GetModuleFileNameW (hModule, nullptr, 0), MAX_PATH) + 1); len = GetModuleFileNameW (hModule, modulePath.data (), MAX_PATH); if (len > 0 && len < MAX_PATH) { wchar_t* lastSlash = wcsrchr (modulePath.data (), L'\\'); if (!lastSlash) lastSlash = wcsrchr (modulePath.data (), L'/'); if (lastSlash) *lastSlash = L'\0'; std::wstring programPath (modulePath.data ()); if (!programPath.empty () && (programPath.back () == L'\\' || programPath.back () == L'/')) { programPath.pop_back (); } SetEnvironmentVariableW (L"ProgramPath", programPath.c_str ()); } } // 处理宽字符串环境变量展开 std::wstring ProcessEnvVars (const std::wstring &input) { DWORD requiredSize = ExpandEnvironmentStringsW (input.c_str (), nullptr, 0); if (requiredSize == 0) return input; std::wstring buffer (requiredSize, L'\0'); if (!ExpandEnvironmentStringsW (input.c_str (), &buffer [0], requiredSize)) { return input; } buffer.resize (requiredSize - 1); // 去除终止空字符 return buffer.c_str (); } std::wstring ProcessEnvVars (LPCWSTR input) { return ProcessEnvVars (std::wstring (input)); } // 处理ANSI字符串环境变量展开 std::string ProcessEnvVars (const std::string &input) { DWORD requiredSize = ExpandEnvironmentStringsA (input.c_str (), nullptr, 0); if (requiredSize == 0) return input; std::string buffer (requiredSize, '\0'); if (!ExpandEnvironmentStringsA (input.c_str (), &buffer [0], requiredSize)) { return input; } buffer.resize (requiredSize - 1); // 去除终止空字符 return buffer.c_str (); } std::string ProcessEnvVars (LPCSTR input) { return ProcessEnvVars (std::string (input)); } std::string GetCurrentDirectoryA () { std::vector buf (Max (GetCurrentDirectoryA (0, nullptr), MAX_PATH) + 1); GetCurrentDirectoryA (buf.size (), buf.data ()); return buf.data (); } std::wstring GetCurrentDirectoryW () { std::vector buf (Max (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1); GetCurrentDirectoryW (buf.size (), buf.data ()); return buf.data (); } std::wstring GetFileDirectoryW (const std::wstring &filePath) { std::vector buf (filePath.capacity () + 1); lstrcpyW (buf.data (), filePath.c_str ()); PathRemoveFileSpecW (buf.data ()); return buf.data (); } std::string GetFileDirectoryA (const std::string &filePath) { std::vector buf (filePath.capacity () + 1); lstrcpyA (buf.data (), filePath.c_str ()); PathRemoveFileSpecA (buf.data ()); return buf.data (); } size_t EnumerateFilesW (const std::wstring &directory, const std::wstring &filter, std::vector &outFiles, bool recursive = false) { std::wstring searchPath = directory; if (!searchPath.empty () && searchPath.back () != L'\\') { searchPath += L'\\'; } searchPath += filter; WIN32_FIND_DATAW findData; HANDLE hFind = FindFirstFileW (searchPath.c_str (), &findData); if (hFind != INVALID_HANDLE_VALUE) { do { if (!(findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)) { outFiles.push_back (directory + L"\\" + findData.cFileName); } } while (FindNextFileW (hFind, &findData)); FindClose (hFind); } if (recursive) { std::wstring subDirSearchPath = directory + L"\\*"; hFind = FindFirstFileW (subDirSearchPath.c_str (), &findData); if (hFind != INVALID_HANDLE_VALUE) { do { if ((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) && wcscmp (findData.cFileName, L".") != 0 && wcscmp (findData.cFileName, L"..") != 0) { EnumerateFilesW (directory + L"\\" + findData.cFileName, filter, outFiles, true); } } while (FindNextFileW (hFind, &findData)); FindClose (hFind); } } return outFiles.size (); } // 检查是否为 Windows 设备名(大小写不敏感) bool IsReservedName (const std::wstring &name) { static const wchar_t* reserved [] = { L"CON", L"PRN", L"AUX", L"NUL", L"COM1", L"COM2", L"COM3", L"COM4", L"COM5", L"COM6", L"COM7", L"COM8", L"COM9", L"LPT1", L"LPT2", L"LPT3", L"LPT4", L"LPT5", L"LPT6", L"LPT7", L"LPT8", L"LPT9" }; std::wstring upperName = StringToUpper (name); for (const auto& res : reserved) { if (upperName == res || (upperName.rfind (res, 0) == 0 && upperName.length () > wcslen (res) && upperName [wcslen (res)] == L'.')) { return true; } } return false; } // Windows 文件命名规范检查 (Unicode) bool IsValidWindowsNameW (LPCWSTR name) { if (!name || !*name) return false; std::wstring wname (name); if (wname.find_first_of (L"<>:\"/\\|?*") != std::wstring::npos) return false; if (IsReservedName (wname)) return false; if (wname.back () == L' ' || wname.back () == L'.') return false; return true; } // Windows 文件命名规范检查 (ANSI) bool IsValidWindowsNameA (LPCSTR name) { if (!name || !*name) return false; std::string str (name); if (str.find_first_of ("<>:\"/\\|?*") != std::string::npos) return false; // 转换 ANSI 到宽字符 int len = MultiByteToWideChar (CP_ACP, 0, name, -1, NULL, 0); if (len <= 0) return false; std::wstring wname (len - 1, L'\0'); MultiByteToWideChar (CP_ACP, 0, name, -1, &wname [0], len); if (IsReservedName (wname)) return false; if (str.back () == ' ' || str.back () == '.') return false; return true; } bool IsValidWindowsName (LPCSTR name) { return IsValidWindowsNameA (name); } bool IsValidWindowsName (LPCWSTR name) { return IsValidWindowsNameW (name); } bool IsValidWindowsName (const std::wstring &name) { return IsValidWindowsName (name.c_str ()); } bool IsValidWindowsName (const std::string &name) { return IsValidWindowsName (name.c_str ()); } std::wstring GetRootFolderNameFromFilePath (const std::wstring &lpFilePath) { std::vector szPath (Max (lpFilePath.length (), MAX_PATH) + 1); if (!PathCanonicalizeW (szPath.data (), lpFilePath.c_str ())) return L""; if (PathRemoveFileSpecW (szPath.data ()) == FALSE) return L""; LPCWSTR pszFolder = PathFindFileNameW (szPath.data ()); if (*pszFolder != L'\0') return std::wstring (pszFolder); WCHAR rootName [3] = {szPath [0], L':', L'\0'}; return std::wstring (rootName); } std::wstring GetSafeTimestampForFilename () { ::FILETIME ft; GetSystemTimeAsFileTime (&ft); SYSTEMTIME st; FileTimeToSystemTime (&ft, &st); std::wstringstream wss; wss << std::setfill (L'0') << st.wYear << std::setw (2) << st.wMonth << std::setw (2) << st.wDay << L"_" << std::setw (2) << st.wHour << std::setw (2) << st.wMinute << std::setw (2) << st.wSecond << std::setw (3) << st.wMilliseconds; return wss.str (); } size_t EnumFiles ( const std::wstring &lpDir, const std::wstring &lpFilter, std::vector &aszOutput, bool bOutputWithPath = false, bool bSortByLetter = false, bool bIncludeSubDir = false ) { if (!bIncludeSubDir) aszOutput.clear (); std::vector filters; size_t start = 0; while (start < lpFilter.length ()) { size_t pos = lpFilter.find (L'\\', start); if (pos == std::wstring::npos) pos = lpFilter.length (); filters.emplace_back (lpFilter.substr (start, pos - start)); start = pos + 1; } std::function enumDir; enumDir = [&] (const std::wstring &physicalPath, std::wstring relativePath) { WIN32_FIND_DATAW ffd; HANDLE hFind = FindFirstFileW ((physicalPath + L"\\*").c_str (), &ffd); if (hFind == INVALID_HANDLE_VALUE) return; do { if (wcscmp (ffd.cFileName, L".") == 0 || wcscmp (ffd.cFileName, L"..") == 0) continue; const bool isDir = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY); const std::wstring newPhysical = physicalPath + L"\\" + ffd.cFileName; std::wstring newRelative = relativePath; if (isDir) { if (bIncludeSubDir) { newRelative += ffd.cFileName; newRelative += L"\\"; enumDir (newPhysical, newRelative); } } else { for (const auto &filter : filters) { if (PathMatchSpecW (ffd.cFileName, filter.c_str ())) { aszOutput.push_back ( bOutputWithPath ? newPhysical : (relativePath + ffd.cFileName) ); break; } } } } while (FindNextFileW (hFind, &ffd)); FindClose (hFind); }; enumDir (lpDir, L""); if (bSortByLetter) std::sort (aszOutput.begin (), aszOutput.end ()); return aszOutput.size (); } std::wstring GetRelativePath ( const std::wstring &pszBaseDir, const std::wstring &pszFullPath, DWORD cchRelative ) { std::vector szBase (Max (pszBaseDir.length (), pszFullPath.length (), MAX_PATH) + 1); wcscpy_s (szBase.data (), MAX_PATH, pszBaseDir.c_str ()); if (szBase [wcslen (szBase.data ()) - 1] != L'\\') { wcscat_s (szBase.data (), MAX_PATH, L"\\"); } std::vector buf (Max (MAX_PATH, szBase.size ()) + 1); BOOL res = PathRelativePathToW ( buf.data (), szBase.data (), FILE_ATTRIBUTE_DIRECTORY, pszFullPath.c_str (), FILE_ATTRIBUTE_NORMAL ); if (res) return buf.data (); else return L""; } size_t EnumDirectory ( const std::wstring &lpDir, std::vector &aszOutput, bool bOutputWithPath = false, bool bSortByLetter = false, bool bIncludeSubDir = false ) { aszOutput.clear (); std::function enumDir; enumDir = [&] (const std::wstring &physicalPath, const std::wstring &relativePath) { WIN32_FIND_DATAW ffd; HANDLE hFind = FindFirstFileW ((physicalPath + L"\\*").c_str (), &ffd); if (hFind == INVALID_HANDLE_VALUE) return; do { const std::wstring name = ffd.cFileName; if (name == L"." || name == L"..") continue; const bool isDir = (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0; std::wstring newPhysical = physicalPath + L"\\" + name; std::wstring newRelative = relativePath + name; if (isDir) { if (bIncludeSubDir) enumDir (newPhysical, newRelative + L"\\"); if (bOutputWithPath) aszOutput.push_back (newPhysical); else aszOutput.push_back (newRelative); } } while (FindNextFileW (hFind, &ffd)); FindClose (hFind); }; enumDir (lpDir, L""); if (bSortByLetter) std::sort (aszOutput.begin (), aszOutput.end ()); return aszOutput.size (); } static DWORD CALLBACK ProgressRoutine ( LARGE_INTEGER TotalFileSize, LARGE_INTEGER TotalBytesTransferred, LARGE_INTEGER /*StreamSize*/, LARGE_INTEGER /*StreamBytesTransferred*/, DWORD /*dwStreamNumber*/, DWORD /*dwCallbackReason*/, HANDLE /*hSourceFile*/, HANDLE /*hDestinationFile*/, LPVOID lpData ) { auto *pCallback = reinterpret_cast *> (lpData); if (pCallback && *pCallback) { int progress = static_cast ( (TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart ); (*pCallback) (progress); } return PROGRESS_CONTINUE; } bool RenameFileW ( const std::wstring &lpSrcPath, const std::wstring &lpDestPath, std::function fProgress = nullptr ) { LPPROGRESS_ROUTINE pRoutine = nullptr; LPVOID pData = nullptr; if (fProgress) { pRoutine = ProgressRoutine; pData = &fProgress; } DWORD flags = MOVEFILE_COPY_ALLOWED; BOOL ok = MoveFileWithProgressW ( lpSrcPath.c_str (), lpDestPath.c_str (), pRoutine, pData, flags ); return ok != FALSE; } bool RenameFileA ( const std::string &lpSrcPath, const std::string &lpDestPath, std::function fProgress = nullptr ) { LPPROGRESS_ROUTINE pRoutine = nullptr; LPVOID pData = nullptr; if (fProgress) { pRoutine = ProgressRoutine; pData = &fProgress; } DWORD flags = MOVEFILE_COPY_ALLOWED; BOOL ok = MoveFileWithProgressA ( lpSrcPath.c_str (), lpDestPath.c_str (), pRoutine, pData, flags ); return ok != FALSE; } bool RenameFileW (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function fProgress = nullptr) { struct BuildTask { LPWSTR src = nullptr, dest = nullptr; ~BuildTask () { if (src != nullptr) { delete [] src; src = nullptr; } if (dest != nullptr) { delete [] dest; dest = nullptr; } } }; BuildTask bt; bt.src = new WCHAR [lpSrcDir.length () + lpSrcName.length () + 2]; bt.dest = new WCHAR [lpSrcDir.length () + lpDestName.length () + 2]; PathCombineW (bt.src, lpSrcDir.c_str (), lpSrcName.c_str ()); PathCombineW (bt.dest, lpSrcDir.c_str (), lpDestName.c_str ()); return RenameFileW (bt.src, bt.dest, fProgress); } bool RenameFileA (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function fProgress = nullptr) { struct BuildTask { LPSTR src = nullptr, dest = nullptr; ~BuildTask () { if (src != nullptr) { delete [] src; src = nullptr; } if (dest != nullptr) { delete [] dest; dest = nullptr; } } }; BuildTask bt; bt.src = new CHAR [lpSrcDir.length () + lpSrcName.length () + 2]; bt.dest = new CHAR [lpSrcDir.length () + lpDestName.length () + 2]; PathCombineA (bt.src, lpSrcDir.c_str (), lpSrcName.c_str ()); PathCombineA (bt.dest, lpSrcDir.c_str (), lpDestName.c_str ()); return RenameFileA (bt.src, bt.dest, fProgress); } bool RenameFile (const std::wstring &lpSrcPath, const std::wstring &lpDestPath, std::function fProgress = nullptr) { return RenameFileW (lpSrcPath, lpDestPath, fProgress); } bool RenameFile (const std::string &lpSrcPath, const std::string &lpDestPath, std::function fProgress = nullptr) { return RenameFileA (lpSrcPath, lpDestPath, fProgress); } bool RenameFile (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function fProgress = nullptr) { return RenameFileW (lpSrcDir, lpSrcName, lpDestName, fProgress); } bool RenameFile (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function fProgress = nullptr) { return RenameFileA (lpSrcDir, lpSrcName, lpDestName, fProgress); } bool RenameDirectoryW ( const std::wstring &lpSrcPath, const std::wstring &lpDestPath, std::function fProgress = nullptr ) { LPPROGRESS_ROUTINE pRoutine = nullptr; LPVOID pData = nullptr; if (fProgress) { pRoutine = ProgressRoutine; pData = &fProgress; } DWORD flags = MOVEFILE_COPY_ALLOWED; BOOL ok = MoveFileWithProgressW ( lpSrcPath.c_str (), lpDestPath.c_str (), pRoutine, pData, flags ); return ok != FALSE; } bool RenameDirectoryA ( const std::string &lpSrcPath, const std::string &lpDestPath, std::function fProgress = nullptr ) { LPPROGRESS_ROUTINE pRoutine = nullptr; LPVOID pData = nullptr; if (fProgress) { pRoutine = ProgressRoutine; pData = &fProgress; } DWORD flags = MOVEFILE_COPY_ALLOWED; BOOL ok = MoveFileWithProgressA ( lpSrcPath.c_str (), lpDestPath.c_str (), pRoutine, pData, flags ); return ok != FALSE; } bool RenameDirectoryW ( const std::wstring &lpParentDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function fProgress = nullptr ) { struct PathBuilder { LPWSTR src = nullptr; LPWSTR dest = nullptr; ~PathBuilder () { delete [] src; delete [] dest; } } pb; pb.src = new WCHAR [lpParentDir.length () + lpSrcName.length () + 2]; pb.dest = new WCHAR [lpParentDir.length () + lpDestName.length () + 2]; PathCombineW (pb.src, lpParentDir.c_str (), lpSrcName.c_str ()); PathCombineW (pb.dest, lpParentDir.c_str (), lpDestName.c_str ()); return RenameDirectoryW (pb.src, pb.dest, fProgress); } bool RenameDirectoryA ( const std::string &lpParentDir, const std::string &lpSrcName, const std::string &lpDestName, std::function fProgress = nullptr ) { struct PathBuilder { LPSTR src = nullptr; LPSTR dest = nullptr; ~PathBuilder () { delete [] src; delete [] dest; } } pb; pb.src = new CHAR [lpParentDir.length () + lpSrcName.length () + 2]; pb.dest = new CHAR [lpParentDir.length () + lpDestName.length () + 2]; PathCombineA (pb.src, lpParentDir.c_str (), lpSrcName.c_str ()); PathCombineA (pb.dest, lpParentDir.c_str (), lpDestName.c_str ()); return RenameDirectoryA (pb.src, pb.dest, fProgress); } bool RenameDirectory ( const std::wstring &src, const std::wstring &dst, std::function fProgress = nullptr ) { return RenameDirectoryW (src, dst, fProgress); } bool RenameDirectory ( const std::string &src, const std::string &dst, std::function fProgress = nullptr ) { return RenameDirectoryA (src, dst, fProgress); } bool RenameDirectory ( const std::wstring &parentDir, const std::wstring &srcName, const std::wstring &dstName, std::function fProgress = nullptr ) { return RenameDirectoryW (parentDir, srcName, dstName, fProgress); } bool RenameDirectory ( const std::string &parentDir, const std::string &srcName, const std::string &dstName, std::function fProgress = nullptr ) { return RenameDirectoryA (parentDir, srcName, dstName, fProgress); } std::wstring CombinePath (const std::wstring &left, const std::wstring &right) { std::vector buf (left.capacity () + right.capacity () + 2); PathCombineW (buf.data (), left.c_str (), right.c_str ()); return buf.data (); } #ifdef PathCommonPrefix #undef PathCommonPrefix #endif std::wstring PathCommonPrefix (const std::wstring &file1, const std::wstring &file2) { std::vector buf (Max (file1.capacity (), file2.capacity (), MAX_PATH) + 2); PathCommonPrefixW (file1.c_str (), file2.c_str (), buf.data ()); return buf.data (); } #undef GetFullPathName std::wstring GetFullPathName (const std::wstring &lpFileName) { if (lpFileName.empty ()) return L""; DWORD length = GetFullPathNameW (lpFileName.c_str (), 0, nullptr, nullptr); if (length == 0) return L""; std::vector buffer (length + 1, L'\0'); DWORD result = GetFullPathNameW (lpFileName.c_str (), length, buffer.data (), nullptr); if (result == 0) return L""; return std::wstring (buffer.data (), result); } bool PathEquals (const std::wstring &path1, const std::wstring &path2) { size_t maxlen = Max (path1.capacity () + 1, path2.capacity () + 1, MAX_PATH); std::vector buf1 (maxlen), buf2 (maxlen); PathCanonicalizeW (buf1.data (), path1.c_str ()); PathCanonicalizeW (buf2.data (), path2.c_str ()); return IsNormalizeStringEquals (buf1.data (), buf2.data ()); }