C++之创建Windows系统服务

Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。

一.一个简单的Windows服务

#include <iostream>
#include <Windows.h>
#include <winsvc.h>
#include <string>

#pragma comment (lib,"Advapi32.lib")

#define SERVICE_NAME "TestService"
#define SERVICE_DESC "TestService cao shang pa"

SERVICE_STATUS gServiceStatus;
SERVICE_STATUS_HANDLE gServiceStatusHandle;
HANDLE gServiceStopEvent = NULL;

void WINAPI ServiceMain(int argc, char** argv);
void WINAPI ServiceCtrlHandler(DWORD request);
void ReportServiceStatus(DWORD CurrentStatus, DWORD Win32ExitCode, DWORD WaitHint);

void WINAPI ServiceMain(int argc, char** argv)
{
    gServiceStatusHandle = RegisterServiceCtrlHandler(SERVICE_NAME, ServiceCtrlHandler);

    if (!gServiceStatusHandle)
    {
        std::cout<<"RegisterServiceCtrlHandler failed"<<std::endl;
        OutputDebugString("RegisterServiceCtrlHandler failed");
        return;

    }

    std::cout<<"RegisterServiceCtrlHandler succeed"<<std::endl;
    OutputDebugString("RegisterServiceCtrlHandler succeed");

    //向SCM 报告运行状态.
    ReportServiceStatus(SERVICE_START_PENDING, NO_ERROR, 3000);
    OutputDebugString("Service starting...");
    //在此处添加你自己希望服务做的工作,
    // TODO

    gServiceStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    if (!gServiceStopEvent)
    {
        ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
        OutputDebugString("Service stopped");
        return;
    }
    else
    {
        ReportServiceStatus(SERVICE_RUNNING, NO_ERROR, 0);
        OutputDebugString("Service running...");
    }

    WaitForSingleObject(gServiceStopEvent, INFINITE);
    ReportServiceStatus(SERVICE_STOPPED, NO_ERROR, 0);
    OutputDebugString("Service stopped");
}

void WINAPI ServiceCtrlHandler(DWORD request)
{
    switch (request)
    {
    case SERVICE_CONTROL_STOP:
        ReportServiceStatus(SERVICE_STOP_PENDING, NO_ERROR, 0);
        OutputDebugString("Service stopping...");
        SetEvent(gServiceStopEvent);
        return;

    case SERVICE_CONTROL_SHUTDOWN:
        break;

    default:
        break;

    }
    ReportServiceStatus(gServiceStatus.dwCurrentState, NO_ERROR, 0);
}

void ReportServiceStatus(DWORD CurrentStatus, DWORD Win32ExitCode, DWORD WaitHint)
{
    static DWORD nCheckPoint = 1;
    gServiceStatus.dwServiceType = SERVICE_WIN32;
    gServiceStatus.dwCurrentState = CurrentStatus;
    gServiceStatus.dwWin32ExitCode = Win32ExitCode;
    gServiceStatus.dwWaitHint = WaitHint;
    if (CurrentStatus == SERVICE_START_PENDING)
    {
        gServiceStatus.dwControlsAccepted = 0;
    }
    else
    {
        gServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
    }
    if ((CurrentStatus == SERVICE_RUNNING) || (CurrentStatus == SERVICE_STOPPED))
    {
        gServiceStatus.dwCheckPoint = 0;
    }
    else
    {
        gServiceStatus.dwCheckPoint = nCheckPoint++;
    }
    gServiceStatus.dwServiceSpecificExitCode = 0;

    SetServiceStatus(gServiceStatusHandle, &gServiceStatus);
}

int main(int argc, char *argv[])
{
    SERVICE_TABLE_ENTRY entrytable[2];
    entrytable[0].lpServiceName = const_cast<char *>(std::string(SERVICE_NAME).c_str());
    entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
    entrytable[1].lpServiceName = NULL;
    entrytable[1].lpServiceProc = NULL;
    // 也可以写成下面这种形式.
    //    SERVICE_TABLE_ENTRY entrytable[] =
    //    {
    //        {
    //            SERVICE_NAME,
    //            (LPSERVICE_MAIN_FUNCTION)ServiceMain
    //        },
    //        {
    //            NULL,
    //            NULL
    //        }
    //    };

    if (!StartServiceCtrlDispatcher(entrytable))
    {
        std::cout<<"StartServiceCtrlDispatcher failed";
        OutputDebugString("StartServiceCtrlDispatcher failed");
    }

    return 0;
}

代码很简单,api手册上都可以查到,需要注意的一点是ServiceMain函数是服务的入口点,它运行在一个单独的线程当中,这个线程是由控制分派器创建的。

下面是一些服务相关的操作

// 创建服务,注意"="后面有一个空格
sc create TestService binpath= C:\Users\zhang\Desktop\TestService\out\TestService.exe
// 启动服务器
sc start TestService 
// 查询服务当前状态
sc query TestService 
// 停止服务
sc stop TestService 
// 删除服务
sc delete TestService

下面是安装服务的脚本InstallService.bat

@echo off

rem 获取绝对路径
set "CURRENT_DIR=%~dp0"

set "EXE_NAME=TestService.exe"

@echo %CURRENT_DIR%%EXE_NAME%

rem 创建windows服务
sc create TestService binpath= %CURRENT_DIR%%EXE_NAME%
sc config TestService start=AUTO
sc start TestService

下面是卸载服务的脚本UninstallService.bat

@echo off

rem 获取绝对路径
set "CURRENT_DIR=%~dp0"

set "EXE_NAME=TestService.exe"

@echo %CURRENT_DIR%%EXE_NAME%

rem 删除windows服务
sc stop TestService
sc delete TestService

当然也可以在代码中完成InstallService.bat和UninstallService.bat这两个脚本的功能

int InstallService()
{
    if (IsInstalled())
    {
        std::cout<<"Service already installed"<<std::endl;
        OutputDebugString("Service already installed");
        return 0;
    }

    //打开服务控制管理器.
    SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hSCM == NULL)
    {
        std::cout<<"OpenSCManager failed"<<std::endl;
        OutputDebugString("OpenSCManager failed");
        return -1;
    }

    // Get the executable file path
    TCHAR szFilePath[MAX_PATH];
    GetModuleFileName(NULL, szFilePath, MAX_PATH);

    //创建服务,并设置服务自动启动.
    SC_HANDLE hService = CreateService(
                hSCM, SERVICE_NAME, SERVICE_NAME,
                SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
                SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
                szFilePath, NULL, NULL, NULL, NULL, NULL);

    if (hService == NULL)
    {
        CloseServiceHandle(hSCM);
        std::cout<<"CreateService failed"<<std::endl;
        OutputDebugString("CreateService failed");
        return -1;
    }

    //设置服务描述(在服务列表中可与看到)
    SERVICE_DESCRIPTION Description;
    TCHAR szDescription[1024];
    ZeroMemory(szDescription, 0);
    ZeroMemory(&Description, sizeof (SERVICE_DESCRIPTION));
    lstrcpy(szDescription, SERVICE_DESC);
    Description.lpDescription = szDescription;
    ChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &Description);

    if (StartService(hService, 0, NULL) == FALSE)
    {
        CloseServiceHandle(hService);
        CloseServiceHandle(hSCM);
        std::cout<<"StartService failed"<<std::endl;
        OutputDebugString("StartService failed");
        return -1;
    }

    CloseServiceHandle(hService);
    CloseServiceHandle(hSCM);

    std::cout<<"Install service succeed"<<std::endl;
    OutputDebugString("Install service succeed");

    return 0;
}
int UninstallService()
{
    if (!IsInstalled())
    {
        std::cout<<"Service not installed"<<std::endl;
        OutputDebugString("Service not installed");
        return 0;
    }

    SC_HANDLE hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
    if (hSCM == NULL)
    {
        std::cout<<"OpenSCManager failed"<<std::endl;
        OutputDebugString("OpenSCManager failed");
        return -1;
    }

    SC_HANDLE hService = OpenService(hSCM, SERVICE_NAME, SERVICE_QUERY_STATUS | SERVICE_STOP | DELETE);
    if (hService == NULL)
    {
        CloseServiceHandle(hSCM);
        std::cout<<"OpenService failed"<<std::endl;
        OutputDebugString("OpenService failed");
        return -1;
    }

    SERVICE_STATUS status;
    if (QueryServiceStatus(hService, &status) == FALSE)
    {
        CloseServiceHandle(hService);
        CloseServiceHandle(hSCM);
        std::cout<<"QueryServiceStatus failed"<<std::endl;
        OutputDebugString("QueryServiceStatus failed");
        return -1;
    }
    if (status.dwCurrentState == SERVICE_RUNNING)
    {
        if (ControlService(hService, SERVICE_CONTROL_STOP, &status) == FALSE)
        {
            CloseServiceHandle(hService);
            CloseServiceHandle(hSCM);
            std::cout<<"Stop Service failed"<<std::endl;
            OutputDebugString("Stop Service failed");
            return -1;
        }
    }
    //如果服务状态为已停止,则卸载该系统服务.
    if (status.dwCurrentState == SERVICE_STOPPED)
    {
        //删除服务.
        BOOL bDelete = DeleteService(hService);
        CloseServiceHandle(hService);
        CloseServiceHandle(hSCM);

        if (bDelete)
        {
            std::cout<<"Uninstall service succeed"<<std::endl;
            OutputDebugString("Uninstall service succeed");
            return 0;
        }
        else
        {
            std::cout<<"Uninstall service failed"<<std::endl;
            OutputDebugString("Uninstall service failed");
            return -1;
        }
    }

    return -1;
}

然后把main函数也改一下

int main(int argc, char *argv[])
{
    if (argc == 2)
    {
        if (strcmp(argv[1], "-install") == 0)
        {
            InstallService();
        }
        else if (strcmp(argv[1], "-uninstall") == 0)
        {
            UninstallService();
        }
    }
    else
    {
        SERVICE_TABLE_ENTRY entrytable[2];
        entrytable[0].lpServiceName = const_cast<char *>(std::string(SERVICE_NAME).c_str());
        entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;
        entrytable[1].lpServiceName = NULL;
        entrytable[1].lpServiceProc = NULL;
        // 也可以写成下面这种形式.
        //    SERVICE_TABLE_ENTRY entrytable[] =
        //    {
        //        {
        //            SERVICE_NAME,
        //            (LPSERVICE_MAIN_FUNCTION)ServiceMain
        //        },
        //        {
        //            NULL,
        //            NULL
        //        }
        //    };

        if (!StartServiceCtrlDispatcher(entrytable))
        {
            std::cout<<"StartServiceCtrlDispatcher failed";
            OutputDebugString("StartServiceCtrlDispatcher failed");
        }
    }

    return 0;
}

这样就能用下面的指令来安装和卸载服务了

TestService -install
TestService -uninstall

二.DebugView调试工具

我们可以用这款软件来调试windows服务程序,代码中用OutputDebugString打印调试信息,DebugView就能捕获并显示出来
如下图所示,把能勾的都勾上

原文链接:https://blog.csdn.net/caoshangpa/article/details/79475677

  • 3
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

草上爬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值