Skip to content

Commit

Permalink
Added C# Sample for BackgroundTaskBuilder
Browse files Browse the repository at this point in the history
Signed-off-by: Godly Alias <[email protected]>
  • Loading branch information
godlytalias committed Nov 26, 2024
1 parent 9582949 commit e123eae
Show file tree
Hide file tree
Showing 21 changed files with 529 additions and 0 deletions.
40 changes: 40 additions & 0 deletions Samples/BackgroundTask/cs-winui/BackgroundTaskBuilder.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.12.35514.174
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BackgroundTaskBuilder", "BackgroundTaskBuilder\BackgroundTaskBuilder.csproj", "{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|ARM64 = Debug|ARM64
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|ARM64 = Release|ARM64
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|ARM64.ActiveCfg = Debug|ARM64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|ARM64.Build.0 = Debug|ARM64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|ARM64.Deploy.0 = Debug|ARM64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|x64.ActiveCfg = Debug|x64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|x64.Build.0 = Debug|x64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|x64.Deploy.0 = Debug|x64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|x86.ActiveCfg = Debug|x86
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|x86.Build.0 = Debug|x86
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Debug|x86.Deploy.0 = Debug|x86
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|ARM64.ActiveCfg = Release|ARM64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|ARM64.Build.0 = Release|ARM64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|ARM64.Deploy.0 = Release|ARM64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|x64.ActiveCfg = Release|x64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|x64.Build.0 = Release|x64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|x64.Deploy.0 = Release|x64
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|x86.ActiveCfg = Release|x86
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|x86.Build.0 = Release|x86
{18896EE2-23CF-4C44-B5D9-1A9867BB7D69}.Release|x86.Deploy.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
16 changes: 16 additions & 0 deletions Samples/BackgroundTask/cs-winui/BackgroundTaskBuilder/App.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<Application
x:Class="BackgroundTaskBuilder.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BackgroundTaskBuilder">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
<!-- Other merged dictionaries here -->
</ResourceDictionary.MergedDictionaries>
<!-- Other app resources here -->
</ResourceDictionary>
</Application.Resources>
</Application>
44 changes: 44 additions & 0 deletions Samples/BackgroundTask/cs-winui/BackgroundTaskBuilder/App.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
using BackgroundTaskBuilder;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI.Xaml.Shapes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel;
using Windows.ApplicationModel.Activation;
using Windows.Foundation;
using Windows.Foundation.Collections;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace BackgroundTaskBuilder
{
/// <summary>
/// Provides application-specific behavior to supplement the default Application class.
/// </summary>
public partial class App : Application
{
public App()
{
this.InitializeComponent();
}

protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
m_window = new MainWindow();
m_window.Activate();
}

private Window? m_window;
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@

using System;
using System.IO; // Path
using System.Threading; // EventWaitHandle
using System.Collections.Generic; // Queue
using System.Runtime.InteropServices; // Guid, RegistrationServices
using Windows.ApplicationModel.Background; // IBackgroundTask
using Windows.UI.Notifications; // ToastNotificationManager, ToastTemplateType, ToastNotification

namespace BackgroundTaskBuilder
{
// Background task implementation.
// {87654321-1234-1234-1234-1234567890AE} is GUID to register this task with BackgroundTaskBuilder. Generate a random GUID before implementing.
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("87654321-1234-1234-1234-1234567890AE")]
[ComSourceInterfaces(typeof(IBackgroundTask))]
public class BackgroundTask : IBackgroundTask
{
private volatile int cleanupTask; // flag used to indicate to Run method that it should exit

public BackgroundTask()
{
cleanupTask = 0;
}

/// <summary>
/// This method is the main entry point for the background task. The system will believe this background task
/// is complete when this method returns.
/// </summary>
[MTAThread]
public void Run(IBackgroundTaskInstance taskInstance)
{
// Wire the cancellation handler.
taskInstance.Canceled += this.OnCanceled;

// Set the progress to indicate this task has started
taskInstance.Progress = 10;

// Create the toast notification content
var toastXml = ToastNotificationManager.GetTemplateContent(ToastTemplateType.ToastText01);
var toastTextElements = toastXml.GetElementsByTagName("text");
toastTextElements[0].AppendChild(toastXml.CreateTextNode("C# Background task executed"));

// Create the toast notification
var toast = new ToastNotification(toastXml);

// Show the toast notification
ToastNotificationManager.CreateToastNotifier().Show(toast);
}

/// <summary>
/// This method is signaled when the system requests the background task be canceled. This method will signal
/// to the Run method to clean up and return.
/// </summary>
[MTAThread]
public void OnCanceled(IBackgroundTaskInstance taskInstance, BackgroundTaskCancellationReason cancellationReason)
{
cleanupTask = 1;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows10.0.19041.0</TargetFramework>
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
<RootNamespace>BackgroundTaskBuilder</RootNamespace>
<ApplicationManifest>app.manifest</ApplicationManifest>
<Platforms>x86;x64;ARM64</Platforms>
<RuntimeIdentifiers>win-x86;win-x64;win-arm64</RuntimeIdentifiers>
<PublishProfile>win-$(Platform).pubxml</PublishProfile>
<UseWinUI>true</UseWinUI>
<EnableMsixTooling>true</EnableMsixTooling>
<Nullable>enable</Nullable>
<WindowsAppSDKBackgroundTask>true</WindowsAppSDKBackgroundTask>
</PropertyGroup>

<ItemGroup>
<Content Include="Assets\SplashScreen.scale-200.png" />
<Content Include="Assets\LockScreenLogo.scale-200.png" />
<Content Include="Assets\Square150x150Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.scale-200.png" />
<Content Include="Assets\Square44x44Logo.targetsize-24_altform-unplated.png" />
<Content Include="Assets\StoreLogo.png" />
<Content Include="Assets\Wide310x150Logo.scale-200.png" />
</ItemGroup>

<ItemGroup>
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>

<!--
Defining the "Msix" ProjectCapability here allows the Single-project MSIX Packaging
Tools extension to be activated for this project even if the Windows App SDK Nuget
package has not yet been restored.
-->
<ItemGroup Condition="'$(DisableMsixProjectCapabilityAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<ProjectCapability Include="Msix" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Windows.SDK.BuildTools" Version="10.0.26100.2454" />
<PackageReference Include="Microsoft.WindowsAppSDK" Version="1.7.241114004-experimental1" />
</ItemGroup>

<!--
Defining the "HasPackageAndPublishMenuAddedByProject" property here allows the Solution
Explorer "Package and Publish" context menu entry to be enabled for this project even if
the Windows App SDK Nuget package has not yet been restored.
-->
<PropertyGroup Condition="'$(DisableHasPackageAndPublishMenuAddedByProject)'!='true' and '$(EnableMsixTooling)'=='true'">
<HasPackageAndPublishMenu>true</HasPackageAndPublishMenu>
</PropertyGroup>

<!-- Publish Properties -->
<PropertyGroup>
<PublishReadyToRun Condition="'$(Configuration)' == 'Debug'">False</PublishReadyToRun>
<PublishReadyToRun Condition="'$(Configuration)' != 'Debug'">True</PublishReadyToRun>
<PublishTrimmed Condition="'$(Configuration)' == 'Debug'">False</PublishTrimmed>
<PublishTrimmed Condition="'$(Configuration)' != 'Debug'">True</PublishTrimmed>
<AllowUnsafeBlocks>True</AllowUnsafeBlocks>
</PropertyGroup>
</Project>
71 changes: 71 additions & 0 deletions Samples/BackgroundTask/cs-winui/BackgroundTaskBuilder/ComServer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
using System;
using System.Runtime.InteropServices;
using WinRT;

namespace BackgroundTaskBuilder
{
// COM server startup code.
internal class ComServer
{
[DllImport("ole32.dll")]
public static extern int CoRegisterClassObject(
ref Guid classId,
[MarshalAs(UnmanagedType.Interface)] IClassFactory objectAsUnknown,
uint executionContext,
uint flags,
out uint registrationToken);

public const uint CLSCTX_LOCAL_SERVER = 4;
public const uint REGCLS_MULTIPLEUSE = 1;

public const uint S_OK = 0x00000000;
public const uint CLASS_E_NOAGGREGATION = 0x80040110;
public const uint E_NOINTERFACE = 0x80004002;

public const string IID_IUnknown = "00000000-0000-0000-C000-000000000046";
public const string IID_IClassFactory = "00000001-0000-0000-C000-000000000046";

[ComImport]
[ComVisible(false)]
[Guid(IID_IClassFactory)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface IClassFactory
{
[PreserveSig]
uint CreateInstance(IntPtr objectAsUnknown, ref Guid interfaceId, out IntPtr objectPointer);

[PreserveSig]
uint LockServer(bool Lock);
}

internal class BackgroundTaskFactory<TaskType, TaskInterface> : IClassFactory where TaskType : TaskInterface, new()
{
public BackgroundTaskFactory()
{
}

public uint CreateInstance(IntPtr objectAsUnknown, ref Guid interfaceId, out IntPtr objectPointer)
{
if (objectAsUnknown != IntPtr.Zero)
{
objectPointer = IntPtr.Zero;
return CLASS_E_NOAGGREGATION;
}

if ((interfaceId != typeof(TaskType).GUID) && (interfaceId != new Guid(IID_IUnknown)))
{
objectPointer = IntPtr.Zero;
return E_NOINTERFACE;
}

objectPointer = MarshalInterface<TaskInterface>.FromManaged(new TaskType());
return S_OK;
}

public uint LockServer(bool lockServer)
{
return S_OK;
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?xml version="1.0" encoding="utf-8"?>
<Window
x:Class="BackgroundTaskBuilder.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:BackgroundTaskBuilder"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="BackgroundTaskBuilder">

<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<Button x:Name="myButton" Click="myButton_Click">Register BG Task</Button>
</StackPanel>
</Window>
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.Windows.ApplicationModel.Background;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.ApplicationModel.Background;
using Windows.Foundation;
using Windows.Foundation.Collections;
using WinRT;
using WinRT.Interop;

// To learn more about WinUI, the WinUI project structure,
// and more about our project templates, see: http://aka.ms/winui-project-info.

namespace BackgroundTaskBuilder
{
/// <summary>
/// An empty window that can be used on its own or navigated to within a Frame.
/// </summary>
public sealed partial class MainWindow : Window
{
static private uint _RegistrationToken;
public MainWindow()
{
this.InitializeComponent();
}
private void unregisterTasks()
{
var allRegistrations = BackgroundTaskRegistration.AllTasks;
foreach (var taskPair in allRegistrations)
{
IBackgroundTaskRegistration task = taskPair.Value;
task.Unregister(true);
}
}

private void myButton_Click(object sender, RoutedEventArgs e)
{
myButton.Content = "Registered Task for TimeZone Change";
myButton.IsEnabled = false;
unregisterTasks();
registerTimeZoneChangedTask();
}

private void registerTimeZoneChangedTask()
{
var taskBuilder = new Microsoft.Windows.ApplicationModel.Background.BackgroundTaskBuilder
{
Name = "TimeZoneChangedTask"
};
taskBuilder.SetTaskEntryPointClsid(typeof(BackgroundTask).GUID);
taskBuilder.SetTrigger(new SystemTrigger(SystemTriggerType.TimeZoneChange, false));
BackgroundTaskRegistration task = taskBuilder.Register();


Guid taskGuid = typeof(BackgroundTask).GUID;
ComServer.CoRegisterClassObject(ref taskGuid,
new ComServer.BackgroundTaskFactory<BackgroundTask, IBackgroundTask>(),
ComServer.CLSCTX_LOCAL_SERVER,
ComServer.REGCLS_MULTIPLEUSE,
out _RegistrationToken);
}
}
}
Loading

0 comments on commit e123eae

Please sign in to comment.