当前位置: 首页 > news >正文

windows服务开发

参考博客:
C++调用StartService启动服务失败1053分析与解决
StartServiceCtrlDispatcher函数
指定的服务已标记为删除
安装和卸载服务

windows服务开发分为两个步骤:

  1. 编写服务程序.exe
  2. 安装服务程序,使在services.msc里面可以看见自己的服务

编写服务程序

问:为什么需要编写服务程序?是不是随便一个exe都可以作为服务程序运行?
答:服务程序必须主动调用StartServiceCtrlDispatcher上报自己的当前状态,否则服务控制台由于不知道服务的运行状态的而报错,例如:StartService启动服务失败1053。所以开发服务程序的时候我们必须通过StartServiceCtrlDispatcher上报状态并且处理服务事件。

  1. 调用StartServiceCtrlDispatcher,设置服务事件回调。如果程序作为非服务状态运行则会返回错误:ERROR_FAILED_SERVICE_CONTROLLER_CONNECT,程序会一直阻塞运行,直至SERVICE_STOPPED状态才返回
  2. 注册并相应服务控制事件,例如服务控制台停止事件
  3. 上报服务当前状态

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");
}

编写服务安装和卸载程序

注意步骤:

  1. 打开服务管理器OpenSCManager
  2. 创建或者打开服务:CreateService OpenService
  3. 启动服务:StartService
  4. 查询服务状态: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:如果服务管理器打开了,则删除服务管理器会失败[指定的服务已标记为删除]。必须关闭重试。

相关文章:

  • leetcode-每日一题-二进制表示中质数个计算置位(简单,popcount算法)
  • 利用styleSheet,避免js手动频繁修改样式
  • 火爆的超级人工智能ChatGPT,唯独鄙视中国人
  • [附源码]Python计算机毕业设计Django医院挂号住院管理系统
  • 前端工程师常考手写面试题指南
  • 易基因|m6A去甲基化酶ALKBH5通过降低PHF20 mRNA甲基化抑制结直肠癌进展 | 肿瘤研究
  • Git 在gitconfig 中的多用户配置
  • 数据结构的起航,用C语言实现一个简约却不简单的顺序表!(零基础也能看懂)
  • 职场经验:为什么要学习自动化测试?过来人告诉你答案
  • 2022系统分析师论文真题
  • C++ Reference: Standard C++ Library reference: Containers: deque: deque
  • RabbitMQ——RabbitMQ的六种工作模式详解
  • 测试工程师面试题
  • HashMap部分源码解析
  • Expedita dolor commodi laborum quos.Distinctio aliquam voluptatum sit.
  • 使用openssl工具生成CSR文件
  • Java 反射总结
  • Kafka(四)- Kafka 生产者
  • Electron结合Vue使用说明
  • 另一种在ARM/x86架构处理器上部署WebDAV服务器的方法
  • 电加热油锅炉工作原理_电加热导油
  • 大型电蒸汽锅炉_工业电阻炉
  • 燃气蒸汽锅炉的分类_大连生物质蒸汽锅炉
  • 天津市维修锅炉_锅炉汽化处理方法
  • 蒸汽汽锅炉厂家_延安锅炉厂家
  • 山西热水锅炉厂家_酒店热水 锅炉
  • 蒸汽锅炉生产厂家_燃油蒸汽发生器
  • 燃煤锅炉烧热水_张家口 淘汰取缔燃煤锅炉
  • 生物质锅炉_炉
  • 锅炉天然气_天燃气热风炉