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.
Aqui está o processo:
- Crie um arquivo de configuração que especifique as correções que você deseja aplicar ao seu aplicativo.
- 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.
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.
Uma lista de eventos será exibida. Para muitos desses eventos, a palavra SUCESSO aparecerá na coluna Resultado.
Opcionalmente, você pode filtrar eventos para mostrar apenas falhas.
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.
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.
O segundo problema aparece na imagem a seguir.
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.
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.
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.json
de 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 applications
chaves , processes
e 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.
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.
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.
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.
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.
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).
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.
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.
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.
Adicione uma referência de projeto ao projeto de correção de tempo de execução em sua solução.
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.
Escolha o projeto PSF Launcher e seu projeto de aplicativo de área de trabalho e, em seguida, escolha o botão OK .
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.
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 applications
chaves , processes
e 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.