您的位置:首页 > 编程语言 > C语言/C++

Simple Windows Service in C++

2016-07-19 16:33 387 查看


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_STATUS
 structure that will be used to report the status of the service to the Windows Service
Control Manager (SCM).

Hide   Copy Code
SERVICE_STATUS        g_ServiceStatus = {0};


We will also need a 
SERVICE_STATUS_HANDLE
 that is used to reference our service instance once it is registered with
the SCM.

Hide   Copy Code
SERVICE_STATUS_HANDLE g_StatusHandle = NULL;


Here are some additional globals and function declarations that will be used and explained as we go along.

Hide   Copy Code
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

Hide   Copy Code
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 
StartServiceCtrlDispatcher
 so the SCM can call your Service Entry point (
ServiceMain
 in
the example above). You want to defer any initialization until your Service Entry point, which is defined next.


Service Entry Point

Hide   Shrink 

   Copy
Code
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 
dwControlsAccepted
 field
of the 
SERVICE_STATUS
structure as a bit mask.
Set Service Status to 
SERVICE_PENDING
 then
to 
SERVICE_RUNNING
. Set status to 
SERVICE_STOPPED
 on
any errors and on exit. Always set 
SERVICE_STATUS.dwControlsAccepted
 to 0 when setting status to
SERVICE_STOPPED
 or 
SERVICE_PENDING
.
Perform start up tasks. Like creating threads/events/mutex/IPCs/etc.


Service Control Handler

Hide   Shrink 

   Copy
Code
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_STOP
 request. You can handle other requests such as 
SERVICE_CONTROL_CONTINUE
SERVICE_CONTROL_INTERROGATE
SERVICE_CONTROL_PAUSE
,
SERVICE_CONTROL_SHUTDOWN
 and
others supported by the 
Handler
 or 
HandlerEx
 function
that can be registered with the 
RegisterServiceCtrlHandler(Ex)
 function.


Service Worker Thread

Hide   Copy Code
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_ServiceStopEvent
event.
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:

Hide   Copy Code
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:

Hide   Copy Code
C:\>sc delete "My Sample Service"

http://www.codeproject.com/Articles/499465/Simple-Windows-Service-in-Cplusplus
然后安装服务

点开始运行cmd.exe

输入以下:

sc create your_service_name binpath= D:\backup\GetXML.exe     //这步注意等号右边有个空格

sc start your_service_name  //启动服务, 也可以启动任务管理器在服务一栏中找到你的服务启动或停止

 sc stop testservicename  //停止服务

sc delete testservicename //删除服务,该服务将在下次重启后删除,在重启之前将不能注册
同一个名字的服务。 

启动服务, 停止服务,等也可以在windows任务管理器中管理
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: