修复日志不打印到GUI的问题,添加UAC

This commit is contained in:
MoeGrid
2026-08-03 23:50:34 +08:00
parent 93d19f272b
commit 549d825f41
9 changed files with 115 additions and 37 deletions
+3 -1
View File
@@ -73,7 +73,9 @@ target_include_directories(sega_mount PRIVATE src res)
if (WIN32)
target_link_libraries(sega_mount PRIVATE ${SEGA_WIN_LIBS} imgui comdlg32)
# WinMain 入口需要 Windows 子系统(无参数时不弹控制台窗口)
set_target_properties(sega_mount PROPERTIES LINK_FLAGS "/SUBSYSTEM:WINDOWS")
# manifest 请求管理员权限(UAC 提权)
set_target_properties(sega_mount PROPERTIES LINK_FLAGS
"/SUBSYSTEM:WINDOWS /MANIFESTUAC:\"level='requireAdministrator' uiAccess='false'\"")
endif ()
set_target_properties(sega_mount PROPERTIES OUTPUT_NAME sega_mount)
+62 -4
View File
@@ -84,10 +84,68 @@ namespace driver {
if (!StartServiceW(hSvc, 0, nullptr)) {
DWORD last = GetLastError();
if (last != ERROR_SERVICE_ALREADY_RUNNING) {
if (error) *error = "StartService 失败:" + utils::last_error_str(last);
CloseServiceHandle(hSvc);
CloseServiceHandle(hScm);
return false;
// 文件不存在(旧服务路径失效):删除旧服务,重新提取驱动并创建
if (last == ERROR_FILE_NOT_FOUND) {
LOG_INFO("服务路径失效,重新安装驱动");
CloseServiceHandle(hSvc);
hSvc = nullptr;
// 删除旧服务
hSvc = OpenServiceW(hScm, SERVICE_NAME, SERVICE_ALL_ACCESS | DELETE);
if (hSvc) {
DeleteService(hSvc);
CloseServiceHandle(hSvc);
hSvc = nullptr;
}
// 重新提取驱动到系统目录
wchar_t sys_dir2[MAX_PATH] = {};
UINT sys_len2 = GetSystemDirectoryW(sys_dir2, MAX_PATH);
if (sys_len2 == 0 || sys_len2 > MAX_PATH) {
if (error) *error = "GetSystemDirectory 失败:" + utils::last_error_str();
CloseServiceHandle(hScm);
return false;
}
std::wstring dst_path2 = std::wstring(sys_dir2) + L"\\drivers\\" + DRIVER_FILENAME;
if (!utils::extract_resource_to_file(IDR_DRIVER_SYS, dst_path2, error)) {
CloseServiceHandle(hScm);
return false;
}
LOG_INFO("驱动已提取到 {}", utils::wstr_to_str(dst_path2));
// 重新创建服务
hSvc = CreateServiceW(
hScm, SERVICE_NAME, SERVICE_NAME,
SERVICE_ALL_ACCESS,
SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
dst_path2.c_str(),
nullptr, nullptr, nullptr, nullptr, nullptr
);
if (!hSvc) {
if (error) *error = "CreateService 失败:" + utils::last_error_str();
CloseServiceHandle(hScm);
return false;
}
LOG_INFO("服务已重新安装:{}", utils::wstr_to_str(dst_path2));
// 再次尝试启动
if (!StartServiceW(hSvc, 0, nullptr)) {
DWORD last2 = GetLastError();
if (last2 != ERROR_SERVICE_ALREADY_RUNNING) {
if (error) *error = "StartService 失败:" + utils::last_error_str(last2);
CloseServiceHandle(hSvc);
CloseServiceHandle(hScm);
return false;
}
}
} else {
if (error) *error = "StartService 失败:" + utils::last_error_str(last);
CloseServiceHandle(hSvc);
CloseServiceHandle(hScm);
return false;
}
}
}
-1
View File
@@ -12,7 +12,6 @@ inline bool g_unmounting = false;
inline std::vector<std::string> g_log_lines;
inline std::mutex g_log_mutex;
inline bool g_auto_scroll = true;
inline bool g_log_capture_enabled = false;
// ===== DX11 全局变量 =====
inline ID3D11Device *g_pd3dDevice = nullptr;
+4 -2
View File
@@ -1,7 +1,9 @@
#define LOG_MODULE "GUI"
#include "gui_utils.h"
#include "gui_common.h"
#include "config.h"
#include "utils/strings.h"
#include "utils/log.h"
#include <windows.h>
#include <commdlg.h>
#include <shlobj.h>
@@ -12,9 +14,9 @@ void load_config_file(const std::wstring &path) {
g_config_path = utils::wstr_to_str(path);
std::string err;
if (parse_config(path, g_cfg, &err)) {
g_log_lines.push_back(std::format("[INFO] 配置已加载:{}", g_config_path));
LOG_INFO("配置已加载:{}", g_config_path);
} else {
g_log_lines.push_back(std::format("[ERROR] {}", err));
LOG_ERROR("{}", err);
}
}
+17 -12
View File
@@ -1,3 +1,4 @@
#define LOG_MODULE "UI"
#include "ui.h"
#include "gui_common.h"
#include "gui_utils.h"
@@ -6,13 +7,19 @@
#include "resource.h"
#include "utils/resource.h"
#include "utils/strings.h"
#include "utils/log.h"
#include "imgui.h"
#include "icons/lucide.h"
#include <format>
#include <windows.h>
// 初始化 ImGui:主题、DPI 缩放、字体加载
// 初始化 ImGui:主题、DPI 缩放、字体加载、日志捕获
void InitUI(float main_scale) {
// 注册日志 sink:将 LOG_XXX 输出同步到 GUI 日志面板
logger::set_sink([](logger::Level level, const std::string &line) {
std::lock_guard<std::mutex> lock(g_log_mutex);
g_log_lines.push_back(line);
});
ImGuiIO &io = ImGui::GetIO();
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
@@ -82,7 +89,7 @@ void DrawUI() {
g_config_path_w = utils::to_wstring(g_config_path);
std::string err;
save_config(g_config_path_w, g_cfg, &err);
g_log_lines.emplace_back("[INFO] 配置已保存");
LOG_INFO("配置已保存");
}
// 主题切换按钮
@@ -233,13 +240,12 @@ void DrawUI() {
if (ImGui::Button(g_driver_ready ? (ICON_PLAY " 挂载") : (ICON_CIRCLE_ALERT " 挂载(需要驱动)"))) {
if (g_driver_ready && !g_mounting) {
g_mounting = true;
g_log_lines.emplace_back("[INFO] 开始挂载...");
LOG_INFO("开始挂载...");
auto result = icf_mount::mount_icf_apps(g_cfg);
if (result.success) {
g_log_lines.push_back(std::format("[INFO] 挂载成功:{} 个 APP{} 个 OPT",
result.apps.size(), result.opts.size()));
LOG_INFO("挂载成功:{} 个 APP{} 个 OPT", result.apps.size(), result.opts.size());
} else {
g_log_lines.push_back(std::format("[ERROR] 挂载失败:{}", result.error));
LOG_ERROR("挂载失败:{}", result.error);
}
g_mounting = false;
}
@@ -249,13 +255,12 @@ void DrawUI() {
if (ImGui::Button(ICON_SQUARE " 卸载")) {
if (g_driver_ready && !g_unmounting) {
g_unmounting = true;
g_log_lines.emplace_back("[INFO] 开始卸载...");
LOG_INFO("开始卸载...");
auto result = icf_mount::unmount_icf_apps(g_cfg);
if (result.success) {
g_log_lines.push_back(std::format("[INFO] 卸载成功:{} 个 APP{} 个 OPT",
result.apps.size(), result.opts.size()));
LOG_INFO("卸载成功:{} 个 APP{} 个 OPT", result.apps.size(), result.opts.size());
} else {
g_log_lines.push_back(std::format("[ERROR] 卸载失败:{}", result.error));
LOG_ERROR("卸载失败:{}", result.error);
}
g_unmounting = false;
}
@@ -271,11 +276,11 @@ void DrawUI() {
ImGui::BeginChild("LogPanel", ImVec2(-1, -1), ImGuiChildFlags_Borders);
{
std::lock_guard<std::mutex> lock(g_log_mutex);
std::lock_guard lock(g_log_mutex);
for (const auto &line: g_log_lines) {
if (line.find("[ERROR]") != std::string::npos)
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.3f, 0.3f, 1.0f));
else if (line.find("[WARN]") != std::string::npos)
else if (line.find("[WARN ") != std::string::npos || line.find("[WARN]") != std::string::npos)
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.8f, 0.2f, 1.0f));
else
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.7f, 0.7f, 0.7f, 1.0f));
+2 -1
View File
@@ -191,6 +191,7 @@ namespace icf_mount {
if (!mount_res.success) {
LOG_ERROR("挂载 OPT {} 失败:{}", entry->version, mount_res.error);
all_ok = false;
}
result.opts.push_back(mount_entry);
@@ -222,7 +223,7 @@ namespace icf_mount {
result.success = all_ok;
if (!all_ok) {
result.error = "部分 APP 挂载失败";
result.error = "部分容器挂载失败,详见日志";
}
return result;
}
+2 -6
View File
@@ -146,9 +146,9 @@ static int run_gui(HINSTANCE hInstance) {
std::string svc_err;
g_driver_ready = driver::ensure_running(&svc_err);
if (g_driver_ready)
g_log_lines.emplace_back("[INFO] 驱动服务已就绪");
LOG_INFO("驱动服务已就绪");
else
g_log_lines.push_back(std::format("[ERROR] 驱动:{}", svc_err));
LOG_ERROR("驱动:{}", svc_err);
}
// 初始化 ImGui DPI 感知
@@ -186,9 +186,6 @@ static int run_gui(HINSTANCE hInstance) {
ImGui_ImplWin32_Init(hwnd);
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
// 启用日志捕获
g_log_capture_enabled = true;
// 主循环
bool done = false;
while (!done) {
@@ -247,7 +244,6 @@ static int run_gui(HINSTANCE hInstance) {
}
// 清理
g_log_capture_enabled = false;
ImGui_ImplDX11_Shutdown();
ImGui_ImplWin32_Shutdown();
ImGui::DestroyContext();
+18 -10
View File
@@ -6,6 +6,9 @@ namespace logger {
// 全局最低输出等级
static auto g_min_level = Level::Debug;
// 日志 sink 回调
static LogSink g_sink = nullptr;
// 等级对应的标签文字(固定5字符宽度对齐)
static const char *level_tag(Level level) {
switch (level) {
@@ -32,11 +35,19 @@ namespace logger {
g_min_level = level;
}
void set_sink(LogSink sink) {
g_sink = std::move(sink);
}
void output_raw(Level level, const char *module, const std::string &message) {
if (static_cast<int>(level) < static_cast<int>(g_min_level)) return;
// 组装完整日志行: [LEVEL][MODULE] message
std::string line = std::string("[") + level_tag(level) + "][" + module + "] " + message;
// 控制台输出
HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
WORD orig_attr = 7; // 默认灰白
WORD orig_attr = 7;
if (hStdout != INVALID_HANDLE_VALUE) {
CONSOLE_SCREEN_BUFFER_INFO csbi{};
if (GetConsoleScreenBufferInfo(hStdout, &csbi)) {
@@ -44,19 +55,16 @@ namespace logger {
}
SetConsoleTextAttribute(hStdout, level_color(level));
}
// 输出: [LEVEL][MODULE] message\n
std::fputs("[", stdout);
std::fputs(level_tag(level), stdout);
std::fputs("][", stdout);
std::fputs(module, stdout);
std::fputs("] ", stdout);
std::fputs(message.c_str(), stdout);
std::fputs(line.c_str(), stdout);
std::fputc('\n', stdout);
std::fflush(stdout);
if (hStdout != INVALID_HANDLE_VALUE) {
SetConsoleTextAttribute(hStdout, orig_attr);
}
// sink 回调(GUI 捕获)
if (g_sink) {
g_sink(level, line);
}
}
}
+7
View File
@@ -2,6 +2,7 @@
#include <string>
#include <format>
#include <functional>
namespace logger {
// 日志等级
@@ -12,9 +13,15 @@ namespace logger {
Error
};
// 日志 sink 回调类型:接收完整格式化行 "[LEVEL][MODULE] message"
using LogSink = std::function<void(Level level, const std::string &line)>;
// 设置全局最低输出等级(低于此等级的日志不输出),默认 Debug(全部输出)
void set_min_level(Level level);
// 设置日志 sink 回调(传入 nullptr 取消),每次输出时会额外调用
void set_sink(LogSink sink);
// 原始字符串输出(已格式化完成),带模块名
void output_raw(Level level, const char *module, const std::string &message);