From 329e9bd9337c715b07d6c46c8d4aacb999d31cb4 Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Thu, 30 Apr 2026 22:49:05 +0800
Subject: [PATCH] =?UTF-8?q?improve:UIA=E7=BD=AE=E9=A1=B6?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Ink Canvas/Helpers/UIAccessHelper.cs | 557 ++++++++++++++++++
.../Helpers/WindowSettingsHelper.cs | 32 +-
2 files changed, 577 insertions(+), 12 deletions(-)
create mode 100644 Ink Canvas/Helpers/UIAccessHelper.cs
diff --git a/Ink Canvas/Helpers/UIAccessHelper.cs b/Ink Canvas/Helpers/UIAccessHelper.cs
new file mode 100644
index 00000000..cc0335d1
--- /dev/null
+++ b/Ink Canvas/Helpers/UIAccessHelper.cs
@@ -0,0 +1,557 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+using System.Text;
+
+namespace Ink_Canvas.Helpers
+{
+ ///
+ /// 通过 Winlogon 令牌模拟实现 UIAccess 提权重启。
+ /// 1. 找到当前会话中 winlogon.exe 的令牌,复制为模拟令牌;
+ /// 2. SetThreadToken 暂时模拟 winlogon(拥有 TCB 权限);
+ /// 3. 在自身令牌副本上 SetTokenInformation(TokenUIAccess, TRUE);
+ /// 4. RevertToSelf 后用 CreateProcessWithTokenW 启动新进程;
+ /// 5. 新进程具有 UIAccess 权限,可置顶于 UAC 提示之上。
+ ///
+ public static class UIAccessHelper
+ {
+ #region Constants
+
+ private const uint TOKEN_QUERY = 0x0008;
+ private const uint TOKEN_DUPLICATE = 0x0002;
+ private const uint TOKEN_IMPERSONATE = 0x0004;
+ private const uint TOKEN_ASSIGN_PRIMARY = 0x0001;
+ private const uint TOKEN_ADJUST_DEFAULT = 0x0080;
+ private const uint TOKEN_ADJUST_SESSIONID = 0x0100;
+ private const uint TOKEN_ADJUST_PRIVILEGES = 0x0020;
+
+ private const int SecurityAnonymous = 0;
+ private const int SecurityImpersonation = 2;
+ private const int TokenPrimary = 1;
+ private const int TokenImpersonation = 2;
+
+ // TOKEN_INFORMATION_CLASS
+ private const int TokenSessionId = 12;
+ private const int TokenUIAccess = 26;
+
+ private const uint PROCESS_QUERY_LIMITED_INFORMATION = 0x1000;
+ private const uint TH32CS_SNAPPROCESS = 0x00000002;
+
+ private const uint LOGON_WITH_PROFILE = 0x00000001;
+ private const uint CREATE_NEW_CONSOLE = 0x00000010;
+ private const uint CREATE_UNICODE_ENVIRONMENT = 0x00000400;
+
+ private const uint SE_PRIVILEGE_ENABLED = 0x00000002;
+ private const string SE_ASSIGNPRIMARYTOKEN_NAME = "SeAssignPrimaryTokenPrivilege";
+
+ private static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
+
+ #endregion
+
+ #region Structs
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct LUID
+ {
+ public uint LowPart;
+ public int HighPart;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct LUID_AND_ATTRIBUTES
+ {
+ public LUID Luid;
+ public uint Attributes;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct TOKEN_PRIVILEGES
+ {
+ public uint PrivilegeCount;
+ public LUID_AND_ATTRIBUTES Privilege;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ private struct PROCESSENTRY32W
+ {
+ public uint dwSize;
+ public uint cntUsage;
+ public uint th32ProcessID;
+ public IntPtr th32DefaultHeapID;
+ public uint th32ModuleID;
+ public uint cntThreads;
+ public uint th32ParentProcessID;
+ public int pcPriClassBase;
+ public uint dwFlags;
+ [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
+ public string szExeFile;
+ }
+
+ [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
+ private struct STARTUPINFOW
+ {
+ public uint cb;
+ public IntPtr lpReserved;
+ public IntPtr lpDesktop;
+ public IntPtr lpTitle;
+ public uint dwX, dwY, dwXSize, dwYSize;
+ public uint dwXCountChars, dwYCountChars;
+ public uint dwFillAttribute;
+ public uint dwFlags;
+ public ushort wShowWindow;
+ public ushort cbReserved2;
+ public IntPtr lpReserved2;
+ public IntPtr hStdInput, hStdOutput, hStdError;
+ }
+
+ [StructLayout(LayoutKind.Sequential)]
+ private struct PROCESS_INFORMATION
+ {
+ public IntPtr hProcess;
+ public IntPtr hThread;
+ public uint dwProcessId;
+ public uint dwThreadId;
+ }
+
+ #endregion
+
+ #region P/Invoke
+
+ [DllImport("kernel32.dll")]
+ private static extern IntPtr GetCurrentProcess();
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CloseHandle(IntPtr hObject);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool OpenProcessToken(IntPtr ProcessHandle, uint DesiredAccess, out IntPtr TokenHandle);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool DuplicateTokenEx(
+ IntPtr hExistingToken,
+ uint dwDesiredAccess,
+ IntPtr lpTokenAttributes,
+ int ImpersonationLevel,
+ int TokenType,
+ out IntPtr phNewToken);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool GetTokenInformation(
+ IntPtr TokenHandle,
+ int TokenInformationClass,
+ IntPtr TokenInformation,
+ uint TokenInformationLength,
+ out uint ReturnLength);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool SetTokenInformation(
+ IntPtr TokenHandle,
+ int TokenInformationClass,
+ IntPtr TokenInformation,
+ uint TokenInformationLength);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool SetThreadToken(IntPtr Thread, IntPtr Token);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool RevertToSelf();
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr CreateToolhelp32Snapshot(uint dwFlags, uint th32ProcessID);
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool Process32FirstW(IntPtr hSnapshot, ref PROCESSENTRY32W lppe);
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool Process32NextW(IntPtr hSnapshot, ref PROCESSENTRY32W lppe);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool LookupPrivilegeValueW(string lpSystemName, string lpName, out LUID lpLuid);
+
+ [DllImport("advapi32.dll", SetLastError = true)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool AdjustTokenPrivileges(
+ IntPtr TokenHandle,
+ [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges,
+ ref TOKEN_PRIVILEGES NewState,
+ uint BufferLength,
+ IntPtr PreviousState,
+ IntPtr ReturnLength);
+
+ [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ [return: MarshalAs(UnmanagedType.Bool)]
+ private static extern bool CreateProcessWithTokenW(
+ IntPtr hToken,
+ uint dwLogonFlags,
+ string lpApplicationName,
+ StringBuilder lpCommandLine,
+ uint dwCreationFlags,
+ IntPtr lpEnvironment,
+ string lpCurrentDirectory,
+ ref STARTUPINFOW lpStartupInfo,
+ out PROCESS_INFORMATION lpProcessInformation);
+
+ [DllImport("kernel32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
+ private static extern void GetStartupInfoW(ref STARTUPINFOW lpStartupInfo);
+
+ #endregion
+
+ #region Public API
+
+ ///
+ /// 检查当前进程是否已具有 UIAccess 标志。
+ ///
+ public static bool HasUIAccess()
+ {
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out IntPtr hToken))
+ return false;
+
+ try
+ {
+ IntPtr buf = Marshal.AllocHGlobal(sizeof(uint));
+ try
+ {
+ Marshal.WriteInt32(buf, 0);
+ if (!GetTokenInformation(hToken, TokenUIAccess, buf, sizeof(uint), out _))
+ return false;
+ return Marshal.ReadInt32(buf) != 0;
+ }
+ finally
+ {
+ Marshal.FreeHGlobal(buf);
+ }
+ }
+ finally
+ {
+ CloseHandle(hToken);
+ }
+ }
+
+ ///
+ /// 以 UIAccess 令牌重启自身。当前进程必须已经以管理员身份运行。
+ /// 成功时新进程已启动,调用方应立即退出当前进程。
+ ///
+ /// 追加到新进程的额外命令行参数(例如 --skip-mutex-check)。
+ public static bool RestartWithUIAccess(string extraArgs = null)
+ {
+ try
+ {
+ if (HasUIAccess())
+ {
+ LogHelper.WriteLogToFile("UIAccess | 当前进程已具有 UIAccess,跳过重启");
+ return true;
+ }
+
+ if (!CreateUIAccessToken(out IntPtr uiaToken))
+ {
+ LogHelper.WriteLogToFile($"UIAccess | 创建 UIAccess 令牌失败 (LastError={Marshal.GetLastWin32Error()})", LogHelper.LogType.Error);
+ return false;
+ }
+
+ try
+ {
+ return LaunchWithToken(uiaToken, extraArgs);
+ }
+ finally
+ {
+ CloseHandle(uiaToken);
+ }
+ }
+ catch (Exception ex)
+ {
+ LogHelper.WriteLogToFile($"UIAccess | RestartWithUIAccess 异常: {ex}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+
+ #endregion
+
+ #region Token Manipulation
+
+ private static bool CreateUIAccessToken(out IntPtr uiaToken)
+ {
+ uiaToken = IntPtr.Zero;
+
+ // 1. 获取当前进程的 session id
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, out IntPtr hSelfQuery))
+ {
+ LogHelper.WriteLogToFile($"UIAccess | OpenProcessToken(query) 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Error);
+ return false;
+ }
+
+ uint sessionId;
+ try
+ {
+ IntPtr sesBuf = Marshal.AllocHGlobal(sizeof(uint));
+ try
+ {
+ if (!GetTokenInformation(hSelfQuery, TokenSessionId, sesBuf, sizeof(uint), out _))
+ {
+ LogHelper.WriteLogToFile($"UIAccess | GetTokenInformation(SessionId) 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Error);
+ return false;
+ }
+ sessionId = (uint)Marshal.ReadInt32(sesBuf);
+ }
+ finally { Marshal.FreeHGlobal(sesBuf); }
+ }
+ finally { CloseHandle(hSelfQuery); }
+
+ // 2. 找到同一会话的 winlogon 模拟令牌
+ if (!GetWinlogonImpersonationToken(sessionId, out IntPtr winlogonToken))
+ {
+ LogHelper.WriteLogToFile("UIAccess | 未能获取 winlogon 模拟令牌(需要管理员权限)", LogHelper.LogType.Error);
+ return false;
+ }
+
+ try
+ {
+ // 3. 模拟 winlogon
+ if (!SetThreadToken(IntPtr.Zero, winlogonToken))
+ {
+ LogHelper.WriteLogToFile($"UIAccess | SetThreadToken(winlogon) 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Error);
+ return false;
+ }
+
+ try
+ {
+ // 4. 复制自身令牌为主令牌
+ if (!OpenProcessToken(GetCurrentProcess(), TOKEN_DUPLICATE, out IntPtr hSelfDup))
+ {
+ LogHelper.WriteLogToFile($"UIAccess | OpenProcessToken(dup) 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Error);
+ return false;
+ }
+
+ IntPtr dupToken;
+ try
+ {
+ bool ok = DuplicateTokenEx(
+ hSelfDup,
+ TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_QUERY | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID,
+ IntPtr.Zero,
+ SecurityAnonymous,
+ TokenPrimary,
+ out dupToken);
+
+ if (!ok)
+ {
+ LogHelper.WriteLogToFile($"UIAccess | DuplicateTokenEx 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Error);
+ return false;
+ }
+ }
+ finally { CloseHandle(hSelfDup); }
+
+ // 5. 在副本上设置 UIAccess = TRUE
+ IntPtr uiBuf = Marshal.AllocHGlobal(sizeof(uint));
+ try
+ {
+ Marshal.WriteInt32(uiBuf, 1);
+ if (!SetTokenInformation(dupToken, TokenUIAccess, uiBuf, sizeof(uint)))
+ {
+ int err = Marshal.GetLastWin32Error();
+ LogHelper.WriteLogToFile($"UIAccess | SetTokenInformation(UIAccess) 失败: {err}", LogHelper.LogType.Error);
+ CloseHandle(dupToken);
+ return false;
+ }
+ }
+ finally { Marshal.FreeHGlobal(uiBuf); }
+
+ uiaToken = dupToken;
+ return true;
+ }
+ finally
+ {
+ RevertToSelf();
+ }
+ }
+ finally
+ {
+ CloseHandle(winlogonToken);
+ }
+ }
+
+ private static bool GetWinlogonImpersonationToken(uint sessionId, out IntPtr winlogonToken)
+ {
+ winlogonToken = IntPtr.Zero;
+
+ IntPtr snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (snapshot == INVALID_HANDLE_VALUE || snapshot == IntPtr.Zero)
+ {
+ LogHelper.WriteLogToFile($"UIAccess | CreateToolhelp32Snapshot 失败: {Marshal.GetLastWin32Error()}", LogHelper.LogType.Error);
+ return false;
+ }
+
+ try
+ {
+ var pe = new PROCESSENTRY32W { dwSize = (uint)Marshal.SizeOf(typeof(PROCESSENTRY32W)) };
+ bool more = Process32FirstW(snapshot, ref pe);
+
+ while (more)
+ {
+ if (string.Equals(pe.szExeFile, "winlogon.exe", StringComparison.OrdinalIgnoreCase))
+ {
+ if (TryDuplicateWinlogonToken(pe.th32ProcessID, sessionId, out winlogonToken))
+ return true;
+ }
+ more = Process32NextW(snapshot, ref pe);
+ }
+ }
+ finally { CloseHandle(snapshot); }
+
+ return false;
+ }
+
+ private static bool TryDuplicateWinlogonToken(uint pid, uint sessionId, out IntPtr dupToken)
+ {
+ dupToken = IntPtr.Zero;
+
+ IntPtr hProc = OpenProcess(PROCESS_QUERY_LIMITED_INFORMATION, false, pid);
+ if (hProc == IntPtr.Zero) return false;
+
+ try
+ {
+ if (!OpenProcessToken(hProc, TOKEN_QUERY | TOKEN_DUPLICATE, out IntPtr hToken))
+ return false;
+
+ try
+ {
+ // 检查 session id 匹配
+ IntPtr sesBuf = Marshal.AllocHGlobal(sizeof(uint));
+ try
+ {
+ if (!GetTokenInformation(hToken, TokenSessionId, sesBuf, sizeof(uint), out _))
+ return false;
+ if ((uint)Marshal.ReadInt32(sesBuf) != sessionId)
+ return false;
+ }
+ finally { Marshal.FreeHGlobal(sesBuf); }
+
+ if (!DuplicateTokenEx(
+ hToken,
+ TOKEN_IMPERSONATE | TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE,
+ IntPtr.Zero,
+ SecurityImpersonation,
+ TokenImpersonation,
+ out dupToken))
+ {
+ return false;
+ }
+
+ // 启用 SeAssignPrimaryTokenPrivilege(Inkeys 行为)
+ var tkp = new TOKEN_PRIVILEGES
+ {
+ PrivilegeCount = 1,
+ Privilege = new LUID_AND_ATTRIBUTES { Attributes = SE_PRIVILEGE_ENABLED }
+ };
+ if (LookupPrivilegeValueW(null, SE_ASSIGNPRIMARYTOKEN_NAME, out tkp.Privilege.Luid))
+ {
+ AdjustTokenPrivileges(dupToken, false, ref tkp, (uint)Marshal.SizeOf(tkp), IntPtr.Zero, IntPtr.Zero);
+ }
+
+ return true;
+ }
+ finally { CloseHandle(hToken); }
+ }
+ finally { CloseHandle(hProc); }
+ }
+
+ #endregion
+
+ #region Process Launch
+
+ private static bool LaunchWithToken(IntPtr token, string extraArgs)
+ {
+ string exePath = Process.GetCurrentProcess().MainModule.FileName;
+ string workDir = System.IO.Path.GetDirectoryName(exePath);
+
+ // 重建命令行:保留原始参数,追加 --skip-mutex-check 防止单实例阻塞
+ var cmdBuilder = new StringBuilder(32768);
+ cmdBuilder.Append('"').Append(exePath).Append('"');
+
+ string[] args = Environment.GetCommandLineArgs();
+ for (int i = 1; i < args.Length; i++)
+ {
+ cmdBuilder.Append(' ');
+ AppendQuoted(cmdBuilder, args[i]);
+ }
+
+ if (!string.IsNullOrEmpty(extraArgs))
+ cmdBuilder.Append(' ').Append(extraArgs);
+
+ // 防止单实例 Mutex 阻塞新进程
+ if (Array.IndexOf(args, "--skip-mutex-check") < 0
+ && (extraArgs == null || extraArgs.IndexOf("--skip-mutex-check", StringComparison.Ordinal) < 0))
+ {
+ cmdBuilder.Append(" --skip-mutex-check");
+ }
+
+ var si = new STARTUPINFOW { cb = (uint)Marshal.SizeOf(typeof(STARTUPINFOW)) };
+ GetStartupInfoW(ref si);
+
+ bool ok = CreateProcessWithTokenW(
+ token,
+ LOGON_WITH_PROFILE,
+ null,
+ cmdBuilder,
+ CREATE_UNICODE_ENVIRONMENT,
+ IntPtr.Zero,
+ workDir,
+ ref si,
+ out PROCESS_INFORMATION pi);
+
+ if (!ok)
+ {
+ int err = Marshal.GetLastWin32Error();
+ LogHelper.WriteLogToFile($"UIAccess | CreateProcessWithTokenW 失败: {err}", LogHelper.LogType.Error);
+ return false;
+ }
+
+ CloseHandle(pi.hProcess);
+ CloseHandle(pi.hThread);
+ LogHelper.WriteLogToFile($"UIAccess | 已使用 UIAccess 令牌启动新进程 (PID={pi.dwProcessId})");
+ return true;
+ }
+
+ private static void AppendQuoted(StringBuilder sb, string arg)
+ {
+ if (arg == null) { sb.Append("\"\""); return; }
+
+ bool needQuote = arg.Length == 0 || arg.IndexOfAny(new[] { ' ', '\t', '"' }) >= 0;
+ if (!needQuote) { sb.Append(arg); return; }
+
+ sb.Append('"');
+ int backslashes = 0;
+ foreach (char c in arg)
+ {
+ if (c == '\\') { backslashes++; continue; }
+ if (c == '"')
+ {
+ sb.Append('\\', backslashes * 2 + 1);
+ sb.Append('"');
+ }
+ else
+ {
+ sb.Append('\\', backslashes);
+ sb.Append(c);
+ }
+ backslashes = 0;
+ }
+ sb.Append('\\', backslashes * 2);
+ sb.Append('"');
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/Ink Canvas/Windows/SettingsViews/Helpers/WindowSettingsHelper.cs b/Ink Canvas/Windows/SettingsViews/Helpers/WindowSettingsHelper.cs
index ca915e7b..a99d21ab 100644
--- a/Ink Canvas/Windows/SettingsViews/Helpers/WindowSettingsHelper.cs
+++ b/Ink Canvas/Windows/SettingsViews/Helpers/WindowSettingsHelper.cs
@@ -36,12 +36,6 @@ namespace Ink_Canvas.Windows.SettingsViews.Helpers
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
- [DllImport("UIAccessDLL_x86.dll", EntryPoint = "PrepareUIAccess", CallingConvention = CallingConvention.Cdecl)]
- private static extern Int32 PrepareUIAccessX86();
-
- [DllImport("UIAccessDLL_x64.dll", EntryPoint = "PrepareUIAccess", CallingConvention = CallingConvention.Cdecl)]
- private static extern Int32 PrepareUIAccessX64();
-
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
@@ -300,6 +294,14 @@ namespace Ink_Canvas.Windows.SettingsViews.Helpers
{
try
{
+ // 已具有 UIAccess 时无需重启
+ if (UIAccessHelper.HasUIAccess())
+ {
+ LogHelper.WriteLogToFile("UIAccess | 当前进程已具有 UIAccess 权限");
+ App.IsUIAccessTopMostEnabled = true;
+ return;
+ }
+
OnStopKillProcessTimer?.Invoke();
if (App.watchdogProcess != null && !App.watchdogProcess.HasExited)
@@ -308,18 +310,24 @@ namespace Ink_Canvas.Windows.SettingsViews.Helpers
App.watchdogProcess = null;
}
- App.StartWatchdogIfNeeded();
+ // 使用 Inkeys 方式:通过 winlogon 模拟令牌为自身令牌设置 UIAccess 标志后重启
+ App.IsUIAccessTopMostEnabled = true;
+ App.IsAppExitByUser = true;
+ (Application.Current as App)?.ReleaseMutexForRestart();
- if (Environment.Is64BitProcess)
+ bool started = UIAccessHelper.RestartWithUIAccess();
+ if (started)
{
- PrepareUIAccessX64();
+ Application.Current.Shutdown();
}
else
{
- PrepareUIAccessX86();
+ LogHelper.WriteLogToFile("UIAccess | 启动失败,回退到普通管理员模式", LogHelper.LogType.Warning);
+ App.IsUIAccessTopMostEnabled = false;
+ App.IsAppExitByUser = false;
+ App.StartWatchdogIfNeeded();
+ OnStartKillProcessTimer?.Invoke();
}
-
- OnStartKillProcessTimer?.Invoke();
}
catch (Exception ex)
{