Introdução ao Package Support Framework

O Package Support Framework é um kit de código aberto que ajuda você a aplicar correções ao aplicativo da á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 olhada detalhada em cada componente do Package Support Framework e guia passo a passo para usá-lo.

Entender o que está dentro de uma Estrutura de Suporte a Pacotes

A Estrutura de Suporte ao Pacote contém um executável, uma DLL do gerenciador de runtime e um conjunto de correções de runtime.

PSF (estrutura de suporte do pacote)

Este é 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 inicializador PSF (Package Support Framework).

Quando os usuários iniciam seu aplicativo, o inicializador do Package Support Framework é o primeiro executável 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.

Injeção de DLL da Estrutura de Suporte ao Pacote

Etapa 1: Identificar problemas de compatibilidade do aplicativo empacotado

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 referem-se a suposições de aplicativo sobre o diretório de trabalho e as permissões de caminho do programa.

Usando o Monitor do Processo para identificar um problema

O Monitor de Processo é 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 do aplicativo. Depois de abrir o Monitor do Processo, adicione um filtro (Filtro de Filtro > ...) para incluir apenas eventos do executável do aplicativo.

Filtro de aplicativo ProcMon

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

Eventos ProcMon

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

ProcMon Exclude Success

Se você suspeitar de uma falha de acesso do sistema de arquivos, pesquise eventos com falha no System32/SysWOW64 ou no caminho do arquivo de pacote. Os filtros também podem ajudar aqui. Comece na parte inferior desta lista e role para cima. Falhas que aparecem na parte inferior dessa 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 as coisas que não parecem suspeitas. O PSFSample tem dois problemas. Você pode ver esses problemas na lista que aparece na imagem a seguir.

ProcMon Config.txt

No primeiro problema exibido nesta imagem, o aplicativo não está conseguindo ler do arquivo "Config.txt" localizado no caminho "C:\Windows\SysWOW64". É improvável que o aplicativo esteja tentando referenciar esse caminho diretamente. Provavelmente, ele está tentando ler 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 como em algum lugar do pacote. Examinando dentro do appx, podemos ver que o arquivo existe no mesmo diretório que o executável.

Config.txtde aplicativo

O segundo problema aparece na imagem a seguir.

Arquivo de log procMon

Nesse problema, o aplicativo não está gravando um arquivo .log no caminho do pacote. Isso sugere que uma correção de redirecionamento de arquivo pode ajudar.

Etapa 2: Localizar uma correção de runtime

O PSF contém correções de runtime 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 Arquivos para redirecionar tentativas de gravar ou ler dados em um diretório que não está acessível em um aplicativo que é executado em um contêiner MSIX.

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

Correções de runtime da comunidade

Examine 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 runtime.

Etapa 3: Aplicar uma correção de runtime

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

  • Criar uma pasta de layout de pacote
  • Obter os arquivos da Estrutura de Suporte ao Pacote
  • Adicioná-los ao 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á desempacotar seu conteúdo em uma pasta de layout que servirá como a área de preparo do pacote. Você pode fazer isso a partir de 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 no computador 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.

Layout do Pacote

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 da Estrutura de Suporte ao Pacote

Você pode obter o pacote Nuget PSF usando a ferramenta de linha de comando do 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 do 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 de pacote para .zip e descompactá-la. Todos os arquivos necessários estarão na pasta /bin.

Obter o pacote usando o Visual Studio

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

Adicionar os arquivos da Estrutura de Suporte ao Pacote 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 vai querer incluir todas as correções de runtime necessárias. Em nosso exemplo, precisamos da correção de runtime 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 ser semelhante a este.

Binários de pacote

Modificar o manifesto do pacote

Abra o manifesto do pacote em um editor de texto e defina o Executable atributo do Application elemento como o nome do arquivo executável do Inicializador PSF. Se você souber a arquitetura do aplicativo de destino, selecione a versão apropriada, PSFLauncher32.exe ou PSFLauncher64.exe. Caso contrário, PSFLauncher32.exe funcionará em todos os casos. Veja 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 de aplicativo declarada do arquivo config.json para apontar para o executável que você acabou de substituir. Usando o conhecimento obtido usando o Monitor de Processo, 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"
                                    ]
                                }
                            ]
                        }
                    }
                }
            ]
        }
    ]
}

Veja a seguir um guia para o esquema config.json:

Array chave Valor
de dimensionamento da Web id Use o valor do Id atributo do Application elemento no manifesto do 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 valor do Executable 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 iniciado. Se você não definir esse valor, o sistema operacional usará o System32 diretório como diretório de trabalho do aplicativo.
processos executável Na maioria dos casos, esse 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 a correção, .msix/.appx a ser carregada.
Correções config (Opcional) Controla como a dll de correção se comporta. O formato exato desse valor varia de acordo com a correção por correção, pois cada correção pode interpretar esse "blob" como desejar.

As applicationsteclas , 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 correção de DLL.

Empacotar e testar o aplicativo

Em seguida, crie um pacote.

makeappx pack /d PackageContents /p PSFSamplePackageFixup.msix

Então, assine.

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

Para obter mais informações, confira como criar um certificado de assinatura de pacote e como assinar um pacote usando o 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 runtime aplicada. Repita as etapas de diagnóstico e empacotamento conforme necessário.

Verifique se a Estrutura de Suporte ao Pacote está em execução

Você pode verificar se a correção de runtime está em execução. Uma maneira de fazer isso é abrir o Gerenciador de Tarefas e clicar em Mais detalhes. Localize o aplicativo ao qual a estrutura de suporte ao 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 a Correção de Rastreamento. Essa DLL está incluída no PSF e fornece uma exibição de diagnóstico detalhada do comportamento do aplicativo, semelhante ao Monitor de Processo. Ele foi projetado especialmente para revelar problemas de compatibilidade do aplicativo. Para usar a Correção de Rastreamento, adicione a DLL ao pacote, adicione o fragmento a seguir ao config.json e, 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 infeliz consequência 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 leitura do arquivo Config.txt falha com a mensagem "arquivo não encontrado". Essa é uma falha que é frequentemente observada e geralmente não considerada inesperada. Na prática, é provável que seja melhor começar a filtrar apenas para falhas inesperadas e, em seguida, voltar a todas as falhas se houver um problema que ainda não possa ser identificado.

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

Arquivo TraceShim não encontrado

Acesso do TraceShim negado

Depurar, estender ou criar uma correção de runtime

Você pode usar o Visual Studio para depurar uma correção de runtime, estender uma correção de runtime ou criar uma do zero. Você precisará fazer essas coisas para ter êxito.

  • Adicionar um projeto de empacotamento
  • Adicionar projeto para a correção de runtime
  • Adicionar um projeto que inicia o executável do Inicializador PSF
  • Configurar o projeto de empacotamento

Quando terminar, sua solução será semelhante a esta.

Solução concluída

Vamos examinar cada projeto neste exemplo.

Project Finalidade
DesktopApplicationPackage Esse projeto é baseado no projeto empacotamento de aplicativos do Windows e gera o pacote MSIX.
Runtimefix Esse é um projeto C++ Dynamic-Linked Library que contém uma ou mais funções de substituição que servem como a correção de runtime.
PSFLauncher Este é o Projeto Vazio do C++. Este projeto é um local para coletar os arquivos distribuíveis de runtime da Estrutura de Suporte ao Pacote. 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 da área de trabalho.

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 da área de trabalho, crie uma nova solução em branco no Visual Studio.

Solução em branco

Talvez você também queira adicionar quaisquer projetos de aplicativo que você tenha.

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 empacotamento de aplicativos do Windows, consulte Empacotar seu aplicativo usando o Visual Studio.

Em 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 runtime

Adicione um projeto de DLL (Biblioteca de Vínculo Dinâmico) do C++ à solução.

Biblioteca de correções de runtime

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 de origem do pacote está definida como Todos ou nuget.org.

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

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

pacote nuget

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

Se você pretende criar uma nova correção, não adicione nada a este projeto ainda. Ajudaremos você 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 Inicializador PSF

Adicione um projeto do Projeto Vazio do C++ à solução.

Projeto vazio

Adicione o pacote nuget PSF a este projeto usando as mesmas diretrizes descritas na seção anterior.

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

Referência do Inicializador PSF

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

Referência de correção de runtime

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

Propriedade Valor
Copiar local True
Assemblies Satélite do Local da Cópia True
Saída do Assembly de Referência True
Dependências da Biblioteca de Links Falso
Entradas de dependência da biblioteca de link Falso

Configurar o projeto de empacotamento

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

Adicionar Referência de Projeto

Escolha o projeto inicializador de PSF e seu projeto de aplicativo da área de trabalho e escolha o botão OK .

Projeto de área de trabalho

Observação

Se você não tiver o código-fonte para seu aplicativo, basta escolher o projeto inicializador do PSF. 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 Inicializador PSF e escolha Definir como Ponto de Entrada.

Definir ponto de entrada

Adicione um arquivo nomeado config.json ao projeto de empacotamento e, em seguida, copie e cole o texto json a seguir 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 valor do Id atributo do Application elemento no manifesto do 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 valor do Executable 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 iniciado. Se você não definir esse valor, o sistema operacional usará o System32 diretório como diretório de trabalho do aplicativo.
processos executável Na maioria dos casos, esse 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 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 de acordo com a correção por correção, pois cada correção pode interpretar esse "blob" como desejar.

Quando terminar, seu config.json arquivo será semelhante a este.

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

Observação

As applicationsteclas , 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 correção de DLL.

Depurar uma correção de runtime

No Visual Studio, pressione F5 para iniciar o depurador. A primeira coisa que começa é o aplicativo PSF Launcher, que, por sua vez, inicia seu aplicativo de área de trabalho de destino. Para depurar o aplicativo de área de trabalho de destino, você precisará anexar manualmente ao processo de aplicativo da área de trabalho escolhendo Depurar-Anexar> ao Processo e, em seguida, selecionar o processo do aplicativo. Para permitir a depuração de um aplicativo .NET com uma DLL de correção de runtime nativa, selecione tipos de código gerenciados e nativos (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 runtime. 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 no projeto de correção do runtime.

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 runtime.

Para resolver esse problema, use a implantação do pacote .msix/.appx em vez da implantação de arquivos f5 soltos. 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 do aplicativo e selecione Store –> Criar Pacotes de Aplicativos.

Outro problema com o Visual Studio é que ele não tem suporte interno para anexação a nenhum 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 dê suporte à anexação de processo filho. Observe que geralmente não é possível anexar um depurador JIT (just-in-time) 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. Isso derrota o mecanismo de desvio usado por 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, dá suporte à anexação do processo filho. Agora ele também dá suporte à inicialização e depuração diretas de um aplicativo UWP.

Para depurar a inicialização de aplicativo de destino como um processo filho, inicie 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

(execute até que o aplicativo de destino seja iniciado e interrompa 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 usar do que o suporte direto agora fornecido pelo WinDbg.

Suporte

Tem dúvidas? Pergunte-nos sobre o espaço de conversa do Package Support Framework no site da comunidade técnica MSIX.