vs自帶的有本地服務項目,創建即可。這些不多說了,好多博客都有,我只說幾點注意的點:
1、
選localsystem,選localservice不行,不知道爲啥
2、對於我的功能是要監控主程序是否運行,沒運行的,我需要把主程序啓動,這個是比較麻煩的,因爲服務是不能啓動exe的,具體原因好像是本地服務和winform程序不在同一消息隊列還是什麼的具體忘了,後來也是查了半天找到的方法。
public class SoftStart { public static void Start(string commandLine, bool showWindow) { IntPtr hToken; IntPtr hTokenDup; const int TOKEN_ALL_ACCESS = 268435456; const int TokenSessionId = 12; const uint CREATE_PROCESS_FLAGS = 0x00000020 | 0x00000010 | 0x400; if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, out hToken)) { //throw new Win32Exception(Marshal.GetLastWin32Error()); } var sa = new SECURITY_ATTRIBUTES(); sa.bInheritHandle = true; sa.Length = Marshal.SizeOf(sa); if (!DuplicateTokenEx(hToken, 268435456, ref sa, 1, 1, out hTokenDup)) { var error = Marshal.GetLastWin32Error(); CloseHandle(hToken); //throw new Win32Exception(error); } var si = new STARTUPINFO(); si.cb = Marshal.SizeOf(si); si.lpDesktop = "WinSta0\\Default"; if (!showWindow) { si.dwFlags = 1;//STARTF si.wShowWindow = 0; } IntPtr pEnv; var dwSessionId = WTSGetActiveConsoleSessionId(); if (!SetTokenInformation(hTokenDup, TokenSessionId, out dwSessionId, sizeof(uint))) { var error = Marshal.GetLastWin32Error(); CloseHandle(hToken); CloseHandle(hTokenDup); //throw new Win32Exception(error); } if (!CreateEnvironmentBlock(out pEnv, hTokenDup, 0)) { var error = Marshal.GetLastWin32Error(); CloseHandle(hToken); CloseHandle(hTokenDup); //throw new Win32Exception(error); } PROCESS_INFORMATION pro; if (!CreateProcessAsUser(hTokenDup, null, commandLine, ref sa, ref sa, true, CREATE_PROCESS_FLAGS, pEnv, null, ref si, out pro)) { var error = Marshal.GetLastWin32Error(); CloseHandle(hToken); CloseHandle(hTokenDup); //throw new Win32Exception(error); } if (pEnv != IntPtr.Zero) { DestroyEnvironmentBlock(pEnv); } CloseHandle(hToken); CloseHandle(hTokenDup); } [DllImport("advapi32.dll", SetLastError = true)] public static extern bool SetTokenInformation(IntPtr TokenHandle, int TokenInformationClass, out IntPtr TokenInformation, int TokenInformationLength); [DllImport("advapi32.dll", SetLastError = true)] public static extern bool OpenProcessToken(IntPtr ProcessHandle, int DesiredAccess, out IntPtr TokenHandle); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr GetCurrentProcess(); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr WTSGetActiveConsoleSessionId(); [DllImport("Userenv.dll", SetLastError = true)] public static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment); [DllImport("Userenv.dll", SetLastError = true)] public static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, int bInherit); [DllImport("advapi32.dll", SetLastError = true)] public static extern bool DuplicateTokenEx(IntPtr hExistingToken, int dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int ImpersonationLevel, int dwTokenType, out IntPtr phNewToken); [DllImport("advapi32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Ansi, SetLastError = true)] public static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, uint dwCreationFlags, IntPtr lpEnvrionment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("kernel32.dll", CallingConvention = CallingConvention.StdCall, CharSet = CharSet.Auto, SetLastError = true)] public static extern bool CloseHandle(IntPtr handle); public struct SECURITY_ATTRIBUTES { public int Length; public IntPtr lpSecurityDescriptor; public bool bInheritHandle; } 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; } public struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessID; public int dwThreadID; } }
調用:SoftStart.Start(path,true);path是你要啓動的exe地址,true是要顯示ui。
具體項目源碼:https://files.cnblogs.com/files/dachuang/WindowsServiceTest.zip?t=1658840431,用的是vs2019.
製作完本地服務項目後,需要在主程序安裝和啓動此服務,代碼如下:
//調用安裝並啓動本地服務 LocalServiceMgr lsm = new LocalServiceMgr(); lsm.CheckService("eams-protect");//服務名 public class LocalServiceMgr { public void CheckService(string serviceName) { ServiceController[] services = ServiceController.GetServices(); foreach (ServiceController s in services) { if (s.ServiceName == serviceName) { if (s.Status == ServiceControllerStatus.Running || s.Status == ServiceControllerStatus.StartPending) return; else { s.Start(); return; } } } Start(); } /// <summary> /// 安裝並啓動本地守護服務 /// </summary> /// <returns></returns> public bool Start() { Common.LogHelper.getLogHelper().WriteLog("開始安裝開啓服務"); try { //創建啓動對象 ProcessStartInfo startInfo = new ProcessStartInfo(); startInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory+ "LocalService\\"; startInfo.UseShellExecute = false; startInfo.CreateNoWindow = true; startInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "LocalService\\Install.bat"; //設置啓動動作,確保以管理員身份運行 startInfo.Verb = "runas"; Process.Start(startInfo); return true; } catch(Exception ex) { Common.LogHelper.getLogHelper().WriteLog("安裝開啓服務出錯", ex); return false; } } /// <summary> /// 卸載本地守護服務 /// </summary> /// <returns></returns> public bool Stop() { try { //創建啓動對象 System.Diagnostics.ProcessStartInfo startInfo = new System.Diagnostics.ProcessStartInfo(); startInfo.WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory; startInfo.UseShellExecute = false; startInfo.FileName = AppDomain.CurrentDomain.BaseDirectory + "LocalService\\Uninstall.bat"; //設置啓動動作,確保以管理員身份運行 startInfo.Verb = "runas"; Process.Start(startInfo); return true; } catch { return false; } } }
卸載:
裏面的InstallUtil是windows自帶的有,百度查下吧。沒時間了,先寫到這。