Skip to content

A Windows Service for monitoring laptop lid open/close events.

Notifications You must be signed in to change notification settings

rowandh/lidstatusservice

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 

Repository files navigation

LidStatusService

LidStatusService is a Windows Service for monitoring laptop lid open/close events.

There are a few examples of determining lid open/close events in windowed C# applications [1] [2] or by using a hidden window in a console application [3].

But nowhere seems to provide an example of this process using a Windows Service, which is a little bit different.

How It Works

Monitoring power event changes in Windows requires making a Windows API call to RegisterPowerSettingNotification, whose signature is:

HPOWERNOTIFY WINAPI RegisterPowerSettingNotification(
  _In_ HANDLE  hRecipient,
  _In_ LPCGUID PowerSettingGuid,
  _In_ DWORD   Flags
);

The PowerSettingGuid for lid switch state changes is GUID_LIDSWITCH_STATE_CHANGE. The documentation for Windows Desktop App Development list a few of the most "useful" GUIDs, but to find this one you will have to dig into WinNT.h.

// Lid state changes
// -----------------
//
// Specifies the current state of the lid (open or closed). The callback won't
// be called at all until a lid device is found and its current state is known.
//
// Values:
//
// 0 - closed
// 1 - opened
//
// { BA3E0F4D-B817-4094-A2D1-D56379E6A0F3 }
//

DEFINE_GUID( GUID_LIDSWITCH_STATE_CHANGE,  0xBA3E0F4D, 0xB817, 0x4094, 0xA2, 0xD1, 0xD5, 0x63, 0x79, 0xE6, 0xA0, 0xF3 );

The flags argument that RegisterPowerSettingNotification accepts can have values of DEVICE_NOTIFY_WINDOW_HANDLE (0) for a windowed application or DEVICE_NOTIFY_SERVICE_HANDLE (1) for a service. We have a service, so we will want to call this method using the latter value.

Once we register our service for notifications, we have to define a callback to listen for messages from Windows. We also need to let Windows know about our callback. For a service, the documentation states:

Notifications are sent to the HandlerEx callback function with a dwControl parameter of SERVICE_CONTROL_POWEREVENT and a dwEventType of PBT_POWERSETTINGCHANGE.

Digging further into Microsoft's documentation reveals theses values: SERVICE_CONTROL_POWEREVENT = 0x0000000D PBT_POWERSETTINGCHANGE = 0x8013

The HandlerEx callback has the following signature:

DWORD WINAPI HandlerEx(
  _In_ DWORD  dwControl,
  _In_ DWORD  dwEventType,
  _In_ LPVOID lpEventData,
  _In_ LPVOID lpContext
);

This callback can receive other types of events, but for our implementation, we only care about certain types of power events. In our callback, we can filter for these by checking whether dwControl is a SERVICE_CONTROL_POWEREVENT, and whether dwEventType is PBT_POWERSETTINGCHANGE. The documentation for HandlerEx also states:

SERVICE_CONTROL_POWEREVENT - Notifies a service of system power events. The dwEventType parameter contains additional information. If dwEventType is PBT_POWERSETTINGCHANGE, the lpEventData parameter also contains additional information.

What is this "additional information"? According to the documentation for PBT_POWERSETTINGCHANGE, it's a pointer to a POWERBROADCAST_SETTING struct.

POWERBROADCAST_SETTING has this signature:

typedef struct {
  GUID  PowerSetting;
  DWORD DataLength;
  UCHAR Data[1];
} POWERBROADCAST_SETTING, *PPOWERBROADCAST_SETTING;

Where the Data field is "The new value of the power setting. The type and possible values for this member depend on PowerSetting."

We know from the documentation in WinNT.h that the callback can have two values, 0 for closed, and 1 for open.

That's about it. We can wrap these ugly Windows API call in a nice class and use it in our Windows service!

About

A Windows Service for monitoring laptop lid open/close events.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages