服务如同普通的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服务。