.NET实现可交互的WINDOWS服务的实例代码
这几天想做个文件监控服务,看了一下网上的关于windows服务的文章,数量都不少,都只讲了如何做一个最基本的服务,却没有讲述如何与用户进行交互。查看了msdn,看一下关于服务的描述:
windows 服务应用程序在不同于登录用户的交互区域的窗口区域中运行。窗口区域是包含剪贴板、一组全局原子和一组桌面对象的安全对象。由于 windows 服务的区域不是交互区域,因此 windows 服务应用程序中引发的对话框将是不可见的,并且可能导致程序停止响应。同样,错误信息应记录在 windows 事件日志中,而不是在用户界面中引发。
.net framework 支持的 windows 服务类不支持与交互区域(即登录用户)进行交互。同时,.net framework 不包含表示区域和桌面的类。如果 windows 服务必须与其他区域进行交互,则需要访问非托管的 windows api。
也就是说我们要实现可交互的服务(比如我们想给服务在运行时做一些参数设置等),那我们一定要using system.runtime.interopservices
那么来看一下如果才能实现一个可交互的服务呢。步骤与实现基本的服务一样(各位可自行参考msdn或网上google一下).
在实现onstart时要注意,这里可不能弹出一个form什么的。这样做是没有任何反应的。我们可以在这个方法里运行一个线程。该线程需要访问窗口区域对象或桌面对象,当然 framework里是没有提供这些的,要访问非托管代码的。
来看一下代码,再运行试一下。
using system;
using system.collections;
using system.componentmodel;
using system.data;
using system.diagnostics;
using system.serviceprocess;
using system.threading;
using system.runtime.interopservices;
namespace filewatchservice
{
publicclass service1 : system.serviceprocess.servicebase
{
///
/// 必需的设计器变量。
///
private system.componentmodel.container components =null;
thread threadform =null;
public service1()
{
// 该调用是 windows.forms 组件设计器所必需的。
initializecomponent();
// todo: 在 initcomponent 调用后添加任何初始化
}
#region 组件设计器生成的代码
///
/// 设计器支持所需的方法 - 不要使用代码编辑器
/// 修改此方法的内容。
///
privatevoid initializecomponent()
{
//
// service1
//
this.servicename ="jadewatchservice";
}
#endregion
[stathread]
staticvoid main()
{
system.serviceprocess.servicebase.run(new service1());
}
///
/// 清理所有正在使用的资源。
///
protectedoverridevoid dispose(bool disposing)
{
if (disposing)
{
if (components !=null)
{
components.dispose();
}
}
base.dispose(disposing);
}
///
/// 设置具体的操作,以便服务可以执行它的工作。
///
protectedoverridevoid onstart(string[] args)
{
threadform =new thread(new threadstart(formshow));
threadform.start();
}
///
/// 停止此服务。
///
protectedoverridevoid onstop()
{
if (threadform !=null)
{
if (threadform.isalive)
{
threadform.abort();
threadform =null;
}
}
}
void formshow()
{
getdesktopwindow();
intptr hwinstasave = getprocesswindowstation();
intptr dwthreadid = getcurrentthreadid();
intptr hdesksave = getthreaddesktop(dwthreadid);
intptr hwinstauser = openwindowstation("winsta0", false, 33554432);
if (hwinstauser == intptr.zero)
{
rpcreverttoself();
return;
}
setprocesswindowstation(hwinstauser);
intptr hdeskuser = opendesktop("default", 0, false, 33554432);
rpcreverttoself();
if (hdeskuser == intptr.zero)
{
setprocesswindowstation(hwinstasave);
closewindowstation(hwinstauser);
return;
}
setthreaddesktop(hdeskuser);
intptr dwguithreadid = dwthreadid;
form1 f =new form1(); //此form1可以带notifyicon,可以显示在托盘里,用户可点击托盘图标进行设置
system.windows.forms.application.run(f);
dwguithreadid = intptr.zero;
setthreaddesktop(hdesksave);
setprocesswindowstation(hwinstasave);
closedesktop(hdeskuser);
closewindowstation(hwinstauser);
}
[dllimport("user32.dll")]
staticexternint getdesktopwindow();
[dllimport("user32.dll")]
staticextern intptr getprocesswindowstation();
[dllimport("kernel32.dll")]
staticextern intptr getcurrentthreadid();
[dllimport("user32.dll")]
staticextern intptr getthreaddesktop(intptr dwthread);
[dllimport("user32.dll")]
staticextern intptr openwindowstation(string a, bool b, int c);
[dllimport("user32.dll")]
staticextern intptr opendesktop(string lpszdesktop, uint dwflags,
bool finherit, uint dwdesiredaccess);
[dllimport("user32.dll")]
staticextern intptr closedesktop(intptr p);
[dllimport("rpcrt4.dll", setlasterror =true)]
staticextern intptr rpcimpersonateclient(int i);
[dllimport("rpcrt4.dll", setlasterror =true)]
staticextern intptr rpcreverttoself();
[dllimport("user32.dll")]
staticextern intptr setthreaddesktop(intptr a);
[dllimport("user32.dll")]
staticextern intptr setprocesswindowstation(intptr a);
[dllimport("user32.dll")]
staticextern intptr closewindowstation(intptr a);
}
}