Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Sugestão
O método BackgroundTaskBuilder.SetTaskEntryPointClsid está disponível a partir do Windows 10, versão 2004.
Observação
Este cenário só é aplicável a aplicativos Win32 empacotados. Os aplicativos UWP encontrarão erros ao tentar implementar esse cenário.
APIs importantes
Crie uma classe de tarefa em segundo plano COM e registe-a para ser executada na sua aplicação Win32 empacotada com privilégios totais em resposta a gatilhos. Você pode usar tarefas em segundo plano para fornecer funcionalidade quando seu aplicativo estiver suspenso ou não estiver em execução. Este tópico demonstra como criar e registrar uma tarefa em segundo plano que pode ser executada em seu processo de aplicativo em primeiro plano ou em outro processo.
Criar a classe Tarefa em Segundo Plano
Você pode executar código em segundo plano escrevendo classes que implementam o interface IBackgroundTask. Esse código é executado quando um evento específico é acionado usando, por exemplo, SystemTrigger ou TimeTrigger.
As etapas a seguir mostram como escrever uma nova classe que implementa a interface
- Consulte estas instruções para fazer referência às APIs do WinRT na sua solução de aplicativo Win32 embalada. Isso é necessário para usar o IBackgroundTask e APIs relacionadas.
- Nessa nova classe, implemente a interface IBackgroundTask. O método
IBackgroundTask.Run é um ponto de entrada necessário que será chamado quando o evento especificado for acionado; Este método é necessário em todas as tarefas em segundo plano.
Observação
A própria classe de tarefa em segundo plano — e todas as outras classes no projeto de tarefa em segundo plano — precisam ser públicas .
O código de exemplo a seguir mostra uma classe de tarefa básica em segundo plano que conta primos e a grava em um arquivo até que seja solicitado o cancelamento.
O exemplo C++/WinRT implementa a classe de tarefa em segundo plano como uma coclasse COM .
Exemplo de código de tarefa em segundo plano
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;
}
};
}
Adicione o código de suporte para instanciar a classe COM
Para que a tarefa em segundo plano seja ativada em um aplicativo Win32 de confiança total, a classe de tarefa em segundo plano deve ter código de suporte para que a COM entenda como iniciar o processo do aplicativo se ele não estiver em execução e, em seguida, entenda qual instância do processo é atualmente o servidor para lidar com novas ativações para essa tarefa em segundo plano.
- A COM precisa entender como iniciar o processo do aplicativo se ele ainda não estiver em execução. O processo do aplicativo que hospeda o código da tarefa em segundo plano precisa ser declarado no manifesto do pacote. O código de exemplo a seguir mostra como o SampleTask é hospedado dentro SampleBackgroundApp.exe. Quando a tarefa em segundo plano é iniciada quando nenhum processo está em execução, SampleBackgroundApp.exe será iniciada com argumentos de processo "-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>
- Uma vez que o seu processo seja iniciado com os argumentos certos, ele deve indicar ao COM que é o servidor COM atual para novas instâncias de SampleTask. O código de exemplo a seguir mostra como o processo de aplicativo deve se registrar com COM. Observe que estes exemplos indicam como o processo se identificaria como o servidor COM para SampleTask, permitindo a conclusão de pelo menos uma instância antes de sair. Isso é opcional, e lidar com uma tarefa em segundo plano pode iniciar suas principais funções de processo.
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();
Registrar a tarefa em segundo plano a ser executada
- Descubra se a tarefa em segundo plano já está registada iterando pela propriedade BackgroundTaskRegistration.AllTasks. Este passo é importante; se o seu aplicativo não verificar os registros de tarefas em segundo plano existentes, ele poderá facilmente registrar a tarefa várias vezes, causando problemas com o desempenho e maximizando o tempo de CPU disponível da tarefa antes que o trabalho possa ser concluído. Uma aplicação pode usar a mesma entrada para lidar com todas as tarefas em segundo plano e utilizar outras propriedades, como o Name ou TaskId atribuído a um BackgroundTaskRegistration para decidir qual trabalho deve ser realizado.
O exemplo a seguir itera na propriedade AllTasks e define uma variável flag como true se a tarefa já estiver registrada.
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.
- Se a tarefa em segundo plano ainda não estiver registrada, use BackgroundTaskBuilder para criar uma instância da tarefa em segundo plano. O ponto de entrada da tarefa deve ser o nome da sua classe de tarefa em segundo plano prefixada pelo namespace.
O gatilho da tarefa em segundo plano controla quando a tarefa em segundo plano será executada. Para obter uma lista de possíveis gatilhos, consulte o Windows.ApplicationModel.Background Namespace.
Observação
Apenas um subconjunto de gatilhos é suportado para tarefas em segundo plano do Win32 empacotadas.
Por exemplo, este código cria uma nova tarefa em segundo plano e programa-a para ser executada a cada 15 minutos num 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.
- Você pode adicionar uma condição para controlar quando sua tarefa será executada após o evento de gatilho ocorrer (opcional). Por exemplo, se você não quiser que a tarefa seja executada até que a Internet esteja disponível, use a condição InternetAvailable. Para obter uma lista de condições possíveis, consulte SystemConditionType.
O código de exemplo a seguir atribui uma condição que exige que o usuário esteja presente:
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.
- Registe a tarefa em segundo plano chamando o método Register no objeto BackgroundTaskBuilder. Armazene o resultado do BackgroundTaskRegistration para que possa ser usado na próxima etapa. Observe que a função de registro pode retornar erros na forma de exceções. Certifique-se de ligar para Register em uma tentativa.
O código a seguir registra a tarefa em segundo plano e armazena o resultado:
try
{
var task = builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
try
{
auto task = builder.Register();
}
catch (...)
{
// Indicate an error was encountered.
}
Reunindo tudo
Os exemplos de código a seguir mostram o código completo necessário para executar e registrar sua tarefa em segundo plano COM Win32:
Manifesto completo do pacote do aplicativo Win32
<?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>
Exemplo de código de tarefa em segundo plano completo
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;
}
Observações
Ao contrário dos aplicativos UWP que podem executar tarefas em segundo plano no modo de espera moderno, os aplicativos Win32 não podem executar código a partir das fases de menor energia do modo de espera moderno. Consulte Modern Standby para saber mais.
[! NOTA] Transfira o de exemplo de tarefa em segundo plano Win32 COM do
Consulte os tópicos relacionados a seguir para referência de API, orientação conceitual de tarefas em segundo plano e instruções mais detalhadas para escrever aplicativos que usam tarefas em segundo plano.
Tópicos relacionados
- Responda aos eventos do sistema com tarefas em segundo plano
- Registrar uma tarefa em segundo plano
- Definir condições para executar uma tarefa em segundo plano
- Use um gatilho de manutenção
- Lidar com uma tarefa em segundo plano cancelada
- Monitorar o progresso e a conclusão de tarefas em segundo plano
- Executar uma tarefa em segundo plano em um temporizador
- Crie e registe uma tarefa em segundo plano em execução.
- Converter uma tarefa em segundo plano fora do processo em uma tarefa em segundo plano em processo
Orientação de tarefas em segundo plano
- Diretrizes para tarefas em segundo plano
- Debugar uma tarefa em segundo plano
- Como desencadear eventos de suspensão, retomada e em segundo plano em aplicações UWP (durante a depuração)
Referência da API de tarefa em segundo plano