-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.cpp
More file actions
259 lines (239 loc) · 12.6 KB
/
Copy pathmain.cpp
File metadata and controls
259 lines (239 loc) · 12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
/*
* Copyright (c) 2026 HsingYun (iakext@gmail.com)
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <windows.h>
#include <QApplication>
#include <QCoreApplication>
#include <QScopeGuard>
#include <QTimer>
#include <cstdint>
#include <cstdlib>
#include <exception>
#include <optional>
#include <stdexcept>
#include "src/app/CrashHandler.h"
#include "src/app/FileStagingStore.h"
#include "src/app/SecureSingleInstance.h"
#include "src/app/StartupOptions.h"
#include "src/service/EnhancedModeService.h"
#include "src/ui/CenteredTextStyle.h"
#include "src/ui/I18n.h"
#include "src/ui/MainWindow.h"
#include "src/ui/ThemeManager.h"
#include "src/util/Log.h"
#include "src/uwf/SystemCheck.h"
#include "src/uwf/UwfSnapshot.h"
#include "src/uwf/wmi/WmiClient.h"
namespace {
void restrictDllSearchPath() {
// Release 构建还通过 /DEPENDENTLOADFLAG:0x800 约束进入 main 前的静态
// 导入;这里负责之后没有显式 LOAD_LIBRARY_SEARCH 标志的动态加载。
// 正式包是单文件程序,不需要从应用目录、当前目录或 PATH 查找 DLL。
if (!SetDefaultDllDirectories(LOAD_LIBRARY_SEARCH_SYSTEM32)) {
throw std::system_error(static_cast<int>(GetLastError()), std::system_category(), "restrict process DLL search path");
}
}
std::optional<int> handleSingleInstanceStartup(uwf::app::SecureSingleInstance& singleInstance, const uwf::app::StartupOptions& options) {
// 单实例:已有实例在运行则切到它并退出,不再启动第二个窗口。放在最前面——
// 系统检查等重活之前;若只是把任务转交给已有实例,没必要白做这些。
uwf::app::ApplicationCommandResult forwardedResult;
const auto acquireResult = singleInstance.acquire(options.initialCommand(), &forwardedResult);
if (acquireResult == uwf::app::SecureSingleInstance::AcquireResult::ForwardedExisting) {
UWF_LOG_I("main") << "startup command forwarded to existing instance: command=" << static_cast<int>(options.initialCommand())
<< " outcome=" << static_cast<int>(forwardedResult.outcome);
// CompletedWithFailures 表示所有目标均已得到最终结果,但显式
// --commit-stage 命令仍应返回非零退出码,不能向脚本隐藏逐项失败。
return forwardedResult.outcome == uwf::app::ApplicationCommandOutcome::Succeeded ? EXIT_SUCCESS : EXIT_FAILURE;
}
if (acquireResult == uwf::app::SecureSingleInstance::AcquireResult::Unprotected) {
UWF_LOG_W("main") << "single-instance server unavailable: error=" << singleInstance.errorString().toStdString();
}
return std::nullopt;
}
void initializeUserInterface(QApplication& app) {
// 用自定义 QProxyStyle 抵消 QToolButton / QTabBar 文字基线偏下的问题。
app.setStyle(new uwf::ui::CenteredTextStyle());
// 字体渲染:关 hinting + 关次像素 AA。Microsoft YaHei 在 9-10pt 小字号
// 下,hinter 把笔画对齐像素网格时整除不下来的几条会落在分数像素被 ClearType
// 反锯齿成"半透明 2 像素",看起来比对齐到整数行的笔画细。关掉 hinting 让
// 所有笔画用同一种次像素 AA 处理,粗细就一致;NoSubpixelAntialias 进一步
// 把次像素 AA 退回灰度 AA,避免 ClearType 在某些 DPI 下产生彩边。代价是
// 字看起来略软("Mac 风"),但更整齐。
{
QFont f = app.font();
f.setHintingPreference(QFont::PreferNoHinting);
f.setStyleStrategy(static_cast<QFont::StyleStrategy>(QFont::PreferAntialias | QFont::NoSubpixelAntialias));
app.setFont(f);
}
(void)uwf::ui::I18n::instance();
// 启动时跟随系统主题(读 HKCU\...\Personalize\AppsUseLightTheme),用户
// 之后可以通过工具栏右上角的按钮自由切换。不持久化偏好——每次启动重新探测。
auto& theme = uwf::ui::ThemeManager::instance();
theme.apply(uwf::ui::ThemeManager::detectSystemTheme());
}
uwf::SystemCheckResult checkRuntimeEnvironment() {
// 系统校验不再是硬性拦截:版本不在受支持清单内时只记一条兼容模式提示,
// 程序照常启动,提示通过 GlobalStatusPanel 的信息框告知用户。提示文案不在
// 这里翻译——交给 MainWindow::buildUi 按当前语言现翻译,否则切语言后文案
// 不会跟着变(详见 MainWindow 构造函数注释)。
const auto check = uwf::runSystemChecks();
switch (check.status) {
case uwf::CheckStatus::UnsupportedSystem:
UWF_LOG_W("main") << "unsupported Windows edition: mode=compatibility product=" << check.productName << " edition=" << check.editionId;
break;
case uwf::CheckStatus::Ok:
UWF_LOG_I("main") << "system check completed: product=" << check.productName << " edition=" << check.editionId;
break;
}
// 未提权不再弹模态框拦截——GlobalStatusPanel 会常驻一条红色"需要管理员
// 权限"横幅,程序照常启动,可读但不可改。
if (!uwf::isElevated()) {
UWF_LOG_I("main") << "process is not elevated: mode=read-only";
}
return check;
}
int runMainWindow(QApplication& app, uwf::app::SecureSingleInstance& singleInstance, const uwf::app::StartupOptions& options,
const uwf::SystemCheckResult& check, const uwf::UwfCapability uwfCapability) {
uwf::ui::MainWindow w(uwfCapability, check.status == uwf::CheckStatus::UnsupportedSystem, QString::fromStdString(check.productName),
QString::fromStdString(check.editionId));
QObject::connect(&singleInstance, &uwf::app::SecureSingleInstance::activationRequested, &w, &uwf::ui::MainWindow::raiseToFront);
QObject::connect(&singleInstance, &uwf::app::SecureSingleInstance::commitStageRequested, &w, [&](const std::uint64_t requestToken) {
w.requestFileStagingCommit(
[&singleInstance, requestToken](const uwf::ui::FileStagingBatchResult& result) { singleInstance.completeCommand(requestToken, result.command); });
});
singleInstance.enableCommandNotifications();
switch (options.mode) {
case uwf::app::StartupMode::Interactive:
w.show();
break;
case uwf::app::StartupMode::Quiet:
UWF_LOG_I("main") << "startup mode selected: mode=quiet presentation=system-tray";
w.startInTray();
break;
case uwf::app::StartupMode::CommitStage:
UWF_LOG_I("main") << "startup mode selected: mode=commit-stage presentation=system-tray";
w.startInTray();
QTimer::singleShot(0, &w, [&app, &w] {
w.requestFileStagingCommit([&app](const uwf::ui::FileStagingBatchResult& result) {
UWF_LOG_I("main") << "startup file staging command completed: outcome=" << static_cast<int>(result.command.outcome)
<< " committed=" << result.command.committedFiles << " failures=" << result.command.failedFiles;
app.exit(result.command.outcome == uwf::app::ApplicationCommandOutcome::Succeeded ? EXIT_SUCCESS : EXIT_FAILURE);
});
});
break;
case uwf::app::StartupMode::Service:
case uwf::app::StartupMode::InstallService:
case uwf::app::StartupMode::UninstallService:
throw std::logic_error("service startup mode reached the UI dispatcher");
}
return app.exec();
}
int runApplication(int argc, char* argv[], const uwf::app::StartupOptions& options) {
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
QApplication app(argc, argv);
app.setApplicationName("UWF Manager");
app.setOrganizationName("UWF");
app.setWindowIcon(QIcon(":/icons/app.svg"));
uwf::app::SecureSingleInstance singleInstance;
if (const auto forwardedExitCode = handleSingleInstanceStartup(singleInstance, options)) return *forwardedExitCode;
initializeUserInterface(app);
UWF_LOG_I("main") << "application started: pid=" << QCoreApplication::applicationPid();
const auto check = checkRuntimeEnvironment();
// WMI 运行时守卫覆盖完整 UI 事件循环。窗口及其控制器先销毁,随后守卫在
// 普通栈展开阶段主动释放本线程 WMI 代理与 COM apartment,不等待 TLS 清理。
uwf::initializeWmiRuntime();
const auto shutdownWmi = qScopeGuard([] { uwf::shutdownWmiRuntime(); });
// 兼容模式只表达“系统不在官方支持清单中”,不能替代实际能力探测。用户
// 仍可能自行安装 UWF 驱动与 provider,因此所有系统都以 Embedded namespace
// 和 UWF_Filter 的真实注册状态决定功能是否可用。
const auto uwfCapability = uwf::probeUwfCapability();
if (uwfCapability == uwf::UwfCapability::Unavailable) {
UWF_LOG_W("main") << "UWF unavailable: reason=filter-class-or-namespace-not-registered";
}
// 文件暂存注册表的排除关系属于启动维护,不属于 UI 刷新。这里只执行一次;
// 失败保留现有数据并记录,窗口随后仍可启动供用户检查和修复。
if (uwf::isElevated()) {
try {
uwf::app::registryFileStagingStore(uwf::embeddedWmiSession(), uwfCapability).reconcileDurability();
} catch (const std::exception& error) {
UWF_LOG_W("staging") << "file staging durability maintenance failed: error=" << error.what();
} catch (...) {
UWF_LOG_W("staging") << "file staging durability maintenance failed: error=non-standard-exception";
}
}
return runMainWindow(app, singleInstance, options, check, uwfCapability);
}
QStringList startupArguments(const int argc, char* argv[]) {
QStringList arguments;
arguments.reserve(argc);
for (int index = 0; index < argc; ++index) arguments.append(QString::fromLocal8Bit(argv[index]));
return arguments;
}
int runServiceControlCommand(int argc, char* argv[], const uwf::app::StartupMode mode) {
QCoreApplication app(argc, argv);
app.setApplicationName("UWF Manager");
(void)uwf::ui::I18n::instance();
uwf::initializeWmiRuntime();
const auto shutdownWmi = qScopeGuard([] { uwf::shutdownWmiRuntime(); });
const auto capability = uwf::probeUwfCapability();
uwf::service::WindowsEnhancedModeServiceControl serviceControl;
uwf::service::EnhancedModeManager manager(serviceControl, uwf::embeddedWmiSession(), capability);
uwf::service::EnhancedModeChangeResult result;
switch (mode) {
case uwf::app::StartupMode::InstallService:
result = manager.enable(uwf::ui::I18n::enhancedModeServiceDescription());
break;
case uwf::app::StartupMode::UninstallService:
result = manager.disable();
break;
case uwf::app::StartupMode::Interactive:
case uwf::app::StartupMode::Quiet:
case uwf::app::StartupMode::CommitStage:
case uwf::app::StartupMode::Service:
throw std::logic_error("non-control startup mode reached the service-control dispatcher");
}
if (!result.persistenceWarning.isEmpty()) {
UWF_LOG_W("service") << "enhanced mode changed with UWF persistence warning: error=" << result.persistenceWarning.toStdString();
}
const bool reachedTarget = mode == uwf::app::StartupMode::InstallService ? result.status.state == uwf::service::EnhancedModeState::Enabled
: result.status.state == uwf::service::EnhancedModeState::Disabled;
return reachedTarget ? EXIT_SUCCESS : EXIT_FAILURE;
}
} // namespace
int main(int argc, char* argv[]) {
try {
restrictDllSearchPath();
const auto options = uwf::app::parseStartupOptions(startupArguments(argc, argv));
switch (options.mode) {
case uwf::app::StartupMode::Service:
return uwf::service::runEnhancedModeService();
case uwf::app::StartupMode::InstallService:
case uwf::app::StartupMode::UninstallService:
return runServiceControlCommand(argc, argv, options.mode);
case uwf::app::StartupMode::Interactive:
case uwf::app::StartupMode::Quiet:
case uwf::app::StartupMode::CommitStage:
uwf::app::CrashHandler::install();
return runApplication(argc, argv, options);
}
throw std::logic_error("unknown startup mode");
} catch (const std::exception& error) {
UWF_LOG_E("main") << "fatal application error: error=" << error.what();
} catch (...) {
UWF_LOG_E("main") << "fatal application error: error=non-standard-exception";
}
return EXIT_FAILURE;
}