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.
As aplicações de área de trabalho empacotadas e não empacotadas podem enviar notificações interativas app assim como as aplicações da Plataforma Universal do Windows (UWP). Isso inclui aplicações empacotadas (consulte Criar um novo projeto para aplicações desktop empacotadas WinUI 3app), aplicações empacotadas com localização externa (consulte Atribuir identidade de pacote ao empacotar com localização externa) e aplicações não empacotadas (consulte Criar um novo projeto para aplicações desktop não empacotadas WinUI 3app).
No entanto, para uma área de trabalho appnão empacotada, existem algumas etapas especiais. Isso se deve aos diferentes esquemas de ativação e à falta de identidade do pacote em tempo de execução.
Note
O termo "toast notificação" está a ser substituído por "app notificação". Ambos os termos se referem ao mesmo recurso do Windows, mas com o tempo eliminaremos gradualmente o uso de "toast notificação" na documentação.
Important
Se você estiver escrevendo uma UWP app, consulte a documentação da UWP. Para outros idiomas do ambiente de trabalho, consulte Desktop C#.
Etapa 1: Habilitar o SDK do Windows
Caso ainda não tenhas ativado o SDK do Windows para o app, deves fazê-lo primeiro. Existem alguns passos fundamentais.
- Adicione
runtimeobject.liba dependências adicionais. - Defina o SDK do Windows como alvo.
Clique com o botão direito do mouse em seu projeto e selecione Propriedades.
Na parte superior menu Configuração, selecione Todas as configurações para que a seguinte alteração seja aplicada à depuração e à versão.
Em Vinculador -> Entrada, adicione runtimeobject.lib ao DependênciasAdicionais.
Em seguida, em Geral, certifique-se de que a versão do SDK do Windows está definida como versão 10.0 ou posterior.
Passo 2: Copiar o código da biblioteca compat
Copie o arquivo DesktopNotificationManagerCompat.h e DesktopNotificationManagerCompat.cpp do GitHub para seu projeto. A biblioteca compat abstrai grande parte da complexidade associada às notificações no ambiente de trabalho. As instruções a seguir exigem a biblioteca compat.
Se estiver a usar cabeçalhos pré-compilados, certifique-se de colocar a #include "stdafx.h" como a primeira linha do ficheiro DesktopNotificationManagerCompat.cpp.
Etapa 3: Incluir os arquivos de cabeçalho e namespaces
Inclua o arquivo de cabeçalho da biblioteca compat e os arquivos de cabeçalho e namespaces relacionados ao uso das APIs de notificação do Windows.
#include "DesktopNotificationManagerCompat.h"
#include <NotificationActivationCallback.h>
#include <windows.ui.notifications.h>
using namespace ABI::Windows::Data::Xml::Dom;
using namespace ABI::Windows::UI::Notifications;
using namespace Microsoft::WRL;
Etapa 4: Implementar o ativador
Você deve implementar um manipulador para app ativação de notificação, para que quando o usuário clicar em sua notificação, você app possa fazer algo. Isso é necessário para que a sua notificação persista na Central de Ações (já que a notificação pode ser clicada dias depois, quando a sua app estiver fechada). Esta classe pode ser colocada em qualquer lugar do seu projeto.
Implemente a interface INotificationActivationCallback conforme mostrado abaixo, incluindo um UUID, e também chame CoCreatableClass para sinalizar a sua classe como COM criável. Para o seu UUID, crie um GUID exclusivo usando um dos muitos geradores de GUID online. Este GUID CLSID (identificador de classe) é a forma como o Centro de Ação sabe qual classe ativar no COM.
// The UUID CLSID must be unique to your app. Create a new GUID if copying this code.
class DECLSPEC_UUID("replaced-with-your-guid-C173E6ADF0C3") NotificationActivator WrlSealed WrlFinal
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, INotificationActivationCallback>
{
public:
virtual HRESULT STDMETHODCALLTYPE Activate(
_In_ LPCWSTR appUserModelId,
_In_ LPCWSTR invokedArgs,
_In_reads_(dataCount) const NOTIFICATION_USER_INPUT_DATA* data,
ULONG dataCount) override
{
// TODO: Handle activation
}
};
// Flag class as COM creatable
CoCreatableClass(NotificationActivator);
Passo 5: Registe-se na plataforma de notificação
Depois, deve registar-se na plataforma de notificação. Existem passos diferentes, dependendo de o seu app estar embalado ou desembalado. Se você suportar ambos, então você deve executar ambos os conjuntos de etapas (no entanto, não há necessidade de bifurcar seu código, pois nossa biblioteca lida com isso para você).
Packaged
Se o seu app estiver empacotado (consulte Criar um novo projeto para uma área de trabalho WinUI 3 empacotadaapp) ou empacotado com localização externa (consulte Conceder identidade do pacote empacotando com localização externa), ou se oferece suporte a ambos, no seu Package.appxmanifest adicione:
- Declaração para xmlns:com
- Declaração para xmlns:desktop
- No atributo
IgnorableNamespaces, com eárea de trabalho -
com:Extension para o ativador COM usando o GUID da etapa #4. Certifique-se de incluir o
Arguments="-ToastActivated"para que você saiba que seu lançamento foi a partir de uma app notificação - desktop:Extensão para windows.toastNotificationActivation para declarar o seu app ativador de notificações CLSID (o GUID da etapa #4).
Package.appxmanifest
<Package
...
xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
IgnorableNamespaces="... com desktop">
...
<Applications>
<Application>
...
<Extensions>
<!--Register COM CLSID LocalServer32 registry key-->
<com:Extension Category="windows.comServer">
<com:ComServer>
<com:ExeServer Executable="YourProject\YourProject.exe" Arguments="-ToastActivated" DisplayName="Toast activator">
<com:Class Id="replaced-with-your-guid-C173E6ADF0C3" DisplayName="Toast activator"/>
</com:ExeServer>
</com:ComServer>
</com:Extension>
<!--Specify which CLSID to activate when toast clicked-->
<desktop:Extension Category="windows.toastNotificationActivation">
<desktop:ToastNotificationActivation ToastActivatorCLSID="replaced-with-your-guid-C173E6ADF0C3" />
</desktop:Extension>
</Extensions>
</Application>
</Applications>
</Package>
Unpackaged
Se o seu app estiver desempacotado (consulte Criar um novo projeto para uma área de trabalho appWinUI 3 não empacotada) ou se você suportar ambos, então você tem que declarar seu Application User Model ID (AUMID) e toast ativador CLSID (o GUID da etapa #4) no atalho do seu appem Iniciar.
Escolha um AUMID exclusivo que irá identificar o seu app. Isso geralmente é na forma de [CompanyName]. [AppName]. Mas você quer garantir que ele seja único em todos os aplicativos (então sinta-se à vontade para adicionar alguns dígitos no final).
Passo 5.1: Instalador WiX
Se você estiver usando o WiX para o instalador, edite o arquivo Product.wxs para adicionar as duas propriedades de atalho ao atalho do menu Iniciar, conforme mostrado abaixo. Certifique-se de que o seu GUID da etapa #4 esteja colocado em {}, tal como se vê abaixo.
Product.wxs
<Shortcut Id="ApplicationStartMenuShortcut" Name="Wix Sample" Description="Wix Sample" Target="[INSTALLFOLDER]WixSample.exe" WorkingDirectory="INSTALLFOLDER">
<!--AUMID-->
<ShortcutProperty Key="System.AppUserModel.ID" Value="YourCompany.YourApp"/>
<!--COM CLSID-->
<ShortcutProperty Key="System.AppUserModel.ToastActivatorCLSID" Value="{replaced-with-your-guid-C173E6ADF0C3}"/>
</Shortcut>
Important
Para poderes realmente usar notificações, deves instalar o teu app através do instalador uma vez antes de depurar normalmente, para que o atalho do Menu Iniciar com o teu AUMID e CLSID esteja presente. Depois que o atalho Iniciar estiver presente, você poderá depurar usando F5 do Visual Studio.
Passo 5.2: Registar o servidor AUMID e COM
Em seguida, independentemente do instalador que estiver usando, no código de inicialização do (app) antes de chamar qualquer API de notificação, chame o método RegisterAumidAndComServer, especificando a sua classe de ativador de notificação do passo n.º 4 e o seu AUMID utilizado anteriormente.
// Register AUMID and COM server (for a packaged app, this is a no-operation)
hr = DesktopNotificationManagerCompat::RegisterAumidAndComServer(L"YourCompany.YourApp", __uuidof(NotificationActivator));
Se o seu app oferece suporte a implantação empacotada e desempacotada, sinta-se à vontade para chamar este método independentemente disso. Se você estiver executando empacotado (ou seja, com identidade de pacote em tempo de execução), esse método simplesmente retornará imediatamente. Não há necessidade de fazer um fork do seu código.
Este método permite que você chame as APIs compat para enviar e gerenciar notificações sem ter que fornecer constantemente seu AUMID. E insere a chave de registo LocalServer32 para o servidor COM.
Passo 6: Registar o ativador COM
Para aplicativos empacotados e não empacotados, você deve registrar seu tipo de ativador de notificação para poder lidar com toast ativações.
No código de inicialização do seu app, chame o seguinte método RegisterActivator. Isto deve ser invocado para que o utilizador receba quaisquer ativações toast.
// Register activator type
hr = DesktopNotificationManagerCompat::RegisterActivator();
Etapa 7: enviar uma notificação
O envio de uma notificação é idêntico aos aplicativos UWP, exceto que você usará DesktopNotificationManagerCompat para criar um ToastNotifier. A biblioteca compat lida automaticamente com a diferença entre aplicativos empacotados e não empacotados, para que você não precise bifurcar seu código. Para um app não embalado, a biblioteca de compatibilidade armazena em cache o AUMID que foi fornecido quando chamou RegisterAumidAndComServer, para que não haja preocupação sobre quando fornecer ou não o AUMID.
Certifique-se de usar a associação ToastGeneric como visto abaixo, pois os modelos de notificação herdados do Windows 8.1 toast não ativarão o ativador de notificação COM que você criou na etapa #4.
Important
As imagens http são suportadas apenas em aplicações em pacote que têm acesso à internet no seu manifesto. As aplicações não empacotadas não suportam imagens http; você deve baixar a imagem para seus dados locais app e consultá-la localmente.
// Construct XML
ComPtr<IXmlDocument> doc;
hr = DesktopNotificationManagerCompat::CreateXmlDocumentFromString(
L"<toast><visual><binding template='ToastGeneric'><text>Hello world</text></binding></visual></toast>",
&doc);
if (SUCCEEDED(hr))
{
// See full code sample to learn how to inject dynamic text, buttons, and more
// Create the notifier
// Desktop apps must use the compat method to create the notifier.
ComPtr<IToastNotifier> notifier;
hr = DesktopNotificationManagerCompat::CreateToastNotifier(¬ifier);
if (SUCCEEDED(hr))
{
// Create the notification itself (using helper method from compat library)
ComPtr<IToastNotification> toast;
hr = DesktopNotificationManagerCompat::CreateToastNotification(doc.Get(), &toast);
if (SUCCEEDED(hr))
{
// And show it!
hr = notifier->Show(toast.Get());
}
}
}
Important
As aplicações do ambiente de trabalho não podem usar modelos legados toast (como ToastText02). A ativação dos modelos herdados falhará quando o CLSID COM for especificado. Você deve usar os modelos ToastGeneric do Windows, como visto acima.
Etapa 8: Gerir a ativação
Quando o usuário clica em sua app notificação ou botões na notificação, o método Activate da sua classe NotificationActivator é invocado.
Dentro do método Activate, pode analisar os argumentos especificados na notificação e obter as entradas que o utilizador digitou ou selecionou, ativando o seu app em conformidade.
Note
O método Activate é chamado em um thread separado do thread principal.
// The GUID must be unique to your app. Create a new GUID if copying this code.
class DECLSPEC_UUID("replaced-with-your-guid-C173E6ADF0C3") NotificationActivator WrlSealed WrlFinal
: public RuntimeClass<RuntimeClassFlags<ClassicCom>, INotificationActivationCallback>
{
public:
virtual HRESULT STDMETHODCALLTYPE Activate(
_In_ LPCWSTR appUserModelId,
_In_ LPCWSTR invokedArgs,
_In_reads_(dataCount) const NOTIFICATION_USER_INPUT_DATA* data,
ULONG dataCount) override
{
std::wstring arguments(invokedArgs);
HRESULT hr = S_OK;
// Background: Quick reply to the conversation
if (arguments.find(L"action=reply") == 0)
{
// Get the response user typed.
// We know this is first and only user input since our toasts only have one input
LPCWSTR response = data[0].Value;
hr = DesktopToastsApp::SendResponse(response);
}
else
{
// The remaining scenarios are foreground activations,
// so we first make sure we have a window open and in foreground
hr = DesktopToastsApp::GetInstance()->OpenWindowIfNeeded();
if (SUCCEEDED(hr))
{
// Open the image
if (arguments.find(L"action=viewImage") == 0)
{
hr = DesktopToastsApp::GetInstance()->OpenImage();
}
// Open the app itself
// User might have clicked on app title in Action Center which launches with empty args
else
{
// Nothing to do, already launched
}
}
}
if (FAILED(hr))
{
// Log failed HRESULT
}
return S_OK;
}
~NotificationActivator()
{
// If we don't have window open
if (!DesktopToastsApp::GetInstance()->HasWindow())
{
// Exit (this is for background activation scenarios)
exit(0);
}
}
};
// Flag class as COM creatable
CoCreatableClass(NotificationActivator);
Para suportar corretamente a inicialização enquanto o seu app está fechado, na sua função WinMain, você vai querer determinar se você está sendo iniciado a partir de uma app notificação ou não. Se iniciado a partir de uma notificação, haverá um arg de lançamento de "-ToastActivated". Quando vires isto, deves parar de executar qualquer código de ativação de inicialização normal e permitir que o NotificationActivator controle as janelas de lançamento, se necessário.
// Main function
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE, _In_ LPWSTR cmdLineArgs, _In_ int)
{
RoInitializeWrapper winRtInitializer(RO_INIT_MULTITHREADED);
HRESULT hr = winRtInitializer;
if (SUCCEEDED(hr))
{
// Register AUMID and COM server (for a packaged app, this is a no-operation)
hr = DesktopNotificationManagerCompat::RegisterAumidAndComServer(L"WindowsNotifications.DesktopToastsCpp", __uuidof(NotificationActivator));
if (SUCCEEDED(hr))
{
// Register activator type
hr = DesktopNotificationManagerCompat::RegisterActivator();
if (SUCCEEDED(hr))
{
DesktopToastsApp app;
app.SetHInstance(hInstance);
std::wstring cmdLineArgsStr(cmdLineArgs);
// If launched from toast
if (cmdLineArgsStr.find(TOAST_ACTIVATED_LAUNCH_ARG) != std::string::npos)
{
// Let our NotificationActivator handle activation
}
else
{
// Otherwise launch like normal
app.Initialize(hInstance);
}
app.RunMessageLoop();
}
}
}
return SUCCEEDED(hr);
}
Sequência de eventos de ativação
A sequência de ativação é a seguinte...
Se o seu app já estiver em execução:
- Ativar no seu NotificationActivator é chamado
Se o seu app não estiver a funcionar:
- O seu app é um EXE lançado, recebe os argumentos da linha de comandos de "-ToastActivated"
- Ativar no seu NotificationActivator é chamado
Ativação em primeiro plano vs em segundo plano
Para aplicações de ambiente de trabalho, a ativação em primeiro plano e em segundo plano é tratada de forma idêntica — o seu ativador COM é chamado. Cabe ao seu appcódigo decidir se deseja mostrar uma janela ou simplesmente executar algum trabalho e, em seguida, sair. Portanto, especificar um ativationType de plano de fundo no conteúdo app da notificação não altera o comportamento.
Etapa 9: remover e gerenciar notificações
Remover e gerenciar notificações é idêntico aos aplicativos UWP. No entanto, recomendamos que você use nossa biblioteca de compatibilidade para obter um DesktopNotificationHistoryCompat para que você não tenha que se preocupar em fornecer o AUMID para um ambiente de trabalho app.
std::unique_ptr<DesktopNotificationHistoryCompat> history;
auto hr = DesktopNotificationManagerCompat::get_History(&history);
if (SUCCEEDED(hr))
{
// Remove a specific toast
hr = history->Remove(L"Message2");
// Clear all toasts
hr = history->Clear();
}
Etapa 10: Implementação e depuração
Para implantar e depurar o seu pacote app, consulte Executar, depurar e testar uma aplicação desktop empacotada app.
Para implantar e depurar sua área de trabalho app, você deve instalá-lo app através do instalador uma vez antes de depurar normalmente, para que o atalho Iniciar com seu AUMID e CLSID esteja presente. Depois que o atalho Iniciar estiver presente, você poderá depurar usando F5 do Visual Studio.
Se as suas notificações simplesmente não aparecerem na sua área de trabalho app (e nenhuma exceção for lançada), isso provavelmente significa que o atalho Iniciar não está presente (instale o seu app através do instalador), ou o AUMID que você usou no código não corresponde ao AUMID no seu atalho Iniciar.
Se suas notificações aparecerem, mas não persistirem na Central de Ações (desaparecendo depois que o pop-up for descartado), isso significa que você não implementou o ativador COM corretamente.
Se instalaste tanto o pacote de área de trabalho app como o não empacotado, observa que o pacote app substituirá o não empacotado app ao processar ativações de toast. Isso significa que app as notificações do pacote não empacotado app iniciarão o pacote app quando clicadas. Desinstalar o pacote app reverterá as ativações para o pacote desembrulhado app.
Se receber HRESULT 0x800401f0 CoInitialize has not been called., certifique-se de chamar CoInitialize(nullptr) no seu app antes de chamar as APIs.
Se receber HRESULT 0x8000000e A method was called at an unexpected time. ao chamar as APIs Compat, isso provavelmente significa que não conseguiu invocar os métodos Register necessários (ou, se estiver a utilizar um pacote app, não está a executar o seu app no contexto de pacote).
Se receber vários erros de compilação unresolved external symbol, provavelmente esqueceu de adicionar runtimeobject.lib às Dependências Adicionais na etapa #1 (ou apenas o adicionou à configuração de Depuração e não à configuração de Lançamento).
Lidar com versões mais antigas do Windows
Se você oferecer suporte ao Windows 8.1 ou inferior, convém verificar em tempo de execução se está executando no Windows antes de chamar qualquer APIs de DesktopNotificationManagerCompat ou enviar qualquer notificação do sistema ToastGeneric.
O Windows 8 introduziu toast notificações, mas usou os modelos herdadostoast, como ToastText01. A ativação foi manipulada pelo evento em memória Activated na classe ToastNotification, uma vez que as notificações eram apenas pop-ups breves que não eram persistentes. O Windows 10 introduziu toasts interativos ToastGeneric e também introduziu a Central de Ações, onde as notificações são mantidas por vários dias. A introdução do Centro de Ação exigiu a introdução de um ativador COM, para que o seu toast possa ser ativado dias depois de o ter criado.
| OS | ToastGeneric | Ativador COM | Modelos herdados toast |
|---|---|---|---|
| Windows 10 e posterior | Supported | Supported | Suportado (mas não ativará o servidor COM) |
| Windows 8.1 / 8 | N/A | N/A | Supported |
| Windows 7 e inferior | N/A | N/A | N/A |
Para verificar se está a executar no Windows 10 ou posterior, inclua o cabeçalho <VersionHelpers.h> e verifique o método IsWindows10OrGreater. Se isso retornar true, continue chamando todos os métodos descritos nesta documentação.
#include <VersionHelpers.h>
if (IsWindows10OrGreater())
{
// Running on Windows 10 or later, continue with sending toasts!
}
Problemas conhecidos
CORRIGIDO: App não fica focado depois de clicar : toastNas compilações 15063 e anteriores, os direitos de primeiro plano não estavam sendo transferidos para seu aplicativo quando ativamos o servidor COM. Portanto, o teu app iria simplesmente piscar quando tentaste movê-lo para o primeiro plano. Não havia solução alternativa para esse problema. Corrigimos isso nas compilações 16299 ou posteriores.
Resources
Windows developer