编写windows 服务(c++)
2016-06-23 16:01
405 查看
A Main Entry point (like any application)
A Service Entry point
A Service Control Handler
You can use a Visual Studio template project to help you get started. I just created an "Empty" Win32 Console Application.
Before we get started on the Main Entry Point, we need to declare some globals that will be used throughout the service. To be more object oriented you can always create a class that represents your service and use class members instead of globals. To keep
it simple I will use globals.
We will need a
We will also need a
Here are some additional globals and function declarations that will be used and explained as we go along.
Main Entry Point
int _tmain (int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
{
return GetLastError ();
}
return 0;
}
In the main entry point you quickly call
next.
The Service Main Entry Point performs the following tasks:
Initialize any necessary items which we deferred from the Main Entry Point.
Register the service control handler which will handle Service Stop, Pause, Continue, Shutdown, etc control commands. These are registered via the
Set Service Status to
Perform start up tasks. Like creating threads/events/mutex/IPCs/etc.
The Service Control Handler was registered in your Service Main Entry point. Each service must have a handler to handle control requests from the SCM. The control handler must return within 30 seconds or the SCM will return an error stating that the service
is not responding. This is because the handler will be called in the context of the SCM and will hold the SCM until it returns from the handler.
I have only implemented and supported the
{
// Periodically check if the service has been requested to stop
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
/*
* Perform main service function here
*/
// Simulate some work by sleeping
Sleep(3000);
}
return ERROR_SUCCESS;
}
This sample Service Worker Thread does nothing but sleep and check to see if the service has received a control to stop. Once a stop control has been received the Service Control Handler sets the
breaks and exits. This signals the Service Main routine to return and effectively stop the service.
C:\>sc create "My Sample Service" binPath= C:\SampleService.exe
A space is required between binPath= and the value[?]. Also, use the full absolute path to the service executable.
You should now see the service in the Windows Services console. From here you can start and stop the service.
Introduction
This article shows how to create a basic Windows Service in C++. Services are very useful in many development scenarios depending on the architecture of the application.Background
There are not many Windows Service examples that I found in C++. I used MSDN to write this very basic Windows service.Using the code
At a minimum a service requires the following items:A Main Entry point (like any application)
A Service Entry point
A Service Control Handler
You can use a Visual Studio template project to help you get started. I just created an "Empty" Win32 Console Application.
Before we get started on the Main Entry Point, we need to declare some globals that will be used throughout the service. To be more object oriented you can always create a class that represents your service and use class members instead of globals. To keep
it simple I will use globals.
We will need a
SERVICE_STATUSstructure that will be used to report the status of the service to the Windows Service Control Manager (SCM).
SERVICE_STATUS g_ServiceStatus = {0};
We will also need a
SERVICE_STATUS_HANDLEthat is used to reference our service instance once it is registered with the SCM.
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;
Here are some additional globals and function declarations that will be used and explained as we go along.
SERVICE_STATUS g_ServiceStatus = {0}; SERVICE_STATUS_HANDLE g_StatusHandle = NULL; HANDLE g_ServiceStopEvent = INVALID_HANDLE_VALUE; VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv); VOID WINAPI ServiceCtrlHandler (DWORD); DWORD WINAPI ServiceWorkerThread (LPVOID lpParam); #define SERVICE_NAME _T("My Sample Service")
Main Entry Point
int _tmain (int argc, TCHAR *argv[])
{
SERVICE_TABLE_ENTRY ServiceTable[] =
{
{SERVICE_NAME, (LPSERVICE_MAIN_FUNCTION) ServiceMain},
{NULL, NULL}
};
if (StartServiceCtrlDispatcher (ServiceTable) == FALSE)
{
return GetLastError ();
}
return 0;
}
In the main entry point you quickly call
StartServiceCtrlDispatcherso the SCM can call your Service Entry point (
ServiceMainin the example above). You want to defer any initialization until your Service Entry point, which is defined
next.
Service Entry Point
VOID WINAPI ServiceMain (DWORD argc, LPTSTR *argv) { DWORD Status = E_FAIL; // Register our service control handler with the SCM g_StatusHandle = RegisterServiceCtrlHandler (SERVICE_NAME, ServiceCtrlHandler); if (g_StatusHandle == NULL) { goto EXIT; } // Tell the service controller we are starting ZeroMemory (&g_ServiceStatus, sizeof (g_ServiceStatus)); g_ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwServiceSpecificExitCode = 0; g_ServiceStatus.dwCheckPoint = 0; if (SetServiceStatus (g_StatusHandle , &g_ServiceStatus) == FALSE) { OutputDebugString(_T( "My Sample Service: ServiceMain: SetServiceStatus returned error")); } /* * Perform tasks necessary to start the service here */ // Create a service stop event to wait on later g_ServiceStopEvent = CreateEvent (NULL, TRUE, FALSE, NULL); if (g_ServiceStopEvent == NULL) { // Error creating event // Tell service controller we are stopped and exit g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwWin32ExitCode = GetLastError(); g_ServiceStatus.dwCheckPoint = 1; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { OutputDebugString(_T( "My Sample Service: ServiceMain: SetServiceStatus returned error")); } goto EXIT; } // Tell the service controller we are started g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP; g_ServiceStatus.dwCurrentState = SERVICE_RUNNING; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 0; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { OutputDebugString(_T( "My Sample Service: ServiceMain: SetServiceStatus returned error")); } // Start a thread that will perform the main task of the service HANDLE hThread = CreateThread (NULL, 0, ServiceWorkerThread, NULL, 0, NULL); // Wait until our worker thread exits signaling that the service needs to stop WaitForSingleObject (hThread, INFINITE); /* * Perform any cleanup tasks */ CloseHandle (g_ServiceStopEvent); // Tell the service controller we are stopped g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOPPED; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 3; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { OutputDebugString(_T( "My Sample Service: ServiceMain: SetServiceStatus returned error")); } EXIT: return; }
The Service Main Entry Point performs the following tasks:
Initialize any necessary items which we deferred from the Main Entry Point.
Register the service control handler which will handle Service Stop, Pause, Continue, Shutdown, etc control commands. These are registered via the
dwControlsAcceptedfield of the
SERVICE_STATUSstructure as a bit mask.
Set Service Status to
SERVICE_PENDINGthen to
SERVICE_RUNNING. Set status to
SERVICE_STOPPEDon any errors and on exit. Always set
SERVICE_STATUS.dwControlsAcceptedto 0 when setting status to
SERVICE_STOPPEDor
SERVICE_PENDING.
Perform start up tasks. Like creating threads/events/mutex/IPCs/etc.
Service Control Handler
VOID WINAPI ServiceCtrlHandler (DWORD CtrlCode) { switch (CtrlCode) { case SERVICE_CONTROL_STOP : if (g_ServiceStatus.dwCurrentState != SERVICE_RUNNING) break; /* * Perform tasks necessary to stop the service here */ g_ServiceStatus.dwControlsAccepted = 0; g_ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING; g_ServiceStatus.dwWin32ExitCode = 0; g_ServiceStatus.dwCheckPoint = 4; if (SetServiceStatus (g_StatusHandle, &g_ServiceStatus) == FALSE) { OutputDebugString(_T( "My Sample Service: ServiceCtrlHandler: SetServiceStatus returned error")); } // This will signal the worker thread to start shutting down SetEvent (g_ServiceStopEvent); break; default: break; } }
The Service Control Handler was registered in your Service Main Entry point. Each service must have a handler to handle control requests from the SCM. The control handler must return within 30 seconds or the SCM will return an error stating that the service
is not responding. This is because the handler will be called in the context of the SCM and will hold the SCM until it returns from the handler.
I have only implemented and supported the
SERVICE_CONTROL_STOPrequest. You can handle other requests such as
SERVICE_CONTROL_CONTINUE,
SERVICE_CONTROL_INTERROGATE,
SERVICE_CONTROL_PAUSE,
SERVICE_CONTROL_SHUTDOWNand others supported by the
Handleror
HandlerExfunction that can be registered with the
RegisterServiceCtrlHandler(Ex)function.
Service Worker Thread
DWORD WINAPI ServiceWorkerThread (LPVOID lpParam){
// Periodically check if the service has been requested to stop
while (WaitForSingleObject(g_ServiceStopEvent, 0) != WAIT_OBJECT_0)
{
/*
* Perform main service function here
*/
// Simulate some work by sleeping
Sleep(3000);
}
return ERROR_SUCCESS;
}
This sample Service Worker Thread does nothing but sleep and check to see if the service has received a control to stop. Once a stop control has been received the Service Control Handler sets the
g_ServiceStopEventevent. The Service Worker Thread
breaks and exits. This signals the Service Main routine to return and effectively stop the service.
Installing the Service
You can install the service from the command prompt by running the following command:C:\>sc create "My Sample Service" binPath= C:\SampleService.exe
A space is required between binPath= and the value[?]. Also, use the full absolute path to the service executable.
You should now see the service in the Windows Services console. From here you can start and stop the service.
Uninstalling the Service
You can uninstall the service from the command prompt by running the following command:
C:\>sc delete "My Sample Service"
相关文章推荐
- 处理C++源代码的程序(1)
- C++类的自动转换
- C语言在子函数中调用malloc申请内存的方法
- C++中 explicit显示转换
- VS2010 C++ 操作Excel表格的编程实现
- c++ string问题 cout输出正常,printf输出乱码
- C++中memset函数用法详解
- 排序算法系列---简单选择排序(C++)
- 最值得关注的10个C开源项目和最全面的 C++ 资源、框架大全
- 多文件组成的c++课程设计学生管理系统(单链表)
- VIJOS-P1156
- Longest substring without repeat(C++)
- C++ 代码缩进
- c++读取txt文件到string
- 栈的链式 结构实现
- string 的简单实现
- C、C++文件夹文件遍历
- C语言笔记系列(二)--基本数据类型
- C语言的面向对象写法
- c/c++中float和double类型的存储