using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Security; namespace HotelPms.Share.Util { public class ServiceCore { #region DLLImport [DllImport("advapi32.dll")] public static extern IntPtr OpenSCManager(string lpMachineName, string lpSCDB, int scParameter); [DllImport("Advapi32.dll")] public static extern IntPtr CreateService(IntPtr SC_HANDLE, string lpSvcName, string lpDisplayName, int dwDesiredAccess, int dwServiceType, int dwStartType, int dwErrorControl, string lpPathName, string lpLoadOrderGroup, int lpdwTagId, string lpDependencies, string lpServiceStartName, string lpPassword); [DllImport("advapi32.dll")] public static extern void CloseServiceHandle(IntPtr SCHANDLE); [DllImport("advapi32.dll")] public static extern int StartService(IntPtr SVHANDLE, int dwNumServiceArgs, string lpServiceArgVectors); [DllImport("advapi32.dll", SetLastError = true)] public static extern IntPtr OpenService(IntPtr SCHANDLE, string lpSvcName, int dwNumServiceArgs); [DllImport("advapi32.dll")] public static extern int DeleteService(IntPtr SVHANDLE); [DllImport("kernel32.dll")] public static extern int GetLastError(); const int SERVICE_CONFIG_DESCRIPTION = 0x01; [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool ChangeServiceConfig2(IntPtr hService, int dwInfoLevel, [MarshalAs(UnmanagedType.Struct)] ref SERVICE_DESCRIPTION lpInfo); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct SERVICE_DESCRIPTION { public string lpDescription; } #endregion DLLImport #region Constants declaration. private const int SC_MANAGER_CREATE_SERVICE = 0x0002; private const int SERVICE_WIN32_OWN_PROCESS = 0x00000010; //int SERVICE_DEMAND_START = 0x00000003; private const int SERVICE_ERROR_NORMAL = 0x00000001; private const int STANDARD_RIGHTS_REQUIRED = 0xF0000; private const int SERVICE_QUERY_CONFIG = 0x0001; private const int SERVICE_CHANGE_CONFIG = 0x0002; private const int SERVICE_QUERY_STATUS = 0x0004; private const int SERVICE_ENUMERATE_DEPENDENTS = 0x0008; private const int SERVICE_START = 0x0010; private const int SERVICE_STOP = 0x0020; private const int SERVICE_PAUSE_CONTINUE = 0x0040; private const int SERVICE_INTERROGATE = 0x0080; private const int SERVICE_USER_DEFINED_CONTROL = 0x0100; private const int SERVICE_ALL_ACCESS = (STANDARD_RIGHTS_REQUIRED | SERVICE_QUERY_CONFIG | SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_ENUMERATE_DEPENDENTS | SERVICE_START | SERVICE_STOP | SERVICE_PAUSE_CONTINUE | SERVICE_INTERROGATE | SERVICE_USER_DEFINED_CONTROL); private const int SERVICE_AUTO_START = 0x00000002; #endregion Constants declaration. /// /// 安装和运行 /// /// 程序路径. /// 服务名 /// 服务显示名称. /// 服务安装是否成功. public static bool Install(string svcPath, string svcName, string svcDispName, string description) { try { IntPtr sc_handle = OpenSCManager(null, null, SC_MANAGER_CREATE_SERVICE); if (sc_handle != IntPtr.Zero) { IntPtr sv_handle = CreateService(sc_handle, svcName, svcDispName, SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, svcPath, null, 0, null, null, null); if (sv_handle == IntPtr.Zero) { CloseServiceHandle(sc_handle); return false; } else { var pinfo = new SERVICE_DESCRIPTION { lpDescription = description }; ChangeServiceConfig2(sv_handle, SERVICE_CONFIG_DESCRIPTION, ref pinfo); //试尝启动服务 int i = StartService(sv_handle, 0, null); if (i == 0) { return false; } CloseServiceHandle(sc_handle); return true; } } else return false; } catch { return false; } } /// /// 反安装服务. /// /// 服务名. public static bool UnInstall(string svcName) { IntPtr sc_hndl = IntPtr.Zero; int GENERIC_WRITE = 0x40000000; try { sc_hndl = OpenSCManager(null, null, GENERIC_WRITE); if (sc_hndl != IntPtr.Zero) { int DELETE = 0x10000; IntPtr svc_hndl = OpenService(sc_hndl, svcName, DELETE); if (svc_hndl != IntPtr.Zero) { return DeleteService(svc_hndl) != 0; } else return false; } else return false; } catch { return false; } finally { if (sc_hndl != IntPtr.Zero) { CloseServiceHandle(sc_hndl); } } } #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; // obtain the currently active session id; every logged on user in the system has a unique session id 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) { PROCESS_INFORMATION procInfo; return StartProcessAndBypassUAC(applicationName, string.Empty, out procInfo); } /// /// Launches the given application with full admin rights, and in addition bypasses the Vista UAC prompt /// /// The name of the application to launch /// Process information regarding the launched application that gets returned to the caller /// 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(); // obtain the currently active session id; every logged on user in the system has a unique session id uint dwSessionId = WTSGetActiveConsoleSessionId(); // obtain the process id of the winlogon process that is running within the currently active session Process[] processes = Process.GetProcessesByName("winlogon"); foreach (Process p in processes) { if ((uint)p.SessionId == dwSessionId) { winlogonPid = (uint)p.Id; } } // obtain a handle to the winlogon process hProcess = OpenProcess(MAXIMUM_ALLOWED, false, winlogonPid); // obtain a handle to the access token of the winlogon process if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, ref hPToken)) { CloseHandle(hProcess); return false; } // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser // I would prefer to not have to use a security attribute variable and to just // simply pass null and inherit (by default) the security attributes // of the existing token. However, in C# structures are value types and therefore // cannot be assigned the null value. SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES(); sa.Length = Marshal.SizeOf(sa); // copy the access token of the winlogon process; the newly created token will be a primary token if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup)) { CloseHandle(hProcess); CloseHandle(hPToken); return false; } // By default CreateProcessAsUser creates a process on a non-interactive window station, meaning // the window station has a desktop that is invisible and the process is incapable of receiving // user input. To remedy this we set the lpDesktop parameter to indicate we want to enable user // interaction with the new process. STARTUPINFO si = new STARTUPINFO(); si.cb = (int)Marshal.SizeOf(si); si.lpDesktop = @"winsta0\default"; // interactive window station parameter; basically this indicates that the process created can display a GUI on the desktop // flags that specify the priority and creation method of the process int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE; // create a new process in the current user's logon session bool result = CreateProcessAsUser(hUserTokenDup, // client's access token applicationName, // file to execute command, // command line ref sa, // pointer to process SECURITY_ATTRIBUTES ref sa, // pointer to thread SECURITY_ATTRIBUTES false, // handles are not inheritable dwCreationFlags, // creation flags IntPtr.Zero, // pointer to new environment block null, // name of current directory ref si, // pointer to STARTUPINFO structure out procInfo // receives information about new process ); // invalidate the handles CloseHandle(hProcess); CloseHandle(hPToken); CloseHandle(hUserTokenDup); return result; // return the result } } }