Introdução ao Package Support Framework

O Package Support Framework é um kit de código aberto que ajuda você a aplicar correções ao seu aplicativo de área de trabalho 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 melhores práticas do ambiente moderno do runtime.

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

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

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

Package Support Framework

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 o pacote para apontar para o arquivo executável do iniciador do Package Support Framework (PSF).

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

Package Support Framework DLL Injection

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ê poderá receber mensagens de erro que podem ajudá-lo a identificar um problema de compatibilidade. Use também o Monitor do Processo para identificar problemas. Problemas comuns estão relacionados a suposições de aplicativo relacionadas 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.

ProcMon App Filter

Uma lista de eventos será exibida. Para muitos desses eventos, a palavra SUCESSO aparecerá na coluna Resultado.

ProcMon Events

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

ProcMon Exclude Success

Se você suspeitar de uma falha de acesso ao sistema de arquivos, procure eventos com falha que estejam no System32/SysWOW64 ou no caminho do arquivo do pacote. Os filtros também podem ajudar aqui. Comece na parte inferior desta lista e role para cima. As falhas que aparecem na parte inferior desta lista ocorreram mais recentemente. Preste mais atenção a erros que contenham 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 o arquivo "Config.txt" que está localizado no caminho "C:\Windows\SysWOW64". É improvável que o aplicativo esteja tentando referenciar esse caminho diretamente. Provavelmente, ele está tentando ler esse 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.

ProcMon Logfile

Nesse problema, o aplicativo está falhando ao gravar um arquivo .log em 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 a Correção de Redirecionamento de Arquivo 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 o aplicativo gravar em um arquivo de log que esteja no mesmo diretório que o executável dos 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 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 tenham 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 layout de pacote
  • Obter os arquivos 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 em um prompt de comando usando a ferramenta MakeAppx, com base no caminho de instalação do SDK, é aqui que você encontrará a ferramenta makeappx.exe em seu PC com Windows 10: x86: C:\Arquivos de Programas (x86)\Windows Kits\10\bin\x86\makeappx.exe x64: C:\Arquivos de Programas (x86)\Windows Kits\10\bin\x64\makeappx.exe

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

Isso lhe dará algo parecido com o seguinte.

Package Layout

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

Obter os arquivos do Package Support Framework

Você pode obter o pacote PSF Nuget usando a ferramenta de linha de comando Nuget autônoma ou via 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 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. Procure Microsoft.PackageSupportFramework ou PSF para localizar o pacote em Nuget.org. Em seguida, instale-o.

Adicionar os arquivos do Package Support Framework ao pacote

Adicione as DLLs PSF de 32 bits e 64 bits necessárias e 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 de tempo de execução de 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 pacote agora deve ter a seguinte aparência.

Package Binaries

Modificar o manifesto do pacote

Abra o manifesto do pacote em um editor de texto e defina o Application atributo do elemento como o Executable nome do arquivo executável do PSF Launcher. Se você conhece a arquitetura do aplicativo de destino, selecione a versão apropriada, PSFLauncher32.exe ou PSFLauncher64.exe. Caso contrário, o PSFLauncher32.exe funcionará em todos os casos. Este é 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 esse arquivo na pasta raiz do 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"
                                    ]
                                }
                            ]
                        }
                    }
                }
            ]
        }
    ]
}

A seguir está um guia para o esquema config.json:

Array chave Valor
de dimensionamento da Web ID Use o Id valor do atributo do elemento no manifesto do Application pacote.
de dimensionamento da Web 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 Executable valor do atributo do Application elemento.
de dimensionamento da Web workingDirectory (Opcional) Um caminho relativo ao pacote a ser usado 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.
sistema executável Na maioria dos casos, este será o nome do configurado acima com o caminho e a extensão de executable arquivo removidos.
Correções dll Caminho relativo ao pacote para a correção, .msix/.appx para carregar.
Correções config (Opcional) Controla como a dll fixup se comporta. O formato exato desse valor varia em uma base de correção por fixup, pois cada correção pode interpretar esse "blob" como quiser.

As applicationschaves , processese fixups são matrizes. Isso significa que você pode usar o arquivo config.json para especificar mais de um aplicativo, processo e DLL de correção.

Empacotar e testar o aplicativo

Em seguida, crie um pacote.

makeappx pack /d PackageContents /p PSFSamplePackageFixup.msix

Em seguida, assine.

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 empacotamento conforme necessário.

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

Você pode verificar se a 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 exibir que o Package Support Framework está em execução.

Usar a correção de rastreamento

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.json e, em seguida, empacote e instale o aplicativo.

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

Por padrão, o Trace Fixup 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 do arquivo Config.txt falha com a mensagem "file not found". Esta é uma falha que é frequentemente observada e geralmente não assumida como inesperada. Na prática, é melhor começar filtrando apenas para falhas inesperadas e, em seguida, voltar para todas as falhas se houver um problema que ainda não possa ser identificado.

Por padrão, a saída do Trace Fixup é enviada para o depurador anexado. Para este exemplo, não anexaremos 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.

TraceShim File Not Found

TraceShim Access Denied

Depurar, estender ou criar uma correção de 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 inicia o executável do PSF Launcher
  • Configurar o projeto de empacotamento

Quando terminar, sua solução será mais ou menos assim.

Completed solution

Vejamos cada projeto neste exemplo.

Project Finalidade
DesktopApplicationPackage Este projeto é baseado no projeto Windows Application Packaging e gera o pacote MSIX.
Correção de tempo de execução Este é um projeto de biblioteca de vinculação dinâmica do C++ que contém uma ou mais funções de substituição que servem como a correção de tempo de execução.
PSFLauncher Este é o projeto vazio do 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 você ainda não tiver uma solução para seu aplicativo de área de trabalho, crie uma nova solução em branco no Visual Studio.

Blank solution

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.

Package project template

Para obter mais informações sobre o projeto de empacotamento de aplicativos do Windows, 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-o à 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.

Runtime fix library

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

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

ISO 17 Option

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 PSF* Nuget e instale-o para este projeto.

nuget package

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 obtidos 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 configurando sua solução.

Adicionar um projeto que inicia o executável do PSF Launcher

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

Empty project

Adicione o pacote PSF Nuget a este projeto usando a mesma orientação descrita na seção anterior.

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

PSF Launcher reference

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

runtime fix reference

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

Propriedade Valor
Copiar local Verdadeiro
Assemblies Satélite do Local da Cópia Verdadeiro
Saída do Assembly de Referência Verdadeiro
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.

Add Project Reference

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

Desktop project

Observação

Se você não tiver o código-fonte para sua aplicação, basta escolher o projeto PSF Launcher. Mostraremos como fazer referência ao executável ao 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.

Set entry point

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 Ação do pacote como Conteúdo.

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

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

Array chave Valor
de dimensionamento da Web ID Use o Id valor do atributo do elemento no manifesto do Application pacote.
de dimensionamento da Web 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 Executable valor do atributo do Application elemento.
de dimensionamento da Web workingDirectory (Opcional) Um caminho relativo ao pacote a ser usado 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.
sistema executável Na maioria dos casos, este será o nome do configurado acima com o caminho e a extensão de executable arquivo removidos.
Correções dll Caminho relativo ao pacote para a DLL de correção a ser carregada.
Correções config (Opcional) Controla como a DLL de correção se comporta. O formato exato desse valor varia em uma base de correção por fixup, pois cada correção pode interpretar esse "blob" como quiser.

Quando terminar, seu config.json arquivo terá a seguinte aparência.

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

Observação

As applicationschaves , processese fixups são matrizes. Isso significa que você pode usar o arquivo config.json para especificar mais de um aplicativo, processo e DLL de correção.

Depurar uma correção de 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 apenas 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 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 de tempo de execução.

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

Outro problema com o Visual Studio é que ele não tem suporte interno para anexar a qualquer processo filho iniciado pelo depurador. Isso dificulta a depuração da lógica no caminho de inicialização do aplicativo de destino, que deve ser anexado manualmente pelo Visual Studio após a inicialização.

Para resolver esse problema, use um depurador que ofereça suporte à anexação de processo 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 a inicialização do depurador no lugar do aplicativo de destino, por meio da chave do Registro ImageFileExecutionOptions. Isso derrota o mecanismo de desvio usado pelo PSFLauncher.exe para injetar FixupRuntime.dll no aplicativo de destino. O WinDbg, incluído nas Ferramentas de Depuração para Windows e obtido do SDK do Windows, oferece suporte à anexação de processo filho. Agora ele também oferece suporte à inicialização e depuração direta de um aplicativo UWP.

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

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

No prompt, habilite a WinDbg depuração filho e defina os pontos de interrupção apropriados.

.childdbg 1
g

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

sxe ld fixup.dll
g

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

bp ...

Observação

O PLMDebug também pode ser usado para anexar um depurador a um aplicativo na 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.

Suporte

Tem dúvidas? Consulte-nos no espaço de conversação do Package Support Framework no site da comunidade tecnológica da MSIX.