Compartilhar via


Criadores de perfil CLR e aplicativos da Windows Store

Este tópico aborda o que você precisa pensar ao escrever ferramentas de diagnóstico que analisam o código gerenciado em execução dentro de um aplicativo da Windows Store. Ele também fornece diretrizes para modificar suas ferramentas de desenvolvimento existentes para que elas continuem funcionando quando você executá-las em aplicativos da Windows Store. Para entender essas informações, é melhor se você estiver familiarizado com a API de Criação de Perfil do Common Language Runtime, já usou essa API em uma ferramenta de diagnóstico executada corretamente em aplicativos da área de trabalho do Windows e agora está interessado em modificar a ferramenta para ser executada corretamente em aplicativos da Windows Store.

Introdução

Se você passou do parágrafo introdutório, está familiarizado com a API de Criação de Perfil do CLR. Você já escreveu uma ferramenta de diagnóstico que funciona bem em aplicativos da área de trabalho gerenciada. Agora você está curioso sobre o que fazer para que sua ferramenta funcione com um aplicativo gerenciado da Windows Store. Talvez você já tenha tentado fazer isso funcionar, e descobriu que não é uma tarefa simples. De fato, há uma série de considerações que podem não ser óbvias para todos os desenvolvedores de ferramentas. Por exemplo:

  • Os aplicativos da Windows Store são executados em um contexto com permissões severamente reduzidas.

  • Os arquivos de metadados do Windows têm características exclusivas quando comparados aos módulos gerenciados tradicionais.

  • Os aplicativos da Windows Store têm o hábito de entrar em modo de suspensão quando a interatividade diminui.

  • Seus mecanismos de comunicação entre processos podem não funcionar mais por vários motivos.

Este tópico lista as coisas que você precisa estar ciente e como lidar com elas corretamente.

Se você não estiver familiarizado com a API de Criação de Perfil do CLR, vá para os Recursos no final deste tópico para encontrar melhores informações introdutórias.

Fornecer detalhes sobre APIs específicas do Windows e como elas devem ser usadas também está fora do escopo deste tópico. Considere este tópico um ponto de partida e confira o MSDN para saber mais sobre todas as APIs do Windows referenciadas aqui.

Arquitetura e terminologia

Normalmente, uma ferramenta de diagnóstico tem uma arquitetura como a mostrada na ilustração a seguir. Ele usa o termo "criador de perfil", mas muitas dessas ferramentas vão muito além do desempenho típico ou criação de perfil de memória em áreas como cobertura de código, estruturas de objetos simuladas, depuração de viagem no tempo, monitoramento de aplicativos e assim por diante. Para simplificar, este tópico continuará a se referir a todas essas ferramentas como criadores de perfil.

A seguinte terminologia é usada ao longo deste tópico:

Aplicativo

Esse é o aplicativo que o criador de perfil está analisando. Normalmente, o desenvolvedor desse aplicativo agora está usando o criador de perfil para ajudar a diagnosticar problemas com o aplicativo. Tradicionalmente, esse aplicativo seria um aplicativo da área de trabalho do Windows, mas neste tópico, estamos examinando os aplicativos da Windows Store.

DLL do criador de perfil

Esse é o componente que é carregado no espaço de processo do aplicativo que está sendo analisado. Esse componente, também conhecido como o "agente" do criador de perfil, implementa as interfaces ICorProfilerCallbackICorProfilerCallback Interface(2,3 etc.) e consome as interfaces ICorProfilerInfo(2,3 etc.) para coletar dados sobre o aplicativo analisado e potencialmente modificar aspectos do comportamento do aplicativo.

Interface do usuário do criador de perfil

Esse é um aplicativo da área de trabalho com o qual o usuário do criador de perfil interage. Ele é responsável por exibir o status do aplicativo para o usuário e fornecer ao usuário os meios para controlar o comportamento do aplicativo analisado. Ele é responsável por exibir o status do aplicativo para o usuário e fornecer ao usuário os meios para controlar o comportamento do aplicativo analisado. A interface do usuário do Criador de Perfil também pode atuar como o "gatilho de anexação", que é o processo que chama o método ICLRProfiling::AttachProfiler, para fazer com que o aplicativo analisado carregue a DLL do Criador de Perfil nos casos em que a DLL do criador de perfil não foi carregada na inicialização.

Importante

Sua interface do usuário do Criador de Perfil deve permanecer um aplicativo da área de trabalho do Windows, mesmo quando ele é usado para controlar e relatar em um aplicativo da Windows Store. Não espere ser capaz de empacotar e enviar sua ferramenta de diagnóstico na Windows Store. Sua ferramenta precisa fazer coisas que os aplicativos da Windows Store não podem fazer e muitas dessas coisas residem dentro da interface do usuário do Criador de Perfil.

Ao longo deste documento, o código de exemplo pressupõe que:

  • A DLL do Criador de Perfil é gravada em C++, pois deve ser uma DLL nativa, de acordo com os requisitos da API de Criação de Perfil do CLR.

  • A interface do usuário do Criador de Perfil é gravada em C#. Isso não é necessário, mas como não há requisitos de linguagem para o processo da interface do usuário do Criador de Perfil, por que não escolher uma linguagem concisa e simples?

Dispositivos Windows RT

Os dispositivos Windows RT estão bastante bloqueados. Os criadores de perfil de terceiros simplesmente não podem ser carregados nesses dispositivos. Este documento se concentra em computadores Windows 8.

Consumir APIs do Windows Runtime

Em vários cenários discutidos nas seções a seguir, seu aplicativo de área de trabalho da interface do usuário do Criador de Perfil precisa consumir algumas novas APIs do Windows Runtime. Você vai querer consultar a documentação para entender quais APIs do Windows Runtime podem ser usadas por meio de aplicativos da área de trabalho e se o comportamento delas é diferente quando chamadas de aplicativos da área de trabalho e aplicativos da Windows Store.

Se a interface do usuário do Criador de Perfil for gravada em código gerenciado, haverá algumas etapas que você precisará executar para facilitar o consumo dessas APIs do Windows Runtime. Para obter mais informações, confira o artigo Windows Runtime e aplicativos da área de trabalho gerenciada.

Carregando a DLL do Criador de Perfil

Esta seção descreve como a interface do usuário do Criador de Perfil faz com que o aplicativo da Windows Store carregue a DLL do Criador de Perfil. O código discutido nesta seção pertence ao aplicativo da área de trabalho da interface do usuário do Criador de Perfil e, portanto, envolve o uso de APIs do Windows que são seguras para aplicativos da área de trabalho, mas não necessariamente seguras para aplicativos da Windows Store.

A interface do usuário do Criador de Perfil pode fazer com que a DLL do Criador de Perfil seja carregada no espaço de processo do aplicativo de duas maneiras:

  • Na inicialização do aplicativo, conforme controlado por variáveis de ambiente.

  • Anexando ao aplicativo após a conclusão da inicialização, chamando o método ICLRProfiling::AttachProfiler.

Um dos seus primeiros obstáculos será obter carga de inicialização e anexação da DLL do Criador de Perfil para funcionar corretamente com aplicativos da Windows Store. Ambas as formas de carga compartilham algumas considerações especiais em comum, portanto, vamos começar com elas.

Considerações comuns sobre as cargas de inicialização e anexação

Assinando sua DLL do Criador de Perfil

Quando o Windows tenta carregar sua DLL do Criador de Perfil, ele verifica se a DLL do Criador de Perfil está assinada corretamente. Caso contrário, a carga falhará por padrão. Há duas maneiras de fazer isso:

  • Verifique se a DLL do Criador de Perfil está assinada.

  • Informe ao usuário que ele deve instalar uma licença de desenvolvedor em seu computador Windows 8 antes de usar sua ferramenta. Isso pode ser feito automaticamente no Visual Studio ou manualmente em um prompt de comando. Para obter mais informações, confira Obter uma licença de desenvolvedor.

Permissões do sistema de arquivos

O aplicativo da Windows Store deve ter permissão para carregar e executar a DLL do Criador de Perfil do local no sistema de arquivos em que reside. Por padrão, o aplicativo da Windows Store não tem essa permissão na maioria dos diretórios, e qualquer tentativa com falha de carregar sua DLL do Criador de Perfil produzirá uma entrada no log de eventos do Aplicativo Windows que se parece com isso:

NET Runtime version 4.0.30319.17929 - Loading profiler failed during CoCreateInstance.  Profiler CLSID: '{xxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}'.  HRESULT: 0x80070005.  Process ID (decimal): 4688.  Message ID: [0x2504].

Em geral, os aplicativos da Windows Store só têm permissão para acessar um conjunto limitado de locais no disco. Cada aplicativo da Windows Store pode acessar suas respectivas pastas de dados de aplicativo, bem como algumas outras áreas no sistema de arquivos para as quais todos os aplicativos da Windows Store recebem acesso. É melhor instalar a DLL do Profiler e as dependências dela em algum lugar em Arquivos de Programas ou Arquivos de Programas (x86), porque todos os aplicativos da Windows Store têm permissões para ler e gravar lá por padrão.

Carga de inicialização

Normalmente, em um aplicativo da área de trabalho, a interface do usuário do Criador de Perfil solicita uma carga de inicialização da DLL do Criador de Perfil inicializando um bloco de ambiente que contém as variáveis de ambiente de API de Criação de Perfil do CLR necessárias (ou seja, COR_PROFILER, COR_ENABLE_PROFILING e COR_PROFILER_PATH), e criando um processo com esse bloco de ambiente. O mesmo vale para aplicativos da Windows Store, mas os mecanismos são diferentes.

Não executar com privilégios elevados

Se o Processo A tentar gerar o processo B do aplicativo da Windows Store, o processo A deverá ser executado no nível de integridade médio, não no alto (ou seja, não elevado). Isso significa que a interface do usuário do Criador de Perfil deve estar em execução no nível de integridade médio ou deve gerar outro processo de área de trabalho no nível de integridade médio para cuidar da inicialização do aplicativo da Windows Store.

Escolhendo um aplicativo da Windows Store para o perfil

Primeiro, você vai querer perguntar ao usuário criador de perfil qual aplicativo da Windows Store será iniciado. Para aplicativos da área de trabalho, talvez você mostrasse uma caixa de diálogo Procurar arquivo e o usuário encontraria e selecionaria o .exe desejado. Mas os aplicativos da Windows Store são diferentes e usar uma caixa de diálogo Procurar não faria sentido. Em vez disso, é melhor mostrar ao usuário uma lista de aplicativos da Windows Store para ele escolher.

Você pode usar a classe PackageManager para gerar essa lista. PackageManager é uma classe do Windows Runtime que está disponível para aplicativos da área de trabalho e, na verdade, está disponível somente para aplicativos da área de trabalho.

O seguinte exemplo de código de uma interface do usuário hipotética do Criador de Perfil gravada como um aplicativo da área de trabalho em C# usa a PackageManager para gerar uma lista de aplicativos do Windows:

string currentUserSID = WindowsIdentity.GetCurrent().User.ToString();
IAppxFactory appxFactory = (IAppxFactory) new AppxFactory();
PackageManager packageManager = new PackageManager();
IEnumerable<Package> packages = packageManager.FindPackagesForUser(currentUserSID);

Especificando o bloco de ambiente personalizado

Uma nova interface COM, IPackageDebugSettings, permite personalizar o comportamento de execução de um aplicativo da Windows Store para facilitar algumas formas de diagnóstico. Um de seus métodos, EnableDebugging, permite passar um bloco de ambiente para o aplicativo da Windows Store quando ele é iniciado, juntamente com outros efeitos úteis, como desabilitar a suspensão automática do processo. O bloco de ambiente é importante porque é aí que você precisa especificar as variáveis de ambiente (COR_PROFILER, COR_ENABLE_PROFILINGe COR_PROFILER_PATH)) usadas pelo CLR para carregar sua DLL do Profiler.

Considere o seguinte snippet de código:

IPackageDebugSettings pkgDebugSettings = new PackageDebugSettings();
pkgDebugSettings.EnableDebugging(packageFullName, debuggerCommandLine,
                                                                 (IntPtr)fixedEnvironmentPzz);

Há alguns itens que você precisará acertar:

  • packageFullName pode ser determinado durante a iteração sobre os pacotes e a captura package.Id.FullName.

  • debuggerCommandLine é um pouco mais interessante. Para passar o bloco de ambiente personalizado para o aplicativo da Windows Store, você precisa escrever seu próprio depurador fictício simplista. O Windows gera o aplicativo da Windows Store suspenso e anexa o depurador iniciando o depurador com uma linha de comando como neste exemplo:

    MyDummyDebugger.exe -p 1336 -tid 1424
    

    em que -p 1336 significa que o aplicativo da Windows Store tem a ID do Processo 1336 e -tid 1424 significa a ID do Thread, 1424, que é o thread suspenso. Seu depurador fictício analisaria o ThreadID da linha de comando, retomaria esse thread e sairia.

    Aqui está um exemplo de código C++ para fazer isso (não se esqueça de adicionar a verificação de erros):

    int wmain(int argc, wchar_t* argv[])
    {
        // …
        // Parse command line here
        // …
    
        HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME,
                                                                  FALSE /* bInheritHandle */, nThreadID);
        ResumeThread(hThread);
        CloseHandle(hThread);
        return 0;
    }
    

    Você precisará implantar esse depurador fictício como parte da instalação da ferramenta de diagnóstico e especificar o caminho para esse depurador no parâmetro debuggerCommandLine.

Iniciar o aplicativo da Windows Store

O momento de iniciar o aplicativo da Windows Store finalmente chegou. Se você já tentou fazer isso por conta própria, talvez tenha notado que CreateProcess não é como você cria um processo de aplicativo da Windows Store. Em vez disso, você precisará usar o método IApplicationActivationManager::ActivateApplication. Para fazer isso, você precisará obter a ID do Modelo de Usuário do Aplicativo do aplicativo da Windows Store que está iniciando. E isso significa que você vai precisar explorar um pouco o manifesto para encontrar.

Durante a iteração em seus pacotes (confira "Escolhendo um aplicativo da Windows Store para perfil" na seção Carga de inicialização, anteriormente), você vai querer pegar o conjunto de aplicativos contido no manifesto do pacote atual:

string manifestPath = package.InstalledLocation.Path + "\\AppxManifest.xml";

AppxPackaging.IStream manifestStream;
SHCreateStreamOnFileEx(
                    manifestPath,
                    0x00000040,     // STGM_READ | STGM_SHARE_DENY_NONE
                    0,              // file creation attributes
                    false,          // fCreate
                    null,           // reserved
                    out manifestStream);

IAppxManifestReader manifestReader = appxFactory.CreateManifestReader(manifestStream);

IAppxManifestApplicationsEnumerator appsEnum = manifestReader.GetApplications();

Sim, um pacote pode ter vários aplicativos e cada aplicativo tem sua própria ID do modelo de usuário do aplicativo. Portanto, você terá que perguntar ao usuário para qual aplicativo criar o perfil e obter a ID do Modelo de Usuário do Aplicativo correspondente:

while (appsEnum.GetHasCurrent() != 0)
{
    IAppxManifestApplication app = appsEnum.GetCurrent();
    string appUserModelId = app.GetAppUserModelId();
    //...
}

Por fim, agora você tem o que precisa para iniciar o aplicativo da Windows Store:

IApplicationActivationManager appActivationMgr = new ApplicationActivationManager();
appActivationMgr.ActivateApplication(appUserModelId, appArgs, ACTIVATEOPTIONS.AO_NONE, out pid);

Lembre-se de chamar DisableDebugging

Quando você chamou IPackageDebugSettings::EnableDebugging, você prometeu que limparia sua bagunça chamando o método IPackageDebugSettings::D isableDebugging, portanto, não se esqueça de fazer isso quando a sessão de criação de perfil terminar.

Carga de anexação

Quando a interface do usuário do Criador de Perfil quer anexar a DLL do Criador de Perfil a um aplicativo que já começou a ser executado, ela usa ICLRProfiling::AttachProfiler. O mesmo vale para aplicativos da Windows Store. Mas, além das considerações comuns listadas anteriormente, verifique se o aplicativo da Windows Store de destino não está suspenso.

EnableDebugging

Assim como na carga de inicialização, chame o método IPackageDebugSettings::EnableDebugging. Você não precisa dele para passar em um bloco de ambiente, mas precisa de um de seus outros recursos: desabilitar a suspensão automática do processo. Caso contrário, quando a interface do usuário do Criador de Perfil chamar AttachProfiler, o aplicativo da Windows Store de destino poderá ser suspenso. Na verdade, é bem provável que isso aconteça, já que o usuário estará interagindo com a interface do usuário do Criador de Perfil e o aplicativo da Windows Store não estará ativo em nenhuma das telas do usuário. E se o aplicativo da Windows Store for suspenso, ele não poderá responder a nenhum sinal que o CLR enviar a ele para anexar a DLL do Criador de Perfil.

Portanto, é melhor fazer da seguinte maneira:

IPackageDebugSettings pkgDebugSettings = new PackageDebugSettings();
pkgDebugSettings.EnableDebugging(packageFullName, null /* debuggerCommandLine */,
                                                                 IntPtr.Zero /* environment */);

Essa é a mesma chamada que você faria para a carga de inicialização, exceto que você não especifica uma linha de comando do depurador ou um bloco de ambiente.

DisableDebugging

Como sempre, não se esqueça de chamar IPackageDebugSettings::D isableDebugging quando a sessão de criação de perfil for concluída.

Em execução dentro do aplicativo da Windows Store

Com isso, o aplicativo da Windows Store finalmente carregou sua DLL do Criador de Perfil. Agora, a DLL deve ser ensinada a respeitar as diferentes regras impostas pelos aplicativos da Windows Store, incluindo quais APIs são permitidos e como executar com permissões reduzidas.

Atenha-se às APIs de aplicativo da Windows Store

Ao navegar pela API do Windows, você observará que cada API está documentada como sendo aplicável a aplicativos da área de trabalho, aplicativos da Windows Store ou ambos. Por exemplo, a seção Requisitos da documentação da função InitializeCriticalSectionAndSpinCount indica que a função se aplica somente a aplicativos da área de trabalho. Por outro lado, a função InitializeCriticalSectionEx está disponível para aplicativos desktop e aplicativos da Windows Store.

Ao desenvolver sua DLL do Criador de Perfil, trate-a como se fosse um aplicativo da Windows Store e use apenas APIs documentadas como disponíveis para aplicativos da Windows Store. Analise suas dependências (por exemplo, você pode executar link /dump /imports em sua DLL do Criador de Perfil para auditar) e pesquise os documentos para ver quais das suas dependências estão ok e quais não estão. Na maioria dos casos, suas violações podem ser corrigidas simplesmente substituindo-as por uma forma mais recente da API documentada como segura (por exemplo, substituindo InitializeCriticalSectionAndSpinCount por InitializeCriticalSectionEx).

Você pode notar que a DLL do Criador de Perfil chama algumas APIs que se aplicam apenas a aplicativos da área de trabalho e, no entanto, elas parecem funcionar mesmo quando a DLL do Criador de Perfil é carregada dentro de um aplicativo da Windows Store. Lembre-se de que é arriscado usar qualquer API não documentada com aplicativos da Windows Store em sua DLL do Criador de Perfil quando carregado em um processo de aplicativo da Windows Store:

  • Essas APIs não têm garantia de funcionar quando chamadas no contexto exclusivo em que os aplicativos da Windows Store são executados.

  • Essas APIs podem não funcionar de maneira consistente quando chamadas de diferentes processos de aplicativos da Windows Store.

  • Essas APIs podem parecer funcionar bem em aplicativos da Windows Store na versão atual do Windows, mas podem ser interrompidas ou desabilitadas em versões futuras do SO.

O melhor conselho é corrigir todas as violações e evitar riscos.

Você pode achar que não é capaz de viver sem uma API específica e que nunca vai encontrar um substituto adequado para determinados aplicativos da Windows Store. Se esse for o caso, pelo menos faça o seguinte:

  • Teste, teste e reteste sua API em todos os cenários de uso possíveis.

  • Esteja ciente de que a API pode de repente parar de funcionar ou desaparecer se for chamada de dentro de um aplicativo da Windows Store em versões futuras do Windows. Isso não será considerado uma barreira de compatibilidade pela Microsoft e evitar esses cenários não será uma prioridade.

Permissões reduzidas

Está fora do escopo deste tópico listar todas as maneiras pelas quais as permissões de aplicativo da Windows Store diferem dos aplicativos da área de trabalho. Mas, certamente, o comportamento será diferente sempre que a DLL do Criador de Perfil tentar acessar todos algum recursos (quando carregada em um aplicativo da Windows Store em comparação com um aplicativo da área de trabalho). O sistema de arquivos é o exemplo mais comum. Há apenas alguns locais no disco em que determinado aplicativo da Windows Store tem permissão para acessar (confira Acesso a arquivos e permissões de aplicativos do Windows Runtime) e sua DLL do Criador de Perfil estará sob as mesmas restrições. Teste seu código exaustivamente.

Comunicação entre processos

Conforme mostrado no diagrama no início deste artigo, a DLL do Criador de Perfil (carregada no espaço de processo do aplicativo da Windows Store) provavelmente precisará se comunicar com a interface do usuário do Criador de Perfil (em execução em um espaço de processo de aplicativo de área de trabalho separado) por meio do seu próprio canal de comunicação entre processos personalizados (IPC). A interface do usuário do Criador de Perfil envia sinais para a DLL do Criador de Perfil a fim de modificar o comportamento dela, e a DLL responde enviando dados do aplicativo da Windows Store analisado de volta à interface do usuário do Criador de Perfil para pós-processamento e exibição ao usuário criador de perfil.

A maioria dos criadores de perfil precisa trabalhar dessa maneira, mas suas opções para mecanismos de IPC são mais limitadas quando a DLL do Criador de Perfil é carregada em um aplicativo da Windows Store. Por exemplo, os pipes nomeados não fazem parte do SDK do aplicativo da Windows Store, portanto, você não pode usá-los.

Mas, é claro, os arquivos ainda estão dentro, embora de uma forma mais limitada. Eventos também estão disponíveis.

Comunicação por meio de arquivos

A maioria dos dados provavelmente passará entre a DLL do Criador de Perfil e a interface do usuário do Criador de Perfil por meio de arquivos. A chave é escolher um local de arquivo a que tanto a DLL do Criador de Perfil (no contexto de um aplicativo da Windows Store) quanto a interface do usuário do Criador de Perfil tenham acesso de leitura e gravação. Por exemplo, o caminho da Pasta Temporária é um local que a DLL do Criador de Perfil e a interface do usuário do Criador de Perfil podem acessar, mas nenhum outro pacote de aplicativo da Windows Store pode acessar (protegendo assim qualquer informação que você registre de outros pacotes de aplicativos da Windows Store).

A interface do usuário do Criador de Perfil e a DLL do Criador de Perfil podem determinar esse caminho de maneira independente. A interface do usuário do Criador de Perfil, quando itera em todos os pacotes instalados para o usuário atual (confira o código de exemplo, anteriormente), obtém acesso à classe PackageId, da qual o caminho da Pasta Temporária pode ser derivado com código semelhante a este snippet. (Como sempre, a verificação de erros é omitida para brevidade.)

// C# code for the Profiler UI.
ApplicationData appData =
    ApplicationDataManager.CreateForPackageFamily(
        packageId.FamilyName);

tempDir = appData.TemporaryFolder.Path;

Enquanto isso, a DLL do Criador de Perfil pode fazer basicamente a mesma coisa, embora possa chegar mais facilmente à classe ApplicationData usando a propriedade ApplicationData.Current.

Comunicação por meio de eventos

Se você quiser uma semântica de sinalização simples entre a interface do usuário e a DLL do Criador de Perfil, poderá usar eventos dentro de aplicativos da Windows Store, bem como aplicativos da área de trabalho.

Na DLL do Criador de Perfil, você pode simplesmente chamar a função CreateEventEx para criar um evento nomeado com qualquer nome desejado. Por exemplo:

// Profiler DLL in Windows Store app (C++).
CreateEventEx(
    NULL,  // Not inherited
    "MyNamedEvent"
    CREATE_EVENT_MANUAL_RESET, /* explicit ResetEvent() required; leave initial state unsignaled */
    EVENT_ALL_ACCESS);

Em seguida, a interface do usuário do Criador de Perfil precisa encontrar esse evento nomeado no namespace do aplicativo da Windows Store. Por exemplo, sua interface do usuário do Criador de Perfil pode chamar CreateEventEx, especificando o nome do evento como

AppContainerNamedObjects\<acSid>\MyNamedEvent

<acSid> é a SID do AppContainer do aplicativo da Windows Store. Uma seção anterior deste tópico mostrou como iterar sobre os pacotes instalados do usuário atual. Nesse código de exemplo, você pode obter a packageId. E na packageId, você pode obter o <acSid> com código semelhante ao seguinte:

IntPtr acPSID;
DeriveAppContainerSidFromAppContainerName(packageId.FamilyName, out acPSID);

string acSid;
ConvertSidToStringSid(acPSID, out acSid);

string acDir;
GetAppContainerFolderPath(acSid, out acDir);

Sem notificações de desligamento

Ao executar dentro de um aplicativo da Windows Store, a DLL do Criador de Perfil não deve depender de ICorProfilerCallback::Shutdown ou até mesmo DllMain (com DLL_PROCESS_DETACH) ser chamado para notificar a DLL do Criador de Perfil de que o aplicativo da Windows Store está saindo. Na verdade, você deve esperar que eles nunca sejam chamados. Historicamente, muitas DLLs do Criador de Perfil têm usado essas notificações como locais convenientes para liberar caches em disco, fechar arquivos, enviar notificações de volta para a interface do usuário do Criador de Perfil etc. Mas agora a DLL do Profiler precisa ser organizada de maneira um pouco diferente.

Sua DLL do Criador de Perfil deve estar registrando informações em log à medida em que ela atua. Por motivos de desempenho, talvez seja interessante enviar informações em lote para a memória e liberá-la para o disco à medida que o lote cresce de tamanho além de algum limite. Mas suponha que qualquer informação ainda não liberada para o disco possa ser perdida. Isso significa que você vai querer escolher esse limite com sabedoria e que a interface do usuário do Criador de Perfil precisa ser protegida para lidar com informações incompletas escritas pela DLL do Criador de Perfil.

Arquivos de metadados do Windows Runtime

Está fora do escopo deste documento entrar em detalhes sobre quais são esses arquivos do WinMD (metadados do Windows Runtime). Esta seção está limitada à forma como a API de Criação de Perfil do CLR reage quando arquivos do WinMD são carregados pelo aplicativo da Windows Store que sua DLL do Criador de Perfil está analisando.

WinMDs gerenciados e não gerenciados

Se um desenvolvedor usa o Visual Studio para criar um projeto do Windows Runtime Component e uma compilação desse projeto gera um arquivo do WinMD que descreve os metadados (as descrições de tipo de classes, interfaces etc.) criados pelo desenvolvedor. Se esse projeto for um projeto de linguagem gerenciada escrito em C# ou Visual Basic, esse mesmo arquivo WinMD também conterá a implementação desses tipos (o que significa que ele contém todo o IL compilado do código-fonte do desenvolvedor). Esses arquivos são conhecidos como arquivos WinMD gerenciados. Eles são interessantes porque contêm metadados do Windows Runtime e a implementação subjacente.

Por outro lado, se um desenvolvedor criar um projeto do Windows Runtime Component para C++, uma compilação desse projeto produzirá um arquivo WinMD que contém apenas metadados e a implementação será compilada em uma DLL nativa separada. Da mesma forma, os arquivos WinMD que são fornecidos no SDK do Windows contêm apenas metadados, com a implementação compilada em DLLs nativas separadas que são enviadas como parte do Windows.

As informações abaixo se aplicam a WinMDs gerenciados, que contêm metadados e implementação, e a WinMDs não gerenciados, que contêm apenas metadados.

Os arquivos WinMD se parecem com módulos CLR

No que diz respeito ao CLR, todos os arquivos WinMD são módulos. Portanto, a API de Criação de Perfil do CLR informa à DLL do Criador de Perfil quando os arquivos WinMD são carregados e quais são suas ModuleIDs, da mesma forma que para outros módulos gerenciados.

Sua DLL do Criador de Perfil pode distinguir arquivos WinMD de outros módulos chamando o método ICorProfilerInfo3::GetModuleInfo2 e inspecionando o parâmetro de saída pdwModuleFlags para o sinalizador COR_PRF_MODULE_WINDOWS_RUNTIME. (Ele será definido se e somente se o ModuleID representar um WinMD.)

Lendo metadados do WinMDs

Os arquivos WinMD, como módulos regulares, contêm metadados que podem ser lidos por meio das APIs de Metadados. No entanto, o CLR mapeia os tipos do Windows Runtime para tipos do .NET Framework quando lê arquivos WinMD para que os desenvolvedores que programam em código gerenciado e consumam o arquivo WinMD possam ter uma experiência de programação mais natural. Para obter alguns exemplos desses mapeamentos, confira .Suporte do NET Framework para Aplicativos da Windows Store e do Windows Runtime.

Então, qual exibição o criador de perfil obterá quando usar as APIs de metadados: a exibição de Windows Runtime bruta ou a exibição de .NET Framework mapeada? A resposta é: cabe a você.

Ao chamar o método ICorProfilerInfo::GetModuleMetaData em um WinMD para obter uma interface de metadados, como IMetaDataImport, você pode optar por definir ofNoTransform no parâmetro dwOpenFlags para desativar esse mapeamento. Caso contrário, por padrão, o mapeamento será habilitado. Normalmente, um criador de perfil manterá o mapeamento habilitado para que as cadeias de caracteres obtidas pela DLL do Criador de Perfil dos metadados do WinMD (por exemplo, nomes de tipos) pareçam familiares e naturais para o usuário criador de perfil.

Modificando metadados de WinMDs

Não há suporte para modificar metadados de WinMDs. Se você chamar o método ICorProfilerInfo::GetModuleMetaData para um arquivo WinMD e especificar ofWrite no parâmetro dwOpenFlags ou solicitar uma interface de metadados gravável, como IMetaDataEmit, GetModuleMetaData falhará. Isso é de particular importância para os criadores de perfil de reescrita de IL, que precisam modificar metadados para dar suporte à instrumentação (por exemplo, para adicionar AssemblyRefs ou novos métodos). Portanto, você deve verificar COR_PRF_MODULE_WINDOWS_RUNTIME primeiro (conforme discutido na seção anterior) e evitar solicitar interfaces de metadados graváveis nesses módulos.

Resolvendo referências de assembly com WinMDs

Muitos criadores de perfil precisam resolver referências de metadados manualmente para auxiliar na instrumentação ou inspeção de tipos. Esses criadores de perfil precisam estar cientes de como o CLR resolve referências de assembly que apontam para WinMDs, pois essas referências são resolvidas de uma forma completamente diferente das referências de assembly padrão.

Criadores de perfil de memória

O coletor de lixo e o heap gerenciado não são fundamentalmente diferentes em um aplicativo da Windows Store e em um aplicativo de área de trabalho. No entanto, há algumas diferenças sutis que os autores do criador de perfil precisam estar cientes.

O ForceGC cria um thread gerenciado

Ao fazer criação de perfil de memória, a DLL do Criador de Perfil normalmente cria um thread separado para chamar o método ForceGC Method. Isso não é novidade. Mas o que pode ser surpreendente é que o ato de fazer uma coleta de lixo dentro de um aplicativo da Windows Store pode transformar seu thread em um thread gerenciado (por exemplo, um ThreadID de API de Criação de Perfil será criado para esse thread).

Para entender as consequências disso, é importante entender as diferenças entre chamadas síncronas e assíncronas, conforme definido pela API de Criação de Perfil do CLR. Observe que isso é muito diferente do conceito de chamadas assíncronas em aplicativos da Windows Store. Confira a postagem no blog Por que temos CORPROF_E_UNSUPPORTED_CALL_SEQUENCE para obter mais informações.

O ponto relevante é que as chamadas feitas em threads criados pelo criador de perfil são sempre consideradas síncronas, mesmo que essas chamadas sejam feitas de fora de uma implementação de um dos métodos ICorProfilerCallback da DLL do Criador de Perfil. Pelo menos, esse era o caso. Agora que o CLR transformou o thread do criador de perfil em um thread gerenciado devido à sua chamada ao ForceGC Method, esse thread não é mais considerado o thread do criador de perfil. Assim, o CLR impõe uma definição mais rigorosa do que se qualifica como síncrono para esse thread, ou seja, que uma chamada deve se originar de dentro de um dos métodos ICorProfilerCallback da DLL do Criador de Perfil para se qualificar como síncrona.

O que isso significa na prática? A maioria dos métodos ICorProfilerInfo só é segura para ser chamada de maneira síncrona e falhará imediatamente caso contrário. Portanto, se a DLL do Criador de Perfil reutilizar o thread do ForceGC Method para outras chamadas normalmente feitas em threads criados pelo criador de perfil (por exemplo, para RequestProfilerDetach, RequestReJIT ou RequestRevert), você terá problemas. Até mesmo uma função assíncrona segura, como DoStackSnapshot, tem regras especiais quando chamada de threads gerenciados. (Confira a postagem no blog Deslocamento da pilha do criador de perfil: noções básicas e além para obter mais informações.)

Portanto, recomendamos que qualquer thread criado pela DLL do Criador de Perfil para chamar o ForceGC Method seja usado apenas para a finalidade de disparar GCs e, em seguida, responder aos retornos de chamada do GC. Ele não deve chamar a API de Criação de Perfil para executar outras tarefas, como amostragem de pilha ou desanexação.

ConditionalWeakTableReferences

Do .NET Framework 4.5 em diante, há um novo retorno de chamada GC, ConditionalWeakTableElementReferences, que fornece ao criador de perfil informações mais completas sobre identificadores dependentes. Esses identificadores adicionam efetivamente uma referência de um objeto de origem a um objeto de destino para fins de gerenciamento de tempo de vida do GC. Os identificadores dependentes não são novidade e os desenvolvedores que programam em código gerenciado foram capazes de criar seus identificadores dependentes usando a classe System.Runtime.CompilerServices.ConditionalWeakTable<TKey,TValue> antes mesmo do Windows 8 e do .NET Framework 4.5.

No entanto, os aplicativos XAML gerenciados da Windows Store agora fazem uso intenso de identificadores dependentes. Em particular, o CLR os usa para auxiliar no gerenciamento de ciclos de referência entre objetos gerenciados e objetos de Windows Runtime não gerenciados. Isso significa que é mais importante agora do que nunca que os criadores de perfil de memória sejam informados dessas alças dependentes para que possam ser visualizadas junto com o restante das bordas no gráfico de heap. Sua DLL do Criador de Perfil deve usar RootReferences2, ObjectReferences e ConditionalWeakTableElementReferences juntos para formar uma exibição completa do gráfico de heap.

Conclusão

É possível usar a API de Criação de Perfil do CLR para analisar o código gerenciado em execução dentro de aplicativos da Windows Store. Na verdade, você pode usar um criador de perfil existente que está desenvolvendo e fazer algumas alterações específicas para que ele possa direcionar aplicativos da Windows Store. A interface do usuário do Criador de Perfil deve usar as novas APIs para ativar o aplicativo da Windows Store no modo de depuração. Certifique-se de que a DLL do Criador de Perfil consuma somente as APIs aplicáveis aos aplicativos da Windows Store. O mecanismo de comunicação entre a DLL do Criador de Perfil e a interface do usuário do Criador de Perfil deve ser gravado com as restrições de API do aplicativo da Windows Store em mente e com a conscientização sobre as permissões restritas em vigor para aplicativos da Windows Store. Sua DLL do Criador de Perfil deve estar ciente de como o CLR trata WinMDs e como o comportamento do Coletor de Lixo é diferente em relação aos threads gerenciados.

Recursos

O Common Language Runtime

A interação do CLR com o Windows Runtime

Aplicativos da Windows Store