一个被svchost调用的服务应该做成DLL,所以必须定义DLLMain函数,做为动态库的入口。
DLLMain的代码框架如下:
BOOL APIENTRY DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_DETACH:
// 将服务状态设置为SERVICE_CONTROL_STOP
notifyServiceManager(SERVICE_CONTROL_STOP, 0, 0);
break;
default:
break;
}
return TRUE;
}
这里面最重要的是当卸载DLL时,应当通知OS服务已停止,所以需要将服务的状态设置为SERVICE_CONTROL_STOP。本例调用了一个自定义的函数notifyServiceManager来完成服务状态设定,代码如下:
DWORD __currentStatus;
int notifyServiceManager(DWORD status, DWORD exitCode, DWORD progress)
{
__currentStatus = status;
SERVICE_STATUS serviceStatus;
serviceStatus.dwServiceType = SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS;
serviceStatus.dwCurrentState = status;
serviceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
serviceStatus.dwWin32ExitCode = exitCode;
serviceStatus.dwServiceSpecificExitCode = 0;
serviceStatus.dwCheckPoint = progress;
serviceStatus.dwWaitHint = 0;
return SetServiceStatus(__serviceHandle, &serviceStatus);
}
这个函数的最后,调用了Win32 API SetServiceStatus来设置服务状态,关于SetServiceStatus的详细用法,可以参见MSDN文档。
svchost服务DLL应该导出ServiceMain函数,这个函数是服务的入口,代码如下:
SERVICE_STATUS_HANDLE __serviceHandle = nullptr;
extern "C" __declspec(dllexport) void ServiceMain(int argc, char *argv[])
{
__serviceHandle = RegisterServiceCtrlHandler(argv[0], (LPHANDLER_FUNCTION)ServiceHandler);
notifyServiceManager(SERVICE_START_PENDING, 0, 1);
notifyServiceManager(SERVICE_RUNNING, 0, 0);
HANDLE hThread = CreateThread(nullptr, 0, serviceThread, nullptr, 0, nullptr);
if (hThread == nullptr)
{
// writeEventLog("error on create service thread.");
}
return;
}
注意:ServiceMain函数一定要用extern "C"方式声明,否则,在C++代码中,编译器会为ServiceMain生成一个古怪的名称,因而无法被svchost使用。
上面的代码中创建了一个服务线程,用于执行服务的具体动作。执行代码位域serviceThread函数中,其代码如下:
DWORD WINAPI serviceThread(void *params)
{
// 执行具体的服务代码,一般会是循环,需要判断SERVICE_STOP_PENDING和SERVICE_STOPPED状态
do {
// 执行具体的服务代码
} while ((__currentStatus != SERVICE_STOP_PENDING) && (__currentStatus != SERVICE_STOPPED));
return 0;
}
ServiceMain注册了服务控制消息响应函数,名为ServiceHandler,代码如下:
void __stdcall ServiceHandler(DWORD dwControl)
{
switch (dwControl)
{
case SERVICE_CONTROL_STOP:
// do something ...
notifyServiceManager(SERVICE_STOP_PENDING, 0, 0);
notifyServiceManager(SERVICE_STOPPED, 0, 0);
break;
case SERVICE_CONTROL_PAUSE:
// do something ...
notifyServiceManager(SERVICE_PAUSE_PENDING, 0, 1);
notifyServiceManager(SERVICE_PAUSED, 0, 0);
break;
case SERVICE_CONTROL_CONTINUE:
// do something ...
notifyServiceManager(SERVICE_CONTINUE_PENDING, 0, 1);
notifyServiceManager(SERVICE_RUNNING, 0, 0);
break;
case SERVICE_CONTROL_INTERROGATE:
// do something ...
notifyServiceManager(__currentStatus, 0, 0);
break;
default:
// do something ...
notifyServiceManager(__currentStatus, 0, 0);
break;
}
}
注意:上面的代码中,对于每一个控制事件,都会对服务的状态做相应的更新。
至此为止,可被svchost调用的服务就制作完成了。
下一篇将说明如何将这个服务注册到svchost中。