Organized the project files.

And also fixed some bugs.
This commit is contained in:
Bruce
2025-12-08 16:06:13 +08:00
parent ed7fe3af4b
commit d1813637c5
95 changed files with 46744 additions and 36366 deletions

871
desktopini/filepath.h Normal file
View File

@@ -0,0 +1,871 @@
#pragma once
#include <Windows.h>
#include <string>
#include <algorithm>
#include <shlwapi.h>
#include <vector>
#include <iomanip>
#include <functional>
#include <sstream>
#include "strcmp.h"
#include "version.h"
#include "module.h"
typedef version S_VERSION;
template <typename T> constexpr T Max (T l, T r) { return l > r ? l : r; }
template <typename T> constexpr T Max (T l, T m, T r) { return Max (Max (l, r), m); }
template <typename T> constexpr T Max (T l, T ml, T mr, T r) { return Max (Max (l, ml), Max (mr, r)); }
template <typename CharT> std::basic_string <CharT> replace_substring
(
const std::basic_string <CharT> &str,
const std::basic_string <CharT> &from,
const std::basic_string <CharT> &to
)
{
if (from.empty ()) return str;
std::basic_string <CharT> result;
size_t pos = 0;
size_t start_pos;
while ((start_pos = str.find (from, pos)) != std::basic_string<CharT>::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 <std::string> EnumSubdirectories (const std::string &directory, bool includeParentPath)
{
std::vector<std::string> 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 <std::wstring> EnumSubdirectories (const std::wstring &directory, bool includeParentPath)
{
std::vector<std::wstring> 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 <CHAR> buf (Max <size_t> (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 <WCHAR> buf (Max <size_t> (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 <BYTE> 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 <BYTE> 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 <WCHAR> currentDir (Max <size_t> (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 <WCHAR> modulePath (Max <size_t> (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 <CHAR> buf (Max <size_t> (GetCurrentDirectoryA (0, nullptr), MAX_PATH) + 1);
GetCurrentDirectoryA (buf.size (), buf.data ());
return buf.data ();
}
std::wstring GetCurrentDirectoryW ()
{
std::vector <WCHAR> buf (Max <size_t> (GetCurrentDirectoryW (0, nullptr), MAX_PATH) + 1);
GetCurrentDirectoryW (buf.size (), buf.data ());
return buf.data ();
}
std::wstring GetFileDirectoryW (const std::wstring &filePath)
{
std::vector <WCHAR> 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 <CHAR> 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 <std::wstring> &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 <WCHAR> szPath (Max <size_t> (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 <std::wstring> &aszOutput,
bool bOutputWithPath = false,
bool bSortByLetter = false,
bool bIncludeSubDir = false
) {
if (!bIncludeSubDir) aszOutput.clear ();
std::vector<std::wstring> 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 <void (const std::wstring &, std::wstring)> 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 <WCHAR> szBase (Max <size_t> (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 <WCHAR> buf (Max <size_t> (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<std::wstring> &aszOutput,
bool bOutputWithPath = false,
bool bSortByLetter = false,
bool bIncludeSubDir = false
) {
aszOutput.clear ();
std::function <void (const std::wstring &, const std::wstring &)> 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 <std::function <void (int)> *> (lpData);
if (pCallback && *pCallback)
{
int progress = static_cast <int> (
(TotalBytesTransferred.QuadPart * 100) / TotalFileSize.QuadPart
);
(*pCallback) (progress);
}
return PROGRESS_CONTINUE;
}
bool RenameFileW (
const std::wstring &lpSrcPath,
const std::wstring &lpDestPath,
std::function <void (int)> 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 <void (int)> 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 <void (int)> 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 <void (int)> 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 <void (int)> fProgress = nullptr)
{
return RenameFileW (lpSrcPath, lpDestPath, fProgress);
}
bool RenameFile (const std::string &lpSrcPath, const std::string &lpDestPath, std::function <void (int)> fProgress = nullptr)
{
return RenameFileA (lpSrcPath, lpDestPath, fProgress);
}
bool RenameFile (const std::wstring &lpSrcDir, const std::wstring &lpSrcName, const std::wstring &lpDestName, std::function <void (int)> fProgress = nullptr)
{
return RenameFileW (lpSrcDir, lpSrcName, lpDestName, fProgress);
}
bool RenameFile (const std::string &lpSrcDir, const std::string &lpSrcName, const std::string &lpDestName, std::function <void (int)> fProgress = nullptr)
{
return RenameFileA (lpSrcDir, lpSrcName, lpDestName, fProgress);
}
bool RenameDirectoryW (
const std::wstring &lpSrcPath,
const std::wstring &lpDestPath,
std::function <void (int)> 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 <void (int)> 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 <void (int)> 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 <void (int)> 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 <void (int)> fProgress = nullptr
) {
return RenameDirectoryW (src, dst, fProgress);
}
bool RenameDirectory (
const std::string &src,
const std::string &dst,
std::function <void (int)> fProgress = nullptr
) {
return RenameDirectoryA (src, dst, fProgress);
}
bool RenameDirectory (
const std::wstring &parentDir,
const std::wstring &srcName,
const std::wstring &dstName,
std::function <void (int)> fProgress = nullptr
) {
return RenameDirectoryW (parentDir, srcName, dstName, fProgress);
}
bool RenameDirectory (
const std::string &parentDir,
const std::string &srcName,
const std::string &dstName,
std::function <void (int)> fProgress = nullptr
) {
return RenameDirectoryA (parentDir, srcName, dstName, fProgress);
}
std::wstring CombinePath (const std::wstring &left, const std::wstring &right)
{
std::vector <WCHAR> 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 <WCHAR> buf (Max <size_t> (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 <WCHAR> 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 <size_t> (path1.capacity () + 1, path2.capacity () + 1, MAX_PATH);
std::vector <WCHAR> buf1 (maxlen), buf2 (maxlen);
PathCanonicalizeW (buf1.data (), path1.c_str ());
PathCanonicalizeW (buf2.data (), path2.c_str ());
return IsNormalizeStringEquals (buf1.data (), buf2.data ());
}