KEMBAR78
Windows service improvements for hosting, testing, fallback, and extended commands by kennykerr · Pull Request #3662 · microsoft/windows-rs · GitHub
Skip to content

Conversation

@kennykerr
Copy link
Collaborator

@kennykerr kennykerr commented Jul 14, 2025

This update provides a major overhaul of the windows-services crate and addresses a number of issues to support more scenarios and features while retaining the simplicity of the Service builder by default.

  • Provides the foundation for supporting extended controls by switching from RegisterServiceCtrlHandlerW to RegisterServiceCtrlHandlerExW internally.
  • Provides a new Extended variant for the Command enum to allow services to receive extended control information.
  • Provides a new can_accept builder method to specify other specific commands to accept.
  • Provides a new can_fallback builder method to allow the service to provide specific handling when the service is not started by the Service Control Manager.
  • The run method is no longer fatal so that a caller may decide to gracefully handle and detect when the service is not started by the Service Control Manager.
  • Provides a new handle method to retrieve the handle representing the service. This may be used to call other service-related functions like RegisterPowerSettingNotification.

Additional samples and tests are now provided thanks to the greater flexibility afforded by the new implementation.

Fixes: #3610
Fixes: #3641

@edvard-pettersen-elas-ai

@kennykerr, the API looks good, but there are some additional steps that are required to support SERVICE_CONTROL_POWEREVENT. After having specified can_accept(SERVICE_ACCEPT_POWEREVENT), the application also needs to specify which power events to register for notification by calling RegisterPowerSettingNotification. This requires access to the handle returned by RegisterServiceCtrlHandlerExW, which doesn't seem accessible in the current proposal.

@kennykerr
Copy link
Collaborator Author

kennykerr commented Jul 15, 2025

37c0d93 adds a handle method that you can use to retrieve the service handle. You might for example use it when responding to Command::Start to call RegisterPowerSettingNotification. Something like this:

let mut power_handle = 0;

Service::new()
    .can_stop()
    .can_accept(SERVICE_ACCEPT_POWEREVENT)
    .run(|service, command| {
        if command == Command::Start {
            power_handle = unsafe {
                RegisterPowerSettingNotification(
                    service.handle(),
                    &GUID_GLOBAL_USER_PRESENCE,
                    DEVICE_NOTIFY_SERVICE_HANDLE,
                )
            };
        }

        if let Command::Extended(command) = command {
            if command.control == SERVICE_CONTROL_POWEREVENT {
                debug_assert!(command.ty == PBT_POWERSETTINGCHANGE);
                let data = unsafe { &*(command.data as *const POWERBROADCAST_SETTING) };
                debug_assert!(&data.PowerSetting == &GUID_GLOBAL_USER_PRESENCE);
                debug_assert!(data.DataLength == 4);

                let data = unsafe {
                    std::slice::from_raw_parts(data.Data.as_ptr(), data.DataLength as usize)
                };

                let data = u32::from_le_bytes(data.try_into().unwrap());
                writeln!(log, "Present: {data}").unwrap();
            }
        }
    })
    .unwrap();

@kennykerr

This comment was marked as resolved.

@kennykerr kennykerr merged commit 0dfbc25 into master Jul 21, 2025
29 checks passed
@kennykerr kennykerr deleted the service-state branch July 21, 2025 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add support for running a service exe as a console app. Support extended control codes with windows-services

2 participants