C/C++ 创建windows系统服务程序
Posted 小哈龙
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C/C++ 创建windows系统服务程序相关的知识,希望对你有一定的参考价值。
Windows上面的程序可以分为前台运行和后台运行,像windows的系统服务都是属于后台程序。
那如何将一个程序变成后台运行呢?
可以在 cmd里面用sc命令来操作:Windows 服务的安装和卸载
此次重点介绍如果用c++代码创建一个Windows服务程序。
这里用到了2个创建服务的类和一个依赖头文件和一个使用类,具体解释请看注释,代码如下:
copy_disabler.h(这个为底层依赖头文件,可以不用关心具体类容)
#ifndef COPY_DISABLER_H_
#define COPY_DISABLER_H_
#define DISABLE_COPY(Type)\\
Type(const Type&) = delete;\\
Type& operator=(const Type&) = delete
#define DISABLE_MOVE(Type)\\
Type(Type&&) = delete;\\
Type& operator=(Type&&) = delete
#define DISABLE_COPY_MOVE(Type)\\
DISABLE_COPY(Type);\\
DISABLE_MOVE(Type)
#define DISABLE_COPY_AND_MOVE(Type)\\
private:\\
Type(const Type&);\\
Type& operator=(const Type&);\\
Type(Type&&);\\
Type& operator=(Type&&);
#endif // COPY_DISABLER_H_
service_base.h(这个为底层依赖头文件,可以不用关心具体类容)
#ifndef SERVICE_BASE_H_
#define SERVICE_BASE_H_
#include <windows.h>
#include <atlstr.h>
#include "copy_disabler.h"
// Base Service class used to create windows services.
class ServiceBase
public:
//DISABLE_COPY_MOVE(ServiceBase);
virtual ~ServiceBase()
// Called by windows when starting the service.
bool Run()
return RunInternal(this);
const CString& GetName() const return m_name;
const CString& GetDisplayName() const return m_displayName;
const DWORD GetStartType() const return m_dwStartType;
const DWORD GetErrorControlType() const return m_dwErrorCtrlType;
const CString& GetDependencies() const return m_depends;
// Account info service runs under.
const CString& GetAccount() const return m_account;
const CString& GetPassword() const return m_password;
protected:
ServiceBase(const CString& name,
const CString& displayName,
DWORD dwStartType,
DWORD dwErrCtrlType = SERVICE_ERROR_NORMAL,
DWORD dwAcceptedCmds = SERVICE_ACCEPT_STOP,
const CString& depends = _T(""),
const CString& account = _T(""),
const CString& password = _T(""));
void SetStatus(DWORD dwState, DWORD dwErrCode = NO_ERROR, DWORD dwWait = 0);
// TODO(Olster): Move out of class/make static.
// Writes |msg| to Windows event log.
void WriteToEventLog(const CString& msg, WORD type = EVENTLOG_INFORMATION_TYPE);
virtual void OnStart(DWORD argc, TCHAR* argv[]) = 0;
virtual void OnStop()
virtual void OnPause()
virtual void OnContinue()
virtual void OnShutdown()
virtual void OnSessionChange(DWORD /*evtType*/,
WTSSESSION_NOTIFICATION* /*notification*/)
private:
// Registers handle and starts the service.
static void WINAPI SvcMain(DWORD argc, TCHAR* argv[]);
// Called whenever service control manager updates service status.
static DWORD WINAPI ServiceCtrlHandler(DWORD ctrlCode, DWORD evtType,
void* evtData, void* context);
static bool RunInternal(ServiceBase* svc);
void Start(DWORD argc, TCHAR* argv[]);
void Stop();
void Pause();
void Continue();
void Shutdown();
CString m_name;
CString m_displayName;
DWORD m_dwStartType;
DWORD m_dwErrorCtrlType;
CString m_depends;
CString m_account;
CString m_password;
// Info about service dependencies and user account.
bool m_hasDepends;/* = false*/;
bool m_hasAcc;/* = false*/;
bool m_hasPass;/* = false*/;
SERVICE_STATUS m_svcStatus;
SERVICE_STATUS_HANDLE m_svcStatusHandle;
static ServiceBase* m_service;
DISABLE_COPY_AND_MOVE(ServiceBase)
;
#endif // SERVICE_BASE_H_
Service_base.cpp(这个为底层依赖源文件,可以不用关心具体类容)
#include <stdafx.h>
#include "service_base.h"
#include <cassert>
ServiceBase* ServiceBase::m_service = nullptr;
ServiceBase::ServiceBase(const CString& name,
const CString& displayName,
DWORD dwStartType,
DWORD dwErrCtrlType,
DWORD dwAcceptedCmds,
const CString& depends,
const CString& account,
const CString& password)
: m_name(name),
m_displayName(displayName),
m_dwStartType(dwStartType),
m_dwErrorCtrlType(dwErrCtrlType),
m_depends(depends),
m_account(account),
m_password(password),
m_svcStatusHandle(nullptr)
m_hasDepends = !m_depends.IsEmpty();
m_hasAcc = !m_account.IsEmpty();
m_hasPass = !m_password.IsEmpty();
m_svcStatus.dwControlsAccepted = dwAcceptedCmds;
m_svcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
m_svcStatus.dwCurrentState = SERVICE_START_PENDING;
m_svcStatus.dwWin32ExitCode = NO_ERROR;
m_svcStatus.dwServiceSpecificExitCode = 0;
m_svcStatus.dwCheckPoint = 0;
m_svcStatus.dwWaitHint = 0;
void ServiceBase::SetStatus(DWORD dwState, DWORD dwErrCode, DWORD dwWait)
m_svcStatus.dwCurrentState = dwState;
m_svcStatus.dwWin32ExitCode = dwErrCode;
m_svcStatus.dwWaitHint = dwWait;
::SetServiceStatus(m_svcStatusHandle, &m_svcStatus);
void ServiceBase::WriteToEventLog(const CString& msg, WORD type)
HANDLE hSource = RegisterEventSource(nullptr, m_name);
if (hSource)
const TCHAR* msgData[2] = m_name, msg;
ReportEvent(hSource, type, 0, 0, nullptr, 2, 0, msgData, nullptr);
DeregisterEventSource(hSource);
// static
void WINAPI ServiceBase::SvcMain(DWORD argc, TCHAR* argv[])
assert(m_service);
m_service->m_svcStatusHandle = ::RegisterServiceCtrlHandlerEx(m_service->GetName(),ServiceCtrlHandler, NULL);
if (!m_service->m_svcStatusHandle)
m_service->WriteToEventLog(_T("Can't set service control handler"),EVENTLOG_ERROR_TYPE);
return;
m_service->Start(argc, argv);
// static
DWORD WINAPI ServiceBase::ServiceCtrlHandler(DWORD ctrlCode, DWORD evtType, void* evtData, void* /*context*/)
switch (ctrlCode)
case SERVICE_CONTROL_STOP:
m_service->Stop();
break;
case SERVICE_CONTROL_PAUSE:
m_service->Pause();
break;
case SERVICE_CONTROL_CONTINUE:
m_service->Continue();
break;
case SERVICE_CONTROL_SHUTDOWN:
m_service->Shutdown();
break;
case SERVICE_CONTROL_SESSIONCHANGE:
m_service->OnSessionChange(evtType, reinterpret_cast<WTSSESSION_NOTIFICATION*>(evtData));
break;
default:
break;
return 0;
bool ServiceBase::RunInternal(ServiceBase* svc)
m_service = svc;
TCHAR* svcName = const_cast<CString&>(m_service->GetName()).GetBuffer();
SERVICE_TABLE_ENTRY tableEntry[] =
svcName, SvcMain,
nullptr, nullptr
;
return ::StartServiceCtrlDispatcher(tableEntry) == TRUE;
void ServiceBase::Start(DWORD argc, TCHAR* argv[])
SetStatus(SERVICE_START_PENDING);
OnStart(argc, argv);
SetStatus(SERVICE_RUNNING);
void ServiceBase::Stop()
SetStatus(SERVICE_STOP_PENDING);
OnStop();
SetStatus(SERVICE_STOPPED);
void ServiceBase::Pause()
SetStatus(SERVICE_PAUSE_PENDING);
OnPause();
SetStatus(SERVICE_PAUSED);
void ServiceBase::Continue()
SetStatus(SERVICE_CONTINUE_PENDING);
OnContinue();
SetStatus(SERVICE_RUNNING);
void ServiceBase::Shutdown()
OnShutdown();
SetStatus(SERVICE_STOPPED);
Service_installer.h(这个为底层依赖头文件,可以不用关心具体类容)
#ifndef SERVICE_INSTALLER_H_
#define SERVICE_INSTALLER_H_
#include "service_base.h"
class ServiceInstaller
public:
static bool Install(const ServiceBase& service);
static bool Uninstall(const ServiceBase& service);
private:
ServiceInstaller()
;
#endif // SERVICE_INSTALLER_H_
Service_installer.cpp(这个为底层依赖源文件,可以不用关心具体类容)
#include <stdafx.h>
#include "service_installer.h"
namespace
class ServiceHandle
public:
ServiceHandle(SC_HANDLE handle) : m_handle(handle)
~ServiceHandle()
if (m_handle)
::CloseServiceHandle(m_handle);
operator SC_HANDLE()
return m_handle;
private:
SC_HANDLE m_handle;
;
//static
bool ServiceInstaller::Install(const ServiceBase& service)
CString escapedPath;
TCHAR* modulePath = escapedPath.GetBufferSetLength(MAX_PATH);
if (::GetModuleFileName(nullptr, modulePath, MAX_PATH) == 0)
_tprintf(_T("Couldn't get module file name: %d\\n"), ::GetLastError());
return false;
escapedPath.ReleaseBuffer();
escapedPath.Remove(_T('\\"'));
escapedPath = _T('\\"') + escapedPath + _T('\\"');
ServiceHandle svcControlManager = ::OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT | SC_MANAGER_CREATE_SERVICE);
if (!svcControlManager)
_tprintf(_T("Couldn't open service control manager: %d\\n"), GetLastError());
return false;
const CString& depends = service.GetDependencies();
const CString& acc = service.GetAccount();
const CString& pass = service.GetPassword();
ServiceHandle servHandle = ::CreateService(svcControlManager,
service.GetName(),
service.GetDisplayName(),
SERVICE_QUERY_STATUS,
SERVICE_WIN32_OWN_PROCESS,
service.GetStartType(),
service.GetErrorControlType(),
escapedPath,
nullptr,
nullptr,
(depends.IsEmpty() ? nullptr : depends.GetString()),
(acc.IsEmpty() ? nullptr : acc.GetString()),
(pass.IsEmpty() ? nullptr : pass.GetString()));
if (!servHandle)
_tprintf(_T("Couldn't create service: %d\\n"), ::GetLastError());
return false;
return true;
//static
bool ServiceInstaller::Uninstall(const ServiceBase& service)
ServiceHandle svcControlManager = ::OpenSCManager(nullptr, nullptr, SC_MANAGER_CONNECT);
if (!svcControlManager)
_tprintf(_T("Couldn't open service control manager: %d\\n"), GetLastError());
return false;
ServiceHandle servHandle = ::OpenService(svcControlManager, service.GetName(),
SERVICE_QUERY_STATUS | SERVICE_STOP | DELETE);
if (!servHandle)
_tprintf(_T("Couldn't open service control manager: %d\\n"), ::GetLastError());
return false;
SERVICE_STATUS servStatus = ;
if (::ControlService(servHandle, SERVICE_CONTROL_STOP, &servStatus))
_tprintf(_T("Stoping service %s\\n"), service.GetName());
while (::QueryServiceStatus(servHandle, &servStatus))
if (servStatus.dwCurrentState != SERVICE_STOP_PENDING)
break;
if (servStatus.dwCurrentState != SERVICE_STOPPED)
_tprintf(_T("Failed to stop the service\\n"));
else
_tprintf(_T("Service stopped\\n"));
else
_tprintf(_T("Didn't control service: %d\\n"), ::GetLastError());
if (!::DeleteService(servHandle))
_tprintf(_T("Failed to delete the service: %d\\n"), GetLastError());
return false;
return true;
TestSysService.cpp(具体的使用类,详细的解释见注释)
// TestSysService.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include "sysservice/service_base.h"
#include "sysservice/service_installer.h"
//此类继承基础服务类
class CTestService:public ServiceBase
public:
#ifdef _DEBUG
CTestService(const CString&name)
:ServiceBase(name,
name,
SERVICE_DEMAND_START,
SERVICE_ERROR_NORMAL,
SERVICE_ACCEPT_STOP
)
#else
CTestService(const CString&name)
:ServiceBase(name,
name,
SERVICE_AUTO_START,
SERVICE_ERROR_NORMAL,
SERVICE_ACCEPT_STOP
)
#endif
private:
//服务开启时调用的接口(此接口不能阻塞,如果阻塞服务会一直显示开启中)
void OnStart(DWORD argc, TCHAR* argv[])
OutputDebugString(_T("TestService:Application start running!!!\\n"));
//服务关闭时调用的接口(此接口不能阻塞,如果阻塞服务会一直显示关闭中)
void OnStop()
OutputDebugString(_T("TestService:Application end\\n"));
public:
//如果是以服务的方式运行就到此函数里面直接调用ServiceBase的Run函数。此函数调用完以后,服务会调用OnStart函数。
//如果是控制台的方式运行就到此函数里面写主要的逻辑代码。此函数一般也会到内部调用OnStart和OnStop函数。此函数为主线程,所以不能退出。
bool Run(LPCTSTR param = _T(""))
if (_tcscmp(param, _T("console")) == 0)
//Todo:控制台运行处理 调用OnStart和OnStop
TCHAR cinCmd[128];
bool bStart = false;
while(1)//控制台运行主线程不能退出
_tprintf(_T("->input cmd\\r\\n"));
_tscanf_s(_T("%s"), cinCmd, 128);
if (_tcsncmp(cinCmd, _T("?"), 1) == 0)
_tprintf(_T("\\r\\n========================================\\r\\n"));
_tprintf(_T("\\"?\\" -show cmd help\\r\\n"));
_tprintf(_T("\\"start\\" -start service\\r\\n"));
_tprintf(_T("\\"stop\\" -stop service\\r\\n"));
_tprintf(_T("\\"exit\\" -exit service\\r\\n"));
_tprintf(_T("========================================\\r\\n"));
else if (_tcsncmp(cinCmd, _T("start"), 5) == 0)
if (!bStart)
OnStart(0, NULL);
_tprintf(_T("\\r\\n========================================\\r\\n"));
_tprintf(_T("-> start service\\r\\n"));
_tprintf(_T("========================================\\r\\n"));
bStart = true;
else if (_tcsncmp(cinCmd, _T("stop"), 4) == 0)
if (bStart)
OnStop();
_tprintf(_T("\\n========================================\\n"));
_tprintf(_T("-> stop service\\r\\n"));
_tprintf(_T("========================================\\n"));
bStart = false;
else if (_tcsncmp(cinCmd, _T("exit"), 4) == 0)
_tprintf(_T("\\r\\n========================================\\r\\n"));
_tprintf(_T("-> exit service\\r\\n"));
_tprintf(_T("========================================\\r\\n"));
break;
else
_tprintf(_T("invalid cmd\\r\\n"));
if (bStart)
OnStop();
return true;
return ServiceBase::Run();//服务的方式运行
;
int _tmain(int argc, _TCHAR* argv[])
//创建服务对象
CTestService service("TestService");
//带有参数的调用
if (argc > 1)
if (_tcscmp(argv[1], _T("install")) == 0) //安装服务
OutputDebugString(_T("TestService:Installing service\\n"));
if (!ServiceInstaller::Install(service))
OutputDebugString(_T("TestService:Couldn't install service\\n"));
return -1;
OutputDebugString(_T("TestService:Service installed\\n"));
return 0;
if (_tcscmp(argv[1], _T("uninstall")) == 0) //卸载服务
OutputDebugString(_T("TestService:Uninstalling service\\n"));
if (!ServiceInstaller::Uninstall(service))
OutputDebugString(_T("TestService:Couldn't uninstall service: %d\\n"));
return -1;
OutputDebugString(_T("TestService:Service uninstalled\\n"));
return 0;
if (_tcscmp(argv[1], _T("console")) == 0) //以控制台的方式运行
OutputDebugString(_T("TestService:console running\\n"));
service.Run(_T("console"));
return 0;
else
//以服务的方式运行
OutputDebugString(_T("TestService:start service"));
service.Run();
return 0;
————————————————
版权声明:本文为CSDN博主「萧戈」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/xiaoyafang123/article/details/52235295
以上是关于C/C++ 创建windows系统服务程序的主要内容,如果未能解决你的问题,请参考以下文章