Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Tips/Råd
Metoden BackgroundTaskBuilder.SetTaskEntryPointClsid är tillgänglig från och med Windows 10 version 2004.
Anmärkning
Det här scenariot gäller endast för paketerade Win32-appar. UWP-program får fel vid försök att implementera det här scenariot.
viktiga API:er
Skapa en COM-bakgrundsaktivitetsklass och registrera den för att köras i din fullt betrodda Win32-app som svar på händelser. Du kan använda bakgrundsaktiviteter för att tillhandahålla funktioner när appen är avstängd eller inte körs. Det här avsnittet visar hur du skapar och registrerar en bakgrundsaktivitet som kan köras i förgrundens appprocess eller någon annan process.
Skapa klassen Background Task
Du kan köra kod i bakgrunden genom att skriva klasser som implementerar IBackgroundTask--gränssnittet. Den här koden körs när en specifik händelse utlöses med hjälp av till exempel SystemTrigger eller TimeTrigger.
Följande steg visar hur du skriver en ny klass som implementerar IBackgroundTask--gränssnittet och lägger till den i huvudprocessen.
- Se de här anvisningarna för att referera till WinRT-API:er i din paketerade Win32-programlösning. Detta krävs för att använda IBackgroundTask och relaterade API:er.
- I den nya klassen implementerar du gränssnittet IBackgroundTask. Metoden IBackgroundTask.Run är en obligatorisk startpunkt som anropas när den angivna händelsen utlöses. den här metoden krävs i varje bakgrundsaktivitet.
Anmärkning
Själva bakgrundsaktivitetsklassen – och alla andra klasser i bakgrundsaktivitetsprojektet – måste vara offentlig.
Följande exempelkod visar en grundläggande bakgrundsaktivitetsklass som räknar primtal och skriver den till en fil tills den begärs att avbrytas.
C++/WinRT-exemplet implementerar bakgrundsaktivitetsklassen som en COM-.
exempel på bakgrundsuppgiftskod
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
namespace PackagedWinMainBackgroundTaskSample
{
// {14C5882B-35D3-41BE-86B2-5106269B97E6} is GUID to register this task with BackgroundTaskBuilder. Generate a random GUID before implementing.
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("14C5882B-35D3-41BE-86B2-5106269B97E6")]
[ComSourceInterfaces(typeof(IBackgroundTask))]
public class SampleTask : IBackgroundTask
{
private volatile int cleanupTask; // flag used to indicate to Run method that it should exit
private Queue<int> numbersQueue; // the data structure holding the set of primes in memory
private const int maxPrimeNumber = 1000000000; // the number up to which task will attempt to calculate primes
private const int queueDepthToWrite = 10; // how frequently this task should flush its queue of primes
private const string numbersQueueFile = "numbersQueue.log"; // the file to write to relative to AppData
public SampleTask()
{
cleanupTask = 0;
numbersQueue = new Queue<int>(queueDepthToWrite);
}
/// <summary>
/// This method writes all the numbers in the current queue to the specified file.
/// </summary>
private void FlushNumbersToFile(Queue<int> queueToWrite)
{
string logPath = Path.Combine(ApplicationData.Current.LocalFolder.Path,
System.Diagnostics.Process.GetCurrentProcess().ProcessName);
if (!Directory.Exists(logPath))
{
Directory.CreateDirectory(logPath);
}
logPath = Path.Combine(logPath, numbersQueueFile);
const string delimiter = ", ";
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
// convert the queue to a list of comma separated values.
string stringToWrite = String.Join(delimiter, queueToWrite);
// Add the comma at the end.
stringToWrite += delimiter;
File.AppendAllText(logPath, stringToWrite);
}
/// <summary>
/// This method determines if the specified number is a prime number.
/// </summary>
private bool IsPrimeNumber(int dividend)
{
bool isPrime = true;
for (int divisor = dividend - 1; divisor > 1; divisor -= 1)
{
if ((dividend % divisor) == 0)
{
isPrime = false;
break;
}
}
return isPrime;
}
/// <summary>
/// Given the current number, this method calculates the next prime number (excluding the specified number).
/// </summary>
private int GetNextPrime(int previousNumber)
{
int currentNumber = previousNumber + 1;
while (!IsPrimeNumber(currentNumber))
{
currentNumber += 1;
}
return currentNumber;
}
/// <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)
{
// Start with the first applicable number.
int currentNumber = 1;
taskDeferral = taskInstance.GetDeferral();
// Wire the cancellation handler.
taskInstance.Canceled += this.OnCanceled;
// Set the progress to indicate this task has started
taskInstance.Progress = 10;
// Calculate primes until a cancellation has been requested or until
// the maximum number is reached.
while ((cleanupTask == 0) && (currentNumber < maxPrimeNumber)) {
// Compute the next prime number and add it to our queue.
currentNumber = GetNextPrime(currentNumber);
numbersQueue.Enqueue(currentNumber);
// Once the queue is filled to its max size, flush the numbers to the file.
if (numbersQueue.Count >= queueDepthToWrite)
{
FlushNumbersToFile(numbersQueue);
numbersQueue.Clear();
}
}
// Flush any remaining numbers to the file as part of cleanup.
FlushNumbersToFile(numbersQueue);
if (taskDeferral != null)
{
taskDeferral.Complete();
}
}
/// <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;
}
}
}
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.ApplicationModel.Background.h>
using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::ApplicationModel::Background;
namespace PackagedWinMainBackgroundTaskSample {
// Note insert unique UUID.
struct __declspec(uuid("14C5882B-35D3-41BE-86B2-5106269B97E6"))
SampleTask : implements<SampleTask, IBackgroundTask>
{
const unsigned int MaximumPotentialPrime = 1000000000;
volatile bool isCanceled = false;
BackgroundTaskDeferral taskDeferral = nullptr;
void __stdcall Run (_In_ IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled({ this, &SampleTask::OnCanceled });
taskDeferral = taskInstance.GetDeferral();
unsigned int currentPrimeNumber = 1;
while (!isCanceled && (currentPrimeNumber < MaximumPotentialPrime))
{
currentPrimeNumber = GetNextPrime(currentPrimeNumber);
}
taskDeferral.Complete();
}
void __stdcall OnCanceled (_In_ IBackgroundTaskInstance, _In_ BackgroundTaskCancellationReason)
{
isCanceled = true;
}
};
struct TaskFactory : implements<TaskFactory, IClassFactory>
{
HRESULT __stdcall CreateInstance (_In_opt_ IUnknown* aggregateInterface, _In_ REFIID interfaceId, _Outptr_ VOID** object) noexcept final
{
if (aggregateInterface != NULL) {
return CLASS_E_NOAGGREGATION;
}
return make<SampleTask>().as(interfaceId, object);
}
HRESULT __stdcall LockServer (BOOL) noexcept final
{
return S_OK;
}
};
}
Lägg till supportkoden för att instansiera COM-klassen
För att bakgrundsaktiviteten ska kunna aktiveras i ett win32-program med fullständigt förtroende måste bakgrundsaktivitetsklassen ha stöd för kod så att COM förstår hur appprocessen startas om den inte körs och sedan förstå vilken instans av processen som för närvarande är servern för hantering av nya aktiveringar för den bakgrundsaktiviteten.
- COM måste förstå hur du startar appprocessen om den inte redan körs. Appprocessen som är värd för bakgrundsaktivitetskoden måste deklareras i paketmanifestet. Följande exempelkod visar hur SampleTask- finns i SampleBackgroundApp.exe. När bakgrundsaktiviteten startas när ingen process körs startas SampleBackgroundApp.exe med processargument "-StartSampleTaskServer".
<Extensions>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="SampleBackgroundApp\SampleBackgroundApp.exe" DisplayName="SampleBackgroundApp" Arguments="-StartSampleTaskServer">
<com:Class Id="14C5882B-35D3-41BE-86B2-5106269B97E6" DisplayName="Sample Task" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
- När processen har startats med rätt argument bör den tala om för COM att det är den aktuella COM-servern för nya instanser av SampleTask. Följande exempelkod visar hur programprocessen ska registrera sig med COM. Observera att dessa exempel anger hur processen deklarerar sig själv som COM-servern för SampleTask för minst en instans som ska slutföras innan den avslutas. Detta är valfritt och hantering av en bakgrundsaktivitet kan starta huvudprocessfunktionerna.
class SampleTaskServer
{
SampleTaskServer()
{
comRegistrationToken = 0;
waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
}
~SampleTaskServer()
{
Stop();
}
public void Start()
{
RegistrationServices registrationServices = new RegistrationServices();
comRegistrationToken = registrationServices.RegisterTypeForComClients(typeof(SampleTask), RegistrationClassContext.LocalServer, RegistrationConnectionType.MultipleUse);
// Either have the background task signal this handle when it completes, or never signal this handle to keep this
// process as the COM server until the process is closed.
waitHandle.WaitOne();
}
public void Stop()
{
if (comRegistrationToken != 0)
{
RegistrationServices registrationServices = new RegistrationServices();
registrationServices.UnregisterTypeForComClients(registrationCookie);
}
waitHandle.Set();
}
private int comRegistrationToken;
private EventWaitHandle waitHandle;
}
var sampleTaskServer = new SampleTaskServer();
sampleTaskServer.Start();
class SampleTaskServer
{
public:
SampleTaskServer()
{
waitHandle = EventWaitHandle(false, EventResetMode::AutoResetEvent);
comRegistrationToken = 0;
}
~SampleTaskServer()
{
Stop();
}
void Start()
{
try
{
com_ptr<IClassFactory> taskFactory = make<TaskFactory>();
winrt::check_hresult(CoRegisterClassObject(__uuidof(SampleTask),
taskFactory.get(),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
&comRegistrationToken));
// Either have the background task signal this handle when it completes, or never signal this handle to
// keep this process as the COM server until the process is closed.
waitHandle.WaitOne();
}
catch (...)
{
// Indicate an error has been encountered.
}
}
void Stop()
{
if (comRegistrationToken != 0)
{
CoRevokeClassObject(comRegistrationToken);
}
waitHandle.Set();
}
private:
DWORD comRegistrationToken;
EventWaitHandle waitHandle;
};
SampleTaskServer sampleTaskServer;
sampleTaskServer.Start();
Registrera bakgrundsaktiviteten som ska köras
- Ta reda på om bakgrundsaktiviteten redan har registrerats genom iterering via egenskapen BackgroundTaskRegistration.AllTasks. Det här steget är viktigt; Om din app inte söker efter befintliga registreringar av bakgrundsaktiviteter kan den enkelt registrera aktiviteten flera gånger, vilket orsakar problem med prestanda och maximalt ut aktivitetens tillgängliga CPU-tid innan arbetet kan slutföras. Ett program kan använda samma startpunkt för att hantera alla bakgrundsaktiviteter och använda andra egenskaper som Name eller TaskId som tilldelats en BackgroundTaskRegistration för att bestämma vilket arbete som ska göras.
I följande exempel itereras egenskapen AllTasks och en flaggvariabel anges till true om aktiviteten redan är registrerad.
var taskRegistered = false;
var sampleTaskName = "SampleTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == sampleTaskName)
{
taskRegistered = true;
break;
}
}
// The code in the next step goes here.
bool taskRegistered = false;
std::wstring sampleTaskName = L"SampleTask";
auto allTasks = BackgroundTaskRegistration::AllTasks();
for (auto const& task : allTasks)
{
if (task.Value().Name() == sampleTaskName)
{
taskRegistered = true;
break;
}
}
// The code in the next step goes here.
- Om bakgrundsaktiviteten inte redan är registrerad använder du BackgroundTaskBuilder för att skapa en instans av bakgrundsaktiviteten. Startpunkten för uppgiften ska vara namnet på din bakgrundsuppgiftsklass med namnområdet som prefix.
Utlösaren för bakgrundsaktiviteten styr när bakgrundsaktiviteten ska köras. En lista över möjliga utlösare finns i Windows.ApplicationModel.Background Namespace.
Anmärkning
Endast en delmängd av utlösare stöds för paketerade Win32-bakgrundsaktiviteter.
Den här koden skapar till exempel en ny bakgrundsaktivitet och anger att den ska köras på en 15 minuter lång återkommande TimeTrigger-:
if (!taskRegistered)
{
var builder = new BackgroundTaskBuilder();
builder.Name = sampleTaskName;
builder.SetTaskEntryPointClsid(typeof(SampleTask).GUID);
builder.SetTrigger(new TimeTrigger(15, false));
}
// The code in the next step goes here.
if (!taskRegistered)
{
BackgroundTaskBuilder builder;
builder.Name(sampleTaskName);
builder.SetTaskEntryPointClsid(__uuidof(SampleTask));
builder.SetTrigger(TimeTrigger(15, false));
}
// The code in the next step goes here.
- Du kan lägga till ett villkor för att styra när aktiviteten ska köras när utlösarhändelsen inträffar (valfritt). Om du till exempel inte vill att aktiviteten ska köras förrän Internet är tillgängligt använder du villkoret InternetAvailable. En lista över möjliga villkor finns i SystemConditionType.
Följande exempelkod tilldelar ett villkor som kräver att användaren finns:
builder.AddCondition(new SystemCondition(SystemConditionType.InternetAvailable));
// The code in the next step goes here.
builder.AddCondition(SystemCondition{ SystemConditionType::InternetAvailable });
// The code in the next step goes here.
- Registrera bakgrundsaktiviteten genom att anropa metoden Register på BackgroundTaskBuilder-objektet. Lagra BackgroundTaskRegistration resultat så att det kan användas i nästa steg. Observera att registerfunktionen kan returnera fel i form av undantag. Var noga med att anropa Register i en try-catch.
Följande kod registrerar bakgrundsaktiviteten och lagrar resultatet:
try
{
var task = builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
try
{
auto task = builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
Förenar allt
Följande kodexempel visar den fullständiga kod som krävs för att köra och registrera din COM Win32-bakgrundsaktivitet:
Fullständigt Win32-apppaketmanifest
<?xml version="1.0" encoding="utf-8"?>
<Package
xmlns="http://schemas.microsoft.com/appx/manifest/foundation/windows10"
xmlns:uap="http://schemas.microsoft.com/appx/manifest/uap/windows10"
xmlns:rescap="http://schemas.microsoft.com/appx/manifest/foundation/windows10/restrictedcapabilities"
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
IgnorableNamespaces="uap rescap com">
<Identity
Name="SamplePackagedWinMainBackgroundApp"
Publisher="CN=Contoso"
Version="1.0.0.0" />
<Properties>
<DisplayName>SamplePackagedWinMainBackgroundApp</DisplayName>
<PublisherDisplayName>Contoso</PublisherDisplayName>
<Logo>Images\StoreLogo.png</Logo>
</Properties>
<Dependencies>
<TargetDeviceFamily Name="Windows.Desktop" MinVersion="10.0.19041.0" MaxVersionTested="10.0.19041.0" />
</Dependencies>
<Resources>
<Resource Language="x-generate"/>
</Resources>
<Applications>
<Application Id="App"
Executable="SampleBackgroundApp\$targetnametoken$.exe"
EntryPoint="$targetentrypoint$">
<uap:VisualElements
DisplayName="SampleBackgroundApp"
Description="SampleBackgroundApp"
BackgroundColor="transparent"
Square150x150Logo="Images\Square150x150Logo.png"
Square44x44Logo="Images\Square44x44Logo.png">
<uap:DefaultTile Wide310x150Logo="Images\Wide310x150Logo.png" />
<uap:SplashScreen Image="Images\SplashScreen.png" />
</uap:VisualElements>
<Extensions>
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="SampleBackgroundApp\SampleBackgroundApp.exe" DisplayName="SampleBackgroundApp" Arguments="-StartSampleTaskServer">
<com:Class Id="14C5882B-35D3-41BE-86B2-5106269B97E6" DisplayName="Sample Task" />
</com:ExeServer>
</com:ComServer>
</com:Extension>
</Extensions>
</Application>
</Applications>
<Capabilities>
<rescap:Capability Name="runFullTrust" />
</Capabilities>
</Package>
Komplett exempel på bakgrundsuppgiftskod
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
namespace PackagedWinMainBackgroundTaskSample
{
// Background task implementation.
// {14C5882B-35D3-41BE-86B2-5106269B97E6} is GUID to register this task with BackgroundTaskBuilder. Generate a random GUID before implementing.
[ComVisible(true)]
[ClassInterface(ClassInterfaceType.None)]
[Guid("14C5882B-35D3-41BE-86B2-5106269B97E6")]
[ComSourceInterfaces(typeof(IBackgroundTask))]
public class SampleTask : IBackgroundTask
{
private volatile int cleanupTask; // flag used to indicate to Run method that it should exit
private Queue<int> numbersQueue; // the data structure holding the set of primes in memory
private const int maxPrimeNumber = 1000000000; // the number up to which task will attempt to calculate primes
private const int queueDepthToWrite = 10; // how frequently this task should flush its queue of primes
private const string numbersQueueFile = "numbersQueue.log"; // the file to write to relative to AppData
public SampleTask()
{
cleanupTask = 0;
numbersQueue = new Queue<int>(queueDepthToWrite);
}
/// <summary>
/// This method writes all the numbers in the current queue to the specified file.
/// </summary>
private void FlushNumbersToFile(Queue<int> queueToWrite)
{
string logPath = Path.Combine(ApplicationData.Current.LocalFolder.Path,
System.Diagnostics.Process.GetCurrentProcess().ProcessName);
if (!Directory.Exists(logPath))
{
Directory.CreateDirectory(logPath);
}
logPath = Path.Combine(logPath, numbersQueueFile);
const string delimiter = ", ";
UnicodeEncoding unicodeEncoding = new UnicodeEncoding();
// convert the queue to a list of comma separated values.
string stringToWrite = String.Join(delimiter, queueToWrite);
// Add the comma at the end.
stringToWrite += delimiter;
File.AppendAllText(logPath, stringToWrite);
}
/// <summary>
/// This method determines if the specified number is a prime number.
/// </summary>
private bool IsPrimeNumber(int dividend)
{
bool isPrime = true;
for (int divisor = dividend - 1; divisor > 1; divisor -= 1)
{
if ((dividend % divisor) == 0)
{
isPrime = false;
break;
}
}
return isPrime;
}
/// <summary>
/// Given the current number, this method calculates the next prime number (excluding the specified number).
/// </summary>
private int GetNextPrime(int previousNumber)
{
int currentNumber = previousNumber + 1;
while (!IsPrimeNumber(currentNumber))
{
currentNumber += 1;
}
return currentNumber;
}
/// <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)
{
// Start with the first applicable number.
int currentNumber = 1;
taskDeferral = taskInstance.GetDeferral();
// Wire the cancellation handler.
taskInstance.Canceled += this.OnCanceled;
// Set the progress to indicate this task has started
taskInstance.Progress = 10;
// Calculate primes until a cancellation has been requested or until
// the maximum number is reached.
while ((cleanupTask == 0) && (currentNumber < maxPrimeNumber)) {
// Compute the next prime number and add it to our queue.
currentNumber = GetNextPrime(currentNumber);
numbersQueue.Enqueue(currentNumber);
// Once the queue is filled to its max size, flush the numbers to the file.
if (numbersQueue.Count >= queueDepthToWrite)
{
FlushNumbersToFile(numbersQueue);
numbersQueue.Clear();
}
}
// Flush any remaining numbers to the file as part of cleanup.
FlushNumbersToFile(numbersQueue);
if (taskDeferral != null)
{
taskDeferral.Complete();
}
}
/// <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;
}
}
// COM server startup code.
class SampleTaskServer
{
SampleTaskServer()
{
comRegistrationToken = 0;
waitHandle = new EventWaitHandle(false, EventResetMode.AutoReset);
}
~SampleTaskServer()
{
Stop();
}
public void Start()
{
RegistrationServices registrationServices = new RegistrationServices();
comRegistrationToken = registrationServices.RegisterTypeForComClients(typeof(SampleTask), RegistrationClassContext.LocalServer, RegistrationConnectionType.MultipleUse);
// Either have the background task signal this handle when it completes, or never signal this handle to keep this
// process as the COM server until the process is closed.
waitHandle.WaitOne();
}
public void Stop()
{
if (comRegistrationToken != 0)
{
RegistrationServices registrationServices = new RegistrationServices();
registrationServices.UnregisterTypeForComClients(registrationCookie);
}
waitHandle.Set();
}
private int comRegistrationToken;
private EventWaitHandle waitHandle;
}
// Background task registration code.
class SampleTaskRegistrar
{
public static void Register()
{
var taskRegistered = false;
var sampleTaskName = "SampleTask";
foreach (var task in BackgroundTaskRegistration.AllTasks)
{
if (task.Value.Name == sampleTaskName)
{
taskRegistered = true;
break;
}
}
if (!taskRegistered)
{
var builder = new BackgroundTaskBuilder();
builder.Name = sampleTaskName;
builder.SetTaskEntryPointClsid(typeof(SampleTask).GUID);
builder.SetTrigger(new TimeTrigger(15, false));
}
try
{
var task = builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
}
}
// Application entry point.
static class Program
{
[MTAThread]
static void Main()
{
string[] commandLineArgs = Environment.GetCommandLineArgs();
if (commandLineArgs.Length < 2)
{
// Open the WPF UI when no arguments are specified.
}
else
{
if (commandLineArgs.Contains("-RegisterSampleTask", StringComparer.InvariantCultureIgnoreCase))
{
SampleTaskRegistrar.Register();
}
if (commandLineArgs.Contains("-StartSampleTaskServer", StringComparer.InvariantCultureIgnoreCase))
{
var sampleTaskServer = new SampleTaskServer();
sampleTaskServer.Start();
}
}
return;
}
}
}
#include <unknwn.h>
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.ApplicationModel.Background.h>
using namespace winrt;
using namespace winrt::Windows::Foundation;
using namespace winrt::Windows::Foundation::Collections;
using namespace winrt::Windows::ApplicationModel::Background;
namespace PackagedWinMainBackgroundTaskSample
{
// Background task implementation.
// {14C5882B-35D3-41BE-86B2-5106269B97E6} is GUID to register this task with BackgroundTaskBuilder. Generate a random GUID before implementing.
struct __declspec(uuid("14C5882B-35D3-41BE-86B2-5106269B97E6"))
SampleTask : implements<SampleTask, IBackgroundTask>
{
const unsigned int maxPrimeNumber = 1000000000;
volatile bool isCanceled = false;
BackgroundTaskDeferral taskDeferral = nullptr;
void __stdcall Run (_In_ IBackgroundTaskInstance taskInstance)
{
taskInstance.Canceled({ this, &SampleTask::OnCanceled });
taskDeferral = taskInstance.GetDeferral();
unsigned int currentPrimeNumber = 1;
while (!isCanceled && (currentPrimeNumber < maxPrimeNumber))
{
currentPrimeNumber = GetNextPrime(currentPrimeNumber);
}
taskDeferral.Complete();
}
void __stdcall OnCanceled (_In_ IBackgroundTaskInstance, _In_ BackgroundTaskCancellationReason)
{
isCanceled = true;
}
};
struct TaskFactory : implements<TaskFactory, IClassFactory>
{
HRESULT __stdcall CreateInstance (_In_opt_ IUnknown* aggregateInterface, _In_ REFIID interfaceId, _Outptr_ VOID** object) noexcept final
{
if (aggregateInterface != nullptr) {
return CLASS_E_NOAGGREGATION;
}
return make<SampleTask>().as(interfaceId, object);
}
HRESULT __stdcall LockServer (BOOL) noexcept final
{
return S_OK;
}
};
// COM server startup code.
class SampleTaskServer
{
public:
SampleTaskServer()
{
waitHandle = EventWaitHandle(false, EventResetMode::AutoResetEvent);
comRegistrationToken = 0;
}
~SampleTaskServer()
{
Stop();
}
void Start()
{
try
{
com_ptr<IClassFactory> taskFactory = make<TaskFactory>();
winrt::check_hresult(CoRegisterClassObject(__uuidof(SampleTask),
taskFactory.get(),
CLSCTX_LOCAL_SERVER,
REGCLS_MULTIPLEUSE,
&comRegistrationToken));
// Either have the background task signal this handle when it completes, or never signal this handle to
// keep this process as the COM server until the process is closed.
waitHandle.WaitOne();
}
catch (...)
{
// Indicate an error has been encountered.
}
}
void Stop()
{
if (comRegistrationToken != 0)
{
CoRevokeClassObject(comRegistrationToken);
}
waitHandle.Set();
}
private:
DWORD comRegistrationToken;
EventWaitHandle waitHandle;
};
// Background task registration code.
class SampleTaskRegistrar
{
public static void Register()
{
bool taskRegistered = false;
std::wstring sampleTaskName = L"SampleTask";
auto allTasks = BackgroundTaskRegistration::AllTasks();
for (auto const& task : allTasks)
{
if (task.Value().Name() == sampleTaskName)
{
taskRegistered = true;
break;
}
}
if (!taskRegistered)
{
BackgroundTaskBuilder builder;
builder.Name(sampleTaskName);
builder.SetTaskEntryPointClsid(__uuidof(SampleTask));
builder.SetTrigger(TimeTrigger(15, false));
}
try
{
auto task = builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
}
}
}
using namespace PackagedWinMainBackgroundTaskSample;
// Application entry point.
int wmain(_In_ int argc, _In_reads_(argc) const wchar** argv)
{
unsigned int argumentIndex;
winrt::init_apartment();
if (argc <= 1)
{
return E_INVALIDARG;
}
for (argumentIndex = 0; argumentIndex < argc ; argumentIndex += 1)
{
if (_wcsnicmp(L"RegisterSampleTask",
argv[argumentIndex],
wcslen(L"RegisterSampleTask")) == 0)
{
SampleTaskRegistrar::Register();
}
if (_wcsnicmp(L"StartSampleTaskServer",
argv[argumentIndex],
wcslen(L"StartSampleTaskServer")) == 0)
{
SampleTaskServer sampleTaskServer;
sampleTaskServer.Start();
}
}
return S_OK;
}
Anmärkningar
Till skillnad från UWP-appar som kan köra bakgrundsaktiviteter i modernt vänteläge kan Win32-appar inte köra kod från de lägre energifaserna i modernt vänteläge. Se Modern Standby för mer information.
[! OBS! Ladda ned Win32 COM-bakgrundsaktivitetsexempel för att se liknande kodexempel i kontexten för en komplett Desktop Bridge-app som använder bakgrundsaktiviteter.
Se följande relaterade ämnen för API-referens, konceptuell vägledning för bakgrundsaktiviteter och mer detaljerade instruktioner för att skriva appar som använder bakgrundsuppgifter.
Relaterade ämnen
- Svara på systemhändelser med bakgrundsaktiviteter
- Registrera en bakgrundsaktivitet
- Ange villkor för att köra en bakgrundsaktivitet
- Använd en underhållsutlösare
- Hantera en avbruten bakgrundsaktivitet
- Övervaka förlopp och slutförande av bakgrundsaktiviteter
- Kör en bakgrundsaktivitet på en timer-
- Skapa och registrera en pågående bakgrundsaktivitet.
- Konvertera en bakgrundsaktivitet utanför processen till en bakgrundsaktivitet inom processen
Vägledning för bakgrundsuppgifter
- Riktlinjer för bakgrundsaktiviteter
- Felsöka en bakgrundsaktivitet
- Så här utlöser du paus-, återuppta- och bakgrundshändelser i UWP-appar (vid felsökning)
API-referens för bakgrundsprocesser