Criar um aplicativo WinUI de instância única com C#
Este tutorial demonstra como criar um aplicativo WinUI 3 de instância única com C# e o SDK de Aplicativo do Windows. Os aplicativos de instância única permitem apenas uma instância do aplicativo em execução de cada vez. Os aplicativos WinUI são multiinstâncias por padrão. Eles permitem que você inicie várias instâncias do mesmo aplicativo simultaneamente. Isso é referido a várias instâncias. No entanto, convém implementar a instância única com base no caso de uso do seu aplicativo. A tentativa de iniciar uma segunda instância de um aplicativo de instância única resultará apenas na ativação da janela principal da primeira instância. Este tutorial demonstra como implementar uma única instanciação em um aplicativo WinUI.
Neste artigo, você aprenderá a:
- Desativar o código
Program
gerado pelo XAML - Definir método de
Main
personalizado para redirecionamento - Testar a instanciação única após a implantação da aplicação
Pré-requisitos
Este tutorial usa o Visual Studio e se baseia no modelo de aplicativo em branco WinUI. Se é novo no desenvolvimento com WinUI, pode preparar-se seguindo as instruções em Introdução ao WinUI. Lá, você instalará o Visual Studio, o configurará para desenvolver aplicativos com WinUI enquanto garante que você tenha a versão mais recente do WinUI e do SDK de Aplicativo do Windows e criará um projeto Hello World.
Quando você tiver feito isso, volte aqui para aprender como transformar seu projeto "Hello World" em um aplicativo de instância única.
Observação
Este tutorial é baseado na postagem de blog
Desativar o código do programa gerado automaticamente
Precisamos verificar se há redirecionamento o mais cedo possível, antes de criar qualquer janela. Para fazer isso, devemos definir o símbolo "DISABLE_XAML_GENERATED_MAIN" no arquivo de projeto. Siga estas etapas para desativar o código de programa gerado automaticamente:
Clique com o botão direito do mouse no nome do projeto no Gerenciador de Soluções e selecione Editar arquivo de projeto.
Defina o símbolo DISABLE_XAML_GENERATED_MAIN. Adicione o seguinte XML ao arquivo de projeto:
<PropertyGroup> <DefineConstants>$(DefineConstants);DISABLE_XAML_GENERATED_MAIN</DefineConstants> </PropertyGroup>
Adicionar o símbolo DISABLE_XAML_GENERATED_MAIN desativará o código de programa gerado automaticamente para o seu projeto.
Definir uma classe Program com um método Main
Um arquivo Program.cs personalizado deve ser criado em vez de executar o método Main padrão. O código adicionado à classe Program permite que o aplicativo verifique se há redirecionamento, que não é o comportamento padrão dos aplicativos WinUI.
Navegue até o Gerenciador de Soluções, clique com o botão direito do mouse no nome do projeto e selecione Adicionar | Classe.
Nomeie a nova classe
Program.cs
e selecione Adicionar.Adicione os seguintes namespaces à classe Program, substituindo quaisquer namespaces existentes:
using System; using System.Diagnostics; using System.Runtime.InteropServices; using System.Threading; using System.Threading.Tasks; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; using Microsoft.Windows.AppLifecycle;
Substitua a classe vazia Program pelo seguinte:
public class Program { [STAThread] static int Main(string[] args) { WinRT.ComWrappersSupport.InitializeComWrappers(); bool isRedirect = DecideRedirection(); if (!isRedirect) { Application.Start((p) => { var context = new DispatcherQueueSynchronizationContext( DispatcherQueue.GetForCurrentThread()); SynchronizationContext.SetSynchronizationContext(context); _ = new App(); }); } return 0; } }
O método Main determina se o aplicativo deve redirecionar para a primeira instância ou iniciar uma nova instância depois de chamar DecideRedirection, que definiremos a seguir.
Defina o método DecideRedirection abaixo do método Main:
private static bool DecideRedirection() { bool isRedirect = false; AppActivationArguments args = AppInstance.GetCurrent().GetActivatedEventArgs(); ExtendedActivationKind kind = args.Kind; AppInstance keyInstance = AppInstance.FindOrRegisterForKey("MySingleInstanceApp"); if (keyInstance.IsCurrent) { keyInstance.Activated += OnActivated; } else { isRedirect = true; RedirectActivationTo(args, keyInstance); } return isRedirect; }
DecideRedirection determina se o aplicativo foi registrado registrando uma chave exclusiva que representa a instância do aplicativo. Com base no resultado do registro de chave, ele pode determinar se há uma instância atual do aplicativo em execução. Depois de fazer a determinação, o método sabe se deve redirecionar ou permitir que o aplicativo continue iniciando a nova instância. O método RedirectActivationTo é chamado caso o redirecionamento seja necessário.
Em seguida, vamos criar o método RedirectActivationTo abaixo do método DecideRedirection, juntamente com as instruções DllImport necessárias. Adicione o seguinte código à classe Program:
[DllImport("kernel32.dll", CharSet = CharSet.Unicode)] private static extern IntPtr CreateEvent( IntPtr lpEventAttributes, bool bManualReset, bool bInitialState, string lpName); [DllImport("kernel32.dll")] private static extern bool SetEvent(IntPtr hEvent); [DllImport("ole32.dll")] private static extern uint CoWaitForMultipleObjects( uint dwFlags, uint dwMilliseconds, ulong nHandles, IntPtr[] pHandles, out uint dwIndex); [DllImport("user32.dll")] static extern bool SetForegroundWindow(IntPtr hWnd); private static IntPtr redirectEventHandle = IntPtr.Zero; // Do the redirection on another thread, and use a non-blocking // wait method to wait for the redirection to complete. public static void RedirectActivationTo(AppActivationArguments args, AppInstance keyInstance) { redirectEventHandle = CreateEvent(IntPtr.Zero, true, false, null); Task.Run(() => { keyInstance.RedirectActivationToAsync(args).AsTask().Wait(); SetEvent(redirectEventHandle); }); uint CWMO_DEFAULT = 0; uint INFINITE = 0xFFFFFFFF; _ = CoWaitForMultipleObjects( CWMO_DEFAULT, INFINITE, 1, [redirectEventHandle], out uint handleIndex); // Bring the window to the foreground Process process = Process.GetProcessById((int)keyInstance.ProcessId); SetForegroundWindow(process.MainWindowHandle); }
O método RedirectActivationTo é responsável por redirecionar a ativação para a primeira instância do aplicativo. Ele cria um identificador de evento, inicia um novo thread para redirecionar a ativação e aguarda a conclusão do redirecionamento. Após a conclusão do redirecionamento, o método traz a janela para o primeiro plano.
Finalmente, defina abaixo do método DecideRedirection o método auxiliar OnActivated:
private static void OnActivated(object sender, AppActivationArguments args) { ExtendedActivationKind kind = args.Kind; }
Teste a instanciação única via a implementação do aplicativo
Até agora, temos testado a aplicação fazendo depuração com o Visual Studio. No entanto, só podemos ter um depurador em execução ao mesmo tempo. Essa limitação nos impede de saber se o aplicativo é de instância única porque não podemos depurar o mesmo projeto duas vezes ao mesmo tempo. Para um teste preciso, implantaremos o aplicativo em nosso cliente Windows local. Após a implantação, podemos iniciar o aplicativo na área de trabalho como faria com qualquer aplicativo instalado no Windows.
Navegue até o Gerenciador de Soluções, clique com o botão direito do mouse no nome do projeto e selecione Implantar.
Abra o menu Iniciar e clique no campo de pesquisa.
Digite o nome do seu aplicativo no campo de pesquisa.
Clique no ícone do aplicativo no resultado da pesquisa para iniciar seu aplicativo.
Observação
Se você tiver falhas de aplicativo no modo de lançamento, há alguns problemas conhecidos com aplicativos cortados no SDK de Aplicativos Windows. Você pode desabilitar o corte no projeto definindo a propriedade
PublishTrimmed para falso para todas as configurações de compilação nos arquivos do projeto. Para obter mais informações, consulte esta questão no GitHub. Repita as etapas 2 a 4 para iniciar o mesmo aplicativo novamente e ver se outra instância é aberta. Se o aplicativo for de instância única, a primeira instância será ativada em vez da abertura de uma nova instância.
Resumo
Todo o código abordado aqui está no GitHub , com ramos para as diferentes etapas da série original de blogs do Windows . Consulte o ramo de instância única para obter o código específico deste guia. O ramo main
é o mais abrangente. As outras ramificações destinam-se a mostrar como a arquitetura do aplicativo evoluiu.
Conteúdo relacionado
Instanciação de aplicativos com a API de ciclo de vida do aplicativo
Windows developer