Partilhar via


Introdução à estrutura de suporte a pacotes

O Package Support Framework é um kit de código aberto que ajuda você a aplicar correções ao seu aplicativo de desktop existente (sem modificar o código) para que ele possa ser executado em um contêiner MSIX. O Package Support Framework ajuda seu aplicativo a seguir as práticas recomendadas do ambiente de tempo de execução moderno.

Este artigo fornece uma visão detalhada de cada componente do Package Support Framework e um guia passo a passo para usá-lo.

Entender o que está dentro de uma estrutura de suporte a pacotes

O Package Support Framework contém um executável, uma DLL do gerenciador de tempo de execução e um conjunto de correções de tempo de execução.

Estrutura de Suporte a Pacotes

Aqui está o processo:

  1. Crie um arquivo de configuração que especifique as correções que você deseja aplicar ao seu aplicativo.
  2. Modifique seu pacote para apontar para o arquivo executável do iniciador PSF (Package Support Framework).

Quando os usuários iniciam seu aplicativo, o iniciador do Package Support Framework é o primeiro executável executado. Ele lê o arquivo de configuração e injeta as correções de tempo de execução e a DLL do gerenciador de tempo de execução no processo do aplicativo. O gerenciador de tempo de execução aplica a correção quando é necessário que o aplicativo seja executado dentro de um contêiner MSIX.

Injeção de DLL do Pacote de Suporte Framework

Etapa 1: Identificar problemas de compatibilidade de aplicativos empacotados

Primeiro, crie um pacote para seu aplicativo. Em seguida, instale-o, execute-o e observe seu comportamento. Você pode receber mensagens de erro que podem ajudá-lo a identificar um problema de compatibilidade. Você também pode usar o Process Monitor para identificar problemas. Problemas comuns estão relacionados a suposições do aplicativo em relação ao diretório de trabalho e permissões de caminho do programa.

Usando o Process Monitor para identificar um problema

O Process Monitor é um utilitário poderoso para observar as operações de arquivo e registro de um aplicativo e seus resultados. Isso pode ajudá-lo a entender os problemas de compatibilidade de aplicativos. Depois de abrir o Process Monitor, adicione um filtro (Filter > Filter...) para incluir apenas eventos do executável do aplicativo.

Filtro de aplicativo ProcMon

Será apresentada uma lista de eventos. Para muitos desses eventos, a palavra SUCESSO aparecerá na coluna Resultado .

Eventos ProcMon

Opcionalmente, você pode filtrar eventos para mostrar apenas falhas.

ProcMon exclui sucesso

Se você suspeitar de uma falha de acesso ao sistema de arquivos, procure eventos com falha que estejam sob o caminho do arquivo System32/SysWOW64 ou do pacote. Os filtros também podem ajudar aqui. Comece na parte inferior desta lista e role para cima. As falhas que aparecem no final desta lista ocorreram mais recentemente. Preste mais atenção aos erros que contêm cadeias de caracteres como "acesso negado" e "caminho/nome não encontrado" e ignore coisas que não parecem suspeitas. O PSFSample tem duas questões. Você pode ver esses problemas na lista que aparece na imagem a seguir.

ProcMon Config.txt

No primeiro problema que aparece nesta imagem, o aplicativo está falhando ao ler do arquivo "Config.txt" que está localizado no caminho "C:\Windows\SysWOW64". É improvável que o aplicativo esteja tentando fazer referência a esse caminho diretamente. Muito provavelmente, ele está tentando ler a partir desse arquivo usando um caminho relativo e, por padrão, "System32/SysWOW64" é o diretório de trabalho do aplicativo. Isso sugere que o aplicativo está esperando que seu diretório de trabalho atual seja definido para algum lugar no pacote. Olhando para dentro do appx, podemos ver que o arquivo existe no mesmo diretório que o executável.

App Config.txt

O segundo problema aparece na imagem a seguir.

Arquivo de log ProcMon

Nesse problema, a aplicação está falhando ao gravar um arquivo .log no seu caminho de pacote. Isso sugere que uma correção de redirecionamento de arquivo pode ajudar.

Etapa 2: Encontrar uma correção de tempo de execução

O PSF contém correções de tempo de execução que você pode usar agora, como a correção de redirecionamento de arquivo.

Correção de redirecionamento de arquivo

Você pode usar o File Redirection Fixup para redirecionar tentativas de gravar ou ler dados em um diretório que não está acessível a partir de um aplicativo executado em um contêiner MSIX.

Por exemplo, se seu aplicativo gravar em um arquivo de log que esteja no mesmo diretório que o executável de aplicativos, você poderá usar a Correção de Redirecionamento de Arquivo para criar esse arquivo de log em outro local, como o repositório de dados do aplicativo local.

Correções de tempo de execução (runtime) da comunidade

Certifique-se de revisar as contribuições da comunidade para nossa página do GitHub . É possível que outros desenvolvedores tenham resolvido um problema semelhante ao seu e compartilhado uma correção de tempo de execução.

Etapa 3: Aplicar uma correção de tempo de execução

Você pode aplicar uma correção de tempo de execução existente com algumas ferramentas simples do SDK do Windows e seguindo estas etapas.

  • Criar uma pasta de estrutura de pacote
  • Obter os ficheiros do Package Support Framework
  • Adicione-os ao seu pacote
  • Modificar o manifesto do pacote
  • Criar um arquivo de configuração

Vamos passar por cada tarefa.

Criar a pasta de layout do pacote

Se você já tiver um arquivo .msix (ou .appx), poderá descompactar seu conteúdo em uma pasta de layout que servirá como área de preparo para seu pacote. Você pode fazer isso a partir de um prompt de comando usando a ferramenta MakeAppx, com base no seu caminho de instalação do SDK, é aqui que você encontrará a ferramenta makeappx.exe no seu PC com Windows 10: x86: C:\Program Files (x86)\Windows Kits\10\bin\x86\makeappx.exe x64: C:\Program Files (x86)\Windows Kits\10\bin\x64\makeappx.exe

makeappx unpack /p PSFSamplePackage_1.0.60.0_AnyCPU_Debug.msix /d PackageContents

Isto vai dar-te algo que se parece com o seguinte.

Layout do pacote

Se você não tiver um arquivo .msix (ou .appx) para começar, poderá criar a pasta do pacote e os arquivos do zero.

Obter os ficheiros do Package Support Framework

Você pode obter o pacote Nuget PSF usando a ferramenta de linha de comando Nuget autônoma ou por meio do Visual Studio.

Obter o pacote usando a ferramenta de linha de comando

Instale a ferramenta de linha de comando Nuget a partir deste local: https://www.nuget.org/downloads. Em seguida, na linha de comando do Nuget, execute este comando:

nuget install Microsoft.PackageSupportFramework

Como alternativa, você pode renomear a extensão do pacote para .zip e descompactá-la. Todos os arquivos que você precisa estarão na pasta /bin.

Obter o pacote usando o Visual Studio

No Visual Studio, clique com o botão direito do mouse no nó da solução ou do projeto e escolha um dos comandos Gerenciar Pacotes Nuget. Pesquise por Microsoft.PackageSupportFramework ou PSF para encontrar o pacote no Nuget.org. Em seguida, instale-o.

Adicione os arquivos do Package Support Framework ao seu pacote

Adicione as DLLs PSF de 32 bits e 64 bits necessárias e os arquivos executáveis ao diretório do pacote. Use a tabela a seguir como guia. Você também desejará incluir todas as correções de tempo de execução necessárias. Em nosso exemplo, precisamos da correção do tempo de execução do redirecionamento de arquivo.

O executável do aplicativo é x64 O executável do aplicativo é x86
PSFLauncher64.exe PSFLauncher32.exe
PSFRuntime64.dll PSFRuntime32.dll
PSFRunDll64.exe PSFRunDll32.exe

O conteúdo do seu pacote agora deve ter esta aparência.

Binários do pacote

Modificar o manifesto do pacote

Abra o manifesto do pacote num editor de texto e defina o atributo do elemento ExecutableApplication para o nome do ficheiro executável do PSF Launcher. Se você conhece a arquitetura do seu aplicativo de destino, selecione a versão apropriada, PSFLauncher32.exe ou PSFLauncher64.exe. Caso contrário, PSFLauncher32.exe funcionará em todos os casos. Eis um exemplo.

<Package ...>
  ...
  <Applications>
    <Application Id="PSFSample"
                 Executable="PSFLauncher32.exe"
                 EntryPoint="Windows.FullTrustApplication">
      ...
    </Application>
  </Applications>
</Package>

Criar um arquivo de configuração

Crie um nome config.jsonde arquivo e salve-o na pasta raiz do seu pacote. Modifique a ID do aplicativo declarada do arquivo config.json para apontar para o executável que você acabou de substituir. Usando o conhecimento que você adquiriu usando o Process Monitor, você também pode definir o diretório de trabalho, bem como usar a correção de redirecionamento de arquivo para redirecionar leituras/gravações para arquivos .log no diretório "PSFSampleApp" relativo ao pacote.

{
    "applications": [
        {
            "id": "PSFSample",
            "executable": "PSFSampleApp/PSFSample.exe",
            "workingDirectory": "PSFSampleApp/"
        }
    ],
    "processes": [
        {
            "executable": "PSFSample",
            "fixups": [
                {
                    "dll": "FileRedirectionFixup.dll",
                    "config": {
                        "redirectedPaths": {
                            "packageRelative": [
                                {
                                    "base": "PSFSampleApp/",
                                    "patterns": [
                                        ".*\\.log"
                                    ]
                                }
                            ]
                        }
                    }
                }
            ]
        }
    ]
}

Segue-se um guia para o esquema config.json:

Matriz chave Valor
Aplicações ID Use o valor do atributo Id do elemento Application no manifesto do pacote.
Aplicações executável O caminho relativo ao pacote para o executável que você deseja iniciar. Na maioria dos casos, você pode obter esse valor do arquivo de manifesto do pacote antes de modificá-lo. É o valor do Executable atributo do Application elemento.
Aplicações diretório de trabalho (Opcional) Um caminho relativo ao pacote para usar como o diretório de trabalho do aplicativo que é iniciado. Se você não definir esse valor, o sistema operacional usará o System32 diretório como o diretório de trabalho do aplicativo.
processos executável Na maioria dos casos, este será o nome do executable configurado acima, com o caminho e a extensão de arquivo removidos.
correções dll Caminho relativo ao pacote para carregar a correção, .msix/.appx.
correções Configurações (Opcional) Controla como a dll de correção se comporta. O formato exato desse valor varia de correção por correção, pois cada correção pode interpretar esse "blob" como quiser.

O applications, processese fixups as chaves são matrizes. Isso significa que você pode usar o arquivo config.json para especificar mais de um aplicativo, processo e corrigir DLL.

Empacotar e testar o aplicativo

Em seguida, crie um pacote.

makeappx pack /d PackageContents /p PSFSamplePackageFixup.msix

Em seguida, assine-o.

signtool sign /a /v /fd sha256 /f ExportedSigningCertificate.pfx PSFSamplePackageFixup.msix

Para obter mais informações, consulte como criar um certificado de assinatura de pacote e como assinar um pacote usando signtool

Usando o PowerShell, instale o pacote.

Observação

Lembre-se de desinstalar o pacote primeiro.

powershell Add-AppPackage .\PSFSamplePackageFixup.msix

Execute o aplicativo e observe o comportamento com a correção de tempo de execução aplicada. Repita as etapas de diagnóstico e embalagem conforme necessário.

Verifique se o Package Support Framework está em execução

Você pode verificar se sua correção de tempo de execução está em execução. Uma maneira de fazer isso é abrir o Gerenciador de Tarefas e clicar em Mais detalhes. Encontre o aplicativo ao qual a estrutura de suporte do pacote foi aplicada e expanda os detalhes do aplicativo para obter mais detalhes. Você deve ser capaz de ver que o Package Support Framework está em execução.

Usar a correção de traço

Uma técnica alternativa para diagnosticar problemas de compatibilidade de aplicativos empacotados é usar o Trace Fixup. Essa DLL está incluída no PSF e fornece uma exibição de diagnóstico detalhada do comportamento do aplicativo, semelhante ao Process Monitor. Ele é especialmente projetado para revelar problemas de compatibilidade de aplicativos. Para usar o Trace Fixup, adicione a DLL ao pacote, adicione o seguinte fragmento ao seu config.jsone, em seguida, empacote e instale seu aplicativo.

{
    "dll": "TraceFixup.dll",
    "config": {
        "traceLevels": {
            "filesystem": "allFailures"
        }
    }
}

Por padrão, a Correção de Rastreamento filtra falhas que podem ser consideradas "esperadas". Por exemplo, os aplicativos podem tentar excluir incondicionalmente um arquivo sem verificar se ele já existe, ignorando o resultado. Isso tem a consequência infeliz de que algumas falhas inesperadas podem ser filtradas, portanto, no exemplo acima, optamos por receber todas as falhas das funções do sistema de arquivos. Fazemos isso porque sabemos de antes que a tentativa de ler o arquivo Config.txt falha com a mensagem "arquivo não encontrado". Esta é uma falha que é frequentemente observada e geralmente não assumida como inesperada. Na prática, é provavelmente melhor começar filtrando apenas para falhas inesperadas e, em seguida, voltar para todas as falhas se houver um problema que ainda não pode ser identificado.

Por padrão, a saída do Trace Fixup é enviada para o depurador anexado. Para este exemplo, não vamos anexar um depurador e, em vez disso, usaremos o programa DebugView de SysInternals para exibir sua saída. Depois de executar o aplicativo, podemos ver as mesmas falhas de antes, o que nos apontaria para as mesmas correções de tempo de execução.

Arquivo TraceShim não encontrado

Acesso ao TraceShim negado

Depurar, estender ou criar uma solução em tempo de execução

Você pode usar o Visual Studio para depurar uma correção de tempo de execução, estender uma correção de tempo de execução ou criar uma do zero. Você precisará fazer essas coisas para ser bem-sucedido.

  • Adicionar um projeto de empacotamento
  • Adicionar projeto para a correção de tempo de execução
  • Adicionar um projeto que inicie o executável do Lançador PSF
  • Configurar o projeto de empacotamento

Quando terminar, a sua solução será algo assim.

Solução completa

Vamos examinar cada projeto neste exemplo.

Projeto Propósito
Pacote de Aplicação de Desktop Este projeto é baseado no projeto Windows Application Packaging e gera o pacote MSIX.
Correção de runtime Este é um projeto C++ Dynamic-Linked Library que contém uma ou mais funções de substituição que atuam como correção durante a execução.
PSFLauncher Este é um Projeto Vazio C++. Este projeto é um local para coletar os arquivos distribuíveis de tempo de execução do Package Support Framework. Ele gera um arquivo executável. Esse executável é a primeira coisa que é executada quando você inicia a solução.
WinFormsDesktopApplication Este projeto contém o código-fonte de um aplicativo de desktop.

Para examinar um exemplo completo que contém todos esses tipos de projetos, consulte PSFSample.

Vamos percorrer as etapas para criar e configurar cada um desses projetos em sua solução.

Criar uma solução de pacote

Se tu ainda não tiveres uma solução para a tua aplicação de desktop, cria uma nova Solução em Branco no Visual Studio.

Solução em branco

Você também pode querer adicionar quaisquer projetos de aplicativo que você tem.

Adicionar um projeto de empacotamento

Se você ainda não tiver um projeto de empacotamento de aplicativos do Windows, crie um e adicione-o à sua solução.

Modelo de projeto de pacote

Para obter mais informações sobre o projeto Windows Application Packaging, consulte Empacotar seu aplicativo usando o Visual Studio.

No Gerenciador de Soluções, clique com o botão direito do mouse no projeto de empacotamento, selecione Editar e adicione isso à parte inferior do arquivo de projeto:

<Target Name="PSFRemoveSourceProject" AfterTargets="ExpandProjectReferences" BeforeTargets="_ConvertItems">
<ItemGroup>
  <FilteredNonWapProjProjectOutput Include="@(_FilteredNonWapProjProjectOutput)">
  <SourceProject Condition="'%(_FilteredNonWapProjProjectOutput.SourceProject)'=='<your runtime fix project name goes here>'" />
  </FilteredNonWapProjProjectOutput>
  <_FilteredNonWapProjProjectOutput Remove="@(_FilteredNonWapProjProjectOutput)" />
  <_FilteredNonWapProjProjectOutput Include="@(FilteredNonWapProjProjectOutput)" />
</ItemGroup>
</Target>

Adicionar projeto para a correção de tempo de execução

Adicione um projeto C++Dynamic-Link Library (DLL) à solução.

Biblioteca de correção de execução

Clique com o botão direito do mouse no projeto e escolha Propriedades.

Nas páginas de propriedades, localize o campo Padrão da linguagem C++ e, na lista suspensa ao lado desse campo, selecione a opção ISO C++17 Standard (/std:c++17).

Opção ISO 17

Clique com o botão direito do mouse nesse projeto e, no menu de contexto, escolha a opção Gerenciar pacotes Nuget . Verifique se a opção Origem do pacote está definida como Todos ou nuget.org.

Clique no ícone de configurações ao lado desse campo.

Procure o pacote Nuget PSF* e instale-o para este projeto.

pacote nuget

Se você quiser depurar ou estender uma correção de tempo de execução existente, adicione os arquivos de correção de tempo de execução que você obteve usando as diretrizes descritas na seção Localizar uma correção de tempo de execução deste guia.

Se você pretende criar uma nova correção, não adicione nada a este projeto ainda. Vamos ajudá-lo a adicionar os arquivos certos a este projeto mais adiante neste guia. Por enquanto, continuaremos a configurar a sua solução.

Adicionar um projeto que inicie o executável do Lançador PSF

Adicione um projeto C++ Empty Project à solução.

Projeto vazio

Adicione o pacote Nuget PSF a este projeto usando as mesmas orientações descritas na seção anterior.

Abra as páginas de propriedades do projeto e, na página Configurações gerais , defina a propriedade Nome do Destino como PSFLauncher32 ou PSFLauncher64 dependendo da arquitetura do seu aplicativo.

Referência do lançador PSF

Adicione uma referência de projeto ao projeto de correção de tempo de execução em sua solução.

referência de correção de tempo de execução

Clique com o botão direito do mouse na referência e, na janela Propriedades , aplique esses valores.

Propriedade Valor
Copiar local Verdade
Copiar conjuntos de satélites locais Verdade
Saída de montagem de referência Verdade
Dependências da biblioteca de links Falso
Entradas de dependência da biblioteca de links Falso

Configurar o projeto de empacotamento

No projeto de empacotamento, clique com o botão direito do mouse na pasta Aplicativos e escolha Adicionar Referência.

Adicionar referência do projeto

Escolha o projeto PSF Launcher e seu projeto de aplicativo de desktop e, em seguida, escolha o botão OK .

Projeto Desktop

Observação

Se você não tiver o código-fonte do seu aplicativo, basta escolher o projeto PSF Launcher. Mostraremos como fazer referência ao seu executável quando você criar um arquivo de configuração.

No nó Aplicativos , clique com o botão direito do mouse no aplicativo Iniciador PSF e escolha Definir como Ponto de Entrada.

Definir ponto de entrada

Adicione um arquivo nomeado config.json ao seu projeto de empacotamento e, em seguida, copie e cole o seguinte texto json no arquivo. Defina a propriedade Package Action como Content.

{
    "applications": [
        {
            "id": "",
            "executable": "",
            "workingDirectory": ""
        }
    ],
    "processes": [
        {
            "executable": "",
            "fixups": [
                {
                    "dll": "",
                    "config": {
                    }
                }
            ]
        }
    ]
}

Forneça um valor para cada chave. Use esta tabela como um guia.

Matriz chave Valor
Aplicações ID Use o valor do atributo Id do elemento Application no manifesto do pacote.
Aplicações executável O caminho relativo ao pacote para o executável que você deseja iniciar. Na maioria dos casos, você pode obter esse valor do arquivo de manifesto do pacote antes de modificá-lo. É o valor do Executable atributo do Application elemento.
Aplicações diretório de trabalho (Opcional) Um caminho relativo ao pacote para usar como o diretório de trabalho do aplicativo que é iniciado. Se você não definir esse valor, o sistema operacional usará o System32 diretório como o diretório de trabalho do aplicativo.
processos executável Na maioria dos casos, este será o nome do executable configurado acima, com o caminho e a extensão de arquivo removidos.
correções dll Caminho relativo do pacote para a DLL de correção a ser carregada.
correções Configurações (Opcional) Controla como a DLL de correção se comporta. O formato exato desse valor varia de correção por correção, pois cada correção pode interpretar esse "blob" como quiser.

Quando terminar, o seu config.json ficheiro terá o seguinte aspeto.

{
  "applications": [
    {
      "id": "DesktopApplication",
      "executable": "DesktopApplication/WinFormsDesktopApplication.exe",
      "workingDirectory": "WinFormsDesktopApplication"
    }
  ],
  "processes": [
    {
      "executable": ".*App.*",
      "fixups": [ { "dll": "RuntimeFix.dll" } ]
    }
  ]
}

Observação

O applications, processese fixups as chaves são matrizes. Isso significa que você pode usar o arquivo config.json para especificar mais de um aplicativo, processo e corrigir DLL.

Depurar uma correção em tempo de execução

No Visual Studio, pressione F5 para iniciar o depurador. A primeira coisa que inicia é o aplicativo PSF Launcher, que, por sua vez, inicia seu aplicativo de desktop de destino. Para depurar o aplicativo da área de trabalho de destino, você terá que anexar manualmente ao processo do aplicativo da área de trabalho escolhendo Depurar-Anexar> ao Processo e, em seguida, selecionando o processo do aplicativo. Para permitir a depuração de um aplicativo .NET com uma DLL de correção de tempo de execução nativa, selecione os tipos de código gerenciado e nativo (depuração de modo misto).

Depois de configurar isso, você pode definir pontos de interrupção ao lado de linhas de código no código do aplicativo da área de trabalho e no projeto de correção de tempo de execução. Se você não tiver o código-fonte para seu aplicativo, poderá definir pontos de interrupção somente ao lado de linhas de código em seu projeto de correção de tempo de execução.

Como a depuração F5 executa o aplicativo implantando arquivos soltos a partir do caminho da pasta de layout do pacote, em vez de instalar a partir de um pacote .msix/.appx, a pasta de layout normalmente não tem as mesmas restrições de segurança que uma pasta de pacote instalada. Como resultado, talvez não seja possível reproduzir erros de negação de acesso ao caminho do pacote antes de aplicar uma correção na execução.

Para resolver esse problema, use a implantação de pacote .msix / .appx em vez da implantação de arquivo solto F5. Para criar um arquivo de pacote .msix / .appx, use o utilitário MakeAppx do SDK do Windows, conforme descrito acima. Ou, no Visual Studio, clique com o botão direito do mouse no nó do projeto de aplicativo e selecione Loja -> Criar pacotes de aplicativos.

Outro problema com o Visual Studio é que ele não tem suporte embutido para anexar a quaisquer processos filho lançados pelo depurador. Isso dificulta a depuração da lógica no processo de inicialização do aplicativo de destino, que deve ser ligado manualmente pelo Visual Studio após a execução.

Para resolver este problema, use um depurador que ofereça suporte ao acoplamento de processos filho. Observe que geralmente não é possível anexar um depurador just-in-time (JIT) ao aplicativo de destino. Isso ocorre porque a maioria das técnicas JIT envolve iniciar o depurador no lugar do aplicativo de destino, por meio da chave do Registro ImageFileExecutionOptions. Isto impede o mecanismo de desvio usado por PSFLauncher.exe para injetar FixupRuntime.dll na aplicação alvo. WinDbg, incluído nas Ferramentas de Depuração para Windows e obtido do SDK do Windows, suporta anexação de processo filho. Agora, ele também oferece suporte à inicialização e depuração diretas de um aplicativo UWP.

Para depurar a inicialização do aplicativo de destino como um processo filho, inicie WinDbg.

windbg.exe -plmPackage PSFSampleWithFixup_1.0.59.0_x86__7s220nvg1hg3m -plmApp PSFSample

No prompt WinDbg, habilite a depuração de processos filho e configure os pontos de paragem adequados.

.childdbg 1
g

(executar até que o aplicativo de destino seja iniciado e invada o depurador)

sxe ld fixup.dll
g

(execute até que a DLL de correção seja carregada)

bp ...

Observação

PLMDebug também pode ser usado para anexar um depurador a um aplicativo após a inicialização, e também está incluído nas Ferramentas de Depuração para Windows. No entanto, é mais complexo de usar do que o suporte direto agora fornecido pelo WinDbg.

Apoio

Tem dúvidas? Pergunte-nos no espaço de conversação do Package Support Framework no site da comunidade de tecnologia MSIX.