用C#做Windows Services

用C#做Windows Services,第1张

Windows服务在Visual Studio 以前的版本中叫NT服务 在启用了新的名称 用Visual C# 创建Windows服务不是一件困难的事 本文就将指导你一步一步创建一个Windows服务并使用它 这个服务在启动和停止时 向一个文本文件中写入一些文字信息

第一步 创建服务框架

要创建一个新的 Windows 服务 可以从Visual C# 工程中选取 Windows 服务(Windows Service)选项 给工程一个新文件名 然后点漏手陪击 确定

你可以看到 向导向工程文件中增加Service cs类

其中各属性的含意是:

ü         Autolog                 是否自动写入系统的日志文件

ü  薯备       CanHandlePowerEvent     服务时候接受电源事件

ü         CanPauseAndContinue          服务是否接受暂停或继续运行的请求

ü         CanShutdown 服务是否在运行它的计算机关闭时收到通知 以便能够调用 OnShutDown 过程

ü         CanStop                              服务是否接受停止运行的请求

ü         ServiceName                       服务名

第二步 向服务中增加功能

在 cs代码文件中我们可以看到 有两个被忽略的函数 OnStart和OnStop

OnStart函数在启动服务时执行 OnStop函数在停止服务时执行 在这里 当启动和停止服务时 向一个文本文件中写入一些文字信息 代码如下:

protected override void OnStart(string[] args)

{

FileStream fs = new FileStream(@ d:\mcWindowsService txt FileMode OpenOrCreate FileAccess Write)

StreamWriter m_streamWriter = new StreamWriter(fs)

m_streamWriter BaseStream Seek( SeekOrigin End)

m_streamWriter WriteLine( mcWindowsService:         Service Started +DateTime Now ToString()+ \n )

m_streamWriter Flush()

m_streamWriter Close()

fs Close()

}

protected override void OnStop()

{

FileStream fs = new FileStream(@ d:\mcWindowsService txt FileMode OpenOrCreate FileAccess Write)

StreamWriter m_streamWriter = new StreamWriter(fs)

m_streamWriter BaseStream Seek( SeekOrigin End)

m_streamWriter WriteLine( mcWindowsService: Service Stopped +DateTime Now ToString()+ \n )

m_streamWriter Flush()

m_streamWriter Close()

fs Close()

}

第三步: 将安装程序添加到服务应用程序

Visual Studio NET 随附有安装组件 可用来安装与服务应用程序相关联的资源 安装组件在正在安装到的系统上注册一项单个的服务 并使服务控制管理器知道该服务的存在

要正确安装服务 并不需要在安装程序中进行任何特殊编码 但是 如果需要向安装进程添加特殊功能 则可能偶尔需要修改安装程序的内容

将安装程序添加到服务应用程序的步骤是:

在解决方案中 访问要向其中添加安装组件的服务的Design视图

在属性窗口中 单击添加安装程序返蠢链接

这时项目中就添加了一个新类 ProjectInstaller 和两个安装组件 ServiceProcessInstaller 和 ServiceInstaller 并且服务的属性值被复制到组件

若要确定如何启动服务 请单击 ServiceInstaller 组件并将 StartType 属性设置为适当的值

ü         Manual      服务安装后 必须手动启动

ü         Automatic    每次计算机重新启动时 服务都会自动启动

ü         Disabled     服务无法启动

将serviceProcessInstaller类的Account属性改为 LocalSystem

这样 不论是以哪个用户登录的系统 服务总会启动

第四步 生成服务程序

通过从生成菜单中选择生成来生成项目

注意   不要通过按 F 键来运行项目——不能以这种方式运行服务项目

第五步 安装服务

访问项目中的已编译可执行文件所在的目录

用项目的输出作为参数 从命令行运行 InstallUtil exe 在命令行中输入下列代码

installutil yourproject exe

卸载服务

用项目的输出作为参数 从命令行运行 InstallUtil exe

lishixinzhi/Article/program/net/201311/13879

Windows提供了一套后台服务程序编程接口,用户在编写后台服务程序时需要遵循一定的编程框架,否则服务程序不能正常运行。

服务程序通常编写成控制台类型的应用程序,总的来说,一个遵守服务控制管理程序接口要求的程序 包含下面三个函数:

1)服务程序主函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序。

和其它进程一样,Main函数是服务进程的入口函数,服务控制管理器(SCM)在启动服务程序时,会从服务程序的main函数开始执行。在进入点函数里面要完成ServiceMain的初始化,准确点说是初始化一个SERVICE_TABLE_ENTRY结构数组,这个结构记录了这个服务程序里面所包含的所有服务的名称和服毁备务的进入点函数。然后再调用接口StartServiceCtrlDispatcher 。

Main函数的函数框架如下:

int _tmain(int argc, _TCHAR* argv[])

{

//服务入口点函数表

SERVICE_TABLE_ENTRY dispatchTable[]=

{

{TEXT(SZSERVICENAME),(LPSERVICE_MAIN_FUNCTION)Service_Main},

{ NULL,NULL}

}

if((argc>1)&&((*argv[1]==‘-‘)||(argv[1]=="/")))

{

/*

参数个数大于1是安装或者删除服务,该 *** 作是由用户来执行的

当然也可以讲这一部分功能另写一个程序来实现

*/

if(_stricmp("install",argv[1]+1)==0)

{

installService()

}

else if(_stricmp("remove",argv[1]+1)==0)

{

removeService()

}

else if(_stricmp("debug",argv[1]+1)==0)

{

bDebugServer=true

debugService(argc,argv)

}

}

else

{

/*

如果未能和上面的如何参数匹配,则可能是服务控制管理程序来启动该程序。 立即调用StartServiceCtrlDispatcher 函数

*/

g_logout.Logout("%s\n", "enter StartServiceCtrlDispatcher...")

//通知服务管理器为每一个服务创建服务线程

if(!StartServiceCtrlDispatcher(dispatchTable))

g_logout.Logout("%s\n", "StartServiceCtrlDispatcher failed.")

else

g_logout.Logout("%s\n", "StartServiceCtrlDispatcher OK.")

}

return 0

}

SCM启动一个服务程序之后,它会等待该程序的主线程去调StartServiceCtrlDispatcher。如果那个函数在两分钟内没有被调用,SCM将会认为这个服务有问题,并调用TerminateProcess去杀死这个进程。这就要求你的主厅橘线程要尽可能快的调用StartServiceCtrlDispatcher。

2)服务入口点函数(ServiceMain):执行服务初始化任务,同时纤伏毁执行多个服务的服务进程有多个服务入口函数。

在服务入口函数里,必须立即注册服务控制回调函数。然后调用函数SetServiceStatus 通知SCM 服务现在的状态,否则SCM会认为服务启动失败。

ServiceMain函数框架如下:

void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)

{

//注册服务控制处理函数

sshStatusHandle=RegisterServiceCtrlHandler(TEXT(SZSERVICENAME),Service_Ctrl)

//如果注册失败

if(!sshStatusHandle)

{

g_logout.Logout("%s\n", "RegisterServiceCtrlHandler failed...")

return

}

//初始化 SERVICE_STATUS 结构中的成员

ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS//可执行文件中只有一个单独的服务

ssStatus.dwServiceSpecificExitCode=0

ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP//允许用SCP去停止该服务

//更新服务状态

if(ReportStatusToSCMgr(SERVICE_START_PENDING,//服务状态,服务仍在初始化

NO_ERROR,

3000)) //等待时间

SvcInit( dwArgc, lpszArgv )//服务初始化函数

else

g_logout.Logout("%s\n", "ReportStatusToSCMgr SERVICE_START_PENDING failed...")

}

服务初始化函数SvcInit:

该函数的写法比较重要。在函数中创建一个等待事件,然后一直等待该事件。该线程在服务接到请求之前一直处于挂起状态,直到接到服务停止消息。

VOID SvcInit( DWORD dwArgc, LPTSTR *lpszArgv)

{

/*创建事件*/

ghSvcStopEvent = CreateEvent(

NULL,// default security attributes

TRUE,// manual reset event

FALSE, // not signaled

NULL) // no name

if ( ghSvcStopEvent == NULL)

{

ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 )

return

}

// Report running status when initialization is complete.

ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 )

// 在这里执行服务线程的创建...

while(1)

{

// 等待停止事件被触发

WaitForSingleObject(ghSvcStopEvent, INFINITE)

ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 )

return

}

}

3)控制服务处理程序函数(Handler):在服务程序收到控制请求时由控制分发线程引用。(此处是Service_Ctrl)。

void WINAPI Service_Ctrl(DWORD dwCtrlCode)

{

//处理控制请求码

switch(dwCtrlCode)

{

//先更新服务状态为 SERVICDE_STOP_PENDING,再停止服务。

case SERVICE_CONTROL_STOP:

ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500)

ServiceStop()//由具体的服务程序实现

/*ssStatus.dwCurrentState=SERVICE_STOPPED*/

//其它控制请求...

default:

break

}

}

3. 注意事项

1)安装服务可以另写一个程序,也可以并在服务程序当中,比较简单,这里就不介绍了。

2)服务初始化函数SvcInit里创建等待事件比较重要,在服务接收到服务停止消息后,触发该事件。

3)Service_Main在等待事件触发后立即返回,服务进程就会退出了

在“开始→运行”中键入“regedit.exe”,打开“注斗迟袜册表编辑器”,展开分支“HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services”,在右侧窗格中显示的就是本机安装的服务项。

如果要新建服务,只须点击“编辑空激→新建→项”,然后为此项命名,如“test”;然后右击该项,选择“新建→字符串值”或“新建→DWORD值”即可。添加旦穗一个服务项目具体需要添加的键值如下:

“DisplayName”,字符串值,对应服务名称;

“Description”,字符串值,对应服务描述;

“ImagePath”,字符串值,对应该服务程序所在的路径;

“ObjectName”,字符串值,值为“LocalSystem”,表示本地登录;

“ErrorControl”,DWORD值,值为“1”;

“Start”,DWORD值,值为2表示自动运行,值为3表示手动运行,值为4表示禁止;

“Type”,DWORD值,应用程序对应10,其它对应20。


欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/yw/12517400.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-05-26
下一篇 2023-05-26

发表评论

登录后才能评论

评论列表(0条)

保存