新建自己的windows service
来源:互联网 发布:虚拟充值退款淘宝介入 编辑:程序博客网 时间:2024/04/29 15:09
首先明确一个概念,什么是windows service? windows service 是一些后台运行的服务,我们可以通过控制板面/管理/服务来查看当前计算机中已有的服务,同时可以控制这些服务开启和关闭。所以从使用的角度来看,这里的控制板面/管理/服务实际上是一个service 管理工具。同时windows提供了一个service的管理者SCM service control manager,它传递消息到各个service。
从代码的角度看,一个service一般是一个console工程,虽然有带有交互界面的service,但是后台服务还是使用console较多。这里又有两个概念:main和service main。前者很简单,就是console工程的main函数,而service main指的是提供service逻辑的入口。
MSDN中的main的例子是这样:
void __cdecl _tmain(int argc, TCHAR *argv[])
{
// If command-line parameter is "install", install the service.
// Otherwise, the service is probably being started by the SCM.
if( lstrcmpi( argv[1], TEXT("install")) == 0 )
{
SvcInstall();
return;
}
// TO_DO: Add any additional services for the process to this table.
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION) SvcMain },
{ NULL, NULL }
};
// This call returns when the service has stopped.
// The process should simply terminate when the call returns.
if (!StartServiceCtrlDispatcher( DispatchTable ))
{
SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
}
}
我们暂时专注于红色的两个部分,SERVICE_TABLE_ENTRY是用于记录service name和service main的结构,必须以NULL和NULL结尾(用以判断结束吧,猜测),这个结构传入到StartServiceCtrlDispatcher函数中。这个函数内部会进入循环并等待SCM的消息,如果SCM要求启动某个service,函数就会根据SERVICE_TABLE_ENTRY来调用service main,所以SERVICE_TABLE_ENTRY是一个回调函数表。同时也可以发现,一个main或者说一个exe是可以提供多个service,同时没个service是工作的该进程中的不同线程内的,顺便说一句,main当然是主线程了。
main基本说完了,下面来专注于service main,还是MSDN的例子吧:
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
// Register the handler function for the service
gSvcStatusHandle = RegisterServiceCtrlHandler(
SVCNAME,
SvcCtrlHandler);
if( !gSvcStatusHandle )
{
SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
return;
}
// These SERVICE_STATUS members remain as set here
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
// Report initial status to the SCM
ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
// Perform service-specific initialization and work.
SvcInit( dwArgc, lpszArgv );
}
service开始服务,前面说了,我们可以控制service开启,暂停,关闭等,那么就需要让SCM有一个能控制service状态的方法(当然是回调了。。。),RegisterServiceCtrlHandler函数就是为服务注册控制回调函数的方法,例子中的SvcCtrlHandler就是回调函数handler。这里的注册最好是service main做的第一件事,因为SCM对于注册时间是有要求的,具体时间记不清了,需要查查。。。
同时service还需要向SCM提供自己状态,在上面的例子是通过ReportSvcStatus函数的,下面是它的实现,来源MSDN:
VOID ReportSvcStatus( DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
// Fill in the SERVICE_STATUS structure.
gSvcStatus.dwCurrentState = dwCurrentState;
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
gSvcStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
gSvcStatus.dwControlsAccepted = 0;
else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ( (dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED) )
gSvcStatus.dwCheckPoint = 0;
else gSvcStatus.dwCheckPoint = dwCheckPoint++;
// Report the status of the service to the SCM.
SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}
最主要的函数就是SetServiceStatus, 它负责向SCM提供当前serivce的状态,SERVICE_STATUS (gSvcStatus) 结构体用来封装所有关于service status的信息,里面的一些字段很有趣的, 比如dwCheckPoint , 用于在pending状态下反应service进度。
等等,所谓pending状态,实际上是指service开启,关闭不可能一下子就结束,除非真有人的代码是暴力terminatethread。。。在收到开启消息时,我们可以设置状态为SERVICE_START_PENDING, 等真正完成初始化在设置为SERVICE_RUNNING。最后就是我们的逻辑代码了这里的例子是封装在SvcInit函数里面。
我们再看一下控制函数的例子, 同样来自MSDN:
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
// Handle the requested control code.
switch(dwCtrl)
{
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
// Signal the service to stop.
SetEvent(ghSvcStopEvent);
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
这个应该很清楚了,一般都是控制code的处理,这些code可以在MSDN上查到,同时user也可以自定义一些code。
最后我们还需要安装service,这里需要的API主要是createservice和OpenSCManager啦,比较简单,下面的代码还是来源于MSDN:
VOID SvcInstall()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH];
if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
{
printf("Cannot install service (%d)/n", GetLastError());
return;
}
// Get a handle to the SCM database.
schSCManager = OpenSCManager(
NULL, // local computer
NULL, // ServicesActive database
SC_MANAGER_ALL_ACCESS); // full access rights
if (NULL == schSCManager)
{
printf("OpenSCManager failed (%d)/n", GetLastError());
return;
}
// Create the service
schService = CreateService(
schSCManager, // SCM database
SVCNAME, // name of service
SVCNAME, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_DEMAND_START, // start type
SERVICE_ERROR_NORMAL, // error control type
szPath, // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
printf("CreateService failed (%d)/n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
else printf("Service installed successfully/n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
注意在main里面会调用这个函数阿,所以我们通过命令行就可以install某个exe上面的service了
- 新建自己的windows service
- 如何制作自己的Windows Service Pack
- 启动自己写的Windows Service
- 新建自己的Activity
- 四极管:Windows CE 在windows文件夹加入自己的文件和新建文件夹方法
- yii2:新建自己的layout
- vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局).
- vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局)
- vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局)
- vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局).
- vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局). .
- vs2008如何新建自己工程的环境变量(局部)和 Windows系统(全局).
- caffe在windows下如何在vs2013新建工程开发自己的应用cpu模式
- caffe在windows下如何在vs2013新建工程开发自己的应用cpu模式
- 怎样新建一个Java的Web Service
- 怎样新建一个Java的Web Service
- 怎样新建一个Java的Web Service
- 新建自己的blog的想法
- [sql server] 问题总结9- 字符串拼接
- linux(fedora)开机启动服务
- HashMap遍历的两种方式
- 套接口地址结构及IP端口转换函数简介
- 向量
- 新建自己的windows service
- Android自由的游戏开发框架
- type parameter, type argument & parameteried type
- 入库,出库数据,自动生成库存,简单实用的仓库管理表格或ERP系统.请发一份到我的邮箱545451757@qq.com.谢谢
- guichan控件学习之一
- jpa的基本映射
- RtspProxy RTSP 重定向 Redirect 的实现
- Linq to sql(一) DataContext
- centos samba 配置