Skip to content

[API Proposal]: Extend ServiceBase to allow handling all service control codes #65846

Open
@levicki

Description

@levicki

Background and motivation

Currently, there is OnCustomCommand() method in ServiceBase class which can be overriden and appears to be wired to receive other service control codes sent to underlying native LPHANDLER_FUNCTION_EX callback by the operating system.

However, this method only receives the service control code -- it doesn't receive any other parameters (namely dwEventType and lpEventData) which makes it impossible to actually handle any service control codes that require those such as device notifications, power notifications, etc.

Given that it is possible to call RegisterDeviceNotification() using P/Invoke and pass the native service handle from ServiceBase, it should also be possible to actually receive data that is sent by the OS along with the control code.

I believe this method was misnamed -- it is not receiving commands but service control codes, so I am not sure whether creating an overload with additional parameters is the way to go or if differently named method should be created. I would personally prefer sticking to underlying OS naming, hence the API proposal below.

If it is ever implemented, it would be nice if it was also backported to .Net Framework.

API Proposal

namespace System.ServiceProcess
{
	public class ServiceBase : Component
	{
		protected virtual void HandlerFunctionEx(UInt32 dwControl, UInt32 dwEventType, IntPtr lpEventData, IntPtr lpContext)
		{
		}
	}
}

API Usage

namespace Demo
{
	public static class Win32
	{
		// marshaling omitted for brevity
	}

	partial class DemoService : ServiceBase
	{
		protected override void HandlerFunctionEx(UInt32 dwControl, UInt32 dwEventType, IntPtr lpEventData, IntPtr lpContext)
		{
			Win32.DEV_BROADCAST_HDR dbh = null;

			switch (dwControl) {
			case Win32.SERVICE_CONTROL_DEVICEEVENT: // handle device events
				switch (dwEventType) {
				case Win32.DBT_DEVICEARRIVAL:
					// do something when device is added
					dbh = Marshal.PtrToStructure<Win32.DEV_BROADCAST_HDR>(lpEventData);
					break;
				case Win32.DBT_DEVICEREMOVECOMPLETE:
					// do something when device is removed
					break;
				}
				break;
			}
			// Call base implementation for the rest (i.e. `OnStart()`, `OnStop()`, etc)
			base.HandlerFunctionEx(dwControl, dwEventType, lpEventData, lpContext);
		}
	}
}

Alternative Designs

Alternative would be creating virtual OnDeviceEvent() API and marshaling everything involved in the framework itself, but that would take considerably more effort and I am pretty certain just exposing low level access to all parameters would be enough for users like me who need this kind of functionality in a .Net service.

Risks

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions