Init commit

This commit is contained in:
2026-08-17 06:31:43 +09:00
commit 348d9275f6
428 changed files with 61806 additions and 0 deletions
+16
View File
@@ -0,0 +1,16 @@
add_library(${TG_TOOL} STATIC
src/tool.cpp
src/wintool.cpp
include/tool.h
include/wintool.h
include/ztool_lib_macro.h
)
target_include_directories(${TG_TOOL} PUBLIC
${CMAKE_CURRENT_SOURCE_DIR}/include
)
#target_compile_definitions(${TG_TOOL} PRIVATE
# ZTOOL_SHARED_LIB
# ZTOOL_DLL_OUTPUT
#)
+74
View File
@@ -0,0 +1,74 @@
#ifndef ZCPPWIN_TOOL_H
#define ZCPPWIN_TOOL_H
#include <string>
#include <filesystem>
#if _WIN32
#include <Windows.h>
#endif
#include "ztool_lib_macro.h"
// WINDOWS独享
namespace Z {
#if _WIN32
ZTOOL_API std::wstring HResultToWString(HRESULT hr);
#endif
}
// 字符串转换(UTF8 - WSTRING)
namespace Z {
#if _WIN32
ZTOOL_API std::string wstring_to_u8(const std::wstring &wstr);
ZTOOL_API std::wstring u8_to_wstring(const std::string &u8str);
#endif
}
// windows 文件操作相关
namespace Z {
#if _WIN32
ZTOOL_API std::filesystem::path get_module_path();
ZTOOL_API std::filesystem::path get_module_dir();
#endif
}
// 随机数
namespace Z {
class ZTOOL_API Random {
public:
Random() = delete;
// 产生[min,max]的随机整数
static int Get(int min, int max);
// 产生[min,max)的随机小数
static float Get(float min, float max);
// 产生[min,max)的随机小数
static double Get(double min, double max);
// 重新产生随机种子
static void GenerateSequence();
// 重新产生固定种子
static void GenerateSequence(uint32_t seed);
private:
static bool bInitialized;
static unsigned int m_seed;
static void *m_gen;
static void InitOnce();
static void GenSequence();
static void GenSequence(uint32_t seed);
static void CleanUp();
};
}
// 其他
namespace Z {
ZTOOL_API void print_obj_memory(const void *obj, size_t len);
}
#endif //ZCPPWIN_TOOL_H
+528
View File
@@ -0,0 +1,528 @@
#ifndef ZCPPWIN_WINTOOL_H
#define ZCPPWIN_WINTOOL_H
// ============================================================================
// wintool.h
// ----------------------------------------------------------------------------
// MSVC / Windows / C++20 常用 Win32 工具库声明文件。
//
// 使用方式:
// 1. 将 wintool.h 与 wintool.cpp 加入你的 CLion + CMake 工程。
// 2. 推荐在 CMake 中启用 C++20,并定义 UNICODE、_UNICODE、NOMINMAX。
// 3. 所有接口都位于命名空间 Z 中,直接调用 Z::xxx 即可。
//
// 设计约定:
// - 默认优先使用宽字符版本,也就是 std::wstring / Win32 W 系列 API。
// - 失败时大多数函数会抛出 Z::Win32Error、Z::HResultError 或 std::runtime_error。
// - 资源对象采用 RAII,离开作用域后自动释放 HANDLE、HMODULE、HKEY 等资源。
// - 返回 std::optional 的函数表示“失败或不存在”不一定是异常场景。
//
// 简单示例:
// ZWINTOOL::SetConsoleUtf8();
// auto exe = ZWINTOOL::ModulePathW();
// ZWINTOOL::WriteTextFileUtf8(L"log.txt", "hello\n");
// auto text = ZWINTOOL::ReadTextFileUtf8(L"log.txt");
// ============================================================================
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <windows.h>
#include <objbase.h>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <span>
#include <stdexcept>
#include <string>
#include <string_view>
#include <vector>
#include "ztool_lib_macro.h"
namespace ZWINTOOL {
// 通用字节数组类型,常用于二进制文件、注册表 REG_BINARY 等场景。
using Bytes = std::vector<std::byte>;
/* ---------------------------------------------------------------------------- */
//region 错误处理工具
/* ---------------------------------------------------------------------------- */
// Win32 错误异常。
// 作用:保存 GetLastError / Win32 API 返回的错误码,并生成可读错误文本。
// 用法:catch (const Z::Win32Error& e) 后可通过 e.code() 获取 DWORD 错误码。
class ZTOOL_API Win32Error final : public std::runtime_error {
public:
// error 为 Win32 错误码;context 用于标记失败位置,例如 "CreateFileW"。
explicit Win32Error(DWORD error, std::string_view context = {});
// 返回原始 Win32 错误码。
[[nodiscard]] DWORD code() const noexcept;
private:
DWORD code_{};
};
// HRESULT 错误异常。
// 作用:包装 COM、Shell、DirectX 等 API 常见的 HRESULT 失败值。
// 用法:catch (const Z::HResultError& e) 后可通过 e.hr() 获取 HRESULT。
class ZTOOL_API HResultError final : public std::runtime_error {
public:
// hr 为 HRESULTcontext 用于标记失败位置,例如 "CoCreateInstance"。
explicit HResultError(HRESULT hr, std::string_view context = {});
// 返回原始 HRESULT。
[[nodiscard]] HRESULT hr() const noexcept;
private:
HRESULT hr_{};
};
// 获取当前线程最近一次 Win32 错误码,相当于 GetLastError()。
[[nodiscard]] ZTOOL_API DWORD LastError() noexcept;
// 将 Win32 错误码格式化为宽字符串。
// 用法:std::wstring msg = Z::ErrorMessageW(ERROR_FILE_NOT_FOUND);
[[nodiscard]] ZTOOL_API std::wstring ErrorMessageW(DWORD error = ::GetLastError());
// 将 Win32 错误码格式化为 UTF-8 字符串。
[[nodiscard]] ZTOOL_API std::string ErrorMessageA(DWORD error = ::GetLastError());
// 将 HRESULT 格式化为宽字符串。
[[nodiscard]] ZTOOL_API std::wstring HResultMessageW(HRESULT hr);
// 将 HRESULT 格式化为 UTF-8 字符串。
[[nodiscard]] ZTOOL_API std::string HResultMessageA(HRESULT hr);
// 直接抛出当前 GetLastError() 对应的 Win32Error。
// 用法:if (!ok) Z::ThrowLastError("SomeWin32Api");
ZTOOL_API void ThrowLastError(std::string_view context = {});
// 检查 BOOL 返回值;为 FALSE 时抛出 Win32Error。
ZTOOL_API void ThrowIfFalse(BOOL ok, std::string_view context = {});
// 检查指针;为空时抛出 Win32Error。
ZTOOL_API void ThrowIfNull(const void *pointer, std::string_view context = {});
// 检查 HANDLEnullptr 或 INVALID_HANDLE_VALUE 时抛出 Win32Error。
ZTOOL_API void ThrowIfInvalidHandle(HANDLE handle, std::string_view context = {});
// 检查 HRESULTFAILED(hr) 时抛出 HResultError。
ZTOOL_API void CheckHResult(HRESULT hr, std::string_view context = {});
//endregion
/* ---------------------------------------------------------------------------- */
//region 字符串编码转换工具
/* ---------------------------------------------------------------------------- */
// UTF-8 转 UTF-16。
// 典型用途:把配置文件、网络文本、std::string 传给 Windows W 系列 API。
[[nodiscard]] ZTOOL_API std::wstring Utf8ToWide(std::string_view text);
// UTF-16 转 UTF-8。
// 典型用途:把 Win32 返回的 std::wstring 输出到日志、文件或控制台。
[[nodiscard]] ZTOOL_API std::string WideToUtf8(std::wstring_view text);
// 指定代码页的多字节字符串转 UTF-16。
// 用法:Z::MultiByteToWide(text, CP_ACP) 或 Z::MultiByteToWide(text, CP_UTF8)。
[[nodiscard]] ZTOOL_API std::wstring MultiByteToWide(std::string_view text, UINT codePage);
// UTF-16 转指定代码页多字节字符串。
[[nodiscard]] ZTOOL_API std::string WideToMultiByte(std::wstring_view text, UINT codePage);
//endregion
/* ---------------------------------------------------------------------------- */
//region RAII Win32 资源封装
/* ---------------------------------------------------------------------------- */
// HANDLE RAII 封装。
// 作用:自动调用 CloseHandle,避免文件、进程、线程、事件等句柄泄漏。
// 用法:Z::Handle file(::CreateFileW(...)); if (file) { ... }
class ZTOOL_API Handle final {
public:
constexpr Handle() noexcept = default;
// 接管一个已有 HANDLE;析构时自动 CloseHandle。
explicit Handle(HANDLE handle) noexcept;
~Handle() noexcept;
Handle(const Handle &) = delete;
Handle &operator=(const Handle &) = delete;
Handle(Handle &&other) noexcept;
Handle &operator=(Handle &&other) noexcept;
// 获取原始 HANDLE,不转移所有权。
[[nodiscard]] HANDLE get() const noexcept;
// 获取用于输出参数的地址;会先释放旧句柄。
// 用法:SomeApi(handle.put());
[[nodiscard]] HANDLE *put() noexcept;
// 判断是否持有有效句柄。
[[nodiscard]] bool valid() const noexcept;
explicit operator bool() const noexcept;
// 放弃所有权并返回原始 HANDLE;调用者之后需要自行 CloseHandle。
[[nodiscard]] HANDLE release() noexcept;
// 释放旧句柄并接管新句柄。
void reset(HANDLE handle = nullptr) noexcept;
private:
HANDLE handle_ = nullptr;
};
// HMODULE RAII 封装。
// 作用:LoadLibraryW / FreeLibrary 的安全封装,适合动态加载 DLL。
// 用法:Z::Library dll(L"user32.dll"); auto p = dll.proc<Fn*>("MessageBoxW");
class ZTOOL_API Library final {
public:
Library() noexcept = default;
explicit Library(std::wstring_view path);
~Library() noexcept;
Library(const Library &) = delete;
Library &operator=(const Library &) = delete;
Library(Library &&other) noexcept;
Library &operator=(Library &&other) noexcept;
[[nodiscard]] HMODULE get() const noexcept;
[[nodiscard]] bool valid() const noexcept;
explicit operator bool() const noexcept;
// 加载指定 DLL;已加载其他模块时会先释放。
void load(std::wstring_view path);
// 放弃所有权,调用者之后需要自行 FreeLibrary。
[[nodiscard]] HMODULE release() noexcept;
// 释放旧模块并接管新模块。
void reset(HMODULE module = nullptr) noexcept;
// 获取 DLL 导出函数地址,并转换为指定函数指针类型。
// 用法:using Fn = int (WINAPI*)(HWND,LPCWSTR,LPCWSTR,UINT);
// auto MessageBoxWFn = dll.proc<Fn>("MessageBoxW");
template<class T>
[[nodiscard]] T proc(std::string_view name) const {
if (!module_) {
throw std::logic_error("Z::Library::proc called on empty library");
}
std::string procName{name};
FARPROC p = ::GetProcAddress(module_, procName.c_str());
if (!p) {
ThrowLastError("GetProcAddress");
}
return reinterpret_cast<T>(p);
}
private:
HMODULE module_ = nullptr;
};
// COM 初始化 RAII 封装。
// 作用:构造时 CoInitializeEx,析构时 CoUninitialize。
// 用法:Z::ComApartment com; 然后安全调用 COM / Shell API。
class ZTOOL_API ComApartment final {
public:
// coinit 可传 COINIT_APARTMENTTHREADED 或 COINIT_MULTITHREADED。
explicit ComApartment(DWORD coinit = COINIT_APARTMENTTHREADED);
~ComApartment() noexcept;
ComApartment(const ComApartment &) = delete;
ComApartment &operator=(const ComApartment &) = delete;
// 返回 CoInitializeEx 的结果,通常 S_OK 或 S_FALSE 表示可用。
[[nodiscard]] HRESULT hr() const noexcept;
private:
HRESULT hr_ = S_OK;
bool initialized_ = false;
};
//endregion
/* ---------------------------------------------------------------------------- */
//region 路径与环境变量工具
/* ---------------------------------------------------------------------------- */
// 获取当前 EXE 或指定模块的完整路径。
[[nodiscard]] ZTOOL_API std::wstring ModulePathW(HMODULE module = nullptr);
// 获取当前 EXE 或指定模块所在目录。
[[nodiscard]] ZTOOL_API std::wstring ModuleDirW(HMODULE module = nullptr);
// 获取当前工作目录。
[[nodiscard]] ZTOOL_API std::wstring CurrentDirectoryW();
// 获取系统临时目录。
[[nodiscard]] ZTOOL_API std::wstring TempDirectoryW();
// 获取父目录路径。示例:C:\\a\\b.txt -> C:\\a。
[[nodiscard]] ZTOOL_API std::wstring ParentPathW(std::wstring_view path);
// 获取文件名部分。示例:C:\\a\\b.txt -> b.txt。
[[nodiscard]] ZTOOL_API std::wstring FileNameW(std::wstring_view path);
// 拼接两个路径片段,会自动处理反斜杠。
[[nodiscard]] ZTOOL_API std::wstring JoinPathW(std::wstring_view left, std::wstring_view right);
// 转换为 Windows 长路径形式。绝对路径会加 \\?\ 前缀,便于突破 MAX_PATH 限制。
[[nodiscard]] ZTOOL_API std::wstring ToLongPathW(std::wstring_view path);
// 读取环境变量;不存在时返回 std::nullopt。
[[nodiscard]] ZTOOL_API std::optional<std::wstring> EnvironmentVariableW(std::wstring_view name);
// 设置环境变量;value 为 nullopt 时删除环境变量。
ZTOOL_API void SetEnvironmentVariableWZ(std::wstring_view name,
std::optional<std::wstring_view> value);
// 展开字符串中的环境变量。示例:%TEMP%\\a.txt。
[[nodiscard]] ZTOOL_API std::wstring ExpandEnvironmentStringsWZ(std::wstring_view text);
//endregion
/* ---------------------------------------------------------------------------- */
//region 文件系统工具
/* ---------------------------------------------------------------------------- */
// 判断路径是否存在,文件或目录均可。
[[nodiscard]] ZTOOL_API bool PathExistsW(std::wstring_view path);
// 判断路径是否存在且为普通文件。
[[nodiscard]] ZTOOL_API bool FileExistsW(std::wstring_view path);
// 判断路径是否存在且为目录。
[[nodiscard]] ZTOOL_API bool DirectoryExistsW(std::wstring_view path);
// 递归创建目录。目录已存在时返回 true。
[[nodiscard]] ZTOOL_API bool CreateDirectoryTreeW(std::wstring_view path);
// 读取整个文件为字节数组。失败时抛出 Win32Error。
[[nodiscard]] ZTOOL_API Bytes ReadFileBytes(std::wstring_view path);
// 写入字节数组到文件;append=true 时追加写入,否则覆盖。
ZTOOL_API void WriteFileBytes(std::wstring_view path, std::span<const std::byte> data,
bool append = false);
// 按 UTF-8 文本读取文件。不会自动去除 BOM。
[[nodiscard]] ZTOOL_API std::string ReadTextFileUtf8(std::wstring_view path);
// 按 UTF-8 文本写入文件;writeBom=true 时写入 UTF-8 BOM。
ZTOOL_API void WriteTextFileUtf8(std::wstring_view path, std::string_view text, bool append = false,
bool writeBom = false);
//endregion
/* ---------------------------------------------------------------------------- */
//region 进程与命令行工具
/* ---------------------------------------------------------------------------- */
// 启动进程参数。
// application:可执行文件路径,可为空。
// commandLine:完整命令行;如果 application 为空,应包含可执行文件。
// workingDirectory:工作目录,可为空。
// creationFlagsCreateProcessW 标志。
// inheritHandles:是否继承句柄。
// showWindow/showCommand:控制窗口显示状态。
struct ZTOOL_API ProcessStartInfo {
std::wstring application;
std::wstring commandLine;
std::wstring workingDirectory;
DWORD creationFlags = 0;
bool inheritHandles = false;
bool showWindow = true;
WORD showCommand = SW_SHOWNORMAL;
};
// 启动进程后的结果。
// process/thread 使用 RAII 管理,离开作用域自动 CloseHandle。
struct ZTOOL_API ProcessInfo {
Handle process;
Handle thread;
DWORD processId = 0;
DWORD threadId = 0;
};
// 获取当前进程命令行参数,等价于 main/wmain 的 argv。
[[nodiscard]] ZTOOL_API std::vector<std::wstring> CommandLineArgsW();
// 将单个参数转义为 Windows 命令行安全格式。
[[nodiscard]] ZTOOL_API std::wstring QuoteCommandLineArgW(std::wstring_view arg);
// 把多个参数拼接成安全命令行。
[[nodiscard]] ZTOOL_API std::wstring BuildCommandLineW(std::span<const std::wstring> args);
// 启动进程。失败时抛出 Win32Error。
[[nodiscard]] ZTOOL_API ProcessInfo StartProcess(const ProcessStartInfo &info);
// 等待进程结束。
// 返回:进程退出码;如果超时返回 std::nullopt。
[[nodiscard]] ZTOOL_API std::optional<DWORD> WaitForProcess(HANDLE process,
DWORD milliseconds = INFINITE);
// 判断当前进程是否以管理员权限运行。
[[nodiscard]] ZTOOL_API bool IsProcessElevated();
// 获取当前 Windows 用户名。
[[nodiscard]] ZTOOL_API std::wstring UserNameW();
// 获取计算机名。
[[nodiscard]] ZTOOL_API std::wstring ComputerNameW();
// 获取当前进程 ID。
[[nodiscard]] ZTOOL_API DWORD CurrentProcessId() noexcept;
// 获取当前线程 ID。
[[nodiscard]] ZTOOL_API DWORD CurrentThreadId() noexcept;
//endregion
/* ---------------------------------------------------------------------------- */
//region 注册表工具
/* ---------------------------------------------------------------------------- */
// HKEY RAII 封装。
// 作用:自动 RegCloseKey,提供常用注册表读写和枚举功能。
// 用法:
// auto key = Z::RegKey::Open(HKEY_CURRENT_USER, L"Software\\MyApp");
// auto name = key.GetStringValue(L"Name");
class ZTOOL_API RegKey final {
public:
RegKey() noexcept = default;
// 接管已有 HKEY;析构时自动 RegCloseKey。
explicit RegKey(HKEY key) noexcept;
~RegKey() noexcept;
RegKey(const RegKey &) = delete;
RegKey &operator=(const RegKey &) = delete;
RegKey(RegKey &&other) noexcept;
RegKey &operator=(RegKey &&other) noexcept;
// 打开注册表键;失败时抛出 Win32Error。
static RegKey Open(HKEY root, std::wstring_view subKey, REGSAM access = KEY_READ);
// 尝试打开注册表键;不存在时返回 std::nullopt,其他错误抛异常。
static std::optional<RegKey> TryOpen(HKEY root, std::wstring_view subKey,
REGSAM access = KEY_READ);
// 创建或打开注册表键。
static RegKey Create(HKEY root, std::wstring_view subKey,
REGSAM access = KEY_READ | KEY_WRITE);
[[nodiscard]] HKEY get() const noexcept;
[[nodiscard]] HKEY *put() noexcept;
[[nodiscard]] bool valid() const noexcept;
explicit operator bool() const noexcept;
[[nodiscard]] HKEY release() noexcept;
void reset(HKEY key = nullptr) noexcept;
// 读取字符串值。支持 REG_SZ / REG_EXPAND_SZ;不存在返回 nullopt。
[[nodiscard]] std::optional<std::wstring> GetStringValue(
std::wstring_view valueName = {}) const;
// 写入字符串值。type 通常为 REG_SZ 或 REG_EXPAND_SZ。
void SetStringValue(std::wstring_view valueName, std::wstring_view value,
DWORD type = REG_SZ) const;
// 读取 DWORD 值;不存在返回 nullopt。
[[nodiscard]] std::optional<DWORD> GetDwordValue(
std::wstring_view valueName = {}) const;
// 写入 DWORD 值。
void SetDwordValue(std::wstring_view valueName, DWORD value) const;
// 读取 QWORD 值;不存在返回 nullopt。
[[nodiscard]] std::optional<unsigned long long> GetQwordValue(
std::wstring_view valueName = {}) const;
// 写入 QWORD 值。
void SetQwordValue(std::wstring_view valueName, unsigned long long value) const;
// 读取二进制值;不存在返回 nullopt。
[[nodiscard]] std::optional<Bytes> GetBinaryValue(
std::wstring_view valueName = {}) const;
// 写入二进制值。
void SetBinaryValue(std::wstring_view valueName,
std::span<const std::byte> data) const;
// 枚举子键名。
[[nodiscard]] std::vector<std::wstring> EnumSubKeys() const;
// 枚举值名。
[[nodiscard]] std::vector<std::wstring> EnumValueNames() const;
private:
HKEY key_ = nullptr;
};
//endregion
/* ---------------------------------------------------------------------------- */
//region 窗口工具
/* ---------------------------------------------------------------------------- */
// 获取窗口标题文本。
[[nodiscard]] ZTOOL_API std::wstring WindowTextW(HWND hwnd);
// 获取窗口标题文本并转换为 UTF-8。
[[nodiscard]] ZTOOL_API std::string WindowTextUtf8(HWND hwnd);
// 使用 UTF-8 文本设置窗口标题。
ZTOOL_API void SetWindowTextUtf8(HWND hwnd, std::string_view text);
// 获取窗口类名。
[[nodiscard]] ZTOOL_API std::wstring ClassNameW(HWND hwnd);
// 获取窗口屏幕坐标矩形。
[[nodiscard]] ZTOOL_API RECT WindowRect(HWND hwnd);
// 获取窗口客户区矩形。
[[nodiscard]] ZTOOL_API RECT ClientRect(HWND hwnd);
// 将窗口移动到父窗口或屏幕中央。
ZTOOL_API void CenterWindow(HWND hwnd, HWND parent = nullptr);
//endregion
/* ---------------------------------------------------------------------------- */
//region 剪贴板与控制台工具
/* ---------------------------------------------------------------------------- */
// 设置剪贴板 Unicode 文本。
ZTOOL_API void SetClipboardTextW(std::wstring_view text, HWND owner = nullptr);
// 读取剪贴板 Unicode 文本;没有文本时返回 nullopt。
[[nodiscard]] ZTOOL_API std::optional<std::wstring> GetClipboardTextW(HWND owner = nullptr);
// 将控制台输入/输出代码页设置为 UTF-8。
// 常用于 main 开头,配合中文日志输出。
ZTOOL_API void SetConsoleUtf8();
// 判断当前进程是否已经拥有控制台。
[[nodiscard]] ZTOOL_API bool HasConsole() noexcept;
// 尝试附加父进程控制台;失败则分配一个新控制台。
[[nodiscard]] ZTOOL_API bool AttachOrAllocConsole();
//endregion
} // namespace Z
#endif //ZCPPWIN_WINTOOL_H
+18
View File
@@ -0,0 +1,18 @@
#ifndef ZTOOL_SHARED_LIB_MACRO_H
#define ZTOOL_SHARED_LIB_MACRO_H
#ifdef ZTOOL_SHARED_LIB
#ifdef _WIN32
#ifdef ZTOOL_DLL_OUTPUT
#define ZTOOL_API __declspec(dllexport)
#else
#define ZTOOL_API __declspec(dllimport)
#endif
#else
#define ZTOOL_API __attribute__((visibility("default")))
#endif
#else
#define ZTOOL_API
#endif
#endif //ZTOOL_SHARED_LIB_MACRO_H
+296
View File
@@ -0,0 +1,296 @@
#include "../include/tool.h"
#include <iostream>
#include <iomanip>
#include <vector>
#include <random>
#ifdef _WIN32
#include <Windows.h>
#elif defined(__linux__)
#include <locale>
#include <codecvt>
#include <unistd.h>
#include <limits.h>
#endif
#ifdef _WIN32
std::wstring Z::HResultToWString(HRESULT hr) {
LPWSTR buffer = nullptr;
DWORD flags =
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS;
DWORD len = FormatMessageW(
flags, nullptr, hr,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&buffer), 0, nullptr);
// 如果是 HRESULT_FROM_WIN32(...) 形式,尝试取低 16 位 Win32 error code
if (len == 0 && HRESULT_FACILITY(hr) == FACILITY_WIN32) {
len = FormatMessageW(
flags,
nullptr,
HRESULT_CODE(hr),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
reinterpret_cast<LPWSTR>(&buffer),
0,
nullptr
);
}
if (len == 0) {
wchar_t fallback[64];
swprintf_s(fallback, L"Unknown HRESULT: 0x%08X", static_cast<unsigned>(hr));
return fallback;
}
std::wstring message(buffer, len);
LocalFree(buffer);
return message;
}
#endif
namespace {
std::once_flag initflag{};
}
//region 字符串转换(UTF8 - WSTRING)
namespace Z {
#ifdef _WIN32
std::string wstring_to_u8(const std::wstring &wstr) {
if (wstr.empty())return {};
int len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(),
static_cast<int>(wstr.size()),
nullptr, 0, nullptr, nullptr);
if (len <= 0) throw std::runtime_error("Z::wstring_to_u8 compute length error.");
std::string str(len, '\0');
len = WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(),
static_cast<int>(wstr.size()),
str.data(), len, nullptr, nullptr);
if (len <= 0)throw std::runtime_error("Z::wstring_to_u8 escape error.");
return str;
}
std::wstring u8_to_wstring(const std::string &u8str) {
if (u8str.empty())return {};
int len = MultiByteToWideChar(CP_UTF8, 0, u8str.c_str(), -1, nullptr, 0);
if (len <= 0) throw std::runtime_error("Z::u8_to_wstring compute length error.");
std::wstring ws(len, L'\0');
len = MultiByteToWideChar(CP_UTF8, 0, u8str.c_str(), -1, ws.data(), len);
if (len <= 0) throw std::runtime_error("Z::u8_to_wstring escape error.");
return ws;
}
#else
std::string wstring_to_u8(const std::wstring &wstr) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
return conv.to_bytes(wstr);
}
std::wstring u8_to_wstring(const std::string &u8str) {
std::wstring_convert<std::codecvt_utf8<wchar_t>> conv;
return conv.from_bytes(str);
}
#endif
}
//region filesystem相关
namespace Z {
std::filesystem::path get_module_path() {
#if defined(_WIN32)
#if defined(UNICODE) || defined(_UNICODE)
// Windows Unicode / wide char variant
std::wstring buffer(MAX_PATH, L'\0');
DWORD length = GetModuleFileNameW(
nullptr,
buffer.data(),
static_cast<DWORD>(buffer.size())
);
if (length == 0) {
throw std::runtime_error("GetModuleFileNameW failed");
}
// 如果路径长度刚好达到 buffer 大小,可能被截断,动态扩容
while (length == buffer.size()) {
buffer.resize(buffer.size() * 2);
length = GetModuleFileNameW(
nullptr,
buffer.data(),
static_cast<DWORD>(buffer.size())
);
if (length == 0) {
throw std::runtime_error("GetModuleFileNameW failed");
}
}
buffer.resize(length);
return std::filesystem::path(buffer);
#else
// Windows non-Unicode / narrow char variant
std::string buffer(MAX_PATH, '\0');
DWORD length = GetModuleFileNameA(
nullptr,
buffer.data(),
static_cast<DWORD>(buffer.size())
);
if (length == 0) {
throw std::runtime_error("GetModuleFileNameA failed");
}
// 如果路径长度刚好达到 buffer 大小,可能被截断,动态扩容
while (length == buffer.size()) {
buffer.resize(buffer.size() * 2);
length = GetModuleFileNameA(
nullptr,
buffer.data(),
static_cast<DWORD>(buffer.size())
);
if (length == 0) {
throw std::runtime_error("GetModuleFileNameA failed");
}
}
buffer.resize(length);
return std::filesystem::path(buffer);
#endif
#elif defined(__linux__)
// Linux / GCC variant
std::vector<char> buffer(PATH_MAX);
while (true) {
ssize_t length = readlink(
"/proc/self/exe",
buffer.data(),
buffer.size()
);
if (length == -1) {
throw std::runtime_error("readlink /proc/self/exe failed");
}
// readlink 不会自动追加 '\0'
if (static_cast<size_t>(length) < buffer.size()) {
return std::filesystem::path(
std::string(buffer.data(), static_cast<size_t>(length))
);
}
// 缓冲区不够,扩容重试
buffer.resize(buffer.size() * 2);
}
#else
#error "get_module_path is not implemented for this platform"
#endif
}
std::filesystem::path get_module_dir() {
return get_module_path().parent_path();
}
}
//region 其他
namespace Z {
void print_obj_memory(const void *obj, size_t len) {
auto bytes = static_cast<const unsigned char *>(obj);
int l = static_cast<int>(len);
int w = 1;
while ((l /= 10) > 0) {
w++;
}
for (size_t i = 0; i < len; i += 8) {
for (size_t j = 0; j < 8; ++j) {
auto sum = i + j;
if (sum == len) break;
std::cout << '[' << std::setfill('0') << std::setw(w) << sum << ']'
<< std::setw(3) << static_cast<int>(bytes[sum]) << ' ';
}
std::cout << '\n';
}
std::cout << std::flush;
}
bool Random::bInitialized = false;
void *Random::m_gen = nullptr;
uint32_t Random::m_seed = 0;
int Random::Get(int min, int max) {
InitOnce();
std::uniform_int_distribution dist(min, max);
return dist(*static_cast<std::mt19937 *>(m_gen));
}
float Random::Get(float min, float max) {
InitOnce();
std::uniform_real_distribution dist(min, max);
return dist(*static_cast<std::mt19937 *>(m_gen));
}
double Random::Get(double min, double max) {
InitOnce();
std::uniform_real_distribution dist(min, max);
return dist(*static_cast<std::mt19937 *>(m_gen));
}
void Random::GenerateSequence() {
if (!bInitialized) {
InitOnce();
} else {
GenSequence();
}
}
void Random::GenerateSequence(uint32_t seed) {
if (!bInitialized) {
InitOnce();
}
GenSequence(seed);
}
void Random::InitOnce() {
std::call_once(initflag, []() {
GenSequence();
std::atexit(CleanUp);
bInitialized = true;
});
}
void Random::GenSequence() {
if (m_gen) {
auto *_gen = static_cast<std::mt19937 *>(m_gen);
delete _gen;
}
std::random_device rd{};
m_seed = rd();
m_gen = new std::mt19937(m_seed);
}
void Random::GenSequence(uint32_t seed) {
m_seed = seed;
if (m_gen) {
auto *_gen = static_cast<std::mt19937 *>(m_gen);
delete _gen;
}
m_gen = new std::mt19937(seed);
}
void Random::CleanUp() {
if (m_gen) {
auto *_gen = static_cast<std::mt19937 *>(m_gen);
delete _gen;
m_gen = nullptr;
bInitialized = false;
}
}
}
//
+1368
View File
File diff suppressed because it is too large Load Diff