研究下以前抄的C++版Windows服务

前言

以前做项目需要用到Windows服务,于是随便在网上找了一篇C++版的Windows服务代码,封装的很好,直接拿来用就可以。现在项目需求发生了一点小变化,需要服务时刻监听启动的exe是否异常,如果异常就重新启动。于是研究下代码,顺便熟悉下Windows服务。

文件构成

整个文件有两部分构成

  1. CServiceBase类
  2. ServiceInstall文件,包含安装、卸载、更新服务描述

程序入口处理

因为我们最终需要打包自动安装,卸载程序的时候自动卸载服务,所以在main函数中可以通过参数判断,程序是安装服务,还是卸载服务或者是运行服务。

// 服务启动类型
#define SERVICE_START_TYPE       SERVICE_AUTO_START 


// 服务依赖项
#define SERVICE_DEPENDENCIES     L"" 


// 服务配置为以 LocalSystem(而非 LocalService)身份运行
#define SERVICE_ACCOUNT          NULL //L"NT AUTHORITY\\LocalService" 


// The password to the service account name 
#define SERVICE_PASSWORD         NULL

int _tmain(int argc, TCHAR* argv[])
{
	
	if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/')))) 
	{ 
		if (_wcsicmp(L"install", argv[1] + 1) == 0) 
		{ 
			//通过命令行的方式注册服务
			InstallService( 
				SERVICE_NAME,               // 服务的名称,不用多说,一般为sc使用的名称或net使用的名称
				SERVICE_DISPLAY_NAME,       // 服务显示的名称,显示给用户的名称
				/*
				#define SERVICE_BOOT_START             0x00000000  //系统加载程序加载驱动启动,仅对驱动程序有效
				#define SERVICE_SYSTEM_START           0x00000001  //由 IOInitSystem 函数启动的设备驱动程序
				#define SERVICE_AUTO_START             0x00000002  //操作系统启动的时候启动
				#define SERVICE_DEMAND_START           0x00000003  //手动启动
				#define SERVICE_DISABLED               0x00000004  //服务已被禁用
				
				// 服务启动类型,分为 以上五种,一般为SERVICE_AUTO_START,	
				// 0和1针对于驱动程序,一般操作系统启动不起来大部分原因是驱动程序加载不上
				*/
                SERVICE_START_TYPE,         
				SERVICE_DEPENDENCIES,       // 依赖的服务,一般没有依赖,当然如果你依赖另一个服务要填它的SERVICE_NAME
				// 服务运行的帐号,有四个选项
                // 1. 当前登录账号,一般我们是不知道用户电脑的账号的,而且也不可能统一账号和密码
                // 2. LocalService,计算机上非特权用户 
                // 3. LocalSystem,服务控制管理员使用的帐户
                // 4. NetworkService,提供广泛的本地特权的帐户,该帐户将计算机的凭据提供给所有远程服务器
                // 如果此参数为NULL,则 CreateService使用 LocalSystem帐户
                // NT AUTHORITY\LocalService 为LocalService账号
                // NT AUTHORITY\NetworkService 为NetworkService账号
                // 具体请看参考文献2、3、4和5
                SERVICE_ACCOUNT,            
				SERVICE_PASSWORD            // 帐号的密码,一般填NULL
				); 
            //更新服务描述
			updateServiceDescription(SERVICE_NAME,SERVICE_DESC);
		} 
		else if (_wcsicmp(L"remove", argv[1] + 1) == 0) 
		{ 
			//通过命令行的方式卸载服务
			// "-remove" or "/remove". 
			UninstallService(SERVICE_NAME); 
		} 
	} 
	else 
	{ 
		CImpCertService service(SERVICE_NAME); 
		if (!CServiceBase::Run(service)) 
		{ 
			WriteToLog("服务启动失败,错误码:"+GetLastError());
		} 
	} 
	return 0;
}

这样打包的时候就可以使用命令参数来进行安装或卸载。

比如编译出来是 YYService.exe,我用的是inno setup打包,脚本语言就可以写成

[Run]
Filename:"{app}/YYService.exe"; Parameters:"-install";Flags:runhidden;StatusMsg:"正在安装服务"
Filename: "net.exe";             Parameters: "start YYService";  Flags:runhidden;StatusMsg:"正在启动服务"

[UninstallRun]
Filename:"net.exe"; Parameters:"stop YYService";Flags:runhidden  waituntilterminated;
Filename:"{app}/YYService.exe"; Parameters:"-remove";Flags:runhidden  waituntilterminated;

服务启动与停止

我们首先看服务怎么运行的。

#pragma once

#include <windows.h>


class CServiceBase
{
public:

    // 向SCM注册服务的可执行程序文件,调用Run方法后,SCM后发出Start命令,这将调用服务中的OnStart方法
    static BOOL Run(CServiceBase &service);

    // 构造函数,允许你指定服务可以停止、暂停和继续
    CServiceBase(PWSTR pszServiceName, 
        BOOL fCanStop = TRUE, 
        BOOL fCanShutdown = TRUE, 
        BOOL fCanPauseContinue = FALSE);

    // 服务析构函数
    virtual ~CServiceBase(void);

    // 停止服务
    void Stop();

protected:

    // 在派生类中实现,当调用Run时,会使SCM调用OnStart
    virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv);

    // 在派生类中实现,当服务停止时SCM会调用该方法
    virtual void OnStop();

    // 在派生类中实现,当服务暂停时,SCM会调用该方法
    virtual void OnPause();

    // 在派生类中实现,当服务继续时,SCM会调用该方法
    virtual void OnContinue();

    // 当系统关机时,会调用该方法
    virtual void OnShutdown();

    // 设置服务状态,并将状态报告给SCM
    void SetServiceStatus(DWORD dwCurrentState, 
        DWORD dwWin32ExitCode = NO_ERROR, 
        DWORD dwWaitHint = 0);

    // 将日志信息写入Windows日志中
    void WriteEventLogEntry(PWSTR pszMessage, WORD wType);

    // 将错误信息写入到Windows日志中
    void WriteErrorLogEntry(PWSTR pszFunction, 
        DWORD dwError = GetLastError());

private:

    // 服务的入口点. 注册并启动服务
    static void WINAPI ServiceMain(DWORD dwArgc, LPWSTR *lpszArgv);

    // 这个函数将会在SCM发送控制码给这个服务的时候调用
    static void WINAPI ServiceCtrlHandler(DWORD dwCtrl);

    // 启动服务
    void Start(DWORD dwArgc, PWSTR *pszArgv);
    
    // 暂停服务
    void Pause();

    // 继续服务
    void Continue();

    // 当系统关机时执行
    void Shutdown();

    // 子类对象
    static CServiceBase *s_service;

    // 服务名称
    PWSTR m_name;

    // 服务状态
    SERVICE_STATUS m_status;

    // 服务状态句柄
    SERVICE_STATUS_HANDLE m_statusHandle;
};

#pragma region Includes
#include "ServiceBase.h"
#include <assert.h>
#include <strsafe.h>
#pragma endregion


#pragma region Static Members

// 初始化
CServiceBase *CServiceBase::s_service = NULL;

// 目的:向SCM注册服务的可执行文件,在调用这个方法之后,SCM会发出Start命令从而调用服务的OnStart方法
BOOL CServiceBase::Run(CServiceBase &service)
{
    s_service = &service;

    SERVICE_TABLE_ENTRY serviceTable[] = 
    {
        { service.m_name, ServiceMain },
        { NULL, NULL }
    };

    // 将服务的主线程连接到SCM。
    // StartServiceCtrlDispatcher时,程序由服务控制管理器接管
    // SCM 根据需要启动的服务名称,在传入的数组指针中,找到对应的入口函数,然后调用它
    // 当对应的入口函数返回时结束服务,并将后续代码的控制权转交给对应主进程,由主进程接着执行后面的代码
    // 注意:此处有时间要求,如果时间超过30秒,就应该另起子线程进行初始化
    return StartServiceCtrlDispatcher(serviceTable);
}


// 服务启动的入口点,如果学过Windows驱动就很容易理解这个概念
// 注册服务函数,当SCM发送控制码时,会调用注册的对应函数
void WINAPI CServiceBase::ServiceMain(DWORD dwArgc, PWSTR *pszArgv)
{
    assert(s_service != NULL);

    // 注册服务函数
    s_service->m_statusHandle = RegisterServiceCtrlHandler(
        s_service->m_name, ServiceCtrlHandler);
    if (s_service->m_statusHandle == NULL)
    {
        throw GetLastError();
    }

    // Start the service.
    s_service->Start(dwArgc, pszArgv);
}



//   PURPOSE: 注册控制码对应的函数
//
//   PARAMETERS:
//   * dwCtrlCode - 控制码
//
//     SERVICE_CONTROL_CONTINUE
//     SERVICE_CONTROL_INTERROGATE
//     SERVICE_CONTROL_NETBINDADD
//     SERVICE_CONTROL_NETBINDDISABLE
//     SERVICE_CONTROL_NETBINDREMOVE
//     SERVICE_CONTROL_PARAMCHANGE
//     SERVICE_CONTROL_PAUSE
//     SERVICE_CONTROL_SHUTDOWN
//     SERVICE_CONTROL_STOP
//
void WINAPI CServiceBase::ServiceCtrlHandler(DWORD dwCtrl)
{
    switch (dwCtrl)
    {
    case SERVICE_CONTROL_STOP: s_service->Stop(); break;
    case SERVICE_CONTROL_PAUSE: s_service->Pause(); break;
    case SERVICE_CONTROL_CONTINUE: s_service->Continue(); break;
    case SERVICE_CONTROL_SHUTDOWN: s_service->Shutdown(); break;
    case SERVICE_CONTROL_INTERROGATE: break;
    default: break;
    }
}

#pragma endregion


#pragma region Service Constructor and Destructor

//
//
//   PARAMETERS:
//   * pszServiceName - 服务名称
//   * fCanStop - 服务是否可用暂停
//   * fCanShutdown - 当关机的时候是否会通知服务
//   * fCanPauseContinue - 服务是否可以继续
//
CServiceBase::CServiceBase(PWSTR pszServiceName, 
                           BOOL fCanStop, 
                           BOOL fCanShutdown, 
                           BOOL fCanPauseContinue)
{
    // Service name must be a valid string and cannot be NULL.
    m_name = (pszServiceName == NULL) ? L"" : pszServiceName;

    m_statusHandle = NULL;

    // The service runs in its own process.
    m_status.dwServiceType = SERVICE_WIN32_OWN_PROCESS;

    // The service is starting.
    m_status.dwCurrentState = SERVICE_START_PENDING;

    // The accepted commands of the service.
    DWORD dwControlsAccepted = 0;
    if (fCanStop) 
        dwControlsAccepted |= SERVICE_ACCEPT_STOP;
    if (fCanShutdown) 
        dwControlsAccepted |= SERVICE_ACCEPT_SHUTDOWN;
    if (fCanPauseContinue) 
        dwControlsAccepted |= SERVICE_ACCEPT_PAUSE_CONTINUE;
    m_status.dwControlsAccepted = dwControlsAccepted;

    m_status.dwWin32ExitCode = NO_ERROR;
    m_status.dwServiceSpecificExitCode = 0;
    m_status.dwCheckPoint = 0;
    m_status.dwWaitHint = 0;
}


//
//   FUNCTION: CServiceBase::~CServiceBase()
//
//   PURPOSE: The virtual destructor of CServiceBase. 
//
CServiceBase::~CServiceBase(void)
{
}

#pragma endregion


#pragma region Service Start, Stop, Pause, Continue, and Shutdown

//
//   启动服务
//
//   PURPOSE: The function starts the service. It calls the OnStart virtual 
//   function in which you can specify the actions to take when the service 
//   starts. If an error occurs during the startup, the error will be logged 
//   in the Application event log, and the service will be stopped.
//
//   PARAMETERS:
//   * dwArgc   - number of command line arguments
//   * lpszArgv - array of command line arguments
//
void CServiceBase::Start(DWORD dwArgc, PWSTR *pszArgv)
{
    try
    {
        //告诉SCM启动中
        SetServiceStatus(SERVICE_START_PENDING);

        // 调用子类的启动函数
        OnStart(dwArgc, pszArgv);

        //告诉SCM启动了
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD dwError)
    {
        // Log the error.
        WriteErrorLogEntry(L"Service Start", dwError);

        // 设置服务停止
        SetServiceStatus(SERVICE_STOPPED, dwError);
    }
    catch (...)
    {
        // 写错误日志
        WriteEventLogEntry(L"Service failed to start.", EVENTLOG_ERROR_TYPE);

        // 设置服务停止
        SetServiceStatus(SERVICE_STOPPED);
    }
}



// 留着子类实现,默认不做任何事情
void CServiceBase::OnStart(DWORD dwArgc, PWSTR *pszArgv)
{
}


//
//   FUNCTION: CServiceBase::Stop()
//
//   PURPOSE: The function stops the service. It calls the OnStop virtual 
//   function in which you can specify the actions to take when the service 
//   stops. If an error occurs, the error will be logged in the Application 
//   event log, and the service will be restored to the original state.
//
void CServiceBase::Stop()
{
    DWORD dwOriginalState = m_status.dwCurrentState;
    try
    {
        // 告诉SCM 停止服务中
        SetServiceStatus(SERVICE_STOP_PENDING);

        // 子类停止服务做得事情
        OnStop();

        // 告诉SCM已经停止
        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD dwError)
    {
        // 写错误日志
        WriteErrorLogEntry(L"Service Stop", dwError);

        // 设置服务状态
        SetServiceStatus(dwOriginalState);
    }
    catch (...)
    {
        // 写错误日志
        WriteEventLogEntry(L"Service failed to stop.", EVENTLOG_ERROR_TYPE);

        // 设置服务状态
        SetServiceStatus(dwOriginalState);
    }
}


//
// 默认不做任何事情
void CServiceBase::OnStop()
{
}


//
//   FUNCTION: CServiceBase::Pause()
//
//   PURPOSE: The function pauses the service if the service supports pause 
//   and continue. It calls the OnPause virtual function in which you can 
//   specify the actions to take when the service pauses. If an error occurs, 
//   the error will be logged in the Application event log, and the service 
//   will become running.
//
void CServiceBase::Pause()
{
    try
    {
        // 告诉SCM暂停中
        SetServiceStatus(SERVICE_PAUSE_PENDING);

        // 子类停止时要做的事情
        OnPause();

        // 告诉SCM已停止
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (DWORD dwError)
    {
        // Log the error.
        WriteErrorLogEntry(L"Service Pause", dwError);

        // Tell SCM that the service is still running.
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (...)
    {
        // Log the error.
        WriteEventLogEntry(L"Service failed to pause.", EVENTLOG_ERROR_TYPE);

        // Tell SCM that the service is still running.
        SetServiceStatus(SERVICE_RUNNING);
    }
}


//
void CServiceBase::OnPause()
{
}


// 告诉SCM继续服务
void CServiceBase::Continue()
{
    try
    {
        // Tell SCM that the service is resuming.
        SetServiceStatus(SERVICE_CONTINUE_PENDING);

        // Perform service-specific continue operations.
        OnContinue();

        // Tell SCM that the service is running.
        SetServiceStatus(SERVICE_RUNNING);
    }
    catch (DWORD dwError)
    {
        // Log the error.
        WriteErrorLogEntry(L"Service Continue", dwError);

        // Tell SCM that the service is still paused.
        SetServiceStatus(SERVICE_PAUSED);
    }
    catch (...)
    {
        // Log the error.
        WriteEventLogEntry(L"Service failed to resume.", EVENTLOG_ERROR_TYPE);

        // Tell SCM that the service is still paused.
        SetServiceStatus(SERVICE_PAUSED);
    }
}


//
void CServiceBase::OnContinue()
{
}


//
void CServiceBase::Shutdown()
{
    try
    {
        // 子类关机前做的操作.
        OnShutdown();

        // 告诉SCM停止服务
        SetServiceStatus(SERVICE_STOPPED);
    }
    catch (DWORD dwError)
    {
        // Log the error.
        WriteErrorLogEntry(L"Service Shutdown", dwError);
    }
    catch (...)
    {
        // Log the error.
        WriteEventLogEntry(L"Service failed to shut down.", EVENTLOG_ERROR_TYPE);
    }
}


//
void CServiceBase::OnShutdown()
{
}

#pragma endregion


#pragma region Helper Functions

//
//   FUNCTION: CServiceBase::SetServiceStatus(DWORD, DWORD, DWORD)
//
//   PURPOSE: 设置服务状态并告诉给SCM
//
//   PARAMETERS:
//   * dwCurrentState - 服务当前状态码
//   * dwWin32ExitCode - 服务的错误退出码
//   * dwWaitHint - 挂起服务的大概时间(毫秒)
//
void CServiceBase::SetServiceStatus(DWORD dwCurrentState, 
                                    DWORD dwWin32ExitCode, 
                                    DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;

    // Fill in the SERVICE_STATUS structure of the service.
    m_status.dwCurrentState = dwCurrentState;
    m_status.dwWin32ExitCode = dwWin32ExitCode;
    m_status.dwWaitHint = dwWaitHint;

    m_status.dwCheckPoint = 
        ((dwCurrentState == SERVICE_RUNNING) ||
        (dwCurrentState == SERVICE_STOPPED)) ? 
        0 : dwCheckPoint++;

    // Report the status of the service to the SCM.
    ::SetServiceStatus(m_statusHandle, &m_status);
}

//
//   PURPOSE: 写日志到Windows应用程序日志中
//
//   PARAMETERS:
//   * pszMessage - 日志内容
//   * wType - 日志类型,有以下几种:
//
//     EVENTLOG_SUCCESS
//     EVENTLOG_AUDIT_FAILURE
//     EVENTLOG_AUDIT_SUCCESS
//     EVENTLOG_ERROR_TYPE
//     EVENTLOG_INFORMATION_TYPE
//     EVENTLOG_WARNING_TYPE
//
void CServiceBase::WriteEventLogEntry(PWSTR pszMessage, WORD wType)
{
    HANDLE hEventSource = NULL;
    LPCWSTR lpszStrings[2] = { NULL, NULL };

    hEventSource = RegisterEventSource(NULL, m_name);
    if (hEventSource)
    {
        lpszStrings[0] = m_name;
        lpszStrings[1] = pszMessage;

        ReportEvent(hEventSource,  // Event log handle
            wType,                 // Event type
            0,                     // Event category
            0,                     // Event identifier
            NULL,                  // No security identifier
            2,                     // Size of lpszStrings array
            0,                     // No binary data
            lpszStrings,           // Array of strings
            NULL                   // No binary data
            );

        DeregisterEventSource(hEventSource);
    }
}



//   PURPOSE: 写错误日志到Windows 应用程序日志中
//
//   PARAMETERS:
//   * pszFunction - 错误信息
//   * dwError - 错误码
//
void CServiceBase::WriteErrorLogEntry(PWSTR pszFunction, DWORD dwError)
{
    wchar_t szMessage[260];
    StringCchPrintf(szMessage, ARRAYSIZE(szMessage), 
        L"%s failed w/err 0x%08lx", pszFunction, dwError);
    WriteEventLogEntry(szMessage, EVENTLOG_ERROR_TYPE);
}

#pragma endregion

根据以上代码,可以总结出以下图:
在这里插入图片描述

可以看到启动的流程,需要做一些准备操作,才可以告诉SCM,我启动成功了。

停止和暂停的流程,只需要报告给SCM就可以了。

现在的代码并没有什么业务,只是启动、停止。

我们可以在OnStart和OnStop里面写业务代码

我们写一个类,继承CServiceBase

#include "ServiceBase.h"
#include <string>
using std::wstring;

class CImpService : public CServiceBase
{
public:

	CImpService(PWSTR pszServiceName, 
		BOOL fCanStop = TRUE, 
		BOOL fCanShutdown = TRUE, 
		BOOL fCanPauseContinue = FALSE);
	virtual ~CImpService(void);

protected:

	virtual void OnStart(DWORD dwArgc, PWSTR *pszArgv);
	virtual void OnStop();

private:

};


CImpService::CImpService(PWSTR pszServiceName, 
	BOOL fCanStop, 
	BOOL fCanShutdown, 
	BOOL fCanPauseContinue)
	: CServiceBase(pszServiceName, fCanStop, fCanShutdown, fCanPauseContinue)
{
	
}


CImpService::~CImpService(void)
{

}


void CImpService::OnStart(DWORD dwArgc, LPWSTR *lpszArgv)
{
	// Log a service start message to the Application log.
	WriteEventLogEntry(L"CImpService in OnStart", 
		EVENTLOG_INFORMATION_TYPE);
    //业务代码
}

//
void CImpService::OnStop()
{
	//业务代码
	WriteEventLogEntry(L"CImpService in OnStop", 
		EVENTLOG_INFORMATION_TYPE);

}

服务的安装

void InstallService(PWSTR pszServiceName, 
                    PWSTR pszDisplayName, 
                    DWORD dwStartType,
                    PWSTR pszDependencies, 
                    PWSTR pszAccount, 
                    PWSTR pszPassword)
{
    wchar_t szPath[MAX_PATH];
    SC_HANDLE schSCManager = NULL;
    SC_HANDLE schService = NULL;
	//获取当前exe的路径
    if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
    {
        wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError());
        goto Cleanup;
    }

    // 打开SCM
    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT | 
        SC_MANAGER_CREATE_SERVICE);
    if (schSCManager == NULL)
    {
        wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
        goto Cleanup;
    }

    // 安装服务
    schService = CreateService(
        schSCManager,                   // SCManager database
        pszServiceName,                 // 服务名称
        pszDisplayName,                 // 显示的名称
        SERVICE_QUERY_STATUS,           // 安全性访问权限
        // 服务类型
        // 如果是SERVICE_WIN32_OWN_PROCESS 或 SERVICE_WIN32_SHARE_PROCESS
        // 且使用LocalSystem帐号来运行该服务程序,则还可以附加SERVICE_INTERACTIVE_PROCESS
        // 
        SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS,
        dwStartType,                    // 服务启动选项
        SERVICE_ERROR_NORMAL,           // 发生错误的保护措施
        szPath,                         // 服务的二进制文件路径
        NULL,                           // 加载服务组的名称,NULL不加载
        NULL,                           // 不更改组现有的标签
        pszDependencies,                // 依赖的服务,为NULL代表没有依赖
        pszAccount,                     // 服务的运行账号
        pszPassword                     // 服务运行账号的密码
        );
    if (schService == NULL)
    {
        wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError());
        goto Cleanup;
    }

    wprintf(L"%s is installed.\n", pszServiceName);

Cleanup:
    // Centralized cleanup for all allocated resources.
    if (schSCManager)
    {
        CloseServiceHandle(schSCManager);
        schSCManager = NULL;
    }
    if (schService)
    {
        CloseServiceHandle(schService);
        schService = NULL;
    }
}

服务的卸载

void UninstallService(PWSTR pszServiceName)
{
    SC_HANDLE schSCManager = NULL;
    SC_HANDLE schService = NULL;
    SERVICE_STATUS ssSvcStatus = {};

    // 打开SCM
    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
    if (schSCManager == NULL)
    {
        wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
        goto Cleanup;
    }

    //打开服务,带停止和查询以及删除权限
    schService = OpenService(schSCManager, pszServiceName, SERVICE_STOP | 
        SERVICE_QUERY_STATUS | DELETE);
    if (schService == NULL)
    {
        wprintf(L"OpenService failed w/err 0x%08lx\n", GetLastError());
        goto Cleanup;
    }

    // 尝试停止服务
    if (ControlService(schService, SERVICE_CONTROL_STOP, &ssSvcStatus))
    {
        wprintf(L"Stopping %s.", pszServiceName);
        
		//查询服务状态
        while (QueryServiceStatus(schService, &ssSvcStatus))
        {
            //如果服务状态 等于 正在停止
            if (ssSvcStatus.dwCurrentState == SERVICE_STOP_PENDING)
            {
                wprintf(L".");
               
            }
            else break;//不等于则调出
        }
		//如果服务状态 等于 停止
        if (ssSvcStatus.dwCurrentState == SERVICE_STOPPED)
        {
            wprintf(L"\n%s is stopped.\n", pszServiceName);
        }
        else
        {
            //服务状态不等于停止
            wprintf(L"\n%s failed to stop.\n", pszServiceName);
        }
    }

    // 调用删除服务函数
    if (!DeleteService(schService))
    {
        wprintf(L"DeleteService failed w/err 0x%08lx\n", GetLastError());
        goto Cleanup;
    }

    wprintf(L"%s is removed.\n", pszServiceName);

Cleanup:
    // Centralized cleanup for all allocated resources.
    if (schSCManager)
    {
        CloseServiceHandle(schSCManager);
        schSCManager = NULL;
    }
    if (schService)
    {
        CloseServiceHandle(schService);
        schService = NULL;
    }
}

更新服务描述

/**
 * 更新(添加)服务描述。
 * @param serviceName : 服务名称。
 * @param serviceDescription : 服务描述。
 */
bool updateServiceDescription(LPTSTR serviceName, LPTSTR serviceDescription)
{
	SC_HANDLE schSCManager;
	SC_HANDLE schService;
	SERVICE_DESCRIPTION sd;
	//LPTSTR szDesc = TEXT(serviceDescription);
 
	// 打开SCM
	schSCManager = ::OpenSCManager(
		NULL,                    // local computer
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);  // full access rights 
 
	if (NULL == schSCManager)
	{
		//printf("OpenSCManager failed (%d)\n", GetLastError());
		return false;
	}
 
	// 获取服务句柄
	schService = ::OpenService(
		schSCManager,            // SCM database 
		serviceName,             // name of service 
		SERVICE_CHANGE_CONFIG);  // need change config access 
 
	if (schService == NULL)
	{
		//printf("OpenService failed (%d)\n", GetLastError());
		::CloseServiceHandle(schSCManager);
		return false;
	}
 
	// 改变服务描述
	sd.lpDescription = serviceDescription;
 
	if (!::ChangeServiceConfig2(
		schService,                 // handle to service
		SERVICE_CONFIG_DESCRIPTION, // change: description
		&sd))                       // new description
	{
		//printf("ChangeServiceConfig2 failed\n");
		::CloseServiceHandle(schService);
		::CloseServiceHandle(schSCManager);
		return false;
	}
	//else printf("Service description updated successfully.\n");
 
	::CloseServiceHandle(schService);
	::CloseServiceHandle(schSCManager);
	return true;
}

结尾

Windows服务C++版就到这里,稍加改造便可以在项目中使用。

参考文献

  1. Microsoft Docs:开发 Windows 服务应用

  2. 百度百科:LOCAL SERVICE

  3. Microsoft Docs:服务账号

  4. Microsoft Docs:CreateServiceA

  5. Microsoft Docs:Service

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值