服务是一种应用程序类型,它在后台运行,与 UNIX 后台应用程序类似。服务应用程序通常可以
在本地和通过网络为用户提供一些功能,例如客户端/服务器应用程序、Web 服务器、数据库服
务器以及其他基于服务器的应用程序。
后台服务 程序是在后台悄悄运行的。我们通过将自己的程序登记为服务,可以使自己的程序不出现
在任务管理器中,并且随系统启动而最先运行,随系统关闭而最后停止。
服务控制管理器是一个RPC 服务器,它显露了一组应用编程接口,程序员可以方便的编写程序来配置
服务和控制远程服务器中服务程序。
服务程序通常编写成控制台类型的应用程序,总的来说,一个遵守服务控制管理程序接口要求的程序
包含下面三个函数:
1。服务程序主函数(main):调用系统函数 StartServiceCtrlDispatcher 连接程序主线程到服务控制管理程序。
2。服务入口点函数(ServiceMain):执行服务初始化任务,同时执行多个服务的服务进程有多个服务入口函数。
3。控制服务处理程序函数(Handler):在服务程序收到控制请求时由控制分发线程引用。(此处是Service_Ctrl)。
类型
|
说明
|
SERVICE_FILE_SYSTEM_DRIVER=2
|
文件系统驱动服务。
|
SERVICE_KERNEL_DRIVER=1
|
驱动服务。
|
SERVICE_WIN32_OWN_PROCESS=16
|
独占一个进程的服务。
|
SERVICE_WIN32_SHARE_PROCESS=32
|
与其他服务共享一个进程的服务。
|
新建WIN32控制台程序, 其源文件名为service.cpp 。我用的开发工具是VC++.NET。
//服务程序主函数。
#include "stdafx.h"
#include "Windows.h"
#define SZAPPNAME "serverSample" //服务程序名
#define SZSERVICENAME "serviceSample" //标识服务的内部名
//内部变量
bool bDebugServer=false;
SERVICE_STATUS ssStatus;
SERVICE_STATUS_HANDLE sshStatusHandle;
DWORD dwErr=0;
TCHAR szErr[256];
//下面的函数由程序实现
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);
void WINAPI Service_Ctrl(DWORD dwCtrlCode);
void installService();
void removeService();
void debugService(int argc,char** argv);
bool ReportStatusToSCMgr(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint);
void AddToMessageLog(LPTSTR lpszMsg);
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]=="/")))
{
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 函数。
printf("%s - install to install the service /n",SZAPPNAME);
printf("%s - remove to remove the service /n",SZAPPNAME);
printf("%s - debug to debug the service /n",SZAPPNAME);
printf("/n StartServiceCtrlDispatcher being called./n");
printf("This may take several seconds.Please wait./n");
if(!StartServiceCtrlDispatcher(dispatchTable))
AddToMessageLog(TEXT("StartServiceCtrlDispatcher failed."));
else
AddToMessageLog(TEXT("StartServiceCtrlDispatcher OK."));
}
exit(0);
}
return 0;
}
服务入口点函数 service_main 首先调用系统函数RegisterServiceCtrlHandler 注册服务控制处理函数 service_ctrl,然后调用 ReportStatusToSCMgr 函数,它通过系统函数 SetServiceStatus 更新服务的状态,然后调用特定的服务初始化入口函数 ServiceStart 完成具体的初始化工作。
//服务入口点函数
void ServiceStart(DWORD dwArgc,LPTSTR* lpszArgv);//具体服务的初始化入口函数
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
//注册服务控制处理函数
sshStatusHandle=RegisterServiceCtrlHandler(TEXT(SZSERVICENAME),Service_Ctrl);
//如果注册失败
if(!sshStatusHandle)
{
goto cleanup;
return;
}
//初始化 SERVICE_STATUS 结构中的成员
ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode=0;
//更新服务状态
if(!ReportStatusToSCMgr(
SERVICE_START_PENDING,//服务状态,The service is starting.
NO_ERROR, //退出码
3000)) //等待时间
goto cleanup; //更新服务状态失败则转向 cleanup
ServiceStart(dwArgc,lpszArgv);
return;
cleanup:
//把服务状态更新为 SERVICE_STOPPED,并退出。
if(sshStatusHandle)
(void)ReportStatusToSCMgr(SERVICE_STOPPED,dwErr,0);
}
函数 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(); //由具体的服务程序实现
return;
//暂停服务
case SERVICE_CONTROL_PAUSE:
ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
ServicePause(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_PAUSED;
return;
//继续服务
case SERVICE_CONTROL_CONTINUE:
ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
ServiceContinue(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_RUNNING;
return;
//更新服务状态
case SERVICE_CONTROL_INTERROGATE:
break;
//无效控制码
default:
break;
}
ReportStatusToSCMgr(ssStatus.dwCurrentState,NO_ERROR,0);
}
hService :函数 OpenService or CreateService 返回的服务程序句柄。
dwControl :控制码,不能是SERVICE_CONTROL_SHUTDOWN。
lpServiceStatus:返回最后收到的服务状态信息。
每个已安装服务程序在 HKEY_LOCAL_MACHINE/SYSTE/CurrentControlSet/Services 下都有一个服务名的关键字,程序员可以调用系统函数 CreateService 安装服务程序,并指定服务类型,服务名等。这个函数创建一个服务对象,并将其增加到相关的服务控制管理器数据库中。
//安装服务程序
void installService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szPath[512];
//得到程序磁盘文件的路径
if(GetModuleFileName(NULL,szPath,512)==0)
{
_tprintf(TEXT("Unable to install %s - %s /n"),
TEXT(SZAPPNAME),
GetLastError());//@1获取调用函数返回的最后错误码
return;
}
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//登记服务程序
schService=CreateService(
schSCManager, //服务管理数据库句柄
TEXT(SZSERVICENAME), //服务名
TEXT(SZAPPNAME), //用于显示服务的标识
SERVICE_ALL_ACCESS, //响应所有的访问请求
SERVICE_WIN32_OWN_PROCESS, //服务类型
SERVICE_DEMAND_START, //启动类型
SERVICE_ERROR_NORMAL, //错误控制类型
szPath, //服务程序磁盘文件的路径
NULL, //服务不属于任何组
NULL, //没有tag标识符
NULL, //启动服务所依赖的服务或服务组,这里仅仅是一个空字符串
NULL, //LocalSystem 帐号
NULL);
if(schService)
{
_tprintf(TEXT("%s installed. /n"),TEXT(SZAPPNAME));
CloseServiceHandle(schService);
}
else
{
_tprintf(TEXT("CreateService failed - %s /n"),GetLastError());
}
CloseServiceHandle(schSCManager);
}
else
_tprintf(TEXT("OpenSCManager failed - %s /n"),GetLastError());
}
对于理解此文的人来说应该不难编写,在此我可以给点文档内的参考:声明 SetTheServiceStatus()函数,
// SetTheServiceStatus - This just wraps up SetServiceStatus.
//
void SetTheServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode,
DWORD dwCheckPoint, DWORD dwWaitHint)
{
SERVICE_STATUS ss; // Current status of the service.
//
// Disable control requests until the service is started.
//
if (dwCurrentState == SERVICE_START_PENDING)
ss.dwControlsAccepted = 0;
else
ss.dwControlsAccepted =
SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_SHUTDOWN;
// Other flags include SERVICE_ACCEPT_PAUSE_CONTINUE
// and SERVICE_ACCEPT_SHUTDOWN.
// Initialize ss structure.
ss.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
ss.dwServiceSpecificExitCode = 0;
ss.dwCurrentState = dwCurrentState;
ss.dwWin32ExitCode = dwWin32ExitCode;
ss.dwCheckPoint = dwCheckPoint;
ss.dwWaitHint = dwWaitHint;
// Send status of the service to the Service Controller.
if (!SetServiceStatus(ssh, &ss))
ErrorStopService(TEXT("SetServiceStatus"));
}
然后用如下的方式来调用函数来实现源程序中缺少的功能 :
SetTheServiceStatus(SERVICE_STOPPED, GetLastError(), 0, 0);// Stop the service.
这是在学习windows的服务安装机制时的笔记,主要是一些函数的说明,还有我自己的代码,没有整理过比较乱
OpenSCManager:
The OpenSCManager function establishes a connection to the service control manager on the specified computer and opens the specified service control manager database.
SC_HANDLE OpenSCManager(
LPCTSTR lpMachineName,
LPCTSTR lpDatabaseName,
DWORD dwDesiredAccess 如果以administrators的权限创建服务的话,该字段的值为SC_MANAGER_ALL_ACCESS
);
CreateService:
The CreateService function creates a service object and adds it to the specified service control manager database
SC_HANDLE CreateService(
SC_HANDLE hSCManager,
LPCTSTR lpServiceName, //服务的名称
LPCTSTR lpDisplayName,
DWORD dwDesiredAccess, //SERVICE_ALL_ACCESS
DWORD dwServiceType, //SERVICE_WIN32_OWN_PROCESS
DWORD dwStartType, //SERVICE_AUTO_START
DWORD dwErrorControl, //SERVICE_ERROR_IGNORE
LPCTSTR lpBinaryPathName, //指向二进制文件的路径
LPCTSTR lpLoadOrderGroup,
LPDWORD lpdwTagId,
LPCTSTR lpDependencies,
LPCTSTR lpServiceStartName,
LPCTSTR lpPassword
);
SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler(
LPCTSTR lpServiceName, //服务的名字
LPHANDLER_FUNCTION lpHandlerProc //服务的控制函数的名字
);
#include "windows.h"
#include "stdio.h"
//全局变量
SERVICE_STATUS ServiceStatus;
SERVICE_STATUS_HANDLEServiceStatusHandle;
//函数声明
voidInstallService(char *szServicePath);
voidWINAPIServiceStart(DWORDdwArgc,LPTSTR *lpArgv);
voidWINAPIServiceControl(DWORDdwCode);
DWORDWINAPIService(LPVOIDlpvThread); //服务功能函数
intmain(intargc, char* argv[])
{
//定义SERVICE_TABLE_ENTRY DispatchTable[] 结构
SERVICE_TABLE_ENTRYDispatchTable[2] =
{
{"mixu_yy", ServiceStart},
{NULL, NULL}
};
//安装或者打开服务
StartServiceCtrlDispatcher(DispatchTable);
InstallService(argv[0]);
return 0;
}
//函数定义
voidInstallService(char *szServicePath)
{
SC_HANDLE schSCManager;
SC_HANDLE schService;
SERVICE_STATUS InstallServiceStatus;
DWORD dwErrorCode;
//打开服务管理数据库
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if(schSCManager == NULL)
{
//Open Service Control Manager Database Failed!;
return;
}
//创建服务
schService = CreateService(
schSCManager,
"mixu_yy",
"mixu_yy",
SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,
SERVICE_ERROR_IGNORE,
szServicePath,
NULL,
NULL,
NULL,
NULL,
NULL);
if(schService == NULL)
{
dwErrorCode = GetLastError();
if(dwErrorCode != ERROR_SERVICE_EXISTS)
{
//创建服务失败
CloseServiceHandle(schSCManager);
return;
}
else
{
//要创建的服务已经存在
schService = OpenService(schSCManager, "mixu_yy", SERVICE_START);
if(schService == NULL)
{
//Open Service Failed!;
CloseServiceHandle(schSCManager);
return;
}
}
}
else
{
//Create Service Success!;
}
//启动服务
if(StartService(schService, 0, NULL)==0 )
{
//启动失败
dwErrorCode = GetLastError();
if(dwErrorCode == ERROR_SERVICE_ALREADY_RUNNING)
{
//Service already run!;
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
return ;
}
}
else
{
//Service pending
}
while(QueryServiceStatus(schService, &InstallServiceStatus) != 0)
{
if(InstallServiceStatus.dwCurrentState == SERVICE_START_PENDING)
{
//Sleep(100);
}
else
{
break;
}
}
if(InstallServiceStatus.dwCurrentState != SERVICE_RUNNING)
{
//Failure!
}
else
{
//Sucess!
}
//擦屁股
CloseServiceHandle(schSCManager);
CloseServiceHandle(schService);
return;
}
voidWINAPIServiceStart(DWORDdwArgc,LPTSTR *lpArgv)
{
HANDLEhThread;
ServiceStatus.dwServiceType = SERVICE_WIN32;
ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;
ServiceStatus.dwServiceSpecificExitCode = 0;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
ServiceStatusHandle = RegisterServiceCtrlHandler("mixu_yy", ServiceControl);
if(ServiceStatusHandle == 0)
{
//error
return;
}
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
if(SetServiceStatus(ServiceStatusHandle, &ServiceStatus) == 0)
{
//SetServiceStatus error!
return;
}
//创建服务线程 服务完成的功能在这里调用
hThread = CreateThread(NULL,
0,
Service,
NULL,
0,
NULL);
if(hThread == NULL)
{
//CreateThread error!
return;
}
CloseHandle(hThread);
return;
}
//服务控制模块
voidWINAPIServiceControl(DWORDdwCode)
{
switch(dwCode) {
caseSERVICE_CONTROL_PAUSE:
ServiceStatus.dwCurrentState = SERVICE_PAUSED;
break;
caseSERVICE_CONTROL_CONTINUE:
ServiceStatus.dwCurrentState = SERVICE_RUNNING;
break;
caseSERVICE_CONTROL_STOP:
ServiceStatus.dwCurrentState = SERVICE_STOPPED;
ServiceStatus.dwWin32ExitCode = 0;
ServiceStatus.dwCheckPoint = 0;
ServiceStatus.dwWaitHint = 0;
if(SetServiceStatus(ServiceStatusHandle, &ServiceStatus) == 0)
{
//SetServiceStatus error!
}
return;
caseSERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
if(SetServiceStatus(ServiceStatusHandle, &ServiceStatus) == 0)
{
//SetServiceStatus error!
}
return ;
}
//服务线程函数
DWORDWINAPIService(LPVOIDlpvThread)
{
//实现函数功能的地方。
return 1;
}