This repository was archived by the owner on Sep 29, 2025. It is now read-only.
-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathWin32Helper.cs
More file actions
328 lines (286 loc) · 13.2 KB
/
Copy pathWin32Helper.cs
File metadata and controls
328 lines (286 loc) · 13.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
using Microsoft.Toolkit.Uwp.Notifications;
using System;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Interop;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.UI.WindowsAndMessaging;
namespace AutoPowerTimeOut;
internal class Win32Helper
{
private static readonly Guid GUID_VIDEO_TIMEOUT = new("3c0bc021-c8a8-4e07-a973-6b14cbcb2b7e");
private static readonly Guid GUID_SLEEP_IDLE = new("29f6c1db-86da-48c5-9fdb-f2b67b1f44da");
private static readonly Guid SUB_BUTTONS = new("4f971e89-eebd-4455-a8de-9e59040e7347");
private static readonly Guid POWERBUTTON_ACTION = new("7648efa3-dd9c-4e3e-b566-50f929386280");
private static readonly Guid SLEEPBUTTON_ACTION = new("96996bc0-ad50-47ec-923b-6f41874dd9eb");
private static readonly Guid LIDCLOSE_ACTION = new("5ca83367-6e45-459f-a27b-476b1d01c936");
/// <summary>
/// Sets the display and sleep timeout values for both AC and DC power states.
/// </summary>
/// <param name="acDisplayMinutes">
/// The number of minutes to turn off display when plugged in (AC).
/// </param>
/// <param name="dcDisplayMinutes">
/// The number of minutes to turn off display when on battery (DC).
/// </param>
/// <param name="acSleepMinutes">
/// The number of minutes to put the computer to sleep when plugged in (AC).
/// </param>
/// <param name="dcSleepMinutes">
/// The number of minutes to put the computer to sleep when on battery (DC).
/// </param>
/// <exception cref="Exception"></exception>
public unsafe static void SetDisplayAndSleepTimeout(
uint acDisplayMinutes, uint dcDisplayMinutes, uint acSleepMinutes, uint dcSleepMinutes)
{
try
{
var res = PInvoke.PowerGetActiveScheme(null, out var pActiveScheme);
if (res != WIN32_ERROR.ERROR_SUCCESS)
{
throw new Exception($"PowerGetActiveScheme failed: {res}");
}
var activeScheme = *pActiveScheme;
// Set AC values
_ = PInvoke.PowerWriteACValueIndex(null, activeScheme, PInvoke.GUID_VIDEO_SUBGROUP, GUID_VIDEO_TIMEOUT, acDisplayMinutes * 60);
_ = PInvoke.PowerWriteACValueIndex(null, activeScheme, PInvoke.GUID_SLEEP_SUBGROUP, GUID_SLEEP_IDLE, acSleepMinutes * 60);
// Set DC values
_ = PInvoke.PowerWriteDCValueIndex(null, activeScheme, PInvoke.GUID_VIDEO_SUBGROUP, GUID_VIDEO_TIMEOUT, dcDisplayMinutes * 60);
_ = PInvoke.PowerWriteDCValueIndex(null, activeScheme, PInvoke.GUID_SLEEP_SUBGROUP, GUID_SLEEP_IDLE, dcSleepMinutes * 60);
// Commit changes
_ = PInvoke.PowerSetActiveScheme(null, activeScheme);
}
catch (Exception ex)
{
throw new Exception("Failed to set power settings", ex);
}
}
/// <summary>
/// Gets the current display and sleep timeout values for both AC and DC power states.
/// </summary>
/// <param name="acDisplayMinutes">
/// The number of minutes to turn off display when plugged in (AC).
/// </param>
/// <param name="dcDisplayMinutes">
/// The number of minutes to turn off display when on battery (DC).
/// </param>
/// <param name="acSleepMinutes">
/// The number of minutes to put the computer to sleep when plugged in (AC).
/// </param>
/// <param name="dcSleepMinutes">
/// The number of minutes to put the computer to sleep when on battery (DC).
/// </param>
/// <returns>
/// True if the operation was successful, false otherwise.
/// </returns>
public static unsafe bool GetDisplayAndSleepTimeout(
out uint acDisplayMinutes, out uint dcDisplayMinutes, out uint acSleepMinutes, out uint dcSleepMinutes)
{
acDisplayMinutes = dcDisplayMinutes = acSleepMinutes = dcSleepMinutes = 0;
try
{
// Get the active power scheme
var result = PInvoke.PowerGetActiveScheme(null, out var pActiveScheme);
if (result != WIN32_ERROR.ERROR_SUCCESS)
return false;
var activeScheme = *pActiveScheme;
// Read AC Display Timeout
var acResult = PInvoke.PowerReadACValueIndex(
null, activeScheme, PInvoke.GUID_VIDEO_SUBGROUP, GUID_VIDEO_TIMEOUT, out var acDisplaySec);
if (acResult != WIN32_ERROR.ERROR_SUCCESS)
return false;
// Read DC Display Timeout
var dcResult = PInvoke.PowerReadDCValueIndex(
null, activeScheme, PInvoke.GUID_VIDEO_SUBGROUP, GUID_VIDEO_TIMEOUT, out var dcDisplaySec);
if (dcResult != 0)
return false;
// Read AC Sleep Timeout
acResult = PInvoke.PowerReadACValueIndex(
null, activeScheme, PInvoke.GUID_SLEEP_SUBGROUP, GUID_SLEEP_IDLE, out var acSleepSec);
if (acResult != WIN32_ERROR.ERROR_SUCCESS)
return false;
// Read DC Sleep Timeout
dcResult = PInvoke.PowerReadDCValueIndex(
null, activeScheme, PInvoke.GUID_SLEEP_SUBGROUP, GUID_SLEEP_IDLE, out var dcSleepSec);
if (dcResult != 0)
return false;
acDisplayMinutes = acDisplaySec / 60;
dcDisplayMinutes = dcDisplaySec / 60;
acSleepMinutes = acSleepSec / 60;
dcSleepMinutes = dcSleepSec / 60;
return true;
}
catch
{
acDisplayMinutes = dcDisplayMinutes = acSleepMinutes = dcSleepMinutes = 0;
return false;
}
}
/// <summary>
/// Sets the power button, sleep button, and lid close actions for both AC and DC power states.
/// </summary>
/// <param name="acPowerOption"></param>
/// <param name="dcPowerOption"></param>
/// <param name="acSleepOption"></param>
/// <param name="dcSleepOption"></param>
/// <param name="acLidOption"></param>
/// <param name="dcLidOption"></param>
/// <exception cref="Exception"></exception>
public static unsafe void SetLidPowerSleepButtonControlOptions(
LidPowerSleepButtonOption acPowerOption,
LidPowerSleepButtonOption dcPowerOption,
LidPowerSleepButtonOption acSleepOption,
LidPowerSleepButtonOption dcSleepOption,
LidPowerSleepButtonOption acLidOption,
LidPowerSleepButtonOption dcLidOption)
{
try
{
var res = PInvoke.PowerGetActiveScheme(null, out var pActiveScheme);
if (res != WIN32_ERROR.ERROR_SUCCESS)
{
throw new Exception($"PowerGetActiveScheme failed: {res}");
}
var activeScheme = *pActiveScheme;
// Set values
_ = PInvoke.PowerWriteACValueIndex(null, activeScheme, SUB_BUTTONS, POWERBUTTON_ACTION, (uint)acPowerOption);
_ = PInvoke.PowerWriteDCValueIndex(null, activeScheme, SUB_BUTTONS, POWERBUTTON_ACTION, (uint)dcPowerOption);
_ = PInvoke.PowerWriteACValueIndex(null, activeScheme, SUB_BUTTONS, SLEEPBUTTON_ACTION, (uint)acSleepOption);
_ = PInvoke.PowerWriteDCValueIndex(null, activeScheme, SUB_BUTTONS, SLEEPBUTTON_ACTION, (uint)dcSleepOption);
_ = PInvoke.PowerWriteACValueIndex(null, activeScheme, SUB_BUTTONS, LIDCLOSE_ACTION, (uint)acLidOption);
_ = PInvoke.PowerWriteDCValueIndex(null, activeScheme, SUB_BUTTONS, LIDCLOSE_ACTION, (uint)dcLidOption);
// Commit changes
_ = PInvoke.PowerSetActiveScheme(null, activeScheme);
}
catch (Exception ex)
{
throw new Exception("Failed to set power settings", ex);
}
// Power button
}
/// <summary>
/// Gets the current power options for lid, power button, and sleep button actions.
/// </summary>
/// <param name="acPowerOption"></param>
/// <param name="dcPowerOption"></param>
/// <param name="acSleepOption"></param>
/// <param name="dcSleepOption"></param>
/// <param name="acLidOption"></param>
/// <param name="dcLidOption"></param>
/// <returns></returns>
public static unsafe bool GetLidPowerSleepButtonControlOptions(
out LidPowerSleepButtonOption acPowerOption,
out LidPowerSleepButtonOption dcPowerOption,
out LidPowerSleepButtonOption acSleepOption,
out LidPowerSleepButtonOption dcSleepOption,
out LidPowerSleepButtonOption acLidOption,
out LidPowerSleepButtonOption dcLidOption)
{
acPowerOption = dcPowerOption = acSleepOption = dcSleepOption = acLidOption = dcLidOption = LidPowerSleepButtonOption.Sleep;
try
{
// Get the active power scheme
var result = PInvoke.PowerGetActiveScheme(null, out var pActiveScheme);
if (result != WIN32_ERROR.ERROR_SUCCESS)
return false;
var activeScheme = *pActiveScheme;
// Read values
var acResult = PInvoke.PowerReadACValueIndex(null, activeScheme, SUB_BUTTONS, POWERBUTTON_ACTION, out var acPower);
if (acResult != WIN32_ERROR.ERROR_SUCCESS)
return false;
var dcResult = PInvoke.PowerReadDCValueIndex(null, activeScheme, SUB_BUTTONS, POWERBUTTON_ACTION, out var dcPower);
if (dcResult != 0)
return false;
acResult = PInvoke.PowerReadACValueIndex(null, activeScheme, SUB_BUTTONS, SLEEPBUTTON_ACTION, out var acSleep);
if (acResult != WIN32_ERROR.ERROR_SUCCESS)
return false;
dcResult = PInvoke.PowerReadDCValueIndex(null, activeScheme, SUB_BUTTONS, SLEEPBUTTON_ACTION, out var dcSleep);
if (dcResult != 0)
return false;
acResult = PInvoke.PowerReadACValueIndex(null, activeScheme, SUB_BUTTONS, LIDCLOSE_ACTION, out var acLid);
if (acResult != WIN32_ERROR.ERROR_SUCCESS)
return false;
dcResult = PInvoke.PowerReadDCValueIndex(null, activeScheme, SUB_BUTTONS, LIDCLOSE_ACTION, out var dcLid);
if (dcResult != 0)
return false;
// Cast to enum
acPowerOption = (LidPowerSleepButtonOption)acPower;
dcPowerOption = (LidPowerSleepButtonOption)dcPower;
acSleepOption = (LidPowerSleepButtonOption)acSleep;
dcSleepOption = (LidPowerSleepButtonOption)dcSleep;
acLidOption = (LidPowerSleepButtonOption)acLid;
dcLidOption = (LidPowerSleepButtonOption)dcLid;
return true;
}
catch
{
return false;
}
}
private static bool IsNotificationSupported()
{
// Notifications only supported on Windows 10 19041+
return RuntimeInformation.IsOSPlatform(OSPlatform.Windows) &&
Environment.OSVersion.Version.Build >= 19041;
}
public static bool ShowNotification(string message)
{
if (!IsNotificationSupported())
{
return false;
}
try
{
new ToastContentBuilder()
.AddText("Auto Power Time-out", hintMaxLines: 1)
.AddText(message)
.AddAppLogoOverride(new Uri(Constants.IconPath))
.Show();
return true;
}
catch (Exception ex)
{
Console.WriteLine($"Failed to show notification: {ex.Message}");
return false;
}
}
public static void BringToForegroundEx(Window window, bool topMost)
{
BringToForegroundEx(new HWND(new WindowInteropHelper(window).Handle), topMost);
}
public static void BringToForegroundEx(nint handle, bool topMost)
{
BringToForegroundEx(new HWND(handle), topMost);
}
/// <summary>
/// Brings the app window to foreground. From https://github.com/files-community/Files.
/// </summary>
/// <remarks>
/// For more information, visit
/// <br/>
/// - <a href="https://stackoverflow.com/questions/1544179/what-are-the-differences-between-bringwindowtotop-setforegroundwindow-setwindo" />
/// <br/>
/// - <a href="https://stackoverflow.com/questions/916259/win32-bring-a-window-to-top" />
/// </remarks>
/// <param name="hWnd">The window handle to bring.</param>
/// <param name="topMost">If true, the window will be set as topmost before bringing it to the foreground.</param>
private static unsafe void BringToForegroundEx(HWND hWnd, bool topMost)
{
var hCurWnd = PInvoke.GetForegroundWindow();
var dwMyID = PInvoke.GetCurrentThreadId();
var dwCurID = PInvoke.GetWindowThreadProcessId(hCurWnd);
PInvoke.AttachThreadInput(dwCurID, dwMyID, true);
// Set the window to be the topmost window
PInvoke.SetWindowPos(hWnd, (HWND)(-1), 0, 0, 0, 0, SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE);
if (!topMost)
{
// Restore the window to its original position
PInvoke.SetWindowPos(hWnd, (HWND)(-2), 0, 0, 0, 0, SET_WINDOW_POS_FLAGS.SWP_SHOWWINDOW | SET_WINDOW_POS_FLAGS.SWP_NOSIZE | SET_WINDOW_POS_FLAGS.SWP_NOMOVE);
}
PInvoke.SetForegroundWindow(hWnd);
PInvoke.SetFocus(hWnd);
PInvoke.SetActiveWindow(hWnd);
PInvoke.AttachThreadInput(dwCurID, dwMyID, false);
}
}