c编写windows服务的应用实例
昨天,我研究了一下如何用c#编写windows服务,如果有兄弟不知道怎么弄,可以去看一下,因为我昨天晚上研究了它的应用,今天准备和大家分享一下。
昨天的文章在这里:彻底搞懂如何用c#编写windows服务
c#编写windows服务,这个链接第一次用,不太知道怎么弄。
昨天安装了一个啥也没干的windows服务,我就在想,这个东西能做什么呢?最后我决定制作一个守护程序,功能就是监测另一个程序,看它有没有启动,没有的话就启动它。制作一个简单的程序,我们就来监测它是不是启动了,程序文件名:text.exe。
切换到service的代码视图
整体代码如下,,这里我用LOG文件做了日志:using System; using System.IO; using System.ServiceProcess; using System.Windows.Forms; namespace A_Fw { public partial class TheService : ServiceBase { //定义一个timer public System.Timers.Timer timer = new System.Timers.Timer(); //运行路径 string thepath = Application.StartupPath; //日志文件路径 string logfile = "log.txt"; //被监控程序的进程名,用来检查它是不是已经运行 string jinchengming = "test"; //被监控程序的文件名 string runfilename = "test.exe"; public TheService() { InitializeComponent(); //定义timer事件 timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); timer.Interval = 1000; //时间间隔 } //timer启动后,每隔一段时间检测下被监视程序是否运行,如果没有就运行它 void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { //根据进程名得到被监测程序的进程对象 System.Diagnostics.Process[] myproc = System.Diagnostics.Process.GetProcessesByName(jinchengming); int isrun = myproc.Length; //如果没有进程,说明这个程序没有运行 if (isrun == 0) { try { Log("程序未运行,准备运行..."); //运行被监控程序 System.Diagnostics.Process.Start(thepath + runfilename); Log("程序已经启动..."); } catch (Exception ex) { Log("启动程序时发现错误:" + ex.ToString()); Application.Exit(); } } else { Log("程序正在运行"); } } protected override void OnStart(string[] args) { //服务启动时的事件,timer开始工作 timer.Enabled = true; timer.Start(); Log("服务启动..."); } protected override void OnStop() { //服务停止时的事件,timer停止工作 timer.Enabled = false; timer.Stop(); Log("服务停止..."); } void Log(string logcontent) //记录日志 { using (FileStream st = new FileStream(thepath + logfile, FileMode.Append)) { using (StreamWriter wr = new StreamWriter(st)) { wr.WriteLine(#34;{DateTime.Now.ToLongTimeString()},{logcontent}"); } } } } }出现以下情况
是因为我们写的不是windows窗体服务,添加一下system.windows.Forms.dll,
再引用一下 using System.Windows.Forms; 就可以了。
重新生成解决方案,因为我程序中都是用的应该程序根目录,这样方便调试,所以这次需要把3个文件放在同一目录下
G:x>installUtil.exe A_Fw.exe 安装服务,然后启动服务
运行后,test.exe并未弹出
但查看日志文件没有发现问题
查看进程,发现已经有了test进程,杀死后,还会出现这个进程,说明服务程序没有问题。但需要注意的是,此时test进程为"后台进程"
这是什么原因呢?给服务加上与桌面交互选项也是不行的
查了些资料,确定原因出现在这句:
System.Diagnostics.Process.Start(thepath + runfilename);
我不知道是什么原因,用它启动text.exe就是后台进程,解决方法如下:新建一个文件(我并不知道为啥,这个是网上抄的)
这个文件直接照抄就行了。using System; using System.Runtime.InteropServices; namespace RFW { public class WinAPI_Interop { public static IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero; /// /// 服务程序执行消息提示,前台MessageBox.Show /// /// 消息内容 /// 标题 public static void ShowServiceMessage(string message, string title) { int resp = 0; WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, WTSGetActiveConsoleSessionId(), title, title.Length, message, message.Length, 0, 0, out resp, false); } [DllImport("kernel32.dll", SetLastError = true)] public static extern int WTSGetActiveConsoleSessionId(); [DllImport("wtsapi32.dll", SetLastError = true)] public static extern bool WTSSendMessage(IntPtr hServer, int SessionId, String pTitle, int TitleLength, String pMessage, int MessageLength, int Style, int Timeout, out int pResponse, bool bWait); #region P/Invoke WTS APIs private enum WTS_CONNECTSTATE_CLASS { WTSActive, WTSConnected, WTSConnectQuery, WTSShadow, WTSDisconnected, WTSIdle, WTSListen, WTSReset, WTSDown, WTSInit } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] private struct WTS_SESSION_INFO { public UInt32 SessionID; public string pWinStationName; public WTS_CONNECTSTATE_CLASS State; } [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool WTSEnumerateSessions( IntPtr hServer, [MarshalAs(UnmanagedType.U4)] UInt32 Reserved, [MarshalAs(UnmanagedType.U4)] UInt32 Version, ref IntPtr ppSessionInfo, [MarshalAs(UnmanagedType.U4)] ref UInt32 pSessionInfoCount ); [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern void WTSFreeMemory(IntPtr pMemory); [DllImport("WTSAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool WTSQueryUserToken(UInt32 sessionId, out IntPtr Token); #endregion #region P/Invoke CreateProcessAsUser /// /// Struct, Enum and P/Invoke Declarations for CreateProcessAsUser. /// /// [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct STARTUPINFO { public Int32 cb; public string lpReserved; public string lpDesktop; public string lpTitle; public Int32 dwX; public Int32 dwY; public Int32 dwXSize; public Int32 dwYSize; public Int32 dwXCountChars; public Int32 dwYCountChars; public Int32 dwFillAttribute; public Int32 dwFlags; public Int16 wShowWindow; public Int16 cbReserved2; public IntPtr lpReserved2; public IntPtr hStdInput; public IntPtr hStdOutput; public IntPtr hStdError; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] struct PROCESS_INFORMATION { public IntPtr hProcess; public IntPtr hThread; public int dwProcessId; public int dwThreadId; } /// /// 以当前登录的windows用户(角色权限)运行指定程序进程 /// /// /// 指定程序(全路径) /// 参数 /// 进程属性 /// 线程属性 /// /// /// /// /// 程序启动属性 /// 最后返回的进程信息 /// 是否调用成功 [DllImport("ADVAPI32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, IntPtr lpProcessAttributes, IntPtr lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags, string lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation); [DllImport("KERNEL32.DLL", SetLastError = true, CharSet = CharSet.Auto)] static extern bool CloseHandle(IntPtr hHandle); #endregion /// /// 以当前登录系统的用户角色权限启动指定的进程 /// /// 指定的进程(全路径) public static void CreateProcess(string ChildProcName) { IntPtr ppSessionInfo = IntPtr.Zero; UInt32 SessionCount = 0; if (WTSEnumerateSessions( (IntPtr)WTS_CURRENT_SERVER_HANDLE, // Current RD Session Host Server handle would be zero. 0, // This reserved parameter must be zero. 1, // The version of the enumeration request must be 1. ref ppSessionInfo, // This would point to an array of session info. ref SessionCount // This would indicate the length of the above array. )) { for (int nCount = 0; nCount < SessionCount; nCount++) { WTS_SESSION_INFO tSessionInfo = (WTS_SESSION_INFO)Marshal.PtrToStructure(ppSessionInfo + nCount * Marshal.SizeOf(typeof(WTS_SESSION_INFO)), typeof(WTS_SESSION_INFO)); if (WTS_CONNECTSTATE_CLASS.WTSActive == tSessionInfo.State) { IntPtr hToken = IntPtr.Zero; if (WTSQueryUserToken(tSessionInfo.SessionID, out hToken)) { PROCESS_INFORMATION tProcessInfo; STARTUPINFO tStartUpInfo = new STARTUPINFO(); tStartUpInfo.cb = Marshal.SizeOf(typeof(STARTUPINFO)); bool ChildProcStarted = CreateProcessAsUser( hToken, // Token of the logged-on user. ChildProcName, // Name of the process to be started. null, // Any command line arguments to be passed. IntPtr.Zero, // Default Process" attributes. IntPtr.Zero, // Default Thread"s attributes. false, // Does NOT inherit parent"s handles. 0, // No any specific creation flag. null, // Default environment path. null, // Default current directory. ref tStartUpInfo, // Process Startup Info. out tProcessInfo // Process information to be returned. ); if (ChildProcStarted) { CloseHandle(tProcessInfo.hThread); CloseHandle(tProcessInfo.hProcess); } else { int err = Marshal.GetLastWin32Error(); ShowServiceMessage("CreateProcessAsUser失败:" + err.ToString(), "CreateProcess"); } CloseHandle(hToken); break; } } } WTSFreeMemory(ppSessionInfo); } } } }将打开文件那句改成:try { Log("程序未运行,准备运行..."); //运行被监控程序,下面这句不行 //System.Diagnostics.Process.Start(thepath + runfilename); //用这句才可以打开应用进程 RFW.WinAPI_Interop.CreateProcess(thepath + @runfilename); Log("程序已经启动..."); }重新安装服务,运行效果如下:
明天再来研究,用其它程序来控制这个服务的安装与卸载
如果看得上的话,需要源码可以联系我。