Windows服务编程之服务程序

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Fei_Liu/article/details/73395233

Windows服务程序基本结构

当SCM(服务管理器)启动服务进程时, 该进程必须立即调用StartServiceCtrlDispatcher函数,该函数接收一个服务入口点列表,每个入口点对应该进程中的一个服务,每个入口点由其所对应的服务名称来标识;StartServiceCtrlDispatcher创建了一个命名管道与SCM进行通信,当管道建立后,等待接收到SCM发送的服务启动命令后,创建一个服务线程来调用服务入口点函数,并且实现该服务的命令循环。StartServiceCtrlDispatcher会一直等待SCM传过来的命令,只有该进程对应的所有服务都停止时,才会返回到main函数所在线程,方便进程退出前做一些清理工作。 如果一些初始化工作不超过30秒,也可以在main函数所在线程执行,例如根据不同的命令行参数执行不同的任务,但每个服务自己的初始化工作最好放在自己的服务入口点函数。

每个服务的入口点函数的第一个动作就是调用RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx函数,该函数接收一个称为服务控制处理的函数指针,并将该函数指针保存起来,服务必须实现该函数以便处理来自SCM的各种命令,服务控制处理函数由StartServiceCtrlDispatcher函数来调用,也就是在主线程中调用的,StartServiceCtrlDispatcher函数继续初始化该服务,包括分配内存,从注册表中读入私有的配置数据。

在服务入口点函数初始化服务的过程中,他必须调用SetServiceStatus来定期的给SCM发送状态信息,以表明该服务的启动过程正在如何运行。先看一些该函数原型

BOOL WINAPI SetServiceStatus(
  _In_ SERVICE_STATUS_HANDLE hServiceStatus,
  _In_ LPSERVICE_STATUS      lpServiceStatus
);

第一个参数为RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx返回的服务状态句柄,第二个参数为服务状态结构指针,该结构如下:

typedef struct _SERVICE_STATUS {
  DWORD dwServiceType;
  DWORD dwCurrentState;
  DWORD dwControlsAccepted;
  DWORD dwWin32ExitCode;
  DWORD dwServiceSpecificExitCode;
  DWORD dwCheckPoint;
  DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;
  • dwServiceType参数表示服务类型,它有如下取值:
含义
SERVICE_FILE_SYSTEM_DRIVER Windows文件系统驱动程序,系统保留
SERVICE_KERNEL_DRIVER Windows设备驱动程序,系统保留
SERVICE_WIN32_OWN_PROCESS Windows服务运行于自己的进程,独占进程资源
SERVICE_WIN32_SHARE_PROCESS Windows服务与其他服务共享一个进程,共享进程资源,优点可以节省在单独进程中运行每个一个服务的系统资源,但缺点是一旦一个服务发生错误导致服务程序退出时,其他服务也会停止工作,因此现在也不提倡使用
SERVICE_INTERACTIVE_PROCESS 必须与SERVICE_WIN32_OWN_PROCESS或者SERVICE_WIN32_SHARE_PROCESS共同使用表示可以与桌面进行交互,已经不推荐,可以通过第三方程序实现桌面交互再与服务通信的方式来实现

- dwCurrentState表示当前的服务状态,它有如下取值:

含义
SERVICE_CONTINUE_PENDING 服务处于从暂停状态恢复的过程中
SERVICE_PAUSE_PENDING 服务正在暂停过程中,但还有没完全进入暂停状态
SERVICE_PAUSED 服务已经暂停
SERVICE_RUNNING 服务正在运行
SERVICE_START_PENDING 服务在启动过程中,但还没有准备好对请求进行响应
SERVICE_STOPPED 服务已经停止

- dwControlsAccepted指定服务会接收处理那些控制码,它有如下取值

含义
SERVICE_ACCEPT_NETBINDCHANGE 该服务是一个网络组件,并且能够在服务在服务不重启的情况下,改变其所网络接收的绑定,接收SERVICE_CONTROL_NETBINDADD、SERVICE_CONTROL_NETBINDREMOVE、SERVICE_CONTROL_NETBINDENABLE、SERVICE_CONTROL_NETBINDDISABLE 的通知
SERVICE_ACCEPT_PARAMCHANGE 服务在不重启的情况下能够重新读取其配置参数,接收SERVICE_CONTROL_PARAMCHANGE 通知
SERVICE_ACCEPT_PAUSE_CONTINUE 服务支持暂停和重启,服务能够接收到SERVICE_CONTROL_PAUSE 和SERVICE_CONTROL_CONTINUE的通知
SERVICE_ACCEPT_PRESHUTDOWN 系统在关闭前,能够收到系统的SERVICE_CONTROL_PRESHUTDOWN 通知,用来处理一些关闭前的清理,xp之前不支持此控制码
SERVICE_ACCEPT_SHUTDOWN 能够接收系统退出时的SERVICE_CONTROL_SHUTDOWN 的通知,以便处理一些回收
SERVICE_ACCEPT_STOP 能够接收SERVICE_CONTROL_STOP 的通知来处理一些回收任务

- dwWin32ExitCode逻辑服务正常退出时的退出吗,一般为0(NoError)
- dwServiceSpecificExitCode只有在dwWin32ExitCode设置为ERROR_SERVICE_SPECIFIC_ERROR才有效,可用于服务启动或停止时错误码
- dwCheckPoint,在服务启动,停止,暂停,继续,过程中不断自增来标识一个计数
- dwWaitHint,标识两次调用SetServiceStatus所消耗的时间,这两次调用要么是dwCheckPoint的递增值,要么是dwCurrentState的更改,这个时间超时了,服务管理器可以认为是一种服务发生了错误。

服务控制处理函数(在RegisterServiceCtrlHandler或者RegisterServiceCtrlHandlerEx注册的函数,),用来处理接收来自于SCM的通知,这里以RegisterServiceCtrlHandlerEx注册的函数为例,原型如下:

DWORD WINAPI HandlerEx(
  _In_ DWORD  dwControl,
  _In_ DWORD  dwEventType,
  _In_ LPVOID lpEventData,
  _In_ LPVOID lpContext
);

RegisterServiceCtrlHandler注册函数没有lpContext函数,其中dwControl表示接收到的来自于SCM的通知,除了一些常用通知,还能接收哪些通知与上面SERVICE_STATUS中的dwControlsAccepted有关。其中0-127由系统占用,用户还可以通过RegisterDeviceNotification 注册自己的控制码通知。

下面是一个windows服务程序的基本结构代码,基本满足大多数服务。

#include <windows.h>
#include <tchar.h>
#include <strsafe.h>

#define MyServiceName TEXT("MyService")

bool                    g_bPausedFlag = false;
HANDLE                  g_hSvcStopEvent = NULL;
SERVICE_STATUS          g_MyServiceStatus;
SERVICE_STATUS_HANDLE   g_hMyServiceStatusHandle;

void __stdcall MyServiceMain(DWORD  dwArgc, LPTSTR *lpszArgv);
DWORD __stdcall MyServiceHandlerEx(DWORD  dwControl, DWORD  dwEventType, LPVOID lpEventData, LPVOID lpContext);
void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint);
DWORD MyServiceInitialization(DWORD  dwArgc, LPTSTR *lpszArgv);
DWORD MyServiceWorker(DWORD dwArgc, LPTSTR *lpszArgv);

int _tmain(int argc, TCHAR* argv[])
{
    SERVICE_TABLE_ENTRY dispatchTable[] = { 
        {MyServiceName, (LPSERVICE_MAIN_FUNCTION)MyServiceMain},
        {NULL, NULL} };

    if (!StartServiceCtrlDispatcher(dispatchTable))
    {
        // cleaning worker
    }

    return 0;
}

void __stdcall MyServiceMain(DWORD  dwArgc, LPTSTR *lpszArgv)
{
    g_hSvcStopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
    g_hMyServiceStatusHandle = RegisterServiceCtrlHandlerEx(MyServiceName, (LPHANDLER_FUNCTION_EX)MyServiceHandlerEx, NULL);
    if (g_hMyServiceStatusHandle == NULL)
        return;

    g_MyServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    g_MyServiceStatus.dwServiceSpecificExitCode = 0;
    ReportServiceStatus(SERVICE_START_PENDING, 0, 0);

    DWORD dwRet = MyServiceInitialization(dwArgc, lpszArgv);
    if (dwRet != NO_ERROR)
        ReportServiceStatus(SERVICE_STOPPED, dwRet, 0);
    ReportServiceStatus(SERVICE_RUNNING, 0, 0);

    MyServiceWorker(dwArgc, lpszArgv);

    while (true)
    {
        WaitForSingleObject(g_hSvcStopEvent, INFINITE);
        ReportServiceStatus(SERVICE_STOPPED, 0, 0);
        return;
    }
}

DWORD __stdcall MyServiceHandlerEx(DWORD  dwControl, DWORD  dwEventType, LPVOID lpEventData, LPVOID lpContext)
{
    switch (dwControl)
    {
    case SERVICE_CONTROL_SHUTDOWN:
    case SERVICE_CONTROL_STOP:
        ReportServiceStatus(SERVICE_STOP_PENDING, 0, 0);
        SetEvent(g_hSvcStopEvent);
        break;
    case SERVICE_CONTROL_PAUSE:
        ReportServiceStatus(SERVICE_PAUSE_PENDING, 0, 0);
        g_bPausedFlag = true;
        break;
    case SERVICE_CONTROL_CONTINUE:
        ReportServiceStatus(SERVICE_CONTINUE_PENDING, 0, 0);
        g_bPausedFlag = false;
        break;
    case SERVICE_CONTROL_INTERROGATE:
        break;
    default:
        break;
    }
    return 0;
}

// 执行一些初始化过程
DWORD MyServiceInitialization(DWORD  dwArgc, LPTSTR *lpszArgv)
{
    return NO_ERROR;
}

// 服务工作执行函数
DWORD MyServiceWorker(DWORD dwArgc, LPTSTR *lpszArgv)
{
    return 0;
}

// 向服务控制管理器报告状态信息
void ReportServiceStatus(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;

    g_MyServiceStatus.dwCurrentState = dwCurrentState;
    g_MyServiceStatus.dwWin32ExitCode = dwWin32ExitCode;
    g_MyServiceStatus.dwWaitHint = dwWaitHint;

    if (dwCurrentState == SERVICE_START_PENDING)
        g_MyServiceStatus.dwControlsAccepted = 0;
    else 
        g_MyServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE;

    if ((dwCurrentState == SERVICE_RUNNING) ||
        (dwCurrentState == SERVICE_STOPPED))
        g_MyServiceStatus.dwCheckPoint = 0;
    else 
        g_MyServiceStatus.dwCheckPoint = dwCheckPoint++;

    SetServiceStatus(g_hMyServiceStatusHandle, &g_MyServiceStatus);
}

只需要将上述程序中的MyService替换成自己的服务名称,在MyServiceInitialization函数中完成服务启动时需要的一些初始化工作,如果没有也可以不写此函数,在MyServiceWorker函数中实现自己的服务的主要工作程序。

windows服务配置程序

要修改服务的配置有两种方法,一种就是直接修改注册表,此种方法不提倡,通过SCM管理器提供的接口来配置Windows服务(本质是由SCM来修改注册表),Services.msc与命令行工具sc,都是系统提供的服务配置管理程序。因为SCM是基于RPC的程序,因此也可以配置远程电脑的服务。

Windows服务管理器提供了如下常用的接口函数供我们调用,来配置服务程序:

函数 主要功能
ChangeServiceConfig 修改服务的配置参数
ChangeServiceConfig2 修改一些可选的服务配置参数,例如失败后操作
ControlService 发送控制码到服务
ControlServiceEx 发送控制码到服务
CreateService 创建一个windows服务对象,并将其添加的服务管理器中
DeleteService 从服务管理器中删除一个服务
EnumDependentServices 枚举依赖于某个服务的所有服务
EnumServicesStatusEx 枚举某个服务管理器中的所有服务的状态信息
GetServiceDisplayName 通过服务名称,获取显示名称
GetServiceKeyName 通过服务的显示名称,获取服务名称
OpenSCManager 打开服务管理器,获取服务管理器句柄
OpenService 打开一个服务,获取该服务句柄
QueryServiceConfig 获取服务的配置参数
QueryServiceConfig2 获取可选的服务配置参数
QueryServiceStatusEx 获取当前服务状态信息
StartService 启动一个服务

这些函数具体使用方式和参数请查询MSDN,这里不再详述。

接下来我们实现一个自己的服务配置管理工具,直接上代码:

#include <windows.h>
#include <tchar.h>
#include <stdio.h>
#include <strsafe.h>
#include <Shlwapi.h>
#include <winsvc.h>

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

// 显示提供的所有命令
void DisplayUsage(int argc, TCHAR* argv[]);
void IntallService(int argc, TCHAR* argv[]);
void StartService(int argc, TCHAR* argv[]);
void StopService(int argc, TCHAR* argv[]);
BOOL StopDependentServices(SC_HANDLE schSCManager, SC_HANDLE schService);
void RemoveService(int argc, TCHAR* argv[]);


int _tmain(int argc, TCHAR* argv[])
{
    if (argc < 2)
    {
        DisplayUsage(argc, argv);
        return 0;
    }

    TCHAR szCommand[32] = { 0 };
    StringCchCopy(szCommand, 32, argv[1]);

    if (lstrcmpi(szCommand, _T("create")))
    {
        IntallService(argc, argv);
    }
    else if (lstrcmpi(szCommand, _T("start")))
    {
        StartService(argc, argv);
    }
    else if (lstrcmpi(szCommand, _T("stop")))
    {
        StopService(argc, argv);
    }
    else if (lstrcmpi(szCommand, _T("delete")))
    {
        RemoveService(argc, argv);
    }

    return 0;
}

void DisplayUsage(int argc, TCHAR* argv[])
{

}

void IntallService(int argc, TCHAR* argv[])
{
    if (argc != 4)
    {
        _tprintf(_T("sc create [service name] [binPath= ]"));
        return;
    }

    TCHAR szServiceName[256] = { 0 };
    TCHAR szBinPath[MAX_PATH] = { 0 };
    StringCchCopy(szServiceName, 256, argv[3]);
    StringCchCopy(szBinPath, MAX_PATH, argv[4]);

    if (!PathFileExists(szBinPath))
    {
        _tprintf(_T("文件路径不存在"));
        return;
    }

    SC_HANDLE schSCManager;
    SC_HANDLE schService;

    schSCManager = OpenSCManager(
        NULL,                    // 如果是本机传入NULL,如果是远程写远端机器名
        NULL, SC_MANAGER_ALL_ACCESS);  

    if (NULL == schSCManager)
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    schService = CreateService(
        schSCManager,              // SCM句柄 
        szServiceName,             // 服务名称 
        szServiceName,             // 显示名称 
        SERVICE_ALL_ACCESS,        // 服务权限
        SERVICE_WIN32_OWN_PROCESS, // 服务类型
        SERVICE_AUTO_START,        // 服务启动类型
        SERVICE_ERROR_NORMAL,      // 服务错误控制类型
        szBinPath,                 // 服务exe所在路径
        NULL,                      // 服务所需要加载的组 
        NULL,                      // tag标识符
        NULL,                      // 依赖的服务
        NULL,                      // 服务账户,NULL表示为localSystem
        NULL);                     // 账户密码

    if (schService == NULL)
    {
        _tprintf(_T("CreateService failed (%d)\n"), GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }
    else
    {
        printf("Service installed successfully\n");
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}

void StartService(int argc, TCHAR* argv[])
{
    if (argc != 3)
    {
        _tprintf(_T(" sc start [service name]"));
        return;
    }

    TCHAR szServiceName[256] = { 0 };
    StringCchCopy(szServiceName, 256, argv[3]);

    SC_HANDLE schSCManager;
    SC_HANDLE schService;
    schSCManager = OpenSCManager(NULL, NULL,  SC_MANAGER_ALL_ACCESS);
    if (NULL == schSCManager)
    {
        _tprintf(_T("OpenSCManager failed (%d)\n"), GetLastError());
        return;
    }

    schService = OpenService(
        schSCManager,        
        szServiceName,            
        SERVICE_ALL_ACCESS);  

    if (schService == NULL)
    {
        _tprintf(_T("OpenService failed (%d)\n"), GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }

    SERVICE_STATUS_PROCESS ssStatus;
    DWORD dwBytesNeeded;
    // 查看服务是否已经启动
    if (!QueryServiceStatusEx(
        schService,                     // 服务句柄 
        SC_STATUS_PROCESS_INFO,         // 要获取的信息级别,不同的级别返回的信息详细程度不同
        (LPBYTE)&ssStatus,              // 服务进程状态结构体
        sizeof(SERVICE_STATUS_PROCESS), // 服务进程状态结构体大小
        &dwBytesNeeded))                // 还需要的额外地址空间
    {
        _tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return;
    }

    // 如果服务已经启动,直接返回
    if (ssStatus.dwCurrentState != SERVICE_STOPPED && 
        ssStatus.dwCurrentState != SERVICE_STOP_PENDING)
    {
        _tprintf(_T("Cannot start the service because it is already running\n"));
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return;
    }

    DWORD dwOldCheckPoint;
    DWORD dwStartTickCount;
    DWORD dwWaitTime;
    // 保存原始的CheckPoint
    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = ssStatus.dwCheckPoint;

    // 如果服务正在关闭,则等待关闭后再启动
    while (ssStatus.dwCurrentState == SERVICE_STOP_PENDING)
    {
        dwWaitTime = ssStatus.dwWaitHint / 10;
        if (dwWaitTime < 1000)
            dwWaitTime = 1000;
        else if (dwWaitTime > 10000)
            dwWaitTime = 10000;

        Sleep(dwWaitTime);

        // 检查服务是否关闭
        if (!QueryServiceStatusEx(
            schService,                     
            SC_STATUS_PROCESS_INFO,        
            (LPBYTE)&ssStatus,             
            sizeof(SERVICE_STATUS_PROCESS), 
            &dwBytesNeeded))             
        {
            _tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
            CloseServiceHandle(schService);
            CloseServiceHandle(schSCManager);
            return;
        }

        if (ssStatus.dwCheckPoint > dwOldCheckPoint)
        {
            dwStartTickCount = GetTickCount();
            dwOldCheckPoint = ssStatus.dwCheckPoint;
        }
        else
        {
            if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
            {
                _tprintf(_T("Timeout waiting for service to stop\n"));
                CloseServiceHandle(schService);
                CloseServiceHandle(schSCManager);
                return;
            }
        }
    }

    // 尝试启动服务
    if (!StartService(
        schService,  // 服务句柄
        0,           // 参数个数 
        NULL))       // 参数
    {
        _tprintf(_T("StartService failed (%d)\n"), GetLastError());
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return;
    }
    else
    {
        _tprintf(_T("Service start pending...\n"));
    }

    // 检查服务状态直到到服务启动为止 
    if (!QueryServiceStatusEx(
        schService,                    
        SC_STATUS_PROCESS_INFO,         
        (LPBYTE)&ssStatus,             
        sizeof(SERVICE_STATUS_PROCESS), 
        &dwBytesNeeded))              
    {
        _tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
        CloseServiceHandle(schService);
        CloseServiceHandle(schSCManager);
        return;
    }

    dwStartTickCount = GetTickCount();
    dwOldCheckPoint = ssStatus.dwCheckPoint;
    while (ssStatus.dwCurrentState == SERVICE_START_PENDING)
    {
        dwWaitTime = ssStatus.dwWaitHint / 10;
        if (dwWaitTime < 1000)
            dwWaitTime = 1000;
        else if (dwWaitTime > 10000)
            dwWaitTime = 10000;

        Sleep(dwWaitTime);

        if (!QueryServiceStatusEx(
            schService,             
            SC_STATUS_PROCESS_INFO, 
            (LPBYTE)&ssStatus,             
            sizeof(SERVICE_STATUS_PROCESS), 
            &dwBytesNeeded))              
        {
            _tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
            break;
        }

        if (ssStatus.dwCheckPoint > dwOldCheckPoint)
        {
            dwStartTickCount = GetTickCount();
            dwOldCheckPoint = ssStatus.dwCheckPoint;
        }
        else
        {
            if (GetTickCount() - dwStartTickCount > ssStatus.dwWaitHint)
            {
                break;
            }
        }
    }

    // 检查服务是否启动
    if (ssStatus.dwCurrentState == SERVICE_RUNNING)
    {
        _tprintf(_T("Service started successfully.\n"));
    }
    else
    {
        _tprintf(_T("Service not started. \n"));
        _tprintf(_T("  Current State: %d\n"), ssStatus.dwCurrentState);
        _tprintf(_T("  Exit Code: %d\n"), ssStatus.dwWin32ExitCode);
        _tprintf(_T("  Check Point: %d\n"), ssStatus.dwCheckPoint);
        _tprintf(_T("  Wait Hint: %d\n"), ssStatus.dwWaitHint);
    }

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}

void StopService(int argc, TCHAR* argv[])
{
    if (argc != 3)
    {
        _tprintf(_T(" sc stop [service name]"));
        return;
    }

    TCHAR szServiceName[256] = { 0 };
    StringCchCopy(szServiceName, 256, argv[3]);

    SC_HANDLE schSCManager;
    SC_HANDLE schService;
    schSCManager = OpenSCManager(
        NULL,                    
        NULL,                    
        SC_MANAGER_ALL_ACCESS);  

    if (NULL == schSCManager)
    {
        printf("OpenSCManager failed (%d)\n", GetLastError());
        return;
    }

    schService = OpenService(
        schSCManager,         
        szServiceName,            
        SERVICE_STOP |
        SERVICE_QUERY_STATUS |
        SERVICE_ENUMERATE_DEPENDENTS);

    if (schService == NULL)
    {
        _tprintf(_T("OpenService failed (%d)\n"), GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }

    SERVICE_STATUS_PROCESS ssp;
    DWORD dwBytesNeeded;
    // 检查服务是否已经在关闭状态
    if (!QueryServiceStatusEx(
        schService,
        SC_STATUS_PROCESS_INFO,
        (LPBYTE)&ssp,
        sizeof(SERVICE_STATUS_PROCESS),
        &dwBytesNeeded))
    {
        printf("QueryServiceStatusEx failed (%d)\n", GetLastError());
        goto stop_cleanup;
    }

    if (ssp.dwCurrentState == SERVICE_STOPPED)
    {
        _tprintf(_T("Service is already stopped.\n"));
        goto stop_cleanup;
    }

    DWORD dwStartTime = GetTickCount();
    DWORD dwTimeout = 30000;
    DWORD dwWaitTime;
    // 如果服务正在关闭,等待其完全关闭
    while (ssp.dwCurrentState == SERVICE_STOP_PENDING)
    {
        _tprintf(_T("Service stop pending...\n"));
        dwWaitTime = ssp.dwWaitHint / 10;

        if (dwWaitTime < 1000)
            dwWaitTime = 1000;
        else if (dwWaitTime > 10000)
            dwWaitTime = 10000;

        Sleep(dwWaitTime);

        if (!QueryServiceStatusEx(
            schService,
            SC_STATUS_PROCESS_INFO,
            (LPBYTE)&ssp,
            sizeof(SERVICE_STATUS_PROCESS),
            &dwBytesNeeded))
        {
            _tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
            goto stop_cleanup;
        }

        if (ssp.dwCurrentState == SERVICE_STOPPED)
        {
            _tprintf(_T("Service stopped successfully.\n"));
            goto stop_cleanup;
        }

        if (GetTickCount() - dwStartTime > dwTimeout)
        {
            _tprintf(_T("Service stop timed out.\n"));
            goto stop_cleanup;
        }
    }

    // 如果服务正在运行过程中,需要先关闭依赖该服务的服务
    StopDependentServices(schSCManager, schService);

    // 发送一个服务退出通知给服务程序
    if (!ControlService(
        schService,
        SERVICE_CONTROL_STOP,
        (LPSERVICE_STATUS)&ssp))
    {
        _tprintf(_T("ControlService failed (%d)\n"), GetLastError());
        goto stop_cleanup;
    }

    // 等待服务关闭
    while (ssp.dwCurrentState != SERVICE_STOPPED)
    {
        Sleep(ssp.dwWaitHint);
        if (!QueryServiceStatusEx(
            schService,
            SC_STATUS_PROCESS_INFO,
            (LPBYTE)&ssp,
            sizeof(SERVICE_STATUS_PROCESS),
            &dwBytesNeeded))
        {
            _tprintf(_T("QueryServiceStatusEx failed (%d)\n"), GetLastError());
            goto stop_cleanup;
        }

        if (ssp.dwCurrentState == SERVICE_STOPPED)
            break;

        if (GetTickCount() - dwStartTime > dwTimeout)
        {
            _tprintf(_T("Wait timed out\n"));
            goto stop_cleanup;
        }
    }
    _tprintf(_T("Service stopped successfully\n"));

stop_cleanup:
    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}

BOOL StopDependentServices(SC_HANDLE schSCManager, SC_HANDLE schService)
{
    DWORD i;
    DWORD dwBytesNeeded;
    DWORD dwCount;

    LPENUM_SERVICE_STATUS   lpDependencies = NULL;
    ENUM_SERVICE_STATUS     ess;
    SC_HANDLE               hDepService;
    SERVICE_STATUS_PROCESS  ssp;

    DWORD dwStartTime = GetTickCount();
    DWORD dwTimeout = 30000; 

    if (EnumDependentServices(schService, SERVICE_ACTIVE,
        lpDependencies, 0, &dwBytesNeeded, &dwCount))
    {
        return TRUE;
    }
    else
    {
        if (GetLastError() != ERROR_MORE_DATA)
            return FALSE; 

        // Allocate a buffer for the dependencies.
        lpDependencies = (LPENUM_SERVICE_STATUS)HeapAlloc(
            GetProcessHeap(), HEAP_ZERO_MEMORY, dwBytesNeeded);

        if (!lpDependencies)
            return FALSE;

        __try {
            // Enumerate the dependencies.
            if (!EnumDependentServices(schService, SERVICE_ACTIVE,
                lpDependencies, dwBytesNeeded, &dwBytesNeeded,
                &dwCount))
                return FALSE;

            for (i = 0; i < dwCount; i++)
            {
                ess = *(lpDependencies + i);
                // Open the service.
                hDepService = OpenService(schSCManager,
                    ess.lpServiceName,
                    SERVICE_STOP | SERVICE_QUERY_STATUS);

                if (!hDepService)
                    return FALSE;

                __try {
                    // Send a stop code.
                    if (!ControlService(hDepService,
                        SERVICE_CONTROL_STOP,
                        (LPSERVICE_STATUS)&ssp))
                        return FALSE;

                    // Wait for the service to stop.
                    while (ssp.dwCurrentState != SERVICE_STOPPED)
                    {
                        Sleep(ssp.dwWaitHint);
                        if (!QueryServiceStatusEx(
                            hDepService,
                            SC_STATUS_PROCESS_INFO,
                            (LPBYTE)&ssp,
                            sizeof(SERVICE_STATUS_PROCESS),
                            &dwBytesNeeded))
                            return FALSE;

                        if (ssp.dwCurrentState == SERVICE_STOPPED)
                            break;

                        if (GetTickCount() - dwStartTime > dwTimeout)
                            return FALSE;
                    }
                }
                __finally
                {
                    CloseServiceHandle(hDepService);
                }
            }
        }
        __finally
        {
            HeapFree(GetProcessHeap(), 0, lpDependencies);
        }
    }
    return TRUE;
}


void RemoveService(int argc, TCHAR* argv[])
{
    if (argc != 3)
    {
        _tprintf(_T("sc delete [service name]"));
        return;
    }

    TCHAR szServiceName[256] = { 0 };
    StringCchCopy(szServiceName, 256, argv[3]);

    SC_HANDLE schSCManager;
    SC_HANDLE schService;
    schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);  

    if (NULL == schSCManager)
    {
        _tprintf(_T("OpenSCManager failed (%d)\n"), GetLastError());
        return;
    }

    // 打开服务获取服务句柄
    schService = OpenService(schSCManager, szServiceName, DELETE);
    if (schService == NULL)
    {
        _tprintf(_T("OpenService failed (%d)\n"), GetLastError());
        CloseServiceHandle(schSCManager);
        return;
    }

    // 删除服务
    if (!DeleteService(schService))
    {
        _tprintf(_T("DeleteService failed (%d)\n"), GetLastError());
    }
    else 
        _tprintf(_T("Service deleted successfully\n"));

    CloseServiceHandle(schService);
    CloseServiceHandle(schSCManager);
}
展开阅读全文

没有更多推荐了,返回首页