Files
App-Installer-For-Windows-8…/settings/filepath.h
2025-12-07 15:18:40 +08:00

872 lines
27 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#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 ());
}