Skip to content

Commit 3679b9d

Browse files
Merge pull request #4139 from MicrosoftDocs/alvinashcraft/main-power-mgmt-add-csharp-code
Add c# examples to Power Mgmt topic in AppLifecycle docs
2 parents 7c83d95 + 6ad17b0 commit 3679b9d

File tree

3 files changed

+151
-16
lines changed

3 files changed

+151
-16
lines changed

hub/apps/windows-app-sdk/applifecycle/applifecycle-instancing.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description: Describes how to use app instancing features with the app lifecycle API (Windows App SDK).
33
title: App instancing with the app lifecycle API (Windows App SDK)
44
ms.topic: article
5-
ms.date: 11/16/2021
5+
ms.date: 03/07/2024
66
keywords: AppLifecycle, Windows, ApplicationModel, instancing, single instance, multi instance
77
ms.localizationpriority: medium
88
---
@@ -13,15 +13,16 @@ An app's instancing model determines whether multiple instances of your app's pr
1313

1414
## Prerequisites
1515

16-
17-
1816
To use the app lifecycle API in the Windows App SDK:
1917

2018
1. Download and install the latest release of the Windows App SDK. For more information, see [Install tools for the Windows App SDK](../set-up-your-development-environment.md).
2119
2. Follow the instructions to [Create your first WinUI 3 project](../../winui/winui3/create-your-first-winui3-app.md) or to [use the Windows App SDK in an existing project](../use-windows-app-sdk-in-existing-project.md).
2220

2321
## Single-instance apps
2422

23+
> [!NOTE]
24+
> For an example of how to implement single instancing in a WinUI 3 app with C#, see [Making the app single-instanced](https://blogs.windows.com/windowsdeveloper/2022/01/28/making-the-app-single-instanced-part-3/) on the Windows developer blog.
25+
2526
Apps are single-instanced if there can be only one main process running at a time. Attempting to launch a second instance of a single-instanced app typically results in the first instance's main window being activated instead. Note that this only applies to the main process. Single-instanced apps can create multiple background processes and still be considered single instanced.
2627

2728
UWP apps are single-instanced by default. but have the ability to become multi-instanced by deciding at launch-time whether to create an additional instance or activate an existing instance instead.
@@ -407,7 +408,7 @@ void CALLBACK OnFileClosed(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam
407408
}
408409
```
409410
410-
> [!Warning]
411+
> [!WARNING]
411412
> Although keys are automatically unregistered when their process terminates, race conditions are possible where another instance may have initiated a redirection to the terminated instance before the terminated instance was unregistered. To mitigate this possibility, an app can use [UnregisterKey](/windows/windows-app-sdk/api/winrt/microsoft.windows.applifecycle.appinstance.unregisterkey) to manually unregister its key before it is terminated, giving the app a chance to redirect activations to another app that is not in the process of exiting.
412413
413414
### Instance information

hub/apps/windows-app-sdk/applifecycle/applifecycle-power.md

Lines changed: 140 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description: Describes how to use power management and notification features with the app lifecycle API (Windows App SDK).
33
title: Power management with the app lifecycle API (Windows App SDK)
44
ms.topic: article
5-
ms.date: 11/16/2021
5+
ms.date: 03/07/2024
66
keywords: AppLifecycle, Windows, ApplicationModel, power, battery,
77
ms.localizationpriority: medium
88
---
@@ -15,8 +15,6 @@ The power management APIs use a callback-based model similar to the existing [Po
1515

1616
## Prerequisites
1717

18-
19-
2018
To use the app lifecycle API in the Windows App SDK:
2119

2220
1. Download and install the latest release of the Windows App SDK. For more information, see [Install tools for the Windows App SDK](../set-up-your-development-environment.md).
@@ -26,6 +24,8 @@ To use the app lifecycle API in the Windows App SDK:
2624

2725
The following example demonstrates how to subscribe and respond to [PowerManager](/windows/windows-app-sdk/api/winrt/microsoft.windows.system.power.powermanager) events. This code subscribes to the [BatteryStatusChanged](/windows/windows-app-sdk/api/winrt/microsoft.windows.system.power.powermanager.batterystatuschanged) event during startup. The app then responds to changes by checking the current power level and adjusting its resource usage appropriately. For example, if the battery discharges at a low power state, the app might defer any non-critical background work.
2826

27+
#### [C++/WinRT](#tab/cpp)
28+
2929
> [!NOTE]
3030
> Apps can register and unregister for these events at any time, but most apps will want to set callbacks in `WinMain` that persist as long as the app continues to run.
3131
@@ -96,10 +96,68 @@ void OnPowerSupplyStatusChanged()
9696
}
9797
```
9898

99+
#### [C#](#tab/csharp)
100+
101+
> [!NOTE]
102+
> Apps can register and unregister for these events at any time, but most apps will want to set callbacks that persist as long as the app continues to run.
103+
104+
```csharp
105+
private bool bWorkInProgress;
106+
private EventRegistrationToken batteryToken;
107+
private EventRegistrationToken powerToken;
108+
private EventRegistrationToken powerSourceToken;
109+
private EventRegistrationToken chargeToken;
110+
private EventRegistrationToken dischargeToken;
111+
112+
private void RegisterPowerManagerCallbacks()
113+
{
114+
batteryToken = PowerManager.BatteryStatusChanged += (s, e) => OnBatteryStatusChanged();
115+
powerToken = PowerManager.PowerSupplyStatusChanged += (s, e) => OnPowerSupplyStatusChanged();
116+
powerSourceToken = PowerManager.PowerSourceKindChanged += (s, e) => OnPowerSourceKindChanged();
117+
chargeToken = PowerManager.RemainingChargePercentChanged += (s, e) => OnRemainingChargePercentChanged();
118+
dischargeToken = PowerManager.RemainingDischargeTimeChanged += (s, e) => OnRemainingDischargeTimeChanged();
119+
120+
if (batteryToken != null && powerToken != null && powerSourceToken != null && chargeToken != null && dischargeToken != null)
121+
{
122+
OutputMessage("Successfully registered for state notifications");
123+
}
124+
else
125+
{
126+
OutputMessage("Failed to register for state notifications");
127+
}
128+
}
129+
130+
private void OnBatteryStatusChanged()
131+
{
132+
BatteryStatus batteryStatus = PowerManager.BatteryStatus;
133+
int remainingCharge = PowerManager.RemainingChargePercent;
134+
string status = batteryStatus switch
135+
{
136+
BatteryStatus.Charging => "Charging",
137+
BatteryStatus.Discharging => "Discharging",
138+
BatteryStatus.Idle => "Idle",
139+
BatteryStatus.NotPresent => "NotPresent",
140+
_ => "Unknown"
141+
};
142+
143+
OutputFormattedMessage($"Battery status changed: {status}, {remainingCharge}% remaining");
144+
DetermineWorkloads();
145+
}
146+
147+
private void OnPowerSupplyStatusChanged()
148+
{
149+
//...etc
150+
}
151+
```
152+
153+
---
154+
99155
## Configure app logic based on multiple status values
100156

101157
[PowerManager](/windows/windows-app-sdk/api/winrt/microsoft.windows.system.power.powermanager) events are relatively low-level, and in some scenarios, a single event handler being called might not provide enough information for the app to decide how to behave. In this example, the [PowerSupplyStatusChanged](/windows/windows-app-sdk/api/winrt/microsoft.windows.system.power.powermanager.powersupplystatuschanged) event could be called when the device is disconnected from power. In that case, the app must check the current battery status before deciding how to proceed.
102158

159+
#### [C++/WinRT](#tab/cpp)
160+
103161
```cpp
104162
void DetermineWorkloads()
105163
{
@@ -128,10 +186,44 @@ void DetermineWorkloads()
128186
}
129187
```
130188

189+
#### [C#](#tab/csharp)
190+
191+
```csharp
192+
private void DetermineWorkloads()
193+
{
194+
BatteryStatus batteryStatus = PowerManager.BatteryStatus();
195+
int remainingCharge = PowerManager.RemainingChargePercent();
196+
PowerSupplyStatus powerStatus = PowerManager.PowerSupplyStatus();
197+
PowerSourceKind powerSource = PowerManager.PowerSourceKind();
198+
199+
if ((powerSource == PowerSourceKind.DC
200+
&& batteryStatus == BatteryStatus.Discharging
201+
&& remainingCharge < 25)
202+
|| (powerSource == PowerSourceKind.AC
203+
&& powerStatus == PowerSupplyStatus.Inadequate))
204+
{
205+
// The device is not in a good battery/power state,
206+
// so we should pause any non-critical work.
207+
PauseNonCriticalWork();
208+
}
209+
else if ((batteryStatus != BatteryStatus.Discharging && remainingCharge > 75)
210+
&& powerStatus != PowerSupplyStatus.Inadequate)
211+
{
212+
// The device is in good battery/power state,
213+
// so let's kick of some high-power work.
214+
StartPowerIntensiveWork();
215+
}
216+
}
217+
```
218+
219+
---
220+
131221
## Check screen status
132222

133223
The [PowerManager](/windows/windows-app-sdk/api/winrt/microsoft.windows.system.power.powermanager) class offers information about other device states relevant to an app's power usage. For example, apps can disable graphics processing when the device's display is turned off.
134224

225+
#### [C++/WinRT](#tab/cpp)
226+
135227
```cpp
136228
void OnDisplayStatusChanged()
137229
{
@@ -165,10 +257,39 @@ void OnDisplayStatusChanged()
165257
}
166258
```
167259

260+
#### [C#](#tab/csharp)
261+
262+
```csharp
263+
private void OnDisplayStatusChanged()
264+
{
265+
DisplayStatus displayStatus = PowerManager.DisplayStatus;
266+
string status = displayStatus switch
267+
{
268+
DisplayStatus.Dimmed => "Dimmed",
269+
DisplayStatus.Off => "Off",
270+
DisplayStatus.On => "On",
271+
_ => "Unknown"
272+
};
273+
274+
OutputFormattedMessage($"Display status changed: {status}");
275+
if (displayStatus == DisplayStatus.Off)
276+
{
277+
// The screen is off, let's stop rendering foreground graphics,
278+
// and instead kick off some background work now.
279+
StopUpdatingGraphics();
280+
StartDoingBackgroundWork();
281+
}
282+
}
283+
```
284+
285+
---
286+
168287
## Unsubscribe from events
169288

170289
Apps can register and deregister for notifications during their lifecycle. Use your language's preferred event registration management system if your app doesn't need to receive power status notifications during its entire lifecycle.
171290

291+
#### [C++/WinRT](#tab/cpp)
292+
172293
```cpp
173294
void UnregisterPowerManagerCallbacks()
174295
{
@@ -181,6 +302,22 @@ void UnregisterPowerManagerCallbacks()
181302
}
182303
```
183304

305+
#### [C#](#tab/csharp)
306+
307+
```csharp
308+
private void UnregisterPowerManagerCallbacks()
309+
{
310+
OutputMessage("Unregistering state notifications");
311+
PowerManager.BatteryStatusChanged -= batteryToken;
312+
PowerManager.PowerSupplyStatusChanged -= powerToken;
313+
PowerManager.PowerSourceKindChanged -= powerSourceToken;
314+
PowerManager.RemainingChargePercentChanged -= chargeToken;
315+
PowerManager.RemainingDischargeTimeChanged -= dischargeToken;
316+
}
317+
```
318+
319+
---
320+
184321
## Related topics
185322

186323
* [Windows.System.Power.PowerManager](/uwp/api/Windows.System.Power.PowerManager)

hub/apps/windows-app-sdk/applifecycle/applifecycle-rich-activation.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
description: Describes how to use rich activation features with the app lifecycle API in unpackaged apps (Windows App SDK).
33
title: Rich activation with the app lifecycle API (Windows App SDK)
44
ms.topic: article
5-
ms.date: 11/16/2021
5+
ms.date: 03/07/2024
66
keywords: AppLifecycle, Windows, activation, activation contracts, rich activation, win32, win32 activation, unpackaged app, unpackaged app activation
77
ms.localizationpriority: medium
88
---
@@ -18,12 +18,9 @@ Supporting rich activations requires two steps:
1818

1919
## Prerequisites
2020

21-
> [!IMPORTANT]
22-
> The app lifecycle API is currently supported in the [preview release channel](../preview-channel.md) and [experimental release channel](../experimental-channel.md) of the Windows App SDK. This feature is not currently supported for use by apps in production environments.
23-
2421
To use the app lifecycle API in the Windows App SDK:
2522

26-
1. Download and install the latest preview or experimental release of the Windows App SDK. For more information, see [Install tools for the Windows App SDK](../set-up-your-development-environment.md).
23+
1. Download and install the latest release of the Windows App SDK. For more information, see [Install tools for the Windows App SDK](../set-up-your-development-environment.md).
2724
2. Follow the instructions to [Create your first WinUI 3 project](../../winui/winui3/create-your-first-winui3-app.md) or to [use the Windows App SDK in an existing project](../use-windows-app-sdk-in-existing-project.md).
2825

2926
## Activation details for unpackaged apps
@@ -32,10 +29,10 @@ The current version of the Windows App SDK supports the four most common activat
3229

3330
| Activation kind | Description |
3431
| --------------- | ------------------------------------------------------------ |
35-
| `Launch` | Activate the app from the command line, when the user double-clicks the app's icon, or programmatically via [ShellExecute](/windows/win32/api/shellapi/nf-shellapi-shellexecuteexw) or [CreateProcess](/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw). |
36-
| `File` | Activate an app that has registered for a file type when a file of the type is opened via [ShellExecute](/windows/win32/api/shellapi/nf-shellapi-shellexecuteexw), [Launcher.LaunchFileAsync](/uwp/api/windows.system.launcher.launchfileasync), or the command line. |
37-
| `Protocol` | Activate an app that has registered for a protocol when a string of that protocol is executed via [ShellExecute](/windows/win32/api/shellapi/nf-shellapi-shellexecuteexw), [Launcher.LaunchUriAsync](/uwp/api/windows.system.launcher.launchuriasync), or the command-line. |
38-
| `StartupTask` | Activate the app when the user logs into Windows, either because of a registry key, or because of a shortcut in a well-known startup folder. |
32+
| `Launch` | Activate the app from the command line, when the user double-clicks the app's icon, or programmatically via [ShellExecute](/windows/win32/api/shellapi/nf-shellapi-shellexecuteexw) or [CreateProcess](/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw). |
33+
| `File` | Activate an app that has registered for a file type when a file of the type is opened via [ShellExecute](/windows/win32/api/shellapi/nf-shellapi-shellexecuteexw), [Launcher.LaunchFileAsync](/uwp/api/windows.system.launcher.launchfileasync), or the command line. |
34+
| `Protocol` | Activate an app that has registered for a protocol when a string of that protocol is executed via [ShellExecute](/windows/win32/api/shellapi/nf-shellapi-shellexecuteexw), [Launcher.LaunchUriAsync](/uwp/api/windows.system.launcher.launchuriasync), or the command-line. |
35+
| `StartupTask` | Activate the app when the user logs into Windows, either because of a registry key, or because of a shortcut in a well-known startup folder. |
3936

4037
Each type of unpackaged app retrieves its command line arguments in different ways. For example, C++ Win32 apps expect to receive activation arguments to be passed into `WinMain` in the form of a string (though they also have the option to call [GetCommandLineW](/windows/win32/api/processenv/nf-processenv-getcommandlinew)). Windows Forms apps, however, *must* call [Environment.GetCommandLineArgs](/dotnet/api/system.environment.getcommandlineargs), because arguments will not be automatically passed to them.
4138

0 commit comments

Comments
 (0)