Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Question] PowrProf.PowerSettingRegisterNotification #122

Closed
Huntk23 opened this issue May 14, 2020 · 3 comments
Closed

[Question] PowrProf.PowerSettingRegisterNotification #122

Huntk23 opened this issue May 14, 2020 · 3 comments

Comments

@Huntk23
Copy link

Huntk23 commented May 14, 2020

First of all, excellent library/wrappers. Thank you for this!

I have been stuck trying to figure out why I cannot get PowrProf.PowerSettingRegisterNotification to work. I am trying to read/set a power setting in Win32.

Specifically: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-systemparametersinfoa
SPI_GETPOWEROFFTIMEOUT & SPI_SETPOWEROFFTIMEOUT

Both of these are not supported and references GUID_VIDEO_POWERDOWN_TIMEOUT that says to use RegisterPowerSettingsNotification: https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerpowersettingnotification

I found these under your PowrProf wrapper and have been attempting to get it work. So far, I receive a good message back from PowrProf.PowerSettingRegisterNotification:

ERROR_SUCCESS: The operation completed successfully.

I may not be creating the IntPtr for the recipient correctly? I may not be fully understanding how to utilize the wrapper without reinventing the wheel. I haven't worked much with Win32/PInvoke, but not getting far from trial/error and example research. The simple console application example I have abruptly closes after a couple of seconds. Virtually not making it to the while loop to give me time to change the setting in Windows and print the changed value:

class Program
{
    public static PowrProf.DeviceNotifyCallbackRoutine DeviceNotifyCallbackRoutine { get; set; }

    private static uint HandlerCallback(IntPtr context, uint eventType, IntPtr setting)
    {
        Console.WriteLine($"Setting value changed: {setting}");

        return 0;
    }

    static void Main()
    {
        DeviceNotifyCallbackRoutine = HandlerCallback;

        var deviceNotifySubscribeParameters = new PowrProf.DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS
        {
            Callback = Marshal.GetFunctionPointerForDelegate(DeviceNotifyCallbackRoutine),
            Context = IntPtr.Zero
        };

        var success = PowrProf.PowerSettingRegisterNotification(PowrProf.GUID_VIDEO_POWERDOWN_TIMEOUT, PowrProf.DEVICE_NOTIFY.DEVICE_NOTIFY_CALLBACK, deviceNotifySubscribeParameters.Callback, out var powerNotification);

        Console.WriteLine(success);
        Console.WriteLine($"IsInvalid: {powerNotification.IsInvalid}, IsClosed: {powerNotification.IsClosed}, IsNull: {powerNotification.IsNull}");

        int counter = 0;
        while (!powerNotification.IsInvalid)
        {
            Thread.Sleep(3000);
            if (++counter == 10) break;
        }

        if (!powerNotification.IsNull)
        {
            PowrProf.PowerSettingUnregisterNotification(powerNotification);
        }

        powerNotification.Close();
        powerNotification.Dispose();

        Console.ReadKey();
}
dahall added a commit that referenced this issue May 14, 2020
@dahall
Copy link
Owner

dahall commented May 14, 2020

I've looked into your question and apologize. There is both a bug and a few omissions that are making this hard for you. I've corrected them and committed the updates. They will get released in the next version, due shortly. Here is the function to get the value you want.

public uint GetVideoPowerdownTimeout()
{
   uint timeOut = 0;
   var evt = new AutoResetEvent(false);
   PowerSettingRegisterNotification(GUID_VIDEO_POWERDOWN_TIMEOUT, DEVICE_NOTIFY.DEVICE_NOTIFY_CALLBACK, new DEVICE_NOTIFY_SUBSCRIBE_PARAMETERS { Callback = PowerSettingFunc }, out var powerNotification).ThrowIfFailed();
   evt.WaitOne(1000);
   PowerSettingUnregisterNotification(powerNotification).ThrowIfFailed();
   return timeOut;

   Win32Error PowerSettingFunc(IntPtr Context, uint Type, IntPtr Setting)
   {
      if (Type == (uint)User32.PowerBroadcastType.PBT_POWERSETTINGCHANGE && Setting != IntPtr.Zero)
      {
         var pbSetting = Setting.ToStructure<User32.POWERBROADCAST_SETTING>();
         if (pbSetting.DataLength == Marshal.SizeOf(typeof(uint)))
            timeOut = BitConverter.ToUInt32(pbSetting.Data, 0);
      }
      evt.Set();
      return Win32Error.ERROR_SUCCESS;
   }
}

@dahall dahall closed this as completed May 14, 2020
dahall added a commit that referenced this issue May 14, 2020
@Huntk23
Copy link
Author

Huntk23 commented May 15, 2020

@dahall
Thanks for your swift response and fix! I look forward to the next version release to continue tinkering.

@dahall
Copy link
Owner

dahall commented May 15, 2020

You can pull the 3.2.8 build now as prerelease from AppVeyor's project NuGet source at https://ci.appveyor.com/nuget/vanara-prerelease.

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

No branches or pull requests

2 participants