Comunicação entre processos (IPC)

Este tópico explica várias formas de efetuar a comunicação entre processos (IPC) entre aplicações de secretária do SDK de Aplicações Windows e outras aplicações Win32. Como as aplicações desktop do SDK de Aplicações Windows funcionam como processos Win32 de confiança total, têm acesso direto a todos os mecanismos IPC ao nível do sistema operativo. Alguns mecanismos têm requisitos adicionais quando as aplicações são incluídas com MSIX, como referido nas secções abaixo.

Serviços aplicacionais

Os serviços de aplicações permitem que as aplicações exponham serviços que aceitam e devolvem conjuntos de propriedades de tipos primitivos (ValueSet) em segundo plano. Objetos complexos podem ser passados se forem serializados.

Os serviços de aplicação podem correr fora de processo como tarefa em segundo plano, ou em processo dentro da aplicação em primeiro plano.

Note

Os serviços de aplicações requerem uma aplicação empacotada com identidade de pacote. Estão disponíveis para aplicações do SDK de Aplicações Windows que utilizam a embalagem MSIX.

Os serviços de aplicação são melhores para partilhar pequenas quantidades de dados onde não é necessária uma latência próxima do tempo real.

COM

COM é um sistema distribuído orientado a objetos para criar componentes de software binário que podem interagir e comunicar. Como programador, usas COM para criar componentes de software reutilizáveis e camadas de automação para uma aplicação. Os componentes COM podem estar em processo ou fora de processo, e podem comunicar através de um modelo cliente e servidor . Servidores COM fora de processo têm sido usados há muito tempo como meio de comunicação entre objetos.

Aplicações empacotadas com esta runFullTrust capacidade podem registar servidores COM fora de processo para IPC através do manifesto do pacote. Isto é conhecido como COM Empacotado.

As aplicações desktop do SDK de Aplicações Windows funcionam como processos de confiança total, pelo que também podem registar-se e usar servidores COM diretamente através do Windows Registry, tal como as aplicações Win32 tradicionais.

Filesystem

BroadFileSystemAccess

As aplicações empacotadas podem efetuar IPC através do sistema de ficheiros alargado ao declararem a capacidade restrita broadFileSystemAccess. Esta capacidade concede às APIs Windows.Storage e às APIs Win32 FromApp acesso ao sistema de ficheiros alargado.

Por predefinição, o IPC através do sistema de ficheiros para aplicações empacotadas está limitado aos outros mecanismos descritos nesta secção.

Pasta de Cache do Publicador

O PublisherCacheFolder permite que aplicações embaladas declarem pastas no seu manifesto que podem ser partilhadas com outros pacotes pelo mesmo editor.

A pasta de armazenamento partilhado tem os seguintes requisitos e restrições:

  • Os dados na pasta de armazenamento partilhada não são incluídos em cópias de segurança nem sincronizados entre dispositivos.
  • O utilizador pode limpar o conteúdo da pasta de armazenamento partilhada.
  • Não podes usar a pasta de armazenamento partilhado para partilhar dados entre aplicações de diferentes editoras.
  • Não podes usar a pasta de armazenamento partilhado para partilhar dados entre diferentes utilizadores.
  • A pasta de armazenamento partilhado não tem gestão de versões.

Se publicas várias aplicações e procuras um mecanismo simples para partilhar dados entre elas, então o PublisherCacheFolder é uma opção simples baseada em sistema de ficheiros.

Tubos

Os pipes permitem uma comunicação simples entre um servidor de pipeline e um ou mais clientes de pipes.

Pipes anónimos e pipes nomeados são suportados com as seguintes restrições:

  • Por predefinição, os canais com nome em aplicações empacotadas só são suportados entre processos no mesmo pacote, a menos que um processo seja de confiança plena.
  • Os pipes nomeados podem ser partilhados entre pacotes seguindo as diretrizes para partilhar objetos nomeados.
  • Os pipes com nome em aplicações empacotadas devem incluir LOCAL\ no nome do pipe (por exemplo, \\.\pipe\LOCAL\<pipename>). O LOCAL\ segmento estende o escopo do canal para a sessão de login do chamador e é necessário para aplicações empacotadas em MSIX. Ao usar APIs .NET como NamedPipeServerStream, passa apenas a LOCAL\<pipename> parte — o \\.\pipe\ prefixo é tratado internamente.

As aplicações desktop do SDK de Aplicações Windows funcionam como processos de confiança total, permitindo criar e usar pipes nomeados sem a restrição do mesmo pacote. No entanto, se estiver a comunicar com outra aplicação embalada que não tem confiança total, as restrições acima continuam a ser aplicáveis.

Exemplo de tubo nomeado (C#)

O exemplo seguinte demonstra um servidor e um cliente de pipe com nome completos, sob a forma de duas aplicações de consola. Como as aplicações de ambiente de trabalho do SDK de Aplicações Windows são processos de total confiança, o IPC com tubo nomeado funciona sem quaisquer capacidades especiais ou entradas de manifesto.

Para tentar este exemplo, cria dois projetos de aplicação de consola (direcionando net8.0-windows com ImplicitUsings ativado) e executa primeiro o servidor, depois o cliente num terminal separado.

Servidor de canal — cria um canal nomeado e devolve as mensagens ao cliente em eco:

using System.Text;

string PipeName = @"LOCAL\WinAppSdkIpcDemo";

Console.WriteLine("Named Pipe Server");
Console.WriteLine($"  Process ID: {Environment.ProcessId}");
Console.WriteLine($"  User:       {Environment.UserName}");
Console.WriteLine($"  Pipe:       \\\\.\\pipe\\{PipeName}");
Console.WriteLine();

using var server = new System.IO.Pipes.NamedPipeServerStream(
    PipeName,
    System.IO.Pipes.PipeDirection.InOut,
    maxNumberOfServerInstances: 1,
    System.IO.Pipes.PipeTransmissionMode.Message,
    System.IO.Pipes.PipeOptions.Asynchronous);

Console.WriteLine("Waiting for client...");
await server.WaitForConnectionAsync();
Console.WriteLine("Client connected!");

byte[] buffer = new byte[4096];

while (server.IsConnected)
{
    try
    {
        int bytesRead = await server.ReadAsync(buffer);
        if (bytesRead == 0) break;

        string received = Encoding.UTF8.GetString(buffer, 0, bytesRead);
        Console.WriteLine($"  Received: \"{received}\"");

        if (received.Equals("QUIT", StringComparison.OrdinalIgnoreCase))
            break;

        // Echo the message back with the server's process ID
        string reply = $"Echo from PID {Environment.ProcessId}: {received}";
        await server.WriteAsync(Encoding.UTF8.GetBytes(reply));
        await server.FlushAsync();
    }
    catch (IOException)
    {
        break;
    }
}

Console.WriteLine("Done.");

Cliente Pipe — liga-se ao servidor e envia a entrada do utilizador:

using System.Text;

string PipeName = @"LOCAL\WinAppSdkIpcDemo";

Console.WriteLine("Named Pipe Client");
Console.WriteLine($"  Process ID: {Environment.ProcessId}");
Console.WriteLine();

using var client = new System.IO.Pipes.NamedPipeClientStream(
    serverName: ".",
    pipeName: PipeName,
    System.IO.Pipes.PipeDirection.InOut,
    System.IO.Pipes.PipeOptions.Asynchronous);

Console.WriteLine("Connecting...");
await client.ConnectAsync(timeout: 5000);
client.ReadMode = System.IO.Pipes.PipeTransmissionMode.Message;
Console.WriteLine("Connected! Type messages (or QUIT to exit):");

byte[] buffer = new byte[4096];

while (true)
{
    Console.Write("> ");
    string? input = Console.ReadLine();
    if (string.IsNullOrEmpty(input)) continue;

    await client.WriteAsync(Encoding.UTF8.GetBytes(input));
    await client.FlushAsync();

    if (input.Equals("QUIT", StringComparison.OrdinalIgnoreCase))
        break;

    int bytesRead = await client.ReadAsync(buffer);
    string response = Encoding.UTF8.GetString(buffer, 0, bytesRead);
    Console.WriteLine($"  <- {response}");
}

Console.WriteLine("Done.");

Quando executa ambas as aplicações, o cliente envia mensagens que o servidor devolve, confirmando a comunicação entre processos entre dois processos de desktop de confiança total sem necessidade de configuração especial.

Registry

A utilização do registo para IPC é geralmente desaconselhada, mas é suportada para código existente. As aplicações empacotadas só podem aceder às chaves do registo para as quais têm permissão de acedecer.

As aplicações de ambiente de trabalho empacotadas (ver Construir um pacote MSIX a partir do seu código) aproveitam a virtualização do registo de modo que as escritas globais do registo fiquem contidas numa colmeia privada dentro do pacote MSIX. Isto permite a compatibilidade do código-fonte minimizando o impacto global no registo, podendo ser usado para IPC entre processos no mesmo pacote. Se for necessário usar o registo, este modelo é preferido em vez de manipular o registo global.

RPC

O RPC pode ser usado para ligar uma aplicação empacotada a um endpoint RPC Win32, desde que a aplicação empacotada tenha as capacidades corretas para corresponder às ACLs no endpoint RPC.

As capacidades personalizadas permitem que OEMs e IHVs definam capacidades arbitrárias, ACL os seus endpoints RPC com elas e depois concedam essas capacidades a aplicações cliente autorizadas. Para uma aplicação de amostra completa, veja o exemplo CustomCapability .

Os endpoints RPC também podem ser protegidos com ACL para aplicações empacotadas específicas, de modo a limitar o acesso ao endpoint apenas a essas aplicações, sem exigir a sobrecarga de administração de capacidades personalizadas. Pode usar a API DeriveAppContainerSidFromAppContainerName para derivar um SID a partir de um nome de família de pacotes, e depois ACL o endpoint RPC com o SID, conforme mostrado no exemplo CustomCapability .

Memória partilhada

O mapeamento de ficheiros pode ser usado para partilhar um ficheiro ou memória entre dois ou mais processos com as seguintes restrições:

  • Por defeito, os mapeamentos de ficheiros em aplicações empacotadas só são suportados entre processos no mesmo pacote, a menos que um processo seja de confiança total.
  • Os mapeamentos de ficheiros podem ser partilhados entre pacotes seguindo as diretrizes para partilhar objetos nomeados.

As aplicações desktop do SDK de Aplicações Windows funcionam como processos de confiança total, permitindo criar e usar mapeamentos de ficheiros de memória partilhada sem restrições. Ao comunicar com outra aplicação empacotada que não tenha total confiança, use a abordagem ACL descrita na partilha de objetos nomeados.

A memória partilhada é recomendada para partilhar e manipular eficientemente grandes quantidades de dados.

Loopback

Loopback é o processo de comunicação com um servidor de rede que ouve no localhost (o endereço de loopback).

Para manter a segurança e o isolamento da rede, as ligações de loopback para IPC são bloqueadas por defeito para aplicações empacotadas. Pode ativar ligações de loopback entre aplicações empacotadas de confiança usando capacidades e propriedades de manifestos.

  • Todas as aplicações empacotadas que participam em ligações de retorno têm de declarar a capacidade privateNetworkClientServer nos manifestos do pacote.
  • Duas aplicações empacotadas podem comunicar entre si através de loopback ao declararem LoopbackAccessRules nos respetivos manifestos de pacote.
    • Cada aplicação deve listar a outra nas suas LoopbackAccessRules. O cliente declara uma Regra "out" para o servidor, e o servidor declara Regras "in" para os seus clientes suportados.

Note

O nome da família de pacotes necessário para identificar uma aplicação nestas Regras pode ser encontrado através do editor de manifestos do pacote no Visual Studio durante o período de desenvolvimento, através do Partner Center para aplicações publicadas na Microsoft Store, ou através do comando PowerShell Get-AppxPackage para aplicações já instaladas.

Aplicações e serviços não empacotados não têm identidade de pacote, por isso não podem ser declarados no LoopbackAccessRules. Pode configurar uma aplicação empacotada para estabelecer ligação através de loopback com aplicações e serviços não empacotados através de CheckNetIsolation.exe; no entanto, isto só é possível em cenários de instalação lateral ou depuração em que tem acesso local à máquina e privilégios de administrador.

  • Se uma aplicação empacotada estiver a ligar-se a uma aplicação ou serviço não empacotado, execute CheckNetIsolation.exe LoopbackExempt -a -n=<PACKAGEFAMILYNAME> para adicionar uma isenção de loopback para a aplicação empacotada.
  • Se uma aplicação ou serviço não empacotado estiver a ligar-se a uma aplicação empacotada, execute CheckNetIsolation.exe LoopbackExempt -is -n=<PACKAGEFAMILYNAME> para permitir que a aplicação empacotada receba ligações de loopback de entrada.
    • CheckNetIsolation.exe deve estar a correr continuamente enquanto a aplicação empacotada escuta ligações.

Note

O nome da família de pacotes necessário para a opção -n de CheckNetIsolation.exe pode ser encontrado através do editor de manifesto de pacote no Visual Studio durante o desenvolvimento, através do Partner Center para aplicações publicadas através da Microsoft Store, ou através do comando Get-AppxPackage do PowerShell para aplicações que já estão instaladas.

Escolher um mecanismo IPC

A tabela seguinte resume os mecanismos de IPC e os respetivos casos de utilização mais adequados:

Mecanismo Melhor para Requirements
Serviços aplicacionais Pequena troca de dados com contentores de propriedades Aplicação empacotada com identidade de pacote
COM Componentes reutilizáveis, camadas de automação Nenhum (Win32) ou manifesto de pacote (COM Empacotado)
Canalizações nomeadas Comunicação bidirecional baseada em fluxos Nenhuma para aplicações de confiança total
Memória partilhada Grandes dados, alto desempenho Nenhum para aplicações de confiança total
RPC Programas cliente/servidor distribuídos As ACLs devem permitir o acesso
Registry Compatibilidade com código legado Não recomendado para código novo
Loopback Protocolos baseados em rede (TCP/UDP) privateNetworkClientServer Capacidade para aplicações embaladas