当前位置:   article > 正文

windows服务开发_windows 开发系统服务

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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99

调用

void _main()
{
	CMscSvc::RegisterSvc("testSvr");
}
  • 1
  • 2
  • 3
  • 4
编写服务安装和卸载程序

注意步骤:

  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;
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155

调用

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);
	
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

此时我们就可以安装服务程序,并且在services.msc中查看了。

Note:如果服务管理器打开了,则删除服务管理器会失败[指定的服务已标记为删除]。必须关闭重试。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/69275
推荐阅读
相关标签
  

闽ICP备14008679号