windows服务类似于UINX的守护进程,在后台运行的程序,在系统启动的时刻启动进程,不依赖于交互环境;服务有广泛用途,如QQ管家,360都有服务程序,用于监视程序的运行;
windows服务程序包括两个部分:服务程序(实现你想要的功能)和控制服务的程序(作用是控制服务程序,如创建服务,开始服务,停止服务等)
服务程序主函数结构如下:
int _tmain(int argc, _TCHAR* argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ NULL, NULL }
};
StartServiceCtrlDispatcher( DispatchTable );
return 0;
}
StartServiceCtrlDispatcher函数连接到SCM(服务控制管理器),启动控制分派线程;分派线程会陷入到一个循环当中,等待 DispatchTable[]中所有服务的控制请求;当
DispatchTable[]中的所有服务都停止后,SCM会向控制分派线程发送一个结束的请求,然后StartServiceCtrlDispatcher会返回,程序结束;
DispatchTable[]中记录的分别是服务的名称,和与其对应的服务的入口点,上述服务入口点是SvcMain,可理解为服务主程序;
服务入口点SvcMain是一个函数,撰写方法如下:
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, SvcCtrlHandler);
if( !gSvcStatusHandle )
{
return;
}
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
SvcInit( dwArgc, lpszArgv );
}
RegisterServiceCtrlHandler注册服务的控制函数SvcCtrlHandler,服务的停止,暂停等控制都是通过该函数向服务传递过来的;
SvcCtrlHandler的模式如下:
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
switch(dwCtrl)
{
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(ghSvcStopEvent);//激发一个停止服务的事件
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default: break;
}
}
上面的函数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;
}
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
while(1)
{
// SvcCtrlHandler函数内的停止事件激发,该处结束死循环,服务结束;
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
}
所有想要的工作走可以在上面while的死循环内完成;上面的函数ReportSvcStatus用于设置状态,用于通知SCM当前服务的状态,注意,在服务控制器中中必须每次都设置状态,即使状态没有改变;
上面是服务的典型写法,下面介绍一下服务控制程序的写法:服务程序写好后,需要通过API来控制其创建,开始,暂停,继续及查询等操作;创建服务:
VOID SvcCreate()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH];
if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
{
printf("Cannot install service (%d)\n", GetLastError());
return;
}
int len = _tcslen(szPath);
for(int i = len - 1; i >= 0; --i)
{
if(szPath[i] != _T('\\'))
szPath[i] = _T('\0');
else
break;
}
_tcscat(szPath, _T("Service_Demo.exe"));//上面撰写的服务程序
//打开SCM
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;
}
// 创建服务
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, // 服务程序的全路径名
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);
}
服务创建好后,需要启动,服务才能运行,代码如下:
VOID __stdcall DoStartSvc()
{
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwBytesNeeded;
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // full access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL) ) // no arguments
{
printf("StartService failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else printf("Service start pending...\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
停止服务代码如下:
VOID __stdcall DoStopSvc()
{
SERVICE_STATUS_PROCESS ssp;
DWORD dwStartTime = GetTickCount();
DWORD dwBytesNeeded;
DWORD dwTimeout = 30000; // 30-second time-out
DWORD dwWaitTime;
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_STOP |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS);
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
stop_cleanup:
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
删除服务代码如下:
VOID __stdcall DoDeleteSvc()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_STATUS ssStatus;
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
DELETE); // need delete access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
if (! DeleteService(schService) )
{
printf("DeleteService failed (%d)\n", GetLastError());
}
else printf("Service deleted successfully\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
基本上控制服务的代码模式是:打开SCM,然后是创建或删除或开始或停止API,然后关闭打开的句柄;
具体API用法参考MSDN;
整理的代码Demo GitHub地址git@github.com:grefen/Study.git
网址:https://github.com/grefen/Study/tree/master/SCMDemo
windows服务程序包括两个部分:服务程序(实现你想要的功能)和控制服务的程序(作用是控制服务程序,如创建服务,开始服务,停止服务等)
服务程序主函数结构如下:
int _tmain(int argc, _TCHAR* argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ NULL, NULL }
};
StartServiceCtrlDispatcher( DispatchTable );
return 0;
}
StartServiceCtrlDispatcher函数连接到SCM(服务控制管理器),启动控制分派线程;分派线程会陷入到一个循环当中,等待 DispatchTable[]中所有服务的控制请求;当
DispatchTable[]中的所有服务都停止后,SCM会向控制分派线程发送一个结束的请求,然后StartServiceCtrlDispatcher会返回,程序结束;
DispatchTable[]中记录的分别是服务的名称,和与其对应的服务的入口点,上述服务入口点是SvcMain,可理解为服务主程序;
服务入口点SvcMain是一个函数,撰写方法如下:
VOID WINAPI SvcMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
gSvcStatusHandle = RegisterServiceCtrlHandler( SVCNAME, SvcCtrlHandler);
if( !gSvcStatusHandle )
{
return;
}
gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
gSvcStatus.dwServiceSpecificExitCode = 0;
ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 3000 );
SvcInit( dwArgc, lpszArgv );
}
RegisterServiceCtrlHandler注册服务的控制函数SvcCtrlHandler,服务的停止,暂停等控制都是通过该函数向服务传递过来的;
SvcCtrlHandler的模式如下:
VOID WINAPI SvcCtrlHandler( DWORD dwCtrl )
{
switch(dwCtrl)
{
case SERVICE_CONTROL_STOP:
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
SetEvent(ghSvcStopEvent);//激发一个停止服务的事件
ReportSvcStatus(gSvcStatus.dwCurrentState, NO_ERROR, 0);
return;
case SERVICE_CONTROL_INTERROGATE:
break;
default: break;
}
}
上面的函数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;
}
ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );
while(1)
{
// SvcCtrlHandler函数内的停止事件激发,该处结束死循环,服务结束;
WaitForSingleObject(ghSvcStopEvent, INFINITE);
ReportSvcStatus( SERVICE_STOPPED, NO_ERROR, 0 );
return;
}
}
所有想要的工作走可以在上面while的死循环内完成;上面的函数ReportSvcStatus用于设置状态,用于通知SCM当前服务的状态,注意,在服务控制器中中必须每次都设置状态,即使状态没有改变;
上面是服务的典型写法,下面介绍一下服务控制程序的写法:服务程序写好后,需要通过API来控制其创建,开始,暂停,继续及查询等操作;创建服务:
VOID SvcCreate()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
TCHAR szPath[MAX_PATH];
if( !GetModuleFileName( NULL, szPath, MAX_PATH ) )
{
printf("Cannot install service (%d)\n", GetLastError());
return;
}
int len = _tcslen(szPath);
for(int i = len - 1; i >= 0; --i)
{
if(szPath[i] != _T('\\'))
szPath[i] = _T('\0');
else
break;
}
_tcscat(szPath, _T("Service_Demo.exe"));//上面撰写的服务程序
//打开SCM
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;
}
// 创建服务
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, // 服务程序的全路径名
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);
}
服务创建好后,需要启动,服务才能运行,代码如下:
VOID __stdcall DoStartSvc()
{
SERVICE_STATUS_PROCESS ssStatus;
DWORD dwOldCheckPoint;
DWORD dwStartTickCount;
DWORD dwWaitTime;
DWORD dwBytesNeeded;
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_ALL_ACCESS); // full access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
if (!StartService(
schService, // handle to service
0, // number of arguments
NULL) ) // no arguments
{
printf("StartService failed (%d)\n", GetLastError());
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return;
}
else printf("Service start pending...\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
停止服务代码如下:
VOID __stdcall DoStopSvc()
{
SERVICE_STATUS_PROCESS ssp;
DWORD dwStartTime = GetTickCount();
DWORD dwBytesNeeded;
DWORD dwTimeout = 30000; // 30-second time-out
DWORD dwWaitTime;
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
SERVICE_STOP |
SERVICE_QUERY_STATUS |
SERVICE_ENUMERATE_DEPENDENTS);
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
stop_cleanup:
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
删除服务代码如下:
VOID __stdcall DoDeleteSvc()
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_STATUS ssStatus;
// 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;
}
// Get a handle to the service.
schService = OpenService(
schSCManager, // SCM database
szSvcName, // name of service
DELETE); // need delete access
if (schService == NULL)
{
printf("OpenService failed (%d)\n", GetLastError());
CloseServiceHandle(schSCManager);
return;
}
if (! DeleteService(schService) )
{
printf("DeleteService failed (%d)\n", GetLastError());
}
else printf("Service deleted successfully\n");
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
}
基本上控制服务的代码模式是:打开SCM,然后是创建或删除或开始或停止API,然后关闭打开的句柄;
具体API用法参考MSDN;
整理的代码Demo GitHub地址git@github.com:grefen/Study.git
网址:https://github.com/grefen/Study/tree/master/SCMDemo