C# 通过服务守护前台带有界面的应用程序
如果直接在服务中执行带有UI的应用将会把应用归为后台应用,无法看到UI的,以下方法可以有效解决看不到UI的问题.
private void StartService(string appName) { try { string watchexepath = toWatchServicePath; string serviceName = toWatchServicePath + "\\" + appName+".exe"; UserProcess.PROCESS_INFORMATION processInfo; UserProcess.StartProcessAndBypassUAC(serviceName, "", out processInfo); LogHelper.WriteLog("已重启", serviceName); } catch (Exception ex) { LogHelper.WriteLog("启动时错误", ex.Message); } }
UserProcess类如下:
class UserProcess { #region Structures [StructLayout(LayoutKind.Sequential)] public struct SECURITY_ATTRIBUTES { public int Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } [StructLayout(LayoutKind.Sequential)] public struct STARTUPINFO { public int cb; public String lpReserved; public String lpDesktop; public String lpTitle; public uint dwX; public uint dwY; public uint dwXSize; public uint dwYSize; public uint dwXCountChars; public uint dwYCountChars; public uint dwFillAttribute; public uint dwFlags; public short wShowWindow; public short cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential)] public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public uint dwProcessId; public uint dwThreadId; } #endregion #region Enumerations enum TOKEN_TYPE : int { TokenPrimary = 1, TokenImpersonation = 2 } enum SECURITY_IMPERSONATION_LEVEL : int { SecurityAnonymous = 0, SecurityIdentification = 1, SecurityImpersonation = 2, SecurityDelegation = 3, } enum WTSInfoClass { InitialProgram, ApplicationName, WorkingDirectory, OEMId, SessionId, UserName, WinStationName, DomainName, ConnectState, ClientBuildNumber, ClientName, ClientDirectory, ClientProductId, ClientHardwareId, ClientAddress, ClientDisplay, ClientProtocolType } #endregion #region Constants public const int TOKEN_DUPLICATE = 0x0002; public const uint MAXIMUM_ALLOWED = 0x2000000; public const int CREATE_NEW_CONSOLE = 0x00000010; public const int IDLE_PRIORITY_CLASS = 0x40; public const int NORMAL_PRIORITY_CLASS = 0x20; public const int HIGH_PRIORITY_CLASS = 0x80; public const int REALTIME_PRIORITY_CLASS = 0x100; #endregion #region Win32 API Imports [DllImport("kernel32.dll", SetLastError = true)] private static extern bool CloseHandle(IntPtr hSnapshot); [DllImport("kernel32.dll")] static extern uint WTSGetActiveConsoleSessionId(); [DllImport("wtsapi32.dll", CharSet = CharSet.Unicode, SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] static extern bool WTSQuerySessionInformation(System.IntPtr hServer, int sessionId, WTSInfoClass wtsInfoClass, out System.IntPtr ppBuffer, out uint pBytesReturned); [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)] public extern static bool CreateProcessAsUser(IntPtr hToken, String lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll")] static extern bool ProcessIdToSessionId(uint dwProcessId, ref uint pSessionId); [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")] public extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle); [DllImport("kernel32.dll")] static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId); [DllImport("advapi32", SetLastError = true), SuppressUnmanagedCodeSecurityAttribute] static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, ref IntPtr TokenHandle); #endregion public static string GetCurrentActiveUser() { IntPtr hServer = IntPtr.Zero, state = IntPtr.Zero; uint bCount = 0; uint dwSessionId = WTSGetActiveConsoleSessionId(); string domain = string.Empty, userName = string.Empty; if (WTSQuerySessionInformation(hServer, (int)dwSessionId, WTSInfoClass.DomainName, out state, out bCount)) { domain = Marshal.PtrToStringAuto(state); } if (WTSQuerySessionInformation(hServer, (int)dwSessionId, WTSInfoClass.UserName, out state, out bCount)) { userName = Marshal.PtrToStringAuto(state); } return string.Format("{0}\\{1}", domain, userName); } public static bool StartProcessAndBypassUAC(String applicationName, String command, out PROCESS_INFORMATION procInfo) { uint winlogonPid = 0; IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero; procInfo = new PROCESS_INFORMATION(); uint dwSessionId = WTSGetActiveConsoleSessionId(); Process[] processes = Process.GetProcessesByName("winlogon"); foreach (Process p in processes) { if ((uint)p.SessionId == dwSessionId) { winlogonPid = (uint)p.Id; } } hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) { CloseHandle(hProcess); return false; } SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.Length = Marshal.SizeOf(sa); if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) { CloseHandle(hProcess); CloseHandle(hPToken); return false; } STARTUPINFO si = new STARTUPINFO(); si.cb = (int)Marshal.SizeOf(si); si.lpDesktop = @"winsta0\default"; int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; bool result = CreateProcessAsUser(hUserTokenDup, applicationName, command, ref sa, ref sa, false, dwCreationFlags, IntPtr.Zero, null, ref si, out procInfo ); CloseHandle(hProcess); CloseHandle(hPToken); CloseHandle(hUserTokenDup); return result; } }