Windows服务和桌面程序互相控制
网上有这方面的文章,不过大多介绍不够全面、详尽,而且大部分言必称API。本文试图描述更多使用framework类库,更加详尽的操作方法。
2007年11月5日
http://www.cnblogs.com/birdshover/
一、需求
假定有这样一个需求:
1、需要一个服务来启动应用程序
2、当应用程序启动后会完成一些任务
3、如果应用程序执行任务过程中发生错误,由服务来重启该应用程序
4、服务关闭,应用程序同时关闭
5、应用程序启动后发现服务未注册或者未启动则完成这些动作
6、应用程序可停止服务
二、思路
服务OnStart应该定时检查程序是否处于启动状态,如果启动,读取消息,完成动作。如果未启动,则启动。
服务OnStop需要关闭程序
程序启动后检查服务状态
程序有按钮可以关闭服务
三、方法
1、启动应用程序
要启动应用程序,首先要找到系统中是否有应用程序存在,假定应用程序名称MyTestApp.exe,服务名称MyTestService
找到MyTestApp很简单,就一句话
Process[] p = Process.GetProcessesByName("MyTestApp", ".");
注意要引用System.Diagnostics,为什么GetProcessesByName的参数是"MyTestApp"和".","."是大多.Net程序的类名称,MyTestApp是程序名称,是程序编译选项里的程序集名称。
这里要且只要启动一个,所以
if (p.Length == 0)
{
Process ip = Process.Start(System.IO.Path.Combine(localPath, "MyTestApp.exe"));
ip.StartInfo.CreateNoWindow = false;
ip.StartInfo.UseShellExecute = false;
ip.StartInfo.RedirectStandardInput = true;
ip.StartInfo.RedirectStandardOutput = true;
ip.StartInfo.RedirectStandardError = true;
ip.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
{
Process ip = Process.Start(System.IO.Path.Combine(localPath, "MyTestApp.exe"));
ip.StartInfo.CreateNoWindow = false;
ip.StartInfo.UseShellExecute = false;
ip.StartInfo.RedirectStandardInput = true;
ip.StartInfo.RedirectStandardOutput = true;
ip.StartInfo.RedirectStandardError = true;
ip.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
localPath是程序运行目录
string localPath = System.Windows.Forms.Application.StartupPath;
需要注意,Service项目中不包含System.Windows.Forms.dll的引用,需要自己添加。
好了,这样就能完成使命了,但是还需要实时监视。所以,用Timer.
一共有两个Timer,一个在System.Threading空间下,一个在System.Windows.Forms空间下。使用System.Windows.Forms空间下的Timer,两个不一样。
System.Windows.Forms.Timer t = new System.Windows.Forms.Timer();
t.Interval = 1000;
t.Tick += new EventHandler(t_Tick);
t.Start();
void t_Tick(object sender, EventArgs e)
{
Process[] p = Process.GetProcessesByName("MyTestApp", ".");
if (p.Length == 0)
{
Process ip = Process.Start(System.IO.Path.Combine(localPath, "MyTestApp.exe"));
ip.StartInfo.CreateNoWindow = false;
ip.StartInfo.UseShellExecute = false;
ip.StartInfo.RedirectStandardInput = true;
ip.StartInfo.RedirectStandardOutput = true;
ip.StartInfo.RedirectStandardError = true;
ip.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
}
t.Interval = 1000;
t.Tick += new EventHandler(t_Tick);
t.Start();
void t_Tick(object sender, EventArgs e)
{
Process[] p = Process.GetProcessesByName("MyTestApp", ".");
if (p.Length == 0)
{
Process ip = Process.Start(System.IO.Path.Combine(localPath, "MyTestApp.exe"));
ip.StartInfo.CreateNoWindow = false;
ip.StartInfo.UseShellExecute = false;
ip.StartInfo.RedirectStandardInput = true;
ip.StartInfo.RedirectStandardOutput = true;
ip.StartInfo.RedirectStandardError = true;
ip.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
}
加进去了,发现没有用....还没搞清楚什么原因。试试线程,发现可以。
Thread td;
td = new Thread(doAction);
td.Start();
td.Start();
void doAction()
{
while (true)
{
Process[] p = Process.GetProcessesByName("MyTestApp", ".");
if (p.Length == 0)
{
Process ip = Process.Start(System.IO.Path.Combine(localPath, "MyTestApp.exe"));
ip.StartInfo.CreateNoWindow = false;
ip.StartInfo.UseShellExecute = false;
ip.StartInfo.RedirectStandardInput = true;
ip.StartInfo.RedirectStandardOutput = true;
ip.StartInfo.RedirectStandardError = true;
ip.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
Thread.Sleep(1 * 1000);
}
}
{
while (true)
{
Process[] p = Process.GetProcessesByName("MyTestApp", ".");
if (p.Length == 0)
{
Process ip = Process.Start(System.IO.Path.Combine(localPath, "MyTestApp.exe"));
ip.StartInfo.CreateNoWindow = false;
ip.StartInfo.UseShellExecute = false;
ip.StartInfo.RedirectStandardInput = true;
ip.StartInfo.RedirectStandardOutput = true;
ip.StartInfo.RedirectStandardError = true;
ip.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
}
Thread.Sleep(1 * 1000);
}
}
到现在就满足服务启动程序的要求了。
中午了,要吃饭了,下午上班没什么时间写,下次续....