编写一个简单的windows服务

服务如同普通的win32窗口一样,都有会有句柄,转发,以及处理等概念.只不过这些概念和win32窗口编程稍有不同,在windows服务编程里面,每个服务都有一个控制句柄,以及相应的处理函数.同样,处理函数会在控制分发函数在收到服务控制程序的控制请求时调用.

想要创建一个服务,首先需要在main函数(winmain函数)当中调用StartServiceCtrlDispatcher函数。StartServiceCtrlDispatcher函数会将一个结构体指针用于注册一个服务。结构体的定义如下:

typedef struct _SERVICE_TABLE_ENTRYW {
    LPWSTR                      lpServiceName;
    LPSERVICE_MAIN_FUNCTIONW    lpServiceProc;
}SERVICE_TABLE_ENTRYW, *LPSERVICE_TABLE_ENTRYW;
typedef VOID (WINAPI *LPSERVICE_MAIN_FUNCTIONW)(
    DWORD   dwNumServicesArgs,
    LPWSTR  *lpServiceArgVectors
);

这个结构体包含两项,第一项是服务的名称,第二项是服务的入口函数。传入到StartServiceCtrlDispatcher的指针实际上应该是一个数组的地址。因为MSDN文档要求指针的最后一项必须是0,也就是字符串名称为0,同时函数地址也为0.

static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv);
static WCHAR ServiceName[] = L"Themes";
static SERVICE_TABLE_ENTRYW ServiceTable[] =
{
    {ServiceName, ServiceMain},
    {NULL, NULL}
};
int wmain(int argc, WCHAR *argv[])
{
    StartServiceCtrlDispatcher(ServiceTable);
    return 0;
}
上面是开启一个服务的第一步,在程序控制进入到ServiceMain之后,整个服务开始初始化。实际上ServiceMain函数是作为服务进程的一个线程在运行的。而整个初始化的过程按照初始化的复杂程度可以分为多个部分,也可以一步到位。在ServiceMain函数当中最重要也是最首要的就是调用RegisterServiceCtrlHandlerExW函数。这个函数实现两个功能,第一个是用于向SCM注册一个类似于win32下面的wndproc函数的分发处理函数用于处理服务控制请求。另外这个函数还会返回一个服务状态句柄用于后面向SCM提交请求。在调用RegisterServiceCtrlHandlerExW函数之后,ServiceMain函数首先需要利用RegisterServiceCtrlHandlerExW返回的SERVICE_STATUS_HANDLE句柄来设置状态。如果初始化较为复杂,则首先提交状态为SERVICE_START_PENDING,在这个状态下。服务将不会接受到服务控制请求。然后整个服务开始完整的初始化。初始化结束之后,服务会创建一个事件,然后提交状态为SERVICE_RUNNING。接下来ServiceMain函数会在自己创建的事件上等待,直到RegisterServiceCtrlHandlerExW函数注册的消息分发处理函数在收到SERVICE_CONTROL_STOP请求的时候才会置事件,ServiceMain才会被唤醒做一些服务停止的清理工作。不过我们的示例当中服务启动函数很简单,所以直接在调用RegisterServiceCtrlHandlerExW函数之后就提交状态为SERVICE_RUNNING,代码如下:

SERVICE_STATUS ServiceStatus;

static VOID
UpdateServiceStatus(DWORD dwState)
{
    ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
    ServiceStatus.dwCurrentState = dwState;

    if (dwState == SERVICE_RUNNING)
        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
    else if (dwState == SERVICE_PAUSED)
        ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE;
    else
        ServiceStatus.dwControlsAccepted = 0;

    ServiceStatus.dwWin32ExitCode = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint = 0;

    if (dwState == SERVICE_START_PENDING ||
        dwState == SERVICE_STOP_PENDING ||
        dwState == SERVICE_PAUSE_PENDING ||
        dwState == SERVICE_CONTINUE_PENDING)
        ServiceStatus.dwWaitHint = 10000;
    else
        ServiceStatus.dwWaitHint = 0;

    SetServiceStatus(ServiceStatusHandle,
                     &ServiceStatus);
}
static VOID CALLBACK ServiceMain(DWORD argc, LPWSTR *argv)
{

    ServiceStatusHandle = RegisterServiceCtrlHandlerExW(ServiceName,
                                                        ServiceControlHandler,
                                                        NULL);
    UpdateServiceStatus(SERVICE_RUNNING);
}
上面还有疑问的地方就是SERVICE_STATUS结构体,他的定义如下所示:

typedef struct _SERVICE_STATUS {
  DWORD dwServiceType;
  DWORD dwCurrentState;
  DWORD dwControlsAccepted;
  DWORD dwWin32ExitCode;
  DWORD dwServiceSpecificExitCode;
  DWORD dwCheckPoint;
  DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;
然后就是被转发贤臣调度的函数ServiceControlHandler函数,他的实现如下所示:

static DWORD WINAPI
ServiceControlHandler(DWORD dwControl,
                      DWORD dwEventType,
                      LPVOID lpEventData,
                      LPVOID lpContext)
{
    switch (dwControl)
    {
        case SERVICE_CONTROL_STOP:
            UpdateServiceStatus(SERVICE_STOPPED);
            return ERROR_SUCCESS;

        case SERVICE_CONTROL_PAUSE:
            UpdateServiceStatus(SERVICE_PAUSED);
            return ERROR_SUCCESS;

        case SERVICE_CONTROL_CONTINUE:
            UpdateServiceStatus(SERVICE_RUNNING);
            return ERROR_SUCCESS;

        case SERVICE_CONTROL_INTERROGATE:
            SetServiceStatus(ServiceStatusHandle,
                             &ServiceStatus);
            return ERROR_SUCCESS;

        case SERVICE_CONTROL_SHUTDOWN:
            UpdateServiceStatus(SERVICE_STOPPED);
            return ERROR_SUCCESS;

        default :
            return ERROR_CALL_NOT_IMPLEMENTED;
    }
}
复杂的实现,可以参考http://download.csdn.net/detail/dayenglish/7330255当中的TFTP服务。

你可能感兴趣的:(windows)