windows服务开发
参考博客:
C++调用StartService启动服务失败1053分析与解决
StartServiceCtrlDispatcher函数
指定的服务已标记为删除
安装和卸载服务
windows服务开发分为两个步骤:
- 编写服务程序
.exe
- 安装服务程序,使在
services.msc
里面可以看见自己的服务
编写服务程序
问:为什么需要编写服务程序?是不是随便一个exe都可以作为服务程序运行?
答:服务程序必须主动调用StartServiceCtrlDispatcher
上报自己的当前状态,否则服务控制台由于不知道服务的运行状态的而报错,例如:StartService启动服务失败1053。所以开发服务程序的时候我们必须通过StartServiceCtrlDispatcher
上报状态并且处理服务事件。
- 调用
StartServiceCtrlDispatcher
,设置服务事件回调。如果程序作为非服务状态运行则会返回错误:ERROR_FAILED_SERVICE_CONTROLLER_CONNECT
,程序会一直阻塞运行,直至SERVICE_STOPPED
状态才返回 - 注册并相应服务控制事件,例如服务控制台停止事件
- 上报服务当前状态
CMscSvc.h
:
//如果作为服务程序,需要向服务报告自己的状态,否则服务控制台是不知道服务状态,会失败
class CMscSvc
{
public:
//如果作为服务程序,需要注册服务
static void RegisterSvc(std::string msc_name);
//上报启动成功事件
static void ReportStart();
//上报停止成功事件
static void ReportStop();
private:
//如果作为服务程序需要报告自己的状态
static void ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
//服务主处理函数,内部添加自己的业务逻辑代码。可包装到doWork函数内部
static VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv);
//响应服务控制台事件,例如停止
static VOID WINAPI SvcCtrlHandler(DWORD dwCtrl);
static SERVICE_STATUS_HANDLE s_gSvcStatusHandle;
static SERVICE_STATUS s_gSvcStatus;
static std::string m_msc_name;
};
CMscSvc.cpp
:
SERVICE_STATUS_HANDLE CMscSvc::s_gSvcStatusHandle;
SERVICE_STATUS CMscSvc::s_gSvcStatus;
std::string CMscSvc::m_msc_name = "";
void CMscSvc::RegisterSvc(std::string msc_name)
{
m_msc_name = msc_name;
char szName[MAX_PATH] = "";
_stprintf_s<MAX_PATH>(szName, "%s", m_msc_name.c_str());
SERVICE_TABLE_ENTRY DispatchTable[] ={
{ szName, (LPSERVICE_MAIN_FUNCTION)SvcMain },
{ NULL, NULL }};
if (!StartServiceCtrlDispatcher(DispatchTable))
{
DWORD dwErrcode = GetLastError();
DebugPrint(_T("StartServiceCtrlDispatcher failed,errcode:%d"), dwErrcode);
}
}
void CMscSvc::ReportStart()
{
ReportSvcStatus(SERVICE_RUNNING, 0, 0);
}
void CMscSvc::ReportStop()
{
ReportSvcStatus(SERVICE_STOPPED, 0, 0);
}
VOID WINAPI CMscSvc::SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
// Register the handler function for the service
s_gSvcStatusHandle = RegisterServiceCtrlHandler(m_msc_name.c_str(), SvcCtrlHandler);
if (!s_gSvcStatusHandle)
{
DWORD dwErrcode = GetLastError();
DebugPrint(_T("RegisterServiceCtrlHandler failed,errcode:%d"), dwErrcode);
return;
}
// These SERVICE_STATUS members remain as set here
s_gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
s_gSvcStatus.dwServiceSpecificExitCode = 0;
// Report initial status to the SCM
ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
//上报启动成功状态
ReportStart();
//开始处理业务
doWork();
}
void CMscSvc::ReportSvcStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
static DWORD dwCheckPoint = 1;
// Fill in the SERVICE_STATUS structure.
s_gSvcStatus.dwCurrentState = dwCurrentState;
s_gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
s_gSvcStatus.dwWaitHint = dwWaitHint;
if (dwCurrentState == SERVICE_START_PENDING)
s_gSvcStatus.dwControlsAccepted = 0;
else s_gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
if ((dwCurrentState == SERVICE_RUNNING) ||
(dwCurrentState == SERVICE_STOPPED))
s_gSvcStatus.dwCheckPoint = 0;
else s_gSvcStatus.dwCheckPoint = dwCheckPoint++;
SetServiceStatus(s_gSvcStatusHandle, &s_gSvcStatus);
}
//每当使用controlService函数向服务发送控制代码时,由SCM调用
VOID WINAPI CMscSvc::SvcCtrlHandler(DWORD dwCtrl)
{
// Handle the requested control code.
switch (dwCtrl)
{
case SERVICE_CONTROL_STOP:
{
ReportSvcStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
//退出业务处理逻辑
exitWork()
//上报停止状态成功
ReportStop()
return;
}
case SERVICE_CONTROL_INTERROGATE:
break;
default:
break;
}
}
调用
void _main()
{
CMscSvc::RegisterSvc("testSvr");
}
编写服务安装和卸载程序
注意步骤:
- 打开服务管理器
OpenSCManager
- 创建或者打开服务:
CreateService
OpenService
- 启动服务:
StartService
- 查询服务状态:
QueryServiceStatus
CMsc.h
:
class CMsc
{
public:
CMsc(std::string msc_name,std::string exe_full_path,std::string exe_param = "",std::string msc_desc = "");
~CMsc();
BOOL start();
BOOL stop(BOOL bUnInstall = FALSE/*是否卸载*/);
private:
std::string m_msc_name;
std::string m_msc_display_name;
std::string m_msc_desc;
std::string m_exe_cmd;
};
CMsc.cpp
:
class CSafeSCHandle
{
public:
CSafeSCHandle(const SC_HANDLE& hscm) :m_hscm(hscm){};
~CSafeSCHandle()
{
if (m_hscm)
{
CloseServiceHandle(m_hscm);
}
}
operator const SC_HANDLE&(){ return m_hscm; }
private:
const SC_HANDLE &m_hscm;
};
CMsc::CMsc(std::string msc_name,std::string exe_full_path, std::string exe_param)
{
m_msc_name = msc_name;
m_msc_display_name = m_msc_name;
m_exe_cmd = exe_full_path + _T(" ") + exe_param;
m_msc_desc = msc_desc;
DebugPrint("CMsc name:%s,exe_full_path:%s,exe_param:%s", m_msc_name.c_str(), exe_full_path.c_str(), exe_param.c_str());
}
CMsc::~CMsc()
{
}
BOOL CMsc::start()
{
//打开msc服务管理器
CSafeSCHandle hScm(OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
if (hScm == NULL)
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,start,OpenSCManager failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
//如果服务已经存在则直接start
CSafeSCHandle hService(OpenService(hScm, m_msc_name.c_str(), SERVICE_ALL_ACCESS));
if (hService != NULL)
{
SERVICE_STATUS status;
QueryServiceStatus(hService, &status);
if (status.dwCurrentState == SERVICE_RUNNING)
{
return TRUE;
}
if (StartService(hService, 0, NULL))
{
DebugPrint("CMsc name:%s,start,StartService OK", m_msc_name.c_str());
return TRUE;
}
else
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,start,StartService failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
}
//如果服务不存在则创建
CSafeSCHandle hCService(CreateService(hScm, m_msc_name.c_str(), m_msc_display_name.c_str(), SERVICE_ALL_ACCESS,
SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, m_exe_cmd.c_str(),
NULL, NULL, "", NULL, ""));
if (hCService == NULL)
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,start,CreateService failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
//设置服务描述
if (!m_msc_desc.empty())
{
SERVICE_DESCRIPTION sd;
sd.lpDescription = (char *)m_msc_desc.c_str();
ChangeServiceConfig2(hCService, SERVICE_CONFIG_DESCRIPTION, &sd);
}
SERVICE_STATUS status;
QueryServiceStatus(hCService, &status);
if (status.dwCurrentState == SERVICE_RUNNING)
{
DebugPrint("CMsc name:%s,start,StartService OK,is already runing", m_msc_name.c_str());
return TRUE;
}
if (StartService(hCService, 0, NULL))
{
DebugPrint("CMsc name:%s,start,StartService OK", m_msc_name.c_str());
return TRUE;
}
else
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,start,StartService failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
}
BOOL CMsc::stop(BOOL bUnInstall)
{
//打开msc服务管理器
CSafeSCHandle hScm(OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS));
if (hScm == NULL)
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,stop,OpenSCManager failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
//如果服务已经存在则直接start
CSafeSCHandle hService(OpenService(hScm, m_msc_name.c_str(), SERVICE_ALL_ACCESS));
if (hService == NULL)
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,stop,OpenService failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
//查询服务状态
SERVICE_STATUS status;
QueryServiceStatus(hService, &status);
if (status.dwCurrentState == SERVICE_RUNNING)
{
//停止服务
ControlService(hService, SERVICE_CONTROL_STOP, &status);
if (status.dwCurrentState != NO_ERROR)
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,stop,ControlService failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
return FALSE;
}
}
//如果卸载服务
if (bUnInstall && status.dwCurrentState == SERVICE_STOPPED)
{
if (DeleteService(hService))
{
DebugPrint("CMsc name:%s,stop,DeleteService OK", m_msc_name.c_str());
}
else
{
DWORD dwErrcode = GetLastError();
DebugPrint("CMsc name:%s,stop,DeleteService failed,errcode:%d", m_msc_name.c_str(), dwErrcode);
}
}
DebugPrint("CMsc name:%s,stop,ControlService OK", m_msc_name.c_str());
return TRUE;
}
调用
void _main()
{
//msc_name-服务名称
//exe_full_path exe的全路径
//exe_params exe的执行参数
CMsc msc(msc_name, exe_full_path, "exe_params");
//安装并启动服务
msc.start();
//停止并且卸载服务
msc.stop(TRUE);
}
此时我们就可以安装服务程序,并且在services.msc
中查看了。
Note:如果服务管理器打开了,则删除服务管理器会失败[指定的服务已标记为删除]。必须关闭重试。