如何编写NT Service在MSDN->Platform SDK->DLLs, Processes, and Threads->Service中说得很清楚了,在这里我就不多说了,这里我就只说一些我个人认为的在编写service过程中要注意的地方。
0、在我们通过控制面板或NET START命令启动一个service时, Service Control Manager (SCM)从注册表里拿到service的可执行程序名,然后运行这个程序,从程序的入口main方法里得到service的service_main方法,然后就进入service_main运行。
一个service程序包含最少包含三个部分,一个是main方法,通常的工作是设置service_main方法和处理命令行参数(例如根据不同的参数执行其他的动作,象安装卸载service,手动启动停止service等等);一个是service_main方法,service程序具体要做的工作就写在这个方法里;一个是ServiceCtrlHandler方法,这个方法在service_main里设置,用来处理由SCM发给service的消息,例如service停止,暂停,系统关机等等。
1、手动启动一个service的方法是在service的main方法里调用StartService,StartService根据service的SERVICE_TABLE_ENTRY将程序转入相应的service_main。启动service时所要作的工作是写在service_main里的。通常的模式是在进入service_main后设状态为SERVICE_START_PENDING,然后进行一些初始化动作,然后执行一个线程或进程,在其中进行service的工作,然后设状态为SERVICE_RUNNING。一定要注意的是,启动service后,必须保证在两分钟内service的状态就会被设成SERVICE_RUNNING,否则会报错。
2、停止一个service的方法是在service的main方法里调用ControlService(hService,SERVICE_CONTROL_STOP,&ServStat)发送SERVICE_CONTROL_STOP消息到Service Control Manager (SCM),SCM收到这个消息后就会通知service,执行ServiceCtrlHandler里case SERVICE_CONTROL_STOP:内的工作。结束动作通常也不能太久,因为在关机时,系统会给每个service大概20秒时间清场(这个时间可以在注册表中设置)
3、安装和卸载一个service的方法是在service的main方法里调用CreateService方法和DeleteService方法,卸载方法前先要判断service是否在运行,如果在运行要先将服务停止
否则无法删除。
4、设置service状态的方法是调用SetServiceStatus,在写service的启动和停止动作是要设置其状态,分别在上面提到的service_main和ServiceCtrlHandler里。查询service状态的方法是QueryServiceStatus,在停止服务时,ControlService方法只是发送了一个消息后就立即返回了,因此通常要在执行完ControlService后,利用while、sleep和QueryServiceStatus来不断查询service的状态,直到状态为SERVICE_STOPPED。StartService与ControlService不同,并不是立即返回的,它会直到service_main内的代码执行完后才返回。
5、service_main即使返回,service的程序进程也不会退出,直到service的状态为SERVICE_STOPPED时,才会终止并退出。
6、在设置service状态时,通过指定dwWin32ExitCode和dwServiceSpecificExitCode可以设定当service在此状态下出错时的弹出式Message。不过只能设定一个错误代码。
7、使用ChangeServiceConfig2添加修改service的描述。
8、默认情况下service程序是不能与桌面交互的,即不能打开窗口。通过ChangeServiceConfig函数设定SERVICE_INTERACTIVE_PROCESS属性,或通过控制面板选中"允许服务与桌面交互",则服务程序可以打开窗口。例如在服务中使用CreateProcess创建了一个进程,只要在STARTUPINFO的wShowWindow和dwFlags设定了SW_SHOW和STARTF_USESHOWWINDOW,则进程就会在打开的一个新窗口中运行。
9、不论是否设定SERVICE_INTERACTIVE_PROCESS,在service中都可以通过MessageBox方法弹出MessageBox。这个函数的第一个参数指定为NULL,表示不指定父窗口。在第四个参数中指定MB_DEFAULT_DESKTOP_ONLY或MB_SERVICE_NOTIFICATION表示以桌面为父窗口。
10.如果要停止的一个Service上有其他正在运行的服务依赖着,这时直接停止这个服务就会出错,因此如果需要停止的服务有可能被其他服务所依赖,在停止前必须用EnumDependentServices()方法取得所有依赖于这个服务的服务,将这些服务依次停止后才行。具体代码示例请看MSDN->HOWTO->ID:Q245230。
11、启动service时可以使用启动参数,在定义service_main方法时其两个参数(DWORD argc, LPTSTR *argv),第一个即为参数个数,第二个则是一个参数数组指针。如何传入参数呢,由于service_main并不是程序入口,因此参数是通过main从命令行传至StartService方法,而调用StartService时,StartService的第二第三个参数,就是传入service_main的参数。如果service是auto-started的,每次开机时就会自动启动,没有给我们手工通过命令行传入参数的机会,这时我们只有在安装service的时候,就把参数传入。在CreateService时,将CreateService的lpBinaryPathName值设成例如SimpleService.exe arg1 arg2的样子,这样每当SCM启动service时SCM就会从main方法中获得参数并将其传入这个service的service_main中。
12.在启动一个service之后,在service的状态是”已启动(SERVICE_RUNNING)”之前,这段时间内,是无法启动另一个service的。
例子代码:
#include
#include
#include
#include
#include
#include
#include
#define SERVICE_NAME "TSService"
#define SERVICE_DISPNAME "vPBX PathFinder TSService"
#define SERVICE_DESCRIPTIONNAME "Start vPBX PathFinder service"
#define SERVICE_EXENAME "\ServiceFrame.exe"
#define LOG_FILENAME "\Service.log"
#define START_EXENAME "\vpbxw.exe"
#define STOP_EXENAME "\StopServer.exe"
#define CMD_EXENAME " -svc"
#define REG_ITEM "SOFTWARE\\VisionNex\\vPBX_Server"
#define REG_KEY "home"
#define FLAG_FILENAME "\PortKeeper.svc"
#define START_DELAY 10000
#define STOP_DELAY 2000
#define COUNT_DELAY 50
#define TIME_DELAY 2000
SERVICE_STATUS m_ServiceStatus;
SERVICE_STATUS_HANDLE m_ServiceStatusHandle;
BOOL bRunning=false;
char Path[256];
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv);
void WINAPI ServiceCtrlHandler(DWORD Opcode);
BOOL InstallService(int flag);
BOOL DeleteService();
BOOL StartupService();
BOOL StopService();
BOOL ChangeService();
BOOL EndService();
BOOL QueryReg ();
DWORD GetStatus(SC_HANDLE service);
void LogService(char* error);
BOOL TestTs(int sleep, int count, int sec);
BOOL WaitTsStartup(int sleep, int count, int sec);
int main(int argc, char* argv[])
{
if(!QueryReg()) return 1;
if(argc>1) {
if(strcmp(argv[1],"-i")==0) {
InstallService(0);
}
else if (strcmp(argv[1],"-id")==0){
InstallService(1);
}
else if(strcmp(argv[1],"-d")==0) {
DeleteService();
}
else if(strcmp(argv[1],"-r")==0) {
StartupService();
}
else if(strcmp(argv[1],"-s")==0) {
StopService();
}
else if(strcmp(argv[1],"-c")==0) {
ChangeService();
}
else if(strcmp(argv[1],"-v")==0) {
printf("serivce frame version:1.0.0.5: debug=pipe(limit -0.3)");
}
else {
printf("Unknown Switch Usage\nFor install use -i, for uninstall use -d, for run use -r, for stop use -s\n");
}
}
else {
SERVICE_TABLE_ENTRY DispatchTable[]={{SERVICE_NAME, ServiceMain},{NULL,NULL}};
StartServiceCtrlDispatcher(DispatchTable);
}
return 0;
}
void WINAPI ServiceMain(DWORD argc, LPTSTR *argv)
{
DWORD status;
DWORD specificError;
LogService("Service Startup...");
m_ServiceStatus.dwServiceType = SERVICE_WIN32;
m_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
m_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
m_ServiceStatus.dwWin32ExitCode = 0;
m_ServiceStatus.dwServiceSpecificExitCode = 0;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
m_ServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);
if (m_ServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) {
LogService("Error: RegisterServiceCtrlHandler");
return;
}
/*
//create pipe
SECURITY_ATTRIBUTES sa;
HANDLE hRead,hWrite;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.lpSecurityDescriptor = NULL;
sa.bInheritHandle = TRUE;/*
if (!CreatePipe(&hRead,&hWrite,&sa,0)) {
LogService("Error On CreatePipe()");
}
//---------
hWrite = CreateFile("d:\\process.log",GENERIC_WRITE, FILE_SHARE_READ, &sa, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
*/
PROCESS_INFORMATION pinfo;
STARTUPINFO sinfo;
ZeroMemory(&sinfo, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
char strDir[256];
char strDir_stop[256];
strcpy(strDir,Path);
strcpy(strDir_stop,Path);
strcat(strDir,START_EXENAME);
strcat(strDir_stop,STOP_EXENAME);
LPCTSTR lpszBinaryPathName=strDir;
LPCTSTR lpszBinaryPathName_stop=strDir_stop;
LogService("Start Create StopServer process");
if(!CreateProcess(lpszBinaryPathName_stop, CMD_EXENAME, NULL,NULL,FALSE,0,NULL,Path,&sinfo,&pinfo)) {
LogService("Error: CreateProcess:stop befor start");
return;
}
Sleep(STOP_DELAY);
ZeroMemory(&sinfo, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
//Set Process output
//sinfo.hStdError = hWrite;
//sinfo.hStdOutput = hWrite;
sinfo.wShowWindow = SW_SHOW;
sinfo.dwFlags = STARTF_USESHOWWINDOW ;//| STARTF_USESTDHANDLES;
LogService("Start Create vPBXW process");
if(!CreateProcess(lpszBinaryPathName, CMD_EXENAME, NULL,NULL,TRUE,0,NULL,Path,&sinfo,&pinfo)) {
LogService("Error: CreateProcess:start");
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
m_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
m_ServiceStatus.dwServiceSpecificExitCode = 0;
SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);
return;
}
//CloseHandle(hWrite);
LogService("Created vPBXW process");
//read pipe
/*
char buffer[4096] = {0};
DWORD bytesRead = 0;
int i =1;
while (3)
{
i = i -1;
BOOL ret = ReadFile(hRead,buffer,4095,&bytesRead,NULL);
if (ret == NULL){
LogService("Read return NULL");
break;
}
if(ret == 0){
LogService("Read return 0");
break;
}
if(bytesRead == 0){
LogService("Read size 0");
}
else{
LogService("Read Success");
buffer[bytesRead]=0;
LogService(buffer);
}
}
//-----
*/
if(!TestTs(START_DELAY,COUNT_DELAY,TIME_DELAY)){
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
// CloseHandle(hRead);
return;
}
m_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
if (!SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus)) {
LogService("Error: SetServiceStatus:SERVICE_RUNNING");
return;
}
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
//CloseHandle(hRead);
return;
}
BOOL EndService()
{
PROCESS_INFORMATION pinfo;
STARTUPINFO sinfo;
ZeroMemory(&sinfo, sizeof(sinfo));
sinfo.cb = sizeof(sinfo);
char strDir[256];
strcpy(strDir,Path);
strcat(strDir,STOP_EXENAME);
LPCTSTR lpszBinaryPathName=strDir;
if(!CreateProcess(lpszBinaryPathName, CMD_EXENAME, NULL,NULL,FALSE,0,NULL,Path,&sinfo,&pinfo)) {
LogService("Error: CreateProcess:stop");
return false;
}
LogService("Service Stop...");
LogService("Service Stop OK");
CloseHandle(pinfo.hThread);
CloseHandle(pinfo.hProcess);
return true;
}
void WINAPI ServiceCtrlHandler(DWORD Opcode)
{
switch(Opcode)
{
case SERVICE_CONTROL_STOP:
m_ServiceStatus.dwWin32ExitCode = 0;
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
SetServiceStatus (m_ServiceStatusHandle,&m_ServiceStatus);
bRunning=false;
EndService();
break;
case SERVICE_CONTROL_SHUTDOWN:
bRunning=false;
EndService();
char strDir[256];
strcpy(strDir,Path);
strcat(strDir,FLAG_FILENAME);
remove(strDir);
break;
case SERVICE_CONTROL_INTERROGATE:
break;
}
return;
}
BOOL InstallService(int flag)
{
HANDLE schSCManager,schService;
schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL) {
printf("Error Installing Service\n");
LogService("Error: Installing Service:OpenSCManager");
return false;
}
char strDir[256];
strcpy(strDir,Path);
strcat(strDir,SERVICE_EXENAME);
LPCTSTR lpszBinaryPathName=strDir;
schService = CreateService(schSCManager,
SERVICE_NAME,
SERVICE_DISPNAME,
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
lpszBinaryPathName, // 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("Error Installing Service\n");
LogService("Error: Installing Service:CreateService");
CloseServiceHandle(schSCManager);
return false;
}
printf("Service Installed OK\n");
LogService("Service Installed OK");
if(flag == 1){
ChangeServiceConfig(schService,SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL,NULL,NULL,NULL,NULL,NULL);
}
char description[] = SERVICE_DESCRIPTIONNAME;
SERVICE_DESCRIPTION svrDescription;
svrDescription.lpDescription = description;
ChangeServiceConfig2(schService,SERVICE_CONFIG_DESCRIPTION,&svrDescription);
if (!StartService(schService, 0, NULL)) {
printf("Error Start Service\n");
LogService("Error: Start Service:StartService");
}
else{
printf("Service Startup...\n");
WaitTsStartup(START_DELAY,COUNT_DELAY,TIME_DELAY);
}
CloseServiceHandle(schService);
CloseServiceHandle(schSCManager);
return true;
}
BOOL DeleteService()
{
HANDLE schSCManager;
SC_HANDLE hService;
SERVICE_STATUS ServStat;
schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL){
printf("Error Uninstalling Service\n");
LogService("Error: Uninstalling Service:OpenSCManager");
return false;
}
hService=OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (hService == NULL) {
printf("Error Uninstalling Service\n");
LogService("Error: Uninstalling Service:OpenService");
CloseServiceHandle(schSCManager);
return false;
}
if(GetStatus(hService) != SERVICE_STOPPED) {
if (!ControlService(hService, SERVICE_CONTROL_STOP, &ServStat)) {
printf("Error Stop Service\n");
LogService("Error: Stop Service:ControlService");
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
return false;
}
printf("Service Stop...\n");
LogService("Service Stop...");
Sleep(STOP_DELAY);
printf("Service Stop OK\n");
LogService("Service Stop OK");
}
if(!DeleteService(hService)) {
printf("Error Uninstalling Service\n");
LogService("Error: Uninstalling Service:DeleteService");
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
return false;
}
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
printf("Service Uninstalled OK\n");
LogService("Service Uninstalled OK");
return true;
}
BOOL ChangeService()
{
HANDLE schSCManager;
SC_HANDLE hService;
schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL){
printf("Error Change Service\n");
LogService("Error: Change Service:OpenSCManager");
return false;
}
hService=OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (hService == NULL) {
printf("Error Change Service\n");
LogService("Error: Change Service:OpenService");
CloseServiceHandle(schSCManager);
return false;
}
DWORD dwSize;
LPQUERY_SERVICE_CONFIG lpConfig;
lpConfig = (LPQUERY_SERVICE_CONFIG) LocalAlloc(LPTR, 1024);
if (!QueryServiceConfig(hService, lpConfig, 1024, &dwSize))
{
CloseServiceHandle(hService);
printf ("Query service config failed!\n");
LogService("Query service config failed!");
return false;
}
if(lpConfig->dwServiceType == SERVICE_WIN32_OWN_PROCESS ){
ChangeServiceConfig(hService,SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS, SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL,NULL,NULL,NULL,NULL,NULL);
printf("Service can interact with desktop\n");
LogService("Service can interact with desktop");
}
if(lpConfig->dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS) ){
ChangeServiceConfig(hService,SERVICE_WIN32_OWN_PROCESS , SERVICE_NO_CHANGE, SERVICE_NO_CHANGE, NULL, NULL,NULL,NULL,NULL,NULL,NULL);
printf("Service can't interact with desktop\n");
LogService("Service can't interact with desktop");
}
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
return true;
}
BOOL StartupService()
{
HANDLE schSCManager;
SC_HANDLE hService;
SERVICE_STATUS ServStat;
schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL){
printf("Error Start Service\n");
LogService("Error: Start Service:OpenSCManager");
return false;
}
hService=OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (hService == NULL) {
printf("Error Start Service\n");
LogService("Error: Start Service:OpenService");
CloseServiceHandle(schSCManager);
return false;
}
if(GetStatus(hService) != SERVICE_STOPPED) {
printf("Service already startup\n");
LogService("Error: Service already startup");
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
return false;
}
if (!StartService(hService, 0, NULL)) {
printf("Error Start Service\n");
LogService("Error: Start Service:StartService");
}
else{
printf("Service Startup...\n");
WaitTsStartup(START_DELAY,COUNT_DELAY,TIME_DELAY);
}
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
return true;
}
BOOL StopService()
{
HANDLE schSCManager;
SC_HANDLE hService;
SERVICE_STATUS ServStat;
schSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (schSCManager == NULL){
printf("Error stop Service\n");
LogService("Error: stop Service:OpenSCManager");
return false;
}
hService=OpenService(schSCManager, SERVICE_NAME, SERVICE_ALL_ACCESS);
if (hService == NULL) {
printf("Error stop Service\n");
LogService("Error: stop Service:OpenService");
CloseServiceHandle(schSCManager);
return false;
}
if(GetStatus(hService) != SERVICE_STOPPED) {
if (!ControlService(hService, SERVICE_CONTROL_STOP, &ServStat)) {
printf("Error Stop Service\n");
LogService("Error: Stop Service:ControlService");
}
else{
printf("Service Stop...\n");
Sleep(STOP_DELAY);
printf("Service Stop OK\n");
}
}
else{
printf("Service already stop\n");
LogService("Error: Service already stop");
}
CloseServiceHandle(hService);
CloseServiceHandle(schSCManager);
return true;
}
DWORD GetStatus(SC_HANDLE service)
{
BOOL SUCCESS;
SERVICE_STATUS status;
DWORD CurrentState;
SUCCESS = QueryServiceStatus(service, &status);
switch(status.dwCurrentState)
{
case SERVICE_RUNNING:
CurrentState = SERVICE_RUNNING;
break;
case SERVICE_STOPPED:
CurrentState = SERVICE_STOPPED;
break;
case SERVICE_PAUSED:
CurrentState = SERVICE_PAUSED;
break;
case SERVICE_CONTINUE_PENDING:
CurrentState = SERVICE_CONTINUE_PENDING;
break;
case SERVICE_PAUSE_PENDING:
CurrentState = SERVICE_PAUSE_PENDING;
break;
case SERVICE_START_PENDING:
CurrentState = SERVICE_START_PENDING;
break;
case SERVICE_STOP_PENDING:
CurrentState = SERVICE_STOP_PENDING;
break;
default:
break;
}
return CurrentState;
}
void LogService(char* error)
{
FILE* fp = NULL;
char strDir[256];
strcpy(strDir,Path);
strcat(strDir,LOG_FILENAME);
LPCTSTR lpszBinaryPathName=strDir;
char* fileName = strDir;
time_t currentTime = time(NULL);
char* cTime = ctime(¤tTime);
fp = fopen(fileName, "a");
fprintf(fp, "%s%s\n\n", cTime, error);
fflush(fp);
fclose(fp);
}
BOOL QueryReg ()
{
BOOL ret = true;
HKEY hKey;
DWORD dwType=REG_SZ;
DWORD dwLength=256;
struct HKEY__*RootKey;
TCHAR *SubKey;
TCHAR *KeyName;
TCHAR *ValueName;
RootKey = HKEY_LOCAL_MACHINE;
SubKey = REG_ITEM;
ValueName= REG_KEY;
if(RegOpenKeyEx(RootKey,SubKey,0,KEY_READ,&hKey)==ERROR_SUCCESS) {
if(RegQueryValueEx(hKey,ValueName,NULL,&dwType,(unsigned char *)Path,&dwLength)!=ERROR_SUCCESS) {
printf("Registry Query Error\n");
LogService("Error: QueryReg:RegQueryValueEx ");
ret = false;
}
RegCloseKey(hKey);
}
else {
printf("Registry Query Error\n");
LogService("Error: OpenReg:RegOpenKeyEx ");
ret = false;
}
return ret;
}
BOOL TestTs(int sleep, int count, int sec)
{
FILE* fp = NULL;
char strDir[256];
strcpy(strDir,Path);
strcat(strDir,FLAG_FILENAME);
LPCTSTR lpszBinaryPathName=strDir;
char* fileName = strDir;
int i = count;
Sleep(sleep);
while(i) {
Sleep(sec);
fp = fopen(fileName, "r");
if(fp != NULL) {
bRunning=true;
LogService("TS Startup OK");
LogService("Service Startup OK");
fclose(fp);
return true;
}
i = i - 1;
}
MessageBox(NULL, "Port 8080 may be in use by another application or service.", "TS Startup failure", MB_DEFAULT_DESKTOP_ONLY);
LogService("Error: TS Startup failure");
m_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
m_ServiceStatus.dwCheckPoint = 0;
m_ServiceStatus.dwWaitHint = 0;
//m_ServiceStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
//m_ServiceStatus.dwServiceSpecificExitCode = 1;
m_ServiceStatus.dwWin32ExitCode = 0;
m_ServiceStatus.dwServiceSpecificExitCode = 0;
SetServiceStatus (m_ServiceStatusHandle, &m_ServiceStatus);
return false;
}
BOOL WaitTsStartup(int sleep, int count, int sec){
FILE* fp = NULL;
char strDir[256];
strcpy(strDir,Path);
strcat(strDir,FLAG_FILENAME);
LPCTSTR lpszBinaryPathName=strDir;
char* fileName = strDir;
int i = count;
Sleep(sleep);
while(i) {
Sleep(sec);
fp = fopen(fileName, "r");
if(fp != NULL) {
printf("Service Startup OK\n");
fclose(fp);
return true;
}
i = i - 1;
}
printf("Error: Service startup failure: TS startup failure\n");
return false;
}
示例代码:这个例子是MSDN上的,用来停止一个有其他服务依赖的Service。
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
threadbased.c
Description:
This sample illustrates how to manage threads in a Windows NT
System Service. To install or remove the service, build the
executable as a Win32 Console Application and use the SC utility
in the Windows NT Resource Kit. See the Simple Service Sample
in the Win32 SDK for sample code to install and remove a service.
The following import libraries are required:
advapi32.lib
user32.lib
Dave McPherson (davemm) 11-March-98
--*/
#include
#include
#include
//
// Global variables.
//
HANDLE hStopEvent;
HANDLE hThreads[3] = {NULL,NULL,NULL};
LPTSTR lpszServiceName;
SERVICE_STATUS_HANDLE ssh;
//
// Function prototypes.
//
DWORD WINAPI ThreadProc(LPVOID lpParameter);
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);
void WINAPI Service_Ctrl(DWORD dwCtrlCode);
void ErrorStopService(LPTSTR lpszAPI);
void SetTheServiceStatus(DWORD dwCurrentState,DWORD dwWin32ExitCode,
DWORD dwCheckPoint, DWORD dwWaitHint);
//
// _tmain - Entry point for service. Calls StartServiceCtrlDispatcher
// and then blocks until the ServiceMain function returns.
//
void _tmain(int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ste[] =
{{TEXT(""),(LPSERVICE_MAIN_FUNCTION)Service_Main},{NULL, NULL}};
OutputDebugString(TEXT("Entered service code\n"));
if (!StartServiceCtrlDispatcher(ste))
{
TCHAR error[256];
wsprintf(error,
TEXT("Error code for StartServiceCtrlDispatcher: %u.\n"),
GetLastError());
OutputDebugString(error);
}
else
OutputDebugString(TEXT("StartServiceCtrlDispatcher returned!\n"));
}
//
// Service_Main - This is called by the service control manager after
// the call to StartServiceCtrlDispatcher.
//
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
DWORD ThreadId;
DWORD t;
DWORD dwWaitRes;
// Obtain the name of the service.
lpszServiceName = lpszArgv[0];
// Register the service ctrl handler.
ssh = RegisterServiceCtrlHandler(lpszServiceName,
(LPHANDLER_FUNCTION)Service_Ctrl);
// Create the event to signal the service to stop.
hStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (hStopEvent == NULL)
ErrorStopService(TEXT("CreateEvent"));
/*******************************************************************/
// This is where you can put one-time work that you want to complete
// before starting.
for (t=0;t<3;t++)
{
hThreads[t] = CreateThread(NULL,0,ThreadProc,
(LPVOID)t,0,&ThreadId);
if (hThreads[t] == INVALID_HANDLE_VALUE)
ErrorStopService(TEXT("CreateThread"));
}
/*******************************************************************/
// The service has started.
SetTheServiceStatus(SERVICE_RUNNING, 0, 0, 0);
OutputDebugString(TEXT("SetTheServiceStatus, SERVICE_RUNNING\n"));
//
// Main loop for the service. <-----------------------------
//
while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0){
/***************************************************************/
// Main loop for service.
/***************************************************************/
}
// Now wait for threads to exit.
for (t=1;TRUE;t++)
{
if ((dwWaitRes = WaitForMultipleObjects(3,hThreads,TRUE,1000))
== WAIT_OBJECT_0)
break;
else if((dwWaitRes == WAIT_FAILED)||(dwWaitRes==WAIT_ABANDONED))
ErrorStopService(TEXT("WaitForMultipleObjects"));
else
SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
}
// close the event handle and the thread handle
if (!CloseHandle(hStopEvent))
ErrorStopService(TEXT("CloseHandle"));
if (!CloseHandle(hThreads[0]))
ErrorStopService(TEXT("CloseHandle"));
if (!CloseHandle(hThreads[1]))
ErrorStopService(TEXT("CloseHandle"));
if (!CloseHandle(hThreads[2]))
ErrorStopService(TEXT("CloseHandle"));
// Stop the service.
OutputDebugString(TEXT("SetTheServiceStatus, SERVICE_STOPPED\n"));
SetTheServiceStatus(SERVICE_STOPPED, NO_ERROR, 0, 0);
}
//
// Service_Ctrl - Where control signals from the Service Control Mgr
// are handled.
//
void WINAPI Service_Ctrl(DWORD dwCtrlCode)
{
DWORD dwState = SERVICE_RUNNING;
switch(dwCtrlCode)
{
case SERVICE_CONTROL_STOP:
dwState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_SHUTDOWN:
dwState = SERVICE_STOP_PENDING;
break;
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
// Set the status of the service.
SetTheServiceStatus(dwState, NO_ERROR, 0, 0);
OutputDebugString(
TEXT("SetTheServiceStatus, Service_Ctrl function\n"));
// Tell service_main thread to stop.
if ((dwCtrlCode == SERVICE_CONTROL_STOP) ||
(dwCtrlCode == SERVICE_CONTROL_SHUTDOWN))
{
if (!SetEvent(hStopEvent))
ErrorStopService(TEXT("SetEvent"));
else
OutputDebugString(TEXT("Signal service_main thread\n"));
}
}
//
// ThreadProc - Thread procedure for all three worker threads.
//
DWORD WINAPI ThreadProc(LPVOID lpParameter)
{
INT nThreadNum = (INT)lpParameter;
TCHAR szOutput[25];
while(WaitForSingleObject(hStopEvent, 1000) != WAIT_OBJECT_0)
{
// Just to have something to do, it will beep every second.
Sleep(1000);
wsprintf(szOutput,TEXT("\nThread %d says Beep\n"),nThreadNum);
OutputDebugString(szOutput); //Send visual to debugger.
}
return 0;
}
//
// 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"));
}
//
// ErrorStopService - Use this when there is an API error or bad
// situation this just ends the service and
// displays an error message to the debugger.
//
void ErrorStopService(LPTSTR lpszAPI)
{
INT t;
TCHAR buffer[256] = TEXT("");
TCHAR error[1024] = TEXT("");
LPVOID lpvMessageBuffer;
DWORD dwWaitRes;
wsprintf(buffer,TEXT("API = %s, "), lpszAPI);
lstrcat(error, buffer);
ZeroMemory(buffer, sizeof(buffer));
wsprintf(buffer,TEXT("error code = %d, "), GetLastError());
lstrcat(error, buffer);
// Obtain the error string.
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR)&lpvMessageBuffer, 0, NULL);
ZeroMemory((LPVOID)buffer, (DWORD)sizeof(buffer));
wsprintf(buffer,TEXT("message = %s"), (TCHAR *)lpvMessageBuffer);
lstrcat(error, buffer);
// Free the buffer allocated by the system.
LocalFree(lpvMessageBuffer);
// Write the error string to the debugger.
OutputDebugString(error);
// If you have threads running, tell them to stop. Something went
// wrong, and you need to stop them so you can inform the SCM.
SetEvent(hStopEvent);
// Wait for the threads to stop.
for (t=1;TRUE;t++)
{
if ((dwWaitRes = WaitForMultipleObjects(3,hThreads,TRUE,1000))
== WAIT_OBJECT_0)
break;
else if ((dwWaitRes== WAIT_FAILED)||(dwWaitRes== WAIT_ABANDONED))
break; // Our wait failed
else
{
SetTheServiceStatus(SERVICE_STOP_PENDING, 0, t, 3000);
}
}
// Stop the service.
SetTheServiceStatus(SERVICE_STOPPED, GetLastError(), 0, 0);
}