Click here to Skip to main content
15,892,746 members
Articles / Desktop Programming / MFC

CNTService v1.06 - NT Service Framework

Rate me:
Please Sign up or sign in to vote.
4.97/5 (17 votes)
3 Mar 2000 295.6K   4.5K   128  
A class framework for developing NT services in MFC.
/*
Module : SERV.H
Purpose: Defines the interface for a number of MFC classes which 
         encapsulate the whole area of services in NT. 
Created: PJN / 14-07-1998
History: None

Copyright (c) 1998 by PJ Naughter.  
All rights reserved.
				 


Classes provided include:

CNTService: An C++ encapsulation of an actual running service.
To develop your own service you should derive a class from it and
override the necessary functions to implement your own specific 
behaviour of your service.

CNTScmService: A C++ wrapper for the SC_HANDLE type which represents
a service as returned from the Service Control Manager APIs. You would
use the class in conjuction with the SCM class to install, reconfigure
and uninstall your services.

CNTServiceControlManager: A C++ wrapper for the SC_HANDLE type which
represents the Service Control Manager itself.

CEventLogRecord: A simple C++ class which adds some helpful functions
to the underlying EVENTLOGRECORD structure.

CNTEventLog: A C++ wrapper for the HANDLE for the Event Log APIs. 
This class corresponds almost exactly to the code which internally the 
"Event Viewer" application in NT would use. You could think of this 
as the client side to the NT Event Log API.

CNTEventLogSource: A C++ wrapper for the "Server" side of the Event Log
API's. You would normally use this class in the code when installing
,uninstalling your service or when reporting to the event log while
your service is running.

*/



#ifndef __SERV_H__
#define __SERV_H__




//The CNTServiceCommandLineInfo class aids in parsing the 
//command line at application startup of an NT Service. The 
//structure is styled upon the MFC class CCommandLineInfo
class CNTServiceCommandLineInfo
{
public:
// Constructors / Destructors
	CNTServiceCommandLineInfo();
	~CNTServiceCommandLineInfo();

//Methods
	virtual void ParseParam(LPCTSTR pszParam, BOOL bFlag, BOOL bLast);

//Data
	enum 
	{ 
		RunAsService,
	  InstallService, 
		UninstallService,
		DebugService, 
		ShowServiceHelp 
	} m_nShellCommand;
};






//An encapsulation of the APIs used to register, unregister,
//write, install and uninstall Event log entries i.e. the
//server side to the Event log APIs
class CNTEventLogSource
{
public:
//Constructors / Destructors
	CNTEventLogSource();
	~CNTEventLogSource();

//Methods
	operator HANDLE() const;
	BOOL Attach(HANDLE hEventSource);
	HANDLE Detach();
	BOOL Register(LPCTSTR lpUNCServerName, // server name for source 
                LPCTSTR lpSourceName 	   // source name for registered handle  
                );
  BOOL Report(WORD wType,	        // event type to log 
							WORD wCategory,	    // event category 
							DWORD dwEventID,	  // event identifier 
							PSID lpUserSid,	    // user security identifier (optional) 
							WORD wNumStrings,	  // number of strings to merge with message  
							DWORD dwDataSize,	  // size of binary data, in bytes
							LPCTSTR* lpStrings,	// array of strings to merge with message 
							LPVOID lpRawData 	  // address of binary data 
 						  ) const;
  BOOL Report(WORD wType, DWORD dwEventID, LPCTSTR lpszString) const;
  BOOL Report(WORD wType, DWORD dwEventID, LPCTSTR lpszString1, LPCTSTR lpszString2) const;
  BOOL Report(WORD wType, DWORD dwEventID, DWORD dwCode) const;
	BOOL Deregister();

	static BOOL Install(LPCTSTR lpSourceName, LPCTSTR lpEventMessageFile, DWORD dwTypesSupported);
  static BOOL Uninstall(LPCTSTR lpSourceName);
  
protected:
  static BOOL GetStringArrayFromRegistry(HKEY hKey, const CString& sEntry, CStringArray& array);
  static BOOL SetStringArrayIntoRegistry(HKEY hKey, const CString& sEntry, const CStringArray& array);

  HANDLE m_hEventSource;
  friend class CNTService;
};






//An MFC framework encapsulation of an NT service 
//You are meant to derive your own class from this and
//override its functions to implement your own 
//service specific functionality.
class CNTService
{
public:
//Constructors / Destructors
	CNTService(LPCTSTR lpszServiceName, LPCTSTR lpszDisplayName, DWORD dwControlsAccepted, LPCTSTR lpszDescription = NULL); 
	~CNTService();

//Accessors / Mutators
  CString GetServiceName() const { return m_sServiceName; };
  CString GetDisplayName() const { return m_sDisplayName; };
  CString GetDescription() const { return m_sDescription; };

//Persistance support
	//Allows saving and restoring of a services settings to the 
	//"HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\ServiceName\Parameters"
  //location in the registry
	BOOL    WriteProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszValue);
	BOOL    WriteProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nValue);
  BOOL    WriteProfileStringArray(LPCTSTR lpszSection, LPCTSTR lpszEntry, const CStringArray& array);
	BOOL    WriteProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE pData, UINT nBytes);

	CString GetProfileString(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPCTSTR lpszDefault = NULL);
	UINT    GetProfileInt(LPCTSTR lpszSection, LPCTSTR lpszEntry, int nDefault);
  BOOL    GetProfileStringArray(LPCTSTR lpszSection, LPCTSTR lpszEntry, CStringArray& array); 
	BOOL    GetProfileBinary(LPCTSTR lpszSection, LPCTSTR lpszEntry, LPBYTE* ppData, UINT* pBytes);


//Other Methods
  //Helpful functions to parse the command line and execute the results
	void ParseCommandLine(CNTServiceCommandLineInfo& rCmdInfo);
	BOOL ProcessShellCommand(CNTServiceCommandLineInfo& rCmdInfo);

	//Reports the status of this service back to the SCM
	BOOL ReportStatusToSCM();
	BOOL ReportStatusToSCM(DWORD dwCurrentState, DWORD dwWin32ExitCode, 
	                       DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint, DWORD dwWaitHint);

	//Installs the callback funtion by calling RegisterServiceCtrlHandler
	BOOL RegisterCtrlHandler();

	//Member function which does the job of responding to SCM requests
	virtual void WINAPI ServiceCtrlHandler(DWORD dwControl);						

	//The ServiceMain function for this service
	virtual void WINAPI ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv);

	//Called in reponse to a shutdown request
	virtual void OnStop();

	//Called in reponse to a pause request
	virtual void OnPause();

	//Called in reponse to a continue request
	virtual void OnContinue();

	//Called in reponse to a Interrogate request
	virtual void OnInterrogate();

	//Called in reponse to a Shutdown request
	virtual void OnShutdown();

	//Called in reponse to a user defined request
	virtual void OnUserDefinedRequest(DWORD dwControl);

	//Kicks off the Service. You would normally call this
	//some where in your main/wmain or InitInstance
	//a standard process rather than as a service. If you are
  //using the CNTServiceCommandLineInfo class, then internally
  //it will call this function for you.
	virtual BOOL Run();

	//Installs the service
	virtual BOOL Install();

	//Uninstalls the service
	virtual BOOL Uninstall();

	//Runs the service as a normal function as opposed
	//to a service
	virtual void Debug();

	//Displays help for this service
	virtual void ShowHelp();

protected:
//Methods
  //These two static functions are used internally to
  //go from the SDK functions to the C++ member functions
	static void WINAPI _ServiceCtrlHandler(DWORD dwControl);						
	static void WINAPI _ServiceMain(DWORD dwArgc, LPTSTR* lpszArgv);

	//Used internally by the persistance functions
	HKEY GetSectionKey(LPCTSTR lpszSection);
	HKEY GetServiceRegistryKey();

//Data
	SERVICE_STATUS_HANDLE m_hStatus;
  DWORD                 m_dwControlsAccepted;   // What Control requests will this service repond to
  DWORD                 m_dwCurrentState;       // Current Status of the service
  CString               m_sServiceName;         // Name of the service
  CString               m_sDisplayName;         // Display name for the service
  CString               m_sDescription;         // The description text for the service
  CNTEventLogSource     m_EventLogSource;       // For reporting to the event log
	static CNTService*    sm_lpService;						// Static which contains the this pointer
  CCriticalSection      m_CritSect;             // Protects changes to any member variables from multiple threads
};






////// Forward declaration
class CNTServiceControlManager;


typedef BOOL (CALLBACK* ENUM_SERVICES_PROC)(DWORD dwData, ENUM_SERVICE_STATUS& Service);


//An encapsulation of a service as returned from querying the SCM (i.e. an SC_HANDLE)
class CNTScmService
{
public:
//Constructors / Destructors
	CNTScmService();
	~CNTScmService();

//Methods
  //Releases the underlying SC_HANDLE
  void Close();

	//Allows access to the underlying SC_HANDLE representing the service
	operator SC_HANDLE() const;

	//Attach / Detach support from an SDK SC_HANDLE
	BOOL Attach(SC_HANDLE hService);
	SC_HANDLE Detach();

	//Changes the configuration of this service
	BOOL ChangeConfig(DWORD dwServiceType,	      // type of service 
									  DWORD dwStartType,	        // when to start service 
 									  DWORD dwErrorControl,	      // severity if service fails to start 
 									  LPCTSTR lpBinaryPathName,	  // pointer to service binary file name 
									  LPCTSTR lpLoadOrderGroup,	  // pointer to load ordering group name 
									  LPDWORD lpdwTagId,	        // pointer to variable to get tag identifier 
 									  LPCTSTR lpDependencies,	    // pointer to array of dependency names 
 									  LPCTSTR lpServiceStartName, // pointer to account name of service 
 									  LPCTSTR lpPassword,	        // pointer to password for service account  
 									  LPCTSTR lpDisplayName 	    // pointer to display name 
                    ) const;

	//Send a defined control code to the service
	BOOL Control(DWORD dwControl);

	//These functions call Control() with the 
	//standard predefined control codes
	BOOL Stop() const;			 //Ask the service to stop
	BOOL Pause() const;			 //Ask the service to pause
	BOOL Continue() const;	 //Ask the service to continue
	BOOL Interrogate() const; //Ask the service to update its status to the SCM

	//Start the execution of the service
	BOOL Start(DWORD dwNumServiceArgs,	      // number of arguments 
			       LPCTSTR* lpServiceArgVectors 	// address of array of argument string pointers  
		         ) const;	

	//Determines what Control codes this service supports
	BOOL AcceptStop(BOOL& bStop);                   //Ask the service can it stop
	BOOL AcceptPauseContinue(BOOL& bPauseContinue);	//Ask the service can it pause continue
	BOOL AcceptShutdown(BOOL& bShutdown);           //Ask the service if it is notified of shutdowns

	//Get the most return status of the service reported to the SCM by this service
	BOOL QueryStatus(LPSERVICE_STATUS lpServiceStatus) const;

	//Get the configuration parameters of this service from the SCM
	BOOL QueryConfig(LPQUERY_SERVICE_CONFIG& lpServiceConfig) const;

	//Add a new service to the SCM database
	BOOL Create(CNTServiceControlManager& Manager, // handle to service control manager database  
 						  LPCTSTR lpServiceName,	         // pointer to name of service to start 
						  LPCTSTR lpDisplayName,	         // pointer to display name 
						  DWORD dwDesiredAccess,	         // type of access to service 
						  DWORD dwServiceType,	           // type of service 
						  DWORD dwStartType,	             // when to start service 
						  DWORD dwErrorControl,	           // severity if service fails to start 
						  LPCTSTR lpBinaryPathName,	       // pointer to name of binary file 
						  LPCTSTR lpLoadOrderGroup,	       // pointer to name of load ordering group 
						  LPDWORD lpdwTagId,	             // pointer to variable to get tag identifier 
						  LPCTSTR lpDependencies,	         // pointer to array of dependency names 
						  LPCTSTR lpServiceStartName,	     // pointer to account name of service 
						  LPCTSTR lpPassword 	             // pointer to password for service account 
              );

	//Mark this service as to be deleted from the SCM.
	BOOL Delete() const;

	//Enumerate the services that this service depends upon
	BOOL EnumDependents(DWORD dwServiceState,	                // state of services to enumerate 
                      DWORD dwUserData,                     // User defined data
 										  ENUM_SERVICES_PROC lpEnumServicesFunc // The callback function to use
                      ) const;

	//Get the security information associated with this service
	BOOL QueryObjectSecurity(SECURITY_INFORMATION dwSecurityInformation,	// type of security information requested  
			                     PSECURITY_DESCRIPTOR& lpSecurityDescriptor	  // address of security descriptor 
						   					   ) const;

	//Set the security descriptor associated with this service
	BOOL SetObjectSecurity(SECURITY_INFORMATION dwSecurityInformation,	// type of security information requested  
			                   PSECURITY_DESCRIPTOR lpSecurityDescriptor 	// address of security descriptor 
		                     ) const;

protected:
  SC_HANDLE m_hService;
};






//An encapsulation of the NT Service Control Manager
class CNTServiceControlManager
{
public:
//Constructors / Destructors
	CNTServiceControlManager();
	~CNTServiceControlManager();

//Methods
	//Allows access to the underlying SC_HANDLE representing the SCM
	operator SC_HANDLE() const;

	//Attach / Detach support from an SDK SC_HANDLE
	BOOL Attach(SC_HANDLE hSCM);
	SC_HANDLE Detach();

	//Opens a connection to the SCM
	BOOL Open(LPCTSTR pszMachineName, DWORD dwDesiredAccess);
	
	//Close the connection to the SCM
	void Close();																							 

	//Get the SCM Status
	BOOL QueryLockStatus(LPQUERY_SERVICE_LOCK_STATUS& lpLockStatus) const; 

	//Enumerates the specified services
	BOOL EnumServices(DWORD dwServiceType, DWORD dwServiceState, DWORD dwUserData, ENUM_SERVICES_PROC lpEnumServicesFunc) const;

	//Opens the specified service
  BOOL OpenService(LPCTSTR lpServiceName,	DWORD dwDesiredAccess, CNTScmService& service) const;

	//Lock the SCM database
	BOOL Lock();

	//Unlocks the SCM database
	BOOL Unlock();

protected:
	SC_HANDLE m_hSCM;	 //Handle to the SCM
	SC_LOCK		m_hLock; //Handle of any lock on the Database
};





//A friendlier way of handling EVENTLOGRECORD structures.
class CEventLogRecord
{
public: 
//Constructors / Destructors
  CEventLogRecord();
  CEventLogRecord(const CEventLogRecord& record);
  CEventLogRecord(const EVENTLOGRECORD* pRecord);

//Methods
  CEventLogRecord& operator=(const CEventLogRecord& record);

//Data
  DWORD        m_dwRecordNumber;
  CTime        m_TimeGenerated;
  CTime        m_TimeWritten;
  DWORD        m_dwEventID;
  WORD         m_wEventType;
  WORD         m_wEventCategory;
  CByteArray   m_UserSID;
  CStringArray m_Strings;
  CByteArray   m_Data;
  CString      m_sSourceName;
  CString      m_sComputerName;
};





//An encapsulation of the client side to the 
//NT event log APIs
class CNTEventLog
{
public:
//Constructors / Destructors
	CNTEventLog();
	~CNTEventLog();

//Methods
	operator HANDLE() const;
	BOOL     Attach(HANDLE hEventLog);
	HANDLE   Detach();
	BOOL     Open(LPCTSTR lpUNCServerName, LPCTSTR lpSourceName);
	BOOL     OpenBackup(LPCTSTR lpUNCServerName, LPCTSTR lpFileName);
	BOOL     OpenApplication(LPCTSTR lpUNCServerName);
	BOOL     OpenSystem(LPCTSTR lpUNCServerName);
  BOOL     OpenSecurity(LPCTSTR lpUNCServerName);
	BOOL     Close();
	BOOL     Backup(LPCTSTR lpBackupFileName) const;
	BOOL     Clear(LPCTSTR lpBackupFileName) const;
	BOOL     GetNumberOfRecords(DWORD& dwNumberOfRecords) const;
	BOOL     GetOldestRecord(DWORD& dwOldestRecord) const;
	BOOL     NotifyChange(HANDLE hEvent) const;
  BOOL     ReadNext(CEventLogRecord& record) const;
  BOOL     ReadPrev(CEventLogRecord& record) const;

protected:
	HANDLE m_hEventLog;
};






#endif //__SERV_H__

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions