Профилировщики CLR и приложения для Магазина Windows

В этом разделе описывается, что нужно думать при написании средств диагностики, которые анализируют управляемый код, работающий в приложении Магазина Windows. Он также предоставляет рекомендации по изменению существующих средств разработки, чтобы они продолжали работать при их запуске в приложениях Магазина Windows. Чтобы понять эту информацию, лучше всего ознакомиться с API профилирования среды cl language Runtime, вы уже использовали этот API в средстве диагностики, которое работает правильно в классических приложениях Windows, и вы теперь заинтересованы в изменении средства для правильной работы в приложениях Магазина Windows.

Введение

Если вы сделали это мимо вводного абзаца, то вы знакомы с API профилирования CLR. Вы уже написали средство диагностики, которое хорошо работает в управляемых классических приложениях. Теперь вам интересно, что делать, чтобы средство работало с управляемым приложением Магазина Windows. Возможно, вы уже пытались сделать эту работу, и обнаружили, что это не простая задача. Действительно, существует ряд соображений, которые могут быть не очевидны для всех разработчиков инструментов. Например:

  • Приложения Магазина Windows выполняются в контексте с серьезными разрешениями.

  • Файлы метаданных Windows имеют уникальные характеристики по сравнению с традиционными управляемыми модулями.

  • У приложений Магазина Windows есть привычка приостанавливать себя, когда интерактивность выходит из строя.

  • Механизмы взаимодействия между процессами больше не могут работать по различным причинам.

В этом разделе перечислены вещи, которые необходимо учитывать и как правильно справиться с ними.

Если вы не знакомы с API профилирования СРЕДЫ CLR, перейдите к ресурсам в конце этого раздела, чтобы найти более подробную информацию.

Сведения о конкретных API Windows и их использовании также находятся за пределами область этой статьи. Рассмотрим эту статью как отправную точку и обратитесь к MSDN, чтобы узнать больше о любых API Windows, на которые ссылается здесь.

Архитектура и терминология

Как правило, средство диагностики имеет архитектуру, как показано на следующем рисунке. Он использует термин "профилировщик", но многие такие средства выходят далеко за рамки типичной производительности или профилирования памяти в таких областях, как покрытие кода,макеть объектов, отладка по времени, мониторинг приложений и т. д. Для простоты этот раздел будет продолжать ссылаться на все эти средства в качестве профилировщиков.

В этой статье используется следующая терминология:

Приложение

Это приложение, которое профилировщик анализирует. Как правило, разработчик этого приложения теперь использует профилировщик для диагностики проблем с приложением. Традиционно это приложение будет классическим приложением Windows, но в этом разделе мы рассмотрим приложения Магазина Windows.

DLL профилировщика

Это компонент, который загружается в пространство процесса анализируемого приложения. Этот компонент, также известный как профилировщик "agent", реализует интерфейсы ICorProfilerCallback ICorProfilerCallbackInterface(2,3 и т. д.) и использует интерфейсы ICorProfilerInfo(2,3,3 и т. д.) для сбора данных о анализируемом приложении и потенциально изменения аспектов поведения приложения.

Пользовательский интерфейс профилировщика

Это классическое приложение, с которым взаимодействует пользователь профилировщика. Он отвечает за отображение состояния приложения пользователю и предоставление пользователю средств для управления поведением проанализированного приложения. Этот компонент всегда выполняется в собственном пространстве процесса, отдельно от пространства процесса профилируемого приложения. Пользовательский интерфейс Профилировщика также может выступать в качестве триггера подключения, который вызывает метод ICLRProfiling::AttachProfiler , чтобы привести к загрузке проанализированного приложения DLL Profiler в тех случаях, когда библиотека DLL профилировщика не загружалась при запуске.

Внимание

Пользовательский интерфейс Профилировщика должен оставаться классическим приложением Windows, даже если оно используется для управления и отчета в приложении Магазина Windows. Не ожидайте, что вы сможете упаковать и отправить средство диагностика в Магазине Windows. Средство должно выполнять действия, которые приложения Магазина Windows не могут сделать, и многие из этих элементов находятся в пользовательском интерфейсе Профилировщика.

В этом документе пример кода предполагает следующее:

  • Библиотека DLL Profiler написана на языке C++, так как она должна быть собственной библиотекой DLL в соответствии с требованиями API профилирования CLR.

  • Пользовательский интерфейс Профилировщика написан на C#. Это не обязательно, но потому что нет требований к языку для процесса профилировщика, почему бы не выбрать язык, который является кратким и простым?

Устройства Windows RT

Устройства Windows RT достаточно заблокированы. Сторонние профилировщики просто не могут загружаться на таких устройствах. В этом документе основное внимание уделяется компьютерам с Windows 8.

Использование API среда выполнения Windows

В нескольких сценариях, описанных в следующих разделах, классическое приложение профилировщика пользовательского интерфейса должно использовать некоторые новые среда выполнения Windows API. Вы хотите ознакомиться с документацией, чтобы понять, какие API среда выполнения Windows можно использовать из классических приложений, а также по-разному ли их поведение при вызове из классических приложений и приложений Магазина Windows.

Если пользовательский интерфейс Профилировщика написан в управляемом коде, потребуется выполнить несколько шагов, чтобы упростить использование этих api-интерфейсов среда выполнения Windows. Дополнительные сведения см. в статье об управляемых классических приложениях и среда выполнения Windows.

Загрузка DLL Профилировщика

В этом разделе описывается, как пользовательский интерфейс Профилировщика приводит к загрузке библиотеки DLL Профилировщика в Магазине Windows. Код, рассмотренный в этом разделе, относится к классическому приложению профилировщика пользовательского интерфейса и поэтому включает использование API Windows, безопасных для классических приложений, но не обязательно безопасных для приложений Магазина Windows.

Пользовательский интерфейс Профилировщика может привести к загрузке библиотеки DLL Профилировщика в пространство процессов приложения двумя способами:

  • При запуске приложения, как контролируется переменными среды.

  • Подключившись к приложению после запуска, вызовите метод ICLRProfiling::AttachProfiler .

Одна из первых блокировок будет получать загрузку и подключение библиотеки DLL Profiler для правильной работы с приложениями Магазина Windows. Обе формы загрузки совместно используют некоторые особые аспекты, поэтому начнем с них.

Распространенные рекомендации по запуску и присоединению нагрузки

Подписывание БИБЛИОТЕКи DLL Профилировщика

Когда Windows пытается загрузить библиотеку DLL Профилировщика, она проверяет правильность подписи dll профилировщика. В противном случае загрузка завершается ошибкой по умолчанию. Это можно сделать двумя способами.

  • Убедитесь, что библиотека DLL Profiler подписана.

  • Сообщите пользователю, что перед использованием средства необходимо установить лицензию разработчика на своем компьютере с Windows 8. Это можно сделать автоматически из Visual Studio или вручную из командной строки. Дополнительные сведения см. в разделе "Получение лицензии разработчика".

Разрешения файловой системы

Приложение Магазина Windows должно иметь разрешение на загрузку и выполнение DLL Profiler из расположения в файловой системе, в которой он находится по умолчанию, приложение Магазина Windows не имеет такого разрешения на большинство каталогов, и любая неудачная попытка загрузить библиотеку DLL Profiler создаст запись в журнале событий приложения Windows, который выглядит примерно так:

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

Как правило, приложения Магазина Windows могут получить доступ только к ограниченному набору расположений на диске. Каждое приложение Магазина Windows может получить доступ к собственным папкам данных приложения, а также к нескольким другим областям в файловой системе, для которой предоставляются все приложения Магазина Windows. Лучше установить библиотеку DLL Profiler и ее зависимости в разделе Program Files или Program Files (x86), так как все приложения Магазина Windows имеют разрешения на чтение и выполнение там по умолчанию.

Загрузка запуска

Как правило, в классическом приложении пользовательский интерфейс Профилировщика запрашивает загрузку библиотеки DLL Профилировщика путем инициализации блока среды среды CLR, COR_PROFILERCOR_ENABLE_PROFILINGсодержащего необходимые переменные среды API профилирования CLR (т. е. и COR_PROFILER_PATH), а затем создав новый процесс с этим блоком среды. То же самое относится к приложениям Магазина Windows, но механизмы отличаются.

Не запускайте повышенные привилегии

Если процесс A пытается создать процесс приложения Магазина Windows B, процесс A должен выполняться на среднем уровне целостности, а не на высоком уровне целостности (т. е. не с повышенными привилегиями). Это означает, что пользовательский интерфейс Профилировщика должен работать на среднем уровне целостности, или он должен создать другой рабочий процесс на среднем уровне целостности, чтобы обеспечить запуск приложения Магазина Windows.

Выбор приложения Магазина Windows для профилирования

Во-первых, вам потребуется попросить пользователя профилировщика запустить приложение Магазина Windows. Для классических приложений, возможно, отображается диалоговое окно обзора файлов, и пользователь найдет и выберите файл .exe. Но приложения Магазина Windows отличаются, и использование диалогового окна обзора не имеет смысла. Вместо этого лучше показать пользователю список приложений Магазина Windows, установленных для этого пользователя.

Для создания этого списка можно использовать PackageManager класс. PackageManager— это класс среда выполнения Windows, доступный для классических приложений, и на самом деле он доступен только классическим приложениям.

В следующем примере кода из гипотетического пользовательского интерфейса Profiler, написанного как классическое приложение на C#, используется PackageManager для создания списка приложений Windows:

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

Указание настраиваемого блока среды

Новый com-интерфейс IPackageDebug Параметры позволяет настроить поведение выполнения приложения Магазина Windows, чтобы упростить некоторые формы диагностика. Один из его методов EnableDebugging позволяет передать блок среды в приложение Магазина Windows при запуске, а также другие полезные эффекты, такие как отключение автоматического приостановки процесса. Блок среды важен, так как в этом месте необходимо указать переменные среды (COR_PROFILER, COR_ENABLE_PROFILINGи COR_PROFILER_PATH)), используемые средой CLR для загрузки библиотеки DLL Профилировщика.

Рассмотрим следующий фрагмент кода:

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

Есть несколько элементов, которые вам потребуется получить правильно:

  • packageFullName можно определить при переборе пакетов и захвате package.Id.FullName.

  • debuggerCommandLine немного интереснее. Чтобы передать пользовательский блок среды в приложение Магазина Windows, необходимо написать собственный простой отладчик. Windows создает приостановленное приложение Магазина Windows, а затем присоединяет отладчик, запуская отладчик с помощью командной строки, как в следующем примере:

    MyDummyDebugger.exe -p 1336 -tid 1424
    

    где -p 1336 означает, что приложение Магазина Windows имеет идентификатор процесса 1336 и -tid 1424 означает, что идентификатор потока 1424 — это приостановленный поток. Фиктивный отладчик будет анализировать ThreadID из командной строки, возобновить этот поток, а затем выйти.

    Ниже приведен пример кода C++ для этого (обязательно добавьте ошибку проверка ing!):

    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;
    }
    

    Необходимо развернуть этот фиктивный отладчик в рамках установки средства диагностика, а затем указать путь к этому отладчику в параметреdebuggerCommandLine.

Запуск приложения Магазина Windows

Момент запуска приложения Магазина Windows, наконец, прибыл. Если вы уже попытались сделать это самостоятельно, возможно, вы заметили, что CreateProcess не способ создания процесса приложения Магазина Windows. Вместо этого необходимо использовать метод IApplicationActivationManager::ActivateApplication . Для этого необходимо получить идентификатор пользовательской модели приложения для приложения Магазина Windows, которое вы запускаете. И это означает, что вам потребуется немного прокопать манифест.

При итерации пакетов (см. статью "Выбор приложения Магазина Windows для профиля" в разделе " Загрузка запуска" ранее), необходимо получить набор приложений, содержащихся в манифесте текущего пакета:

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();

Да, один пакет может иметь несколько приложений, и каждый из них имеет собственный идентификатор пользовательской модели приложения. Таким образом, вы хотите попросить пользователя, какое приложение профилировать, и захватить идентификатор пользовательской модели приложения из этого конкретного приложения:

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

Наконец, теперь у вас есть то, что вам нужно запустить приложение Магазина Windows:

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

Не забудьте вызвать DisableDebugging

При вызове IPackageDebug Параметры::EnableDebugging вы пообещали очистить после себя, вызвав метод IPackageDebug Параметры::D isableDebugging, поэтому обязательно сделайте это при завершении сеанса профилирования.

Присоединение нагрузки

Когда пользовательский интерфейс Profiler хочет присоединить библиотеку DLL Profiler к приложению, которое уже запущено, он использует ICLRProfiling::AttachProfiler. То же самое относится к приложениям Магазина Windows. Но в дополнение к общим рекомендациям, перечисленным ранее, убедитесь, что целевое приложение Магазина Windows не приостановлено.

EnableDebugging

Как и при загрузке запуска, вызовите метод IPackageDebug Параметры::EnableDebugging. Для передачи блока среды его не требуется, но вам нужна одна из других функций: отключение автоматической приостановки процесса. В противном случае, когда пользовательский интерфейс Профилировщика вызывает AttachProfiler, целевое приложение Магазина Windows может быть приостановлено. На самом деле это, вероятно, если пользователь взаимодействует с пользовательским интерфейсом Профилировщика, а приложение Магазина Windows не активно на экранах пользователя. И если приложение Магазина Windows приостановлено, оно не сможет реагировать на какой-либо сигнал о том, что среда CLR отправляет в него подключение библиотеки DLL Профилировщика.

Таким образом, вы хотите сделать что-то подобное:

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

Это тот же вызов, который вы сделаете для регистра загрузки запуска, за исключением того, что вы не указываете командную строку отладчика или блок среды.

DisableDebugging

Как всегда, не забудьте вызвать IPackageDebug Параметры::D isableDebugging при завершении сеанса профилирования.

Запуск внутри приложения Магазина Windows

Поэтому приложение Магазина Windows, наконец, загрузило библиотеку DLL Профилировщика. Теперь библиотеку DLL Профилировщика необходимо научить играть с различными правилами, необходимыми для приложений Магазина Windows, включая разрешенные API и способы выполнения с ограниченными разрешениями.

Придерживаться API приложений Магазина Windows

При просмотре API Windows вы заметите, что каждый API документируется как применимый к классическим приложениям, приложениям Магазина Windows или обоим приложениям. Например, раздел "Требования" документации для функции InitializeCriticalSectionAndSpinCount указывает, что функция применяется только к классическим приложениям. Напротив, функция InitializeCriticalSectionEx доступна как для классических приложений, так и для приложений Магазина Windows.

При разработке библиотеки DLL Profiler обработайте его так, как если бы это приложение Магазина Windows, и используйте только API, которые документируются как доступные приложениям Магазина Windows. Анализ зависимостей (например, вы можете запустить link /dump /imports библиотеку DLL Профилировщика для аудита), а затем выполните поиск в документации, чтобы узнать, какие из зависимостей не нужны. В большинстве случаев нарушения можно исправить, просто заменив их более новой формой API, которая задокументирована как безопасная (например, замена InitializeCriticalSectionAndSpinCount на InitializeCriticalSectionEx).

Вы можете заметить, что библиотека DLL Profiler вызывает некоторые API, которые применяются только к классическим приложениям, и все же они работают, даже если библиотека DLL Profiler загружается в приложение Магазина Windows. Помните, что при загрузке в процесс приложения Магазина Windows при загрузке в процесс приложения Магазина Windows рисковать использовать любой API, не документированные для использования с приложениями Магазина Windows, в библиотеке DLL Профилировщика:

  • Такие API не гарантируют работу при вызове в уникальном контексте, в который выполняются приложения Магазина Windows.

  • Такие API могут работать не последовательно при вызове из разных процессов приложения Магазина Windows.

  • Такие API могут работать хорошо из приложений Магазина Windows в текущей версии Windows, но могут быть остановлены или отключены в будущих выпусках Windows.

Лучший совет заключается в том, чтобы исправить все ваши нарушения и избежать риска.

Вы можете найти, что вы абсолютно не можете сделать без определенного API и не можете найти замену, подходящую для приложений Магазина Windows. В таком случае по крайней мере:

  • Тестирование, тестирование, тестирование дневного света из использования этого API.

  • Понять, что API может внезапно нарушить или исчезнуть, если он вызывается из приложений Магазина Windows в будущих выпусках Windows. Это не будет считаться проблемой совместимости корпорацией Майкрософт, и поддержка использования не будет приоритетом.

Сокращенные разрешения

За пределами область этого раздела можно перечислить все способы, которыми отличаются разрешения приложений Магазина Windows от классических приложений. Но, конечно, поведение будет отличаться каждый раз, когда библиотека DLL Profiler (при загрузке в приложение Магазина Windows по сравнению с классическим приложением) пытается получить доступ к любым ресурсам. Файловая система является наиболее распространенным примером. На диске есть только несколько мест, к которым разрешен доступ определенного приложения Магазина Windows (см. сведения о доступе к файлам и разрешениях (среда выполнения Windows приложениях), а библиотека DLL Profiler будет находиться под теми же ограничениями. Тщательно протестируйте код.

Межпроцессное взаимодействие

Как показано на схеме в начале этого документа, библиотека DLL Профилировщика (загруженная в пространство процесса приложения Магазина Windows), скорее всего, потребуется взаимодействовать с пользовательским интерфейсом Профилировщика (запущено в отдельном пространстве процесса классического приложения) через собственный канал обмена данными между процессами (IPC). Пользовательский интерфейс Profiler отправляет сигналы библиотеке DLL Profiler для изменения его поведения, а библиотека DLL Profiler отправляет данные из проанализированного приложения Магазина Windows обратно в пользовательский интерфейс Profiler для последующей обработки и отображения пользователю профилировщика.

Большинство профилировщиков должны работать таким образом, но ваши варианты для механизмов IPC являются более ограниченными при загрузке библиотеки DLL Profiler в приложение Магазина Windows. Например, именованные каналы не являются частью пакета SDK для приложений Магазина Windows, поэтому их нельзя использовать.

Но, конечно, файлы по-прежнему находятся, хотя и в более ограниченной форме. Также доступны события.

Обмен данными с помощью файлов

Большая часть данных, скорее всего, будет передаваться между DLL Profiler и пользовательским интерфейсом Profiler через файлы. Ключ заключается в том, чтобы выбрать расположение файла, в которое входит библиотека DLL Профилировщика (в контексте приложения Магазина Windows), а пользовательский интерфейс Профилировщика имеет доступ на чтение и запись. Например, путь к временной папке — это расположение, к которому можно получить доступ как к пользовательскому интерфейсу Профилировщика, так и к пользовательскому интерфейсу Профилировщика, но к другому пакету приложений Магазина Windows не удается получить доступ (таким образом экранирование любых сведений, которые вы регистрируете из других пакетов приложений Магазина Windows).

Пользовательский интерфейс Профилировщика и БИБЛИОТЕКА DLL Profiler могут самостоятельно определять этот путь. Пользовательский интерфейс Профилировщика, когда он выполняет итерацию по всем пакетам, установленным для текущего пользователя (см. пример кода ранее), получает доступ к PackageId классу, из которого путь к временной папке можно получить с кодом, аналогичным этому фрагменту кода. (Как всегда, ошибка проверка ing опущена для краткости.)

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

tempDir = appData.TemporaryFolder.Path;

Между тем библиотека DLL Профилировщика может сделать в основном то же самое, хотя это может проще добраться до ApplicationData класса с помощью свойства ApplicationData.Current .

Обмен данными с помощью событий

Если требуется простая семантика сигналов между пользовательским интерфейсом Profiler и DLL Profiler, можно использовать события в приложениях Магазина Windows, а также классические приложения.

Из библиотеки DLL Profiler можно просто вызвать функцию CreateEventEx , чтобы создать именованное событие с любым именем, которое вам нравится. Например:

// 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);

Затем пользовательский интерфейс профилировщика должен найти это именованное событие в пространстве имен приложения Магазина Windows. Например, пользовательский интерфейс Profiler может вызвать CreateEventEx, указав имя события в качестве имени события.

AppContainerNamedObjects\<acSid>\MyNamedEvent

<acSid> — это идентификатор безопасности appContainer приложения Магазина Windows. В предыдущем разделе этого раздела показано, как выполнить итерацию по пакетам, установленным для текущего пользователя. В этом примере кода можно получить идентификатор пакета. И из packageId можно получить код, аналогичный <acSid> следующему:

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

string acSid;
ConvertSidToStringSid(acPSID, out acSid);

string acDir;
GetAppContainerFolderPath(acSid, out acDir);

Нет уведомлений о завершении работы

При запуске в приложении Магазина Windows библиотека DLL Profiler не должна полагаться на ICorProfilerCallback::Shutdown или даже DllMainDLL_PROCESS_DETACH) для уведомления библиотеки DLL Profiler о выходе из приложения Магазина Windows. На самом деле, вы должны ожидать, что они никогда не будут называться. Исторически многие библиотеки DLL профилировщика использовали эти уведомления как удобные места для очистки кэшей на диск, закрытия файлов, отправки уведомлений обратно в пользовательский интерфейс Профилировщика и т. д. Но теперь библиотека DLL Профилировщика должна быть организована немного по-другому.

Библиотека DLL Профилировщика должна быть ведения журнала по мере ее использования. По соображениям производительности может потребоваться пакетная информация в памяти и очистить его на диск, так как пакет увеличивается в размере до некоторого порогового значения. Но предположим, что какие-либо сведения еще не промыты на диск могут быть потеряны. Это означает, что вы хотите правильно выбрать пороговое значение, и что пользовательский интерфейс Профилировщика должен быть затверден, чтобы иметь дело с неполными сведениями, написанными библиотекой DLL Profiler.

файлы метаданных среда выполнения Windows

Сведения о том, какие среда выполнения Windows файлы метаданных (WinMD) находятся вне область этого документа. Этот раздел ограничен тем, как API профилирования CLR реагирует, когда файлы WinMD загружаются приложением Магазина Windows, которое анализирует DLL Профилировщика.

Управляемые и неуправляемые WinMDs

Если разработчик использует Visual Studio для создания нового проекта компонента среда выполнения Windows, сборка этого проекта создает файл WinMD, описывающий метаданные (описания типов классов, интерфейсов и т. д.), созданных разработчиком. Если этот проект является управляемым языковым проектом, написанным на C# или Visual Basic, то этот же файл WinMD также содержит реализацию этих типов (то есть содержит все il, скомпилированные из исходного кода разработчика). Такие файлы называются управляемыми файлами WinMD. Они интересны в том, что они содержат как среда выполнения Windows метаданные, так и базовую реализацию.

В отличие от этого, если разработчик создает проект компонента среда выполнения Windows для C++, сборка этого проекта создает файл WinMD, содержащий только метаданные, и реализация компилируется в отдельную собственную библиотеку DLL. Аналогичным образом файлы WinMD, которые предоставляются в пакете SDK для Windows, содержат только метаданные, при этом реализация компилируется в отдельные собственные библиотеки DLL, которые предоставляются в составе Windows.

Приведенные ниже сведения относятся как к управляемым winMD, которые содержат метаданные и реализацию, так и к неуправляемых winMD, которые содержат только метаданные.

Файлы WinMD выглядят как модули CLR

Что касается среды CLR, все файлы WinMD являются модулями. ПОЭТОМУ API профилирования СРЕДЫ CLR сообщает библиотеке DLL Profiler при загрузке файлов WinMD и их идентификаторах moduleID таким же образом, как и для других управляемых модулей.

Библиотека DLL Profiler может отличать файлы WinMD от других модулей, вызвав метод ICorProfilerInfo3::GetModuleInfo2 и проверяя выходной pdwModuleFlags параметр для флага COR_PRF_MODULE_WINDOWS_RUNTIME . (Если и только в том случае, если модульID представляет WinMD.)

Чтение метаданных из WinMD

Файлы WinMD, такие как обычные модули, содержат метаданные, которые можно считывать с помощью API метаданных. Однако среда CLR сопоставляет типы среда выполнения Windows с типами платформа .NET Framework при чтении файлов WinMD, чтобы разработчики, которые программировали в управляемом коде и потребляли winMD-файл, могут иметь более естественный интерфейс программирования. Примеры этих сопоставлений см. в разделе платформа .NET Framework Поддержка приложений Магазина Windows и среда выполнения Windows.

Таким образом, какое представление будет получать профилировщик при использовании API метаданных: необработанное среда выполнения Windows представление или сопоставленное представление платформа .NET Framework? Ответ: это до вас.

При вызове метода ICorProfilerInfo::GetModuleMetaData в WinMD для получения интерфейса метаданных, например IMetaDataImport, можно выбрать наборNoTransform в параметреdwOpenFlags, чтобы отключить это сопоставление. В противном случае по умолчанию сопоставление будет включено. Как правило, профилировщик будет поддерживать сопоставление, чтобы строки, полученные библиотекой DLL Profiler из метаданных WinMD (например, имена типов), выглядели знакомыми и естественными для пользователя профилировщика.

Изменение метаданных из WinMDs

Изменение метаданных в WinMDs не поддерживается. При вызове метода ICorProfilerInfo::GetModuleMetaData для файла WinMD и указанияWrite в dwOpenFlags параметре или запросите интерфейс метаданных, доступный для записи, например IMetaDataEmit, GetModuleMetaData завершится ошибкой. Это особенно важно для профилировщиков перезаписи IL, которые должны изменять метаданные для поддержки инструментирования (например, для добавления AssemblyRefs или новых методов). Поэтому сначала следует проверка для COR_PRF_MODULE_WINDOWS_RUNTIME (как описано в предыдущем разделе) и воздержаться от запроса интерфейсов метаданных для записи в таких модулях.

Разрешение ссылок на сборки с помощью WinMD

Многие профилировщики должны разрешать ссылки на метаданные вручную, чтобы помочь с инструментированием или проверкой типов. Такие профилировщики должны знать, как среда CLR разрешает ссылки на сборки, указывающие на WinMD, так как эти ссылки разрешаются совершенно иначе, чем стандартные ссылки на сборки.

Профилировщики памяти

Сборщик мусора и управляемая куча не отличаются в основном в приложении Магазина Windows и классическом приложении. Однако есть некоторые тонкие различия, о которых авторы профилировщика должны знать.

ForceGC создает управляемый поток

При профилировании памяти библиотека DLL Profiler обычно создает отдельный поток, из которого вызывается метод Метода ForceGC. Это ничего нового. Но что может быть удивительно, что действие сборки мусора внутри приложения Магазина Windows может преобразовать поток в управляемый поток (например, поток профилирования API ThreadID будет создан для этого потока).

Чтобы понять последствия этого, важно понимать различия между синхронными и асинхронными вызовами, определенными API профилирования CLR. Обратите внимание, что это очень отличается от концепции асинхронных вызовов в приложениях Магазина Windows. Дополнительные сведения см. в записи блога "Почему у нас есть CORPROF_E_UNSUPPORTED_CALL_SEQUENCE ".

Соответствующая точка заключается в том, что вызовы, созданные вашим профилировщиком, всегда считаются синхронными, даже если эти вызовы выполняются вне реализации одного из методов ICorProfilerCallback библиотеки DLL Profiler. По крайней мере, это было так. Теперь, когда поток CLR превратил поток профилировщика в управляемый поток из-за вызова метода ForceGC, этот поток больше не считается потоком профилировщика. Таким образом, среда CLR применяет более строгое определение того, что квалифицируется как синхронный для этого потока, а именно то, что вызов должен исходить из одного из методов ICorProfilerCallback библиотеки Profiler, чтобы квалифицировать как синхронный.

Что это означает на практике? Большинство методов ICorProfilerInfo безопасно вызываться синхронно и немедленно завершится ошибкой в противном случае. Поэтому если библиотека DLL Profiler повторно использует поток метода ForceGC для других вызовов, которые обычно выполняются в потоках, созданных профилировщиком (например, requestProfilerDetach, RequestReJIT или RequestRevert), у вас возникнут проблемы. Даже асинхронная безопасная функция, например DoStackSnapshot , имеет специальные правила при вызове из управляемых потоков. (См. запись блогаСтек профилировщика: Основные сведения и дополнительные сведения.)

Поэтому рекомендуется использовать любой поток, создаваемый библиотекой DLL Profiler для вызова метода ForceGC, только для активации GCs, а затем реагирования на обратные вызовы GC. Он не должен вызывать API профилирования для выполнения других задач, таких как выборка стека или отключение.

ConditionalWeakTableReferences

Начиная с платформа .NET Framework 4.5, существует новый обратный вызов GC, ConditionalWeakTableElementReferences, который дает профилировщику более полную информацию о зависимых дескрипторах. Эти дескрипторы фактически добавляют ссылку из исходного объекта в целевой объект для управления временем существования GC. Зависимые дескрипторы не являются новыми, и разработчики, которые программируют в управляемом коде, смогли создать собственные зависимые дескрипторы с помощью System.Runtime.CompilerServices.ConditionalWeakTable<TKey,TValue> класса даже до Windows 8 и платформа .NET Framework 4.5.

Однако управляемые приложения Магазина Windows xaml теперь используют зависимые дескрипторы. В частности, среда CLR использует их для управления циклами ссылок между управляемыми объектами и неуправляемыми среда выполнения Windows объектами. Это означает, что сейчас важнее, чем когда-либо для профилировщиков памяти, чтобы получать сведения об этих зависимых дескрипторах, чтобы их можно было визуализировать вместе с остальными краями в графе кучи. Библиотека DLL Профилировщика должна использовать RootReferences2, ObjectReferences и ConditionalWeakTableElementReferences вместе для формирования полного представления графа кучи.

Заключение

Api профилирования СРЕДЫ CLR можно использовать для анализа управляемого кода, работающего в приложениях Магазина Windows. На самом деле можно использовать существующий профилировщик, который вы разрабатываете и вносите некоторые конкретные изменения, чтобы оно направлено на приложения Магазина Windows. Пользовательский интерфейс Профилировщика должен использовать новые API для активации приложения Магазина Windows в режиме отладки. Убедитесь, что библиотека DLL Профилировщика использует только те API, которые применимы для приложений Магазина Windows. Механизм взаимодействия между библиотекой DLL Профилировщика и пользовательским интерфейсом Profiler должен быть написан с учетом ограничений API приложений Магазина Windows и с учетом ограничений разрешений, доступных для приложений Магазина Windows. Библиотека DLL Профилировщика должна учитывать, как среда CLR обрабатывает WinMDs и как поведение сборщика мусора отличается от управляемых потоков.

Ресурсы

Среда CLR

Взаимодействие среды CLR с среда выполнения Windows

Приложения для Магазина Windows