如题,WinForm 和 Windows Service 通信,就是应用程序和系统服务通信,可以看成是进程间的通信。通信的方式有很多,这里只介绍通过消息队列(MessageQueue)方式。理论知识就不介绍了,直接介绍实例吧。
一、建立工程
建立3个项目,其中,
Common 为类库,包含错误日志类(Log.cs)和数据库访问类(MsSql.cs)
ServiceDemo 为Windows Service服务,包含安装类(Installer1.cs)和服务类(Service1.cs)
ServiceDesk 为WinForm应用程序,包含一个主窗口类(frmMain.cs)
这3个项目要实现的功能是,进程间通信,具体怎么通信呢?这里我设计的是用ServiceDesk这个WinForm实时监控ServiceDemo这个系统服务。ServiceDesk和ServiceDemo之间的通信就通过消息队列(MessageQueue)方式。
对了,补充下理论,消息队列必须安装后才能用,安装步骤如下:
控制面板->添加或删除程序->添加或删除组件
选择应用程序服务器详细信息
勾上消息队列
安装完就可以通过控制面板->管理工具->计算机管理->服务和应用程序访问了
二、书写服务
Service1.cs
public partial class Service1 : ServiceBase { Thread m_thread1;
public Service1() { InitializeComponent(); }
protected override void OnStart(string[] args) { if (m_thread1 != null && m_thread1.ThreadState != System.Threading.ThreadState.Aborted) { m_thread1.Abort(); }
m_thread1 = new Thread(new ThreadStart(Work)); m_thread1.IsBackground = true; m_thread1.Start(); }
protected override void OnStop() {
}
private void Work() { while (true) { //try //{ // string sql = "insert into T_Log(DateTime,Description)values({0},{1})"; // sql = String.Format(sql, DateTime.Now.ToString(), "adsf");
// int Result = Common.MsSql.ExecuteNonQuery(sql, this.GetType()); //} //catch (Exception e) //{ // Common.Log.Write(e); //}
string msg = "消息内容测试"; SendMessage(msg);
System.Threading.Thread.Sleep(500); } }
void SendMessage(string msg) { try { string QueuePath = "./private$/aaaa"; MessageQueue MQueue;
if (!MessageQueue.Exists(QueuePath)) { return; }
MQueue = new MessageQueue(QueuePath);
System.Messaging.Message Msg = new System.Messaging.Message(); Msg.Body = msg;
//XML格式化传输量较大 //Msg.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) }); Msg.Formatter = new System.Messaging.BinaryMessageFormatter(); MQueue.Send(Msg); } catch (Exception ex) { Common.Log.Write(this.GetType(), ex); } } }
三、书写服务控制(WinForm)
frmMain.cs
简单界面
其中组件引用:
serviceController1的ServiceName属性设置为 ServiceDemo
代码:
public partial class frmMain : Form { int i = 1; Thread t1; Thread t2;
string QueuePath = "./private$/aaaa";
public frmMain() { InitializeComponent(); }
private void frmMain_Load(object sender, EventArgs e) { this.notifyIcon1.Icon = new Icon("E:/WorkSpace/WindowsService/ServiceDesk/Resources/Icon1.ico");
frmMain.CheckForIllegalCrossThreadCalls = false;
t1 = new Thread(new ThreadStart(PrintServiceStatus)); t1.Start(); }
private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e) { this.Visible = true; this.WindowState = FormWindowState.Normal; } private void frmMain_FormClosing(object sender, FormClosingEventArgs e) { //取消关闭窗口 e.Cancel = true; //将窗口最小化 this.WindowState = FormWindowState.Minimized; //将窗口隐藏 this.Visible = false; }
private void toolStripMenuItem1_Click(object sender, EventArgs e) { this.Visible = true; this.WindowState = FormWindowState.Normal; }
private void ToolStripMenuItem2_Click(object sender, EventArgs e) { notifyIcon1.Visible = false; Application.Exit(); }
/// <summary> /// 继续 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void toolStripMenuItem_Continue_Click(object sender, EventArgs e) {
}
/// <summary> /// 执行Cmd命令 /// </summary> public void Cmd(string c) { System.Diagnostics.Process process = new System.Diagnostics.Process(); process.StartInfo.FileName = "cmd.exe"; process.StartInfo.UseShellExecute = false; process.StartInfo.CreateNoWindow = true; process.StartInfo.RedirectStandardOutput = true; process.StartInfo.RedirectStandardInput = true; process.Start();
process.StandardInput.WriteLine(c); process.StandardInput.AutoFlush = true; process.StandardInput.WriteLine("exit"); StreamReader reader = process.StandardOutput;//截取输出流 string output = reader.ReadLine();//每次读取一行 while (!reader.EndOfStream) { PrintThrendInfo(output); output = reader.ReadLine(); }
process.WaitForExit(); }
#region 进度显示 private void PrintThrendInfo(string Info) { lock (listView1) { try { ListViewItem Item = new ListViewItem(i.ToString()); Item.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); Item.SubItems.Add(Info); listView1.Items.Add(Item); //listView1.RedrawItems(i - 1, i - 1, false); //线程中不能用这句 i++; if (i >= 1000) { listView1.Items.Clear(); i = 1; } } catch (SystemException ex) { Log.Write(this.GetType(),ex); } } }
private void PrintThrendInfo(string Info, Color ForeColor) { //锁定资源 lock (listView1) { try { ListViewItem Item = new ListViewItem(i.ToString()); Item.SubItems.Add(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")); Item.SubItems.Add(Info); listView1.Items.Add(Item); Item.ForeColor = ForeColor; if (ForeColor == Color.Red || ForeColor == Color.Fuchsia) { Log.Write(this.GetType(), Info); } //listView1.RedrawItems(i - 1, i - 1, false); //线程中不能用这句 i++; if (i >= 10000) { listView1.Items.Clear(); i = 1; } } catch (SystemException ex) { Log.Write(this.GetType(),ex); } } } #endregion
/// <summary> /// 安装 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnInstall_Click(object sender, EventArgs e) { try { t2.Abort(); } catch { } t2 = new Thread(new ThreadStart(Install)); t2.Start(); } void Install() { t1.Suspend(); string c = @"c:windowsmicrosoft.netframeworkv2.0.50727InstallUtil.exe " + AppDomain.CurrentDomain.BaseDirectory + "ServiceDemo.exe"; Cmd(c); t1.Resume(); } /// <summary> /// 卸载 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnUninstall_Click(object sender, EventArgs e) { try { t2.Abort(); } catch { } t2 = new Thread(new ThreadStart(Uninstall)); t2.Start(); } void Uninstall() { t1.Suspend(); string c = @"c:windowsmicrosoft.netframeworkv2.0.50727InstallUtil.exe /u " + AppDomain.CurrentDomain.BaseDirectory + "ServiceDemo.exe"; Cmd(c); t1.Resume(); } /// <summary> /// 启动 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStart_Click(object sender, EventArgs e) { try { t2.Abort(); } catch { } t2 = new Thread(new ThreadStart(Start)); t2.Start(); } void Start() { t1.Suspend(); string c = @"net start ServiceDemo"; Cmd(c); t1.Resume(); } /// <summary> /// 停止 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void btnStop_Click(object sender, EventArgs e) { try { t2.Abort(); } catch { } t2 = new Thread(new ThreadStart(Stop)); t2.Start(); } void Stop() { t1.Suspend(); string c = @"net stop ServiceDemo"; Cmd(c); t1.Resume(); } private void PrintServiceStatus() { if (MessageQueue.Exists(QueuePath)) { MessageQueue.Delete(QueuePath); } while (true) { t1.Join(1000); this.serviceController1.Refresh(); if (this.serviceController1.Status != ServiceControllerStatus.Running) { PrintThrendInfo("服务运行状态:" + this.serviceController1.Status.ToString()); if (MessageQueue.Exists(QueuePath)) { MessageQueue.Delete(QueuePath); } continue; } MessageQueue MQueue; if (MessageQueue.Exists(QueuePath)) { MQueue = new MessageQueue(QueuePath); } else { MQueue = MessageQueue.Create(QueuePath); MQueue.SetPermissions("Administrators", MessageQueueAccessRights.FullControl); MQueue.Label = QueuePath; } //一次读一条,取一条自动去掉读取的这一条 //System.Messaging.Message Msg = MQueue.Receive(new TimeSpan(0, 0, 2)); //一次读取全部消息,但是不去除读过的消息 System.Messaging.Message[] Msg = MQueue.GetAllMessages(); //删除所有消息 MQueue.Purge(); foreach (System.Messaging.Message m in Msg) { //XML格式化传输量较大 //Msg.Formatter = new System.Messaging.XmlMessageFormatter(new Type[] { typeof(string) }); m.Formatter = new System.Messaging.BinaryMessageFormatter(); PrintThrendInfo(m.Body.ToString()); } } } }
三、制作安装
Installer1.cs
[RunInstaller(true)] public partial class Installer1 : Installer { public Installer1() { InitializeComponent(); } public override void Install(IDictionary stateSaver) { Microsoft.Win32.RegistryKey system; //HKEY_LOCAL_MACHINEServicesCurrentControlSet Microsoft.Win32.RegistryKey currentControlSet; //...Services Microsoft.Win32.RegistryKey services; //...<Service Name> Microsoft.Win32.RegistryKey service; //...Parameters - this is where you can put service-specific configuration Microsoft.Win32.RegistryKey config; try { //Let the project installer do its job base.Install(stateSaver); //Open the HKEY_LOCAL_MACHINESYSTEM key system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System"); //Open CurrentControlSet currentControlSet = system.OpenSubKey("CurrentControlSet"); //Go to the services key services = currentControlSet.OpenSubKey("Services"); //Open the key for your service, and allow writing service = services.OpenSubKey(this.serviceInstaller1.ServiceName, true); //Add your service's description as a REG_SZ value named "Description" service.SetValue("Description", "计划按时执行,如一分钟一次"); //(Optional) Add some custom information your service will use... //允许服务与桌面交互 service.SetValue("Type", 0x00000110); config = service.CreateSubKey("Parameters"); } catch (Exception e) { Console.WriteLine("An exception was thrown during service installation:n" + e.ToString()); } } public override void Uninstall(IDictionary savedState) { Microsoft.Win32.RegistryKey system; Microsoft.Win32.RegistryKey currentControlSet; Microsoft.Win32.RegistryKey services; Microsoft.Win32.RegistryKey service; try { //Drill down to the service key and open it with write permission system = Microsoft.Win32.Registry.LocalMachine.OpenSubKey("System"); currentControlSet = system.OpenSubKey("CurrentControlSet"); services = currentControlSet.OpenSubKey("Services"); service = services.OpenSubKey(this.serviceInstaller1.ServiceName, true); //Delete any keys you created during installation (or that your service created) service.DeleteSubKeyTree("Parameters"); //... } catch (Exception e) { Console.WriteLine("Exception encountered while uninstalling service:n" + e.ToString()); } finally { //Let the project installer do its job base.Uninstall(savedState); } } }
四、运行效果
1、安装效果
2、运行
3、卸载