The application implements a very basic service behavior - starting, stopping, pausing and continuing (as we will see that later) - without doing anything useful. Due to this the service code is perfectly clean and easy to understand.
The code is free of any dependencies other than Win32 SDK and SflBase.h itself.
#include <windows.h>
#include "SflBase.h"
class CMyService: public CServiceBaseT<CMyService, SERVICE_ACCEPT_STOP|SERVICE_ACCEPT_PAUSE_CONTINUE>
{
The second template parameter of CServiceBaseT<>
defines the user control commands the service will be registered with and therefore able to react to. In this case the commands are stop, pause and continue, and of cause start command is implied by default.
Note
For example, you may comment out the SERVICE_ACCEPT_PAUSE_CONTINUE
constant and at runtime you see that your service is not eligible for pausing, and only option available is stopping.
SFL_BEGIN_CONTROL_MAP(CMyService)
SFL_HANDLE_CONTROL_STOP()
SFL_HANDLE_CONTROL_PAUSE()
SFL_HANDLE_CONTROL_CONTINUE()
SFL_END_CONTROL_MAP()
You can easily see the connection between service declaration and control command handling: the control map just confirms handling of all the commands listed in the above section.
In fact, each SFL_HANDLE_CONTROL_XXX
entry declares corresponding OnXxx
member function as a control handler.
DWORD OnStop(DWORD& /*dwWin32Err*/, DWORD& /*dwSpecificErr*/, BOOL& bHandled )
{
bHandled = TRUE;
return SERVICE_STOPPED;
}
DWORD OnPause(DWORD& /*dwWin32Err*/, DWORD& /*dwSpecificErr*/, BOOL& bHandled )
{
bHandled = TRUE;
return SERVICE_PAUSED;
}
DWORD OnContinue(DWORD& /*dwWin32Err*/, DWORD& /*dwSpecificErr*/, BOOL& bHandled )
{
bHandled = TRUE;
return SERVICE_RUNNING;
}
A control handler has to explicitly confirm handling by setting bHandled
parameter to TRUE. Return value here must be a service state code the service to switch to.
SFL_BEGIN_SERVICE_MAP(CSimpleServiceApp)
SFL_SERVICE_ENTRY2(CMyService, 0, "My Service")
SFL_END_SERVICE_MAP()
From the map you can see that your application includes the only service instance named "My Service" and implemented by CMyService
class defined above.
To build the app binary you need to run Visual Studio Command Prompt window of the bitness x86 or x64 that you require, change working directory to MinSvc folder and run the command:
> make
As a result, MinSvc.exe
application will be created in the same folder.
Note
Running bare make
will build a debug version, same as make debug
. If you want to build a release version, you call make release
Tip
Prior to registration please make sure there is no service in your system registered with the name "My Service"
SC.EXE application from Windows standard tools will be used for manipulations with the service.
Note
SC.EXE must be run with Administrator privilege.
> sc create "My Service" binPath= <full path to MinSvc.exe>
[SC] CreateService SUCCESS
Warning
The space character after binPath=
key does matter and therefore is mandatory!
Test the registration success by:
> sc query "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 1077 (0x435)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
The newly created service must be in SERVICE_STOPPED
state.
> sc start "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 2 START_PENDING
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
PID : 2752
FLAGS :
Note
Please note that 'start pending' status is immediately returned. For real service being started this is normal to take some time until service functions get ready to serve routine tasks. However, in our case the dummy service does not start any long.
Test the ultimate start success by:
> sc query "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE,PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
The newly created service must be in SERVICE_RUNNING
state.
> sc pause "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 7 PAUSED
(STOPPABLE,PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
Test the pausing success by:
> sc query "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 7 PAUSED
(STOPPABLE,PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
The service must be in SERVICE_PAUSED
state.
> sc continue "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE,PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
Test the continuation success by:
> sc query "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 4 RUNNING
(STOPPABLE,PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
The service must be in SERVICE_RUNNING
state.
> sc stop "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
Note
Same to starting, stopping service may take some time in real applications. So here you may have 'stop pending' status alright. However, our simplistic app reaches stopped status instantly.
Test the ultimate stopping success by:
> sc query "My Service"
SERVICE_NAME: My Service
TYPE : 10 WIN32_OWN_PROCESS
STATE : 1 STOPPED
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x0
The service must be in SERVICE_STOPPED
state.
> sc delete "My Service"
[SC] DeleteService SUCCESS
Test the deletion success by:
> sc query "My Service"
[SC] EnumQueryServicesStatus:OpenService FAILED 1060:
The specified service does not exist as an installed service.
The service must not exist to the moment.