SFL 2.0: Service Framework Library for Native Windows Service Applications, Part II

Inevitable Introduction

In my previous article, Part I, I about service application styles existing in the Windows world; I called them Windows NT style and Windows 2000 style respectively. I have to warn you about these style names; they are unofficial (you never will find them in MSDN), and I needed to invent some names for easier topic comprehension—for myself first. Well, after making this point clear, it’s time to get into this a bit deeper and see why this point is so important and why NT and 2000 are mentioned in this context.

The Windows NT system was completely silent in respect to notifying user-level applications about hardware-level events. For this reason, service applications have had correspondingly simple APIs that provided only user-to-service communication abilities.

But since Windows 2000, some absolutely new functionality has been introduced for service applications—in brief, they had become able to process hardware environment changes and device notifications, and Windows provides several new control codes for this purpose sent to services from the system kernel.

Once this new functionality obviously did not match with previously written service applications, the Windows API was added with extended versions of handler-aware API entry—RegisterServiceCtrlHandlerEx. And since Windows 2000, two service styles—the legacy Windows NT service and the modern Windows 2000 one—became equally supported.

Now, the service that registers the old-style handler function is considered a legacy application that never requires new-style hardware event notification. Nevertheless, this service application can be launched in any Windows NT-based system—NT4/2000/XP/2003/Vista—because of Windows system backward compatibility.

And, the service that registers the extended handler function and claims itself accepting hardware environment notifications is considered a new-style service, and the Windows system notifies it about the requested type of hardware environment changes. Of course, this type of service application is totally compatible with Windows 2000/XP/2003/Vista versions, but naturally becomes incompatible with the Windows NT4 system; therefore, it cannot be launched in that type of system.

Note: For detailed information regarding the mentioned old-fashioned and modern service behaviors, please refer to MSDN articles Handler, HandlerEx, RegisterServiceCtrlHandler, and RegisterServiceCtrlHandlerEx.

Digressing for a moment, it worth mentioning an interesting fact that ATL Service registers the old-style handler function; therefore, this service becomes able to operate in the Windows NT system as well. For the same reason, it never can be notified about network and hardware configuration changes—of course, I mean the standard way that Windows does this for modern-style services. This consideration must be taken into account when making decisions about service implementation, or when advising other people on the question, with no doubt.

But, let me get back to SFL and show you how it solves the service style issue.

Windows 2000-Style SFL Application

To be sure the concept really works, you can create a service that requires some kind of device notification. The first thought that crossed my mind was a CD/DVD-ROM volume mounting event, so you’ll try that. Because the only thing that matters in the case is the service style, the application part will remain similar to previous article’s demo application.

Note: Actually, the application part does differ slightly from the previous Part I demo. The SFL_SERVICE_ENTRY(CDeviceService, IDS_DEVICE_SERVICE) macro is used in the application service map unlike the previously used SFL_SERVICE_ENTRY2. Please don’t be confused by not seeing the service name here; this macro just implies that the service name is kept as a resource string with the IDS_DEVICE_SERVICE identifier.

And now, you can focus on the service class of the current demo.

#pragma once

class CDeviceService: public CServiceBaseT< CDeviceService,
   SERVICE_ACCEPT_STOP |
   SERVICE_ACCEPT_HARDWAREPROFILECHANGE >
{
   SFL_DECLARE_SERVICECLASS_FRIENDS(CDeviceService)

   SFL_BEGIN_CONTROL_MAP_EX(CDeviceService)
   SFL_HANDLE_CONTROL_STOP()
   SFL_HANDLE_CONTROL_EX( SERVICE_CONTROL_DEVICEEVENT,
                          OnDeviceChange )
   SFL_END_CONTROL_MAP_EX()

   DWORD OnStop(DWORD& dwWin32Err, DWORD& dwSpecificErr,
                BOOL& bHandled);
   DWORD OnDeviceChange(DWORD& dwState,
                        DWORD& dwWin32Err,
                        DWORD& dwSpecificErr,
                        BOOL&  bHandled,
                        DWORD  dwEventType,
                        LPVOID lpEventData,
                        LPVOID lpContext);
   void LogEvent(DWORD dwEvent, LPVOID lpParam);

#if defined(_MSC_VER) && (_MSC_VER < 1300)
public:
#endif
   LPVOID GetServiceContext() { return this; }
   BOOL InitInstance(DWORD dwArgc, LPTSTR* lpszArgv,
                     DWORD& dwSpecificErr);

   CDeviceService();
   virtual ~CDeviceService();

private:
   HDEVNOTIFY m_hDevNotify;
   LPTSTR     m_logfile;
};

You easily can see that the service class structure is recognizable: The service class friends declaration macro (this will be explained in the next article), service control map (though of the new extended style) along with control code handlers, and some auxiliary stuff, such as GetServiceContext and InitInstance, that were never introduced before.

Note: The GetServiceContext function is never used in this sample and is provided just for reference. Its purpose and possible usage will be explained in the next article.

The really important points to focus on, and which actually make the service able to process device notifications, are these two:

  • Service accept flag: SERVICE_ACCEPT_HARDWAREPROFILECHANGE
  • Extended version of service control map: SFL_BEGIN(END)_CONTROL_MAP_EX

The extended version of the control map implements the modern style HandlerEx handler function and makes the framework register it with the appropriate API, RegisterServiceCtrlHandlerEx.

The mentioned accept flag informs the Windows system that the service must be notified about hardware configuration changes and device events.

More by Author

Must Read