diff --git a/WeaselSetup/WeaselSetup.cpp b/WeaselSetup/WeaselSetup.cpp
index 259af11f7..e9a1e56e7 100644
--- a/WeaselSetup/WeaselSetup.cpp
+++ b/WeaselSetup/WeaselSetup.cpp
@@ -14,6 +14,8 @@
CAppModule _Module;
static int Run(LPTSTR lpCmdLine);
+static bool IsProcAdmin();
+static int RestartAsAdmin(LPTSTR lpCmdLine);
int WINAPI _tWinMain(HINSTANCE hInstance,
HINSTANCE /*hPrevInstance*/,
@@ -138,8 +140,12 @@ static int Run(LPTSTR lpCmdLine) {
constexpr bool silent = true;
constexpr bool old_ime_support = false;
bool uninstalling = !wcscmp(L"/u", lpCmdLine);
- if (uninstalling)
- return uninstall(silent);
+ if (uninstalling) {
+ if (IsProcAdmin())
+ return uninstall(silent);
+ else
+ return RestartAsAdmin(lpCmdLine);
+ }
if (!wcscmp(L"/ls", lpCmdLine)) {
return SetRegKeyValue(HKEY_CURRENT_USER, L"Software\\Rime\\weasel",
@@ -177,6 +183,11 @@ static int Run(LPTSTR lpCmdLine) {
return SetRegKeyValue(HKEY_CURRENT_USER, L"Software\\Rime\\weasel",
L"UpdateChannel", L"release", REG_SZ);
}
+
+ if (!IsProcAdmin()) {
+ return RestartAsAdmin(lpCmdLine);
+ }
+
bool hans = !wcscmp(L"/s", lpCmdLine);
if (hans)
return install(false, silent, old_ime_support);
@@ -186,3 +197,44 @@ static int Run(LPTSTR lpCmdLine) {
bool installing = !wcscmp(L"/i", lpCmdLine);
return CustomInstall(installing);
}
+
+// https://learn.microsoft.com/zh-cn/windows/win32/api/securitybaseapi/nf-securitybaseapi-checktokenmembership
+bool IsProcAdmin() {
+ BOOL b = FALSE;
+ SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY;
+ PSID AdministratorsGroup;
+ b = AllocateAndInitializeSid(&NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0,
+ &AdministratorsGroup);
+
+ if (b) {
+ if (!CheckTokenMembership(NULL, AdministratorsGroup, &b)) {
+ b = FALSE;
+ }
+ FreeSid(AdministratorsGroup);
+ }
+
+ return (b);
+}
+
+int RestartAsAdmin(LPTSTR lpCmdLine) {
+ SHELLEXECUTEINFO execInfo{0};
+ TCHAR path[MAX_PATH];
+ GetModuleFileName(GetModuleHandle(NULL), path, _countof(path));
+ execInfo.lpFile = path;
+ execInfo.lpParameters = lpCmdLine;
+ execInfo.lpVerb = _T("runas");
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.nShow = SW_SHOWNORMAL;
+ execInfo.fMask = SEE_MASK_NOASYNC | SEE_MASK_NOCLOSEPROCESS;
+ execInfo.hwnd = NULL;
+ execInfo.hProcess = NULL;
+ if (::ShellExecuteEx(&execInfo) && execInfo.hProcess != NULL) {
+ ::WaitForSingleObject(execInfo.hProcess, INFINITE);
+ DWORD dwExitCode = 0;
+ ::GetExitCodeProcess(execInfo.hProcess, &dwExitCode);
+ ::CloseHandle(execInfo.hProcess);
+ return dwExitCode;
+ }
+ return -1;
+}
diff --git a/WeaselSetup/WeaselSetup.vcxproj b/WeaselSetup/WeaselSetup.vcxproj
index 5a2c76763..fece78342 100644
--- a/WeaselSetup/WeaselSetup.vcxproj
+++ b/WeaselSetup/WeaselSetup.vcxproj
@@ -66,7 +66,7 @@
Windows
Imm32.lib;Kernel32.lib;%(AdditionalDependencies)
$(SolutionDir)output\$(ProjectName)$(TargetExt)
- RequireAdministrator
+ AsInvoker
UseLinkTimeCodeGeneration
@@ -108,7 +108,7 @@
true
Imm32.lib;Kernel32.lib;%(AdditionalDependencies)
$(SolutionDir)output\$(ProjectName)$(TargetExt)
- RequireAdministrator
+ AsInvoker
@@ -155,4 +155,4 @@
-
+
\ No newline at end of file
diff --git a/WeaselSetup/xmake.lua b/WeaselSetup/xmake.lua
index 49439e8bd..865392e46 100644
--- a/WeaselSetup/xmake.lua
+++ b/WeaselSetup/xmake.lua
@@ -4,7 +4,7 @@ target("WeaselSetup")
add_rules("add_rcfiles", "use_weaselconstants", "subwin")
add_links("imm32", "kernel32")
- set_policy("windows.manifest.uac", "admin")
+ set_policy("windows.manifest.uac", "invoker")
add_files("$(projectdir)/PerMonitorHighDPIAware.manifest")
add_ldflags("/DEBUG /OPT:REF /OPT:ICF /LARGEADDRESSAWARE /ERRORREPORT:QUEUE")