// ServiceTest.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <winsvc.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
CWinApp theApp;
using namespace std;
//***********************************************************************************//
//变量声明
//***********************************************************************************//
//服务内部名
#define APPNAME "DBDataBackup"
//服务显示名
#define SZSERVICENAME _T("数据库定时清理服务")
//服务状态
SERVICE_STATUS ssStatus;
//服务句柄
SERVICE_STATUS_HANDLE sshStatusHandle;
//SC句柄
SC_HANDLE schSCManager;
SC_HANDLE schService;
LPCTSTR * lpServiceArgVectors;
//服务调试标志
BOOL bDebug=FALSE;
//互斥信号量
CRITICAL_SECTION errCritical;
//服务退出事件
HANDLE hSysExitEvent = NULL;
//***********************************************************************************//
//函数声明
//服务入口函数
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv);
//服务控制处理函数
void WINAPI Service_Ctrl(DWORD dwCtrlCode);
//标准错误输出函数
void StdErrorHandler(CString errorMessage);
//服务安装处理函数
void installService();
//服务卸载处理函数
void removeService();
//服务调试处理函数
void debugService();
//写服务日志
void AddToAppLog(CString errorMessage);
//获得系统时间
CString GetSystemTime();
//服务启动处理函数
void ServiceStart();
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,DWORD dwWin32ExitCode,DWORD dwWaitHint);
//服务停止处理函数
void ServiceStop();
//服务暂停处理函数
void ServicePause();
//服务继续处理函数
void ServiceContinue();
//***********************************************************************************//
int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
//初始化信号量
InitializeCriticalSection(&errCritical);
//初始化MFC
if (!AfxWinInit(::GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
cerr << _T("致命错误: MFC初始化失败") << endl;
return -1;
}
else
{
//注册服务入口,服务名、服务入口函数
//Windows执行服务入口在Service_Main
SERVICE_TABLE_ENTRY dispatchTable[2]={
{SZSERVICENAME,Service_Main},
{ NULL,NULL}};
//获得当前可执行文件目录和文件名
char exeFullPath[MAX_PATH];
GetModuleFileName(NULL,exeFullPath,MAX_PATH);
for(int i=strlen(exeFullPath); i>=0; i--)
{
if(exeFullPath[i]=='//')
{
exeFullPath[i]=0;
break;
}
}
//设置当前进程的当前路径为服务的路径
SetCurrentDirectory(exeFullPath);
//处理命令行参数
if(argc>1&&*argv[1]=='-')
{
//参数为-install,安装服务
if(_stricmp("install",argv[1]+1)==0)
{
//执行安装服务
installService();
}
//参数为-remove,卸载服务
else if(_stricmp("remove",argv[1]+1)==0)
{
//执行卸载服务
removeService();
}
//参数为-debug,调试服务
else if(_stricmp("debug",argv[1]+1)==0)
{
//置服务调试标志
bDebug=TRUE;
//执行调试服务
debugService();
}
else
{
//参数格式不合法
printf("输入 %s - install 来安装服务 /n",APPNAME);
printf("输入 %s - remove 来卸载服务 /n",APPNAME);
printf("输入 %s - debug 来调试服务 /n",APPNAME);
}
exit(0);
}
//如果未能和上面的如何参数匹配,则可能是服务控制管理程序来启动该程序。
CString errmessage;
printf("/n已调用StartServiceCtrlDispatcher./n");
printf("这可能需要几秒钟,请等待./n");
//立即调用StartServiceCtrlDispatcher函数。
if(!StartServiceCtrlDispatcher(dispatchTable))
{
StdErrorHandler("调用StartServiceCtrlDispatcher失败.");
AddToAppLog(errmessage);
}
else
{
StdErrorHandler("调用StartServiceCtrlDispatcher成功.");
AddToAppLog(errmessage);
}
}
return 0;
}
//******************************************************//
//服务入口函数
//******************************************************//
void WINAPI Service_Main(DWORD dwArgc, LPTSTR *lpszArgv)
{
//注册服务控制处理函数,服务APPNAME,控制函数Service_Ctrl
sshStatusHandle=RegisterServiceCtrlHandler(APPNAME,Service_Ctrl);
//如果注册失败
if(!sshStatusHandle)
{
CString err;
err="服务注册失败";
StdErrorHandler(err);
goto cleanup;
return;
}
//初始化 SERVICE_STATUS 结构中的成员
ssStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS;
ssStatus.dwServiceSpecificExitCode=0;
//更新服务状态为正在启动SERVICE_START_PENDING
if(!ReportStatusToSCMgr(
SERVICE_START_PENDING, //服务状态,The service is starting.
NO_ERROR, //退出码
3000)) //等待时间
{
goto cleanup; //更新服务状态失败则转向 cleanup
}
//服务启动主函数
ServiceStart();
return;
cleanup:
//把服务状态更新为 SERVICE_STOPPED,并退出。
if(sshStatusHandle)
{
ReportStatusToSCMgr(SERVICE_STOPPED,GetLastError(),0);
}
}
//******************************************************//
//服务控制处理函数
//******************************************************//
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;
break;
}
//暂停服务
case SERVICE_CONTROL_PAUSE:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
ServicePause(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_PAUSED;
break;
}
//继续服务
case SERVICE_CONTROL_CONTINUE:
{
ReportStatusToSCMgr(SERVICE_STOP_PENDING,NO_ERROR,500);
ServiceContinue(); //由具体的服务程序实现
ssStatus.dwCurrentState=SERVICE_RUNNING;
break;
}
//更新服务状态
case SERVICE_CONTROL_INTERROGATE:
{
break;
}
//无效控制码
default:
{
break;
}
}
//当前服务状态
ReportStatusToSCMgr(ssStatus.dwCurrentState,NO_ERROR,0);
}
//******************************************************//
//服务安装处理函数
//******************************************************//
void installService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
TCHAR szPath[512];
CString err;
//得到程序磁盘文件的路径
if(GetModuleFileName(NULL,szPath,512)==0)
{
err.Format("不能安装 %s - %s /n",TEXT(APPNAME),GetLastError());
StdErrorHandler(err);
return;
}
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//登记服务程序
schService=CreateService(
schSCManager, //服务管理数据库句柄
TEXT(APPNAME), //服务名
TEXT(SZSERVICENAME), //用于显示服务的标识
SERVICE_ALL_ACCESS, //响应所有的访问请求
SERVICE_WIN32_OWN_PROCESS, //服务类型
SERVICE_AUTO_START, //启动类型
SERVICE_ERROR_NORMAL, //错误控制类型
szPath, //服务程序磁盘文件的路径
NULL, //服务不属于任何组
NULL, //没有tag标识符
NULL, //启动服务所依赖的服务或服务组,这里仅仅是一个空字符串
NULL, //LocalSystem 帐号
NULL);
if(schService)
{
err.Format("%s 已安装.",TEXT(APPNAME));
StdErrorHandler(err);
CloseServiceHandle(schService);
}
else
{
err.Format("创建服务失败,服务可能已经安装");
StdErrorHandler(err);
}
CloseServiceHandle(schSCManager);
}
else
{
err.Format("打开SCManager失败");
StdErrorHandler(err);
}
CloseServiceHandle(schSCManager);
return;
}
//******************************************************//
//服务卸载处理函数
//******************************************************//
void removeService()
{
SC_HANDLE schService;
SC_HANDLE schSCManager;
CString err;
//打开服务管理数据库
schSCManager=OpenSCManager(
NULL, //本地计算机
NULL, //默认的数据库
SC_MANAGER_ALL_ACCESS //要求所有的访问权
);
if(schSCManager)
{
//获取服务程序句柄
schService=OpenService(
schSCManager, //服务管理数据库句柄
TEXT(APPNAME), //服务名
SERVICE_ALL_ACCESS //响应所有的访问请求
);
if(schService)
{
//试图停止服务
if(ControlService(
schService, //服务程序句柄
SERVICE_CONTROL_STOP, //停止服务请求码
&ssStatus //接收最后的服务状态信息
))
{
err.Format("停止 %s 中",TEXT(APPNAME));
StdErrorHandler(err);
Sleep(1000);
//等待服务停止
while(QueryServiceStatus(schService,&ssStatus))
{
if(SERVICE_STOP_PENDING==ssStatus.dwCurrentState)
{
cout<<".";
Sleep(1000);
}
else
{
break;
}
}
if(SERVICE_STOPPED==ssStatus.dwCurrentState)
{
err.Format("/n %s 已被停止. /n",TEXT(APPNAME));
StdErrorHandler(err);
}
else
{
err.Format("/n %s 试图停止失败. /n",TEXT(APPNAME));
StdErrorHandler(err);
}
}
//删除已安装的服务程序安装
if(DeleteService(schService))
{
err.Format("%s 已经被卸载. /n",TEXT(APPNAME));
StdErrorHandler(err);
}
else
{
err.Format("删除服务失败");
StdErrorHandler(err);
}
CloseServiceHandle(schService);
}
else
{
err.Format("连接服务失败,不存在此服务");
StdErrorHandler(err);
}
CloseServiceHandle(schSCManager);
}
else
{
err.Format("打开SCManager失败");
StdErrorHandler(err);
}
}
//******************************************************//
//服务启动处理函数
//******************************************************//
void ServiceStart()
{
//默认监测周期是3分钟
int nWaitTime=3000;
// 向SCM报告目前的状态
ReportStatusToSCMgr(SERVICE_START_PENDING, NO_ERROR, 20000);
if(!(hSysExitEvent = CreateEvent(NULL, TRUE, FALSE, NULL))){
StdErrorHandler("服务退出事件创建失败");
return;
}
// 向SCM报告当前进度,运行状态
ReportStatusToSCMgr(SERVICE_RUNNING, NO_ERROR, 0);
StdErrorHandler("服务已启动");
long int times=20;
while(times)
{
times--;
cout<<times<<",";
// 等待停止标志
if(WaitForSingleObject(hSysExitEvent, nWaitTime) == WAIT_OBJECT_0)
{
// 通知SCM服务正在结束
ReportStatusToSCMgr(SERVICE_STOP_PENDING, NO_ERROR, 10000);
StdErrorHandler("数据库定时清理服务正在终止...");
return;
}
Beep(1000,200);
Sleep(nWaitTime);
}
}
//******************************************************//
//服务停止处理函数
//******************************************************//
void ServiceStop()
{
SetEvent(hSysExitEvent);
}
//******************************************************//
//服务暂停处理函数
//******************************************************//
void ServicePause()
{}
//******************************************************//
//服务继续处理函数
//******************************************************//
void ServiceContinue()
{}
//******************************************************//
//服务日志记录处理函数
//******************************************************//
void AddToAppLog(CString errorMessage)
{
}
//******************************************************//
//服务调试处理函数
//******************************************************//
void debugService()
{
ServiceStart();
}
//******************************************************//
//返回当前系统时间
//******************************************************//
CString GetSystemTime()
{
SYSTEMTIME systemTime;
CString timeString;
GetLocalTime(&systemTime);
timeString.Format("%04d年%02d月%02d日 %02d:%02d:%02d",
systemTime.wYear, systemTime.wMonth, systemTime.wDay,
systemTime.wHour, systemTime.wMinute, systemTime.wSecond,
systemTime.wMilliseconds);
return timeString;
}
/*******************************************************
名称:ReportStatusToSCMgr
参数:
dwCurrentState:当前状态
dwWin32ExitCode:win32退出码
dwWaitHint: 该状态可能持续的时间
返回值:BOOL
功能:向Service Control Manager报告状态
*******************************************************/
BOOL ReportStatusToSCMgr(DWORD dwCurrentState,
DWORD dwWin32ExitCode,
DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
BOOL fResult = TRUE;
if(!bDebug) {
// 如果在初始化状态,不接受任何命令
if(dwCurrentState == SERVICE_START_PENDING)
ssStatus.dwControlsAccepted = 0;
else
ssStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
ssStatus.dwCurrentState = dwCurrentState;
ssStatus.dwWin32ExitCode = dwWin32ExitCode;
ssStatus.dwWaitHint = dwWin32ExitCode;
// 如果状态为正在运行或已经停止,则checkpoit为0
if((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED)){
ssStatus.dwCheckPoint = 0;
dwCheckPoint = 1;
}
else
ssStatus.dwCheckPoint = dwCheckPoint++;
// 向服务管理器报告当前状态
if(!(fResult = SetServiceStatus(sshStatusHandle, &ssStatus))) {
// StdErrorHandler(COMMANDHANDLER, "向SCM报告状态失败", SERVICEFLAG);
}
}
return fResult;
}
//******************************************************//
//报告系统错误
//******************************************************//
void StdErrorHandler(CString errorMessage)
{
EnterCriticalSection(&errCritical);
AddToAppLog(errorMessage);
printf("%s:%s/n",GetSystemTime(),errorMessage);
LeaveCriticalSection(&errCritical);
}