VOID _tmain (int argc, LPTSTR argv[])
{
SERVICE_TABLE_ENTRY DispatchTable[] =
{
{ ServiceName, ServiceMain },
{ NULL, NULL }
};
StartServiceCtrlDispatcher (DispatchTable);
return;
}
3. 然后就是ServiceMain函数:
the main program. */
void WINAPI ServiceMain (DWORD argc, LPTSTR argv[])
{
HANDLE hFile = NULL;
DWORD Context = 1;
size_t bytes_need_write = 0;
DWORD bytes_written = 0;
TCHAR write_buffer[255];
SYSTEMTIME cur_time;
DWORD n;
LARGE_INTEGER file_size;
// init logger
logger_set_root_directory(TEXT("C:\\"));
hServStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
hServStatus.dwCurrentState = SERVICE_START_PENDING;
hServStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN;
hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
hServStatus.dwServiceSpecificExitCode = 0;
hServStatus.dwCheckPoint = 0;
// in 2000ms, we should increment dwCheckPoint or set new status
// while current status is a PENDING start/continue/stop state
hServStatus.dwWaitHint = 5000;
/* Warning. Older VC++ version do not have RegisterServiceCtrlHandlerEx
* defined. You can use RegisterServiceCtrlHandler just as well */
#ifdef RegisterServiceCtrlHandlerEx
hSStat = RegisterServiceCtrlHandlerEx(ServiceName, ServerCtrlHandlerEx, &Context);
#else
hSStat = RegisterServiceCtrlHandler(ServiceName, ServerCtrlHandler);
#endif
if (hSStat == NULL) {
GET_ERROR_CODE(n);
UTILS_RIF_WITH_LOG(FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__,
TEXT("Register service ctrl handle failed. Reason: %s\n"),
utils_format_error_string(n));
}
// PENDING start
if (!SetServiceStatus (hSStat, &hServStatus)) {
GET_ERROR_CODE(n);
UTILS_RIF_WITH_LOG(FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__,
TEXT("Set service status failed. Reason: %s\n"),
utils_format_error_string(n));
}
// Open the file and log current time
hFile = CreateFile(TEXT("C:\\testserv.txt"), GENERIC_WRITE, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
GET_ERROR_CODE(n);
UTILS_RIF_WITH_LOG(FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__,
TEXT("Create testserv file failed. Reason: %s\n"),
utils_format_error_string(n));
}
// Seek to the end of file
UTILS_RETURN_IF_FAIL(GetFileSizeEx(hFile, &file_size));
UTILS_RETURN_IF_FAIL(SetFilePointerEx(hFile, file_size, NULL, FILE_BEGIN));
GetLocalTime(&cur_time);
StringCchPrintf(write_buffer, _countof(write_buffer), TEXT("TestServ started, write time: %d-%d-%d %d:%d:%d\n"),
cur_time.wYear, cur_time.wMonth, cur_time.wDay, cur_time.wHour, cur_time.wMinute, cur_time.wSecond);
StringCchLength(write_buffer, _countof(write_buffer), &bytes_need_write);
WriteFile(hFile, write_buffer, bytes_need_write * sizeof(TCHAR), &bytes_written, NULL);
hServStatus.dwCheckPoint = 0;
hServStatus.dwWin32ExitCode = NO_ERROR;
hServStatus.dwServiceSpecificExitCode = 0;
hServStatus.dwCurrentState = SERVICE_RUNNING;
if (!SetServiceStatus(hSStat, &hServStatus)) {
GET_ERROR_CODE(n);
UTILS_RIF_WITH_LOG(FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__,
TEXT("Set service status failed. Reason: %s\n"),
utils_format_error_string(n));
}
// block here until service stop
while (!service_terminate) {
Sleep(1000);
}
// stop service
GetLocalTime(&cur_time);
StringCchPrintf(write_buffer, _countof(write_buffer), TEXT("TestServ stopped, write time: %d-%d-%d %d:%d:%d\n"),
cur_time.wYear, cur_time.wMonth, cur_time.wDay, cur_time.wHour, cur_time.wMinute, cur_time.wSecond);
StringCchLength(write_buffer, _countof(write_buffer), &bytes_need_write);
WriteFile(hFile, write_buffer, bytes_need_write * sizeof(TCHAR), &bytes_written, NULL);
CloseHandle(hFile);
hServStatus.dwCheckPoint = 0;
hServStatus.dwWin32ExitCode = NO_ERROR;
hServStatus.dwServiceSpecificExitCode = 0;
hServStatus.dwCurrentState = SERVICE_STOPPED;
if (!SetServiceStatus(hSStat, &hServStatus)) {
GET_ERROR_CODE(n);
UTILS_RIF_WITH_LOG(FALSE, LOG_LEVEL_ERROR, __SDFILE__, __LINE__,
TEXT("Set service status failed. Reason: %s\n"),
utils_format_error_string(n));
}
return;
}
B. RegisterServiceCtrlHandlerEx函数。用来注册SCM动作的响应函数。也就是stop/continue这些命令的响应。例子:
#ifdef RegisterServiceCtrlHandlerEx
DWORD WINAPI ServerCtrlHandlerEx( DWORD dwControl, DWORD dwEventType,
LPVOID lpEventData, LPVOID lpContext)
#else
DWORD WINAPI ServerCtrlHandler( DWORD dwControl)
#endif
// requested control code
{
DWORD n;
switch (dwControl) {
case SERVICE_CONTROL_SHUTDOWN:
case SERVICE_CONTROL_STOP:
service_terminate = TRUE;
hServStatus.dwCheckPoint++;
hServStatus.dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR;
hServStatus.dwServiceSpecificExitCode = 0;
hServStatus.dwCurrentState = SERVICE_STOP_PENDING;
if (!SetServiceStatus(hSStat, &hServStatus)) {
GET_ERROR_CODE(n);
UTILS_RVIF_WITH_LOG(FALSE, NO_ERROR, LOG_LEVEL_ERROR, __SDFILE__, __LINE__,
TEXT("Set service status failed. Reason: %s\n"),
utils_format_error_string(n));
}
return NO_ERROR;
case SERVICE_CONTROL_PAUSE:
break;
case SERVICE_CONTROL_CONTINUE:
break;
case SERVICE_CONTROL_INTERROGATE:
return NO_ERROR;
default:
if (dwControl > 127 && dwControl < 256) /* User Defined */
break;
}
return ERROR_CALL_NOT_IMPLEMENTED;
}
(1) 对于没有handle的control命令,return ERROR_CALL_NOT_IMPLEMENTED,对于handle的,返回NO_ERROR。例外是对于SERVICE_CONTROL_INTERROGATE,也要返回NO_ERROR,即使我们没有handle这个control。更具体的信息查看MSDN。
4. service本身的关键代码就是这些,下面是使用SCM如何创建一个service:
int _tmain(int argc, PTSTR argv[], PTSTR env[])
{
DWORD errcode = 0;
SC_HANDLE hManager = NULL;
SC_HANDLE hService = NULL;
setlocale(LC_ALL, "CHS");
// Open SCManager
hManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (NULL == hManager) {
errcode = GetLastError();
_tprintf(TEXT("Open service manager failed. Reason: %s\n"), utils_format_error_string(errcode));
goto failed;
}
// create service
hService = CreateService(
hManager, // SCM database
SVCNAME, // name of service
SVCNAME, // service name to display
SERVICE_ALL_ACCESS, // desired access
SERVICE_WIN32_OWN_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
TEXT("C:\\ScheduleDownload\\Practise\\TestServ\\Debug\\TestServ.exe"), // path to service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (NULL == hService) {
errcode = GetLastError();
_tprintf(TEXT("Create service failed. Reason: %s\n"), utils_format_error_string(errcode));
CloseServiceHandle(hManager);
goto failed;
}
CloseServiceHandle(hService);
CloseServiceHandle(hManager);
return 0;
failed:
// wait key
_getch();
return 1;
}
这就比较简单了,使用OpenSCManager打开SCM,使用CreateService创建一个service,此时在windows的服务中就能看到了。start type中,设定为SERVICE_AUTO_START就会在开机时启动(不需要用户登录就会启动的,已经测试过了)。其他的函数比如StartService/DeleteService/QueryService...看看MSDN就OK了。