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")