Что такое microsoft windows desktop runtime

Windows Runtime

Стиль этой статьи неэнциклопедичен или нарушает нормы русского языка.

Windows Runtime, или WinRT — это новая(по состоянию на 2011 год) модель программирования от Microsoft, являющаяся основой для разработки приложений в стиле Метро в новой операционной системе Windows 8 [1] [2] . WinRT поддерживает разработку на C++ (обычно с использованием расширения языка Component Extensions, C++/CX), управляемых языках C# и VB.NET, а также JavaScript.

WinRT по существу является API на основе технологии COM. Из-за своей COM-подобной основы, WinRT позволяет относительно легко обращаться к нему из различных языков программирования, как это происходит в COM, но это, по существу, неуправляемый, родной API. Определения API хранятся в «.winmd» файлах, закодированных в формате метаданных ECMA 335, который используется в .Net с некоторыми изменениями. [3] Этот общий формат метаданных позволяет значительно уменьшить накладные расходы при вызове WinRT из .NET приложений по сравнению с P/Invoke, имея при этом намного более простой синтаксис. [4] Новый язык C++/CX (Component Extensions), который заимствует некоторые элементы синтаксиса из C++/CLI, позволяет создавать и использовать WinRT-компоненты с меньшим количеством видимой для программиста обвязки по сравнению с классическим программированием COM в C++, и в то же время накладывает меньше ограничений по сравнению с C++/CLI на смешение типов. Обычный С++ (с COM-специфичными требованиями) также может быть использован для программирования с компонентами WinRT. [5] Это возможно с помощью новой библиотеки шаблонов Windows Runtime C++ Template Library (WRL), которая аналогична по своей цели тому, что библиотека ATL обеспечивает для COM. [6] Документация MSDN однако рекомендует использовать C++/CX вместо WRL. [7]

Примечания

  1. Abel AvramDesign Details of the Windows Runtime. InfoQ (21 September 2011). Архивировано из первоисточника 11 сентября 2012.
  2. Brian Klug & Ryan SmithMicrosoft BUILD: Windows 8, A Pre-Beta Preview. AnandTech (13 September 2011). Архивировано из первоисточника 11 сентября 2012.
  3. WinRT demystified — Miguel de Icaza
  4. http://social.msdn.microsoft.com/Forums/en-US/winappswithcsharp/thread/d510d916-a090-412c-a17f-e4421ad9a137/
  5. Visual C++ and WinRT/Metro — Some fundamentals — CodeProject®
  6. Using the Windows Runtime from C++ | BUILD2011 | Channel 9
  7. Windows Runtime C++ Template Library

Ссылки

Wikimedia Foundation . 2010 .

Смотреть что такое «Windows Runtime» в других словарях:

Windows Runtime — Entwickler Microsoft Corporation Aktuelle Vorabversion 6.2.8102.0 (30. August 2011) Betriebssystem Microsoft Windows 8 Developer Preview Kategorie Laufzeitumgebung Lizenz … Deutsch Wikipedia

Windows 2.0 — Part of the Microsoft Windows family … Wikipedia

Windows 2.0 — Windows 2.x Bildschirmfoto … Deutsch Wikipedia

Windows 2.x — Bildschirmfoto … Deutsch Wikipedia

Windows Store — Entwickler Microsoft Corporation Betriebssystem Windows 8 (Developer Preview) Der Windows Store (von Windows nach dem gleichnamigen Betriebssystem und engl. Store = Geschäft) ist ein zukünftiges Internet Verkaufsportal vom Softwarehersteller… … Deutsch Wikipedia

Windows RT — Разработчик Microsoft Семейство ОС Windows Исходный код Закрытый исходный код Первый выпуск 26 октября 2012 года[1] Поддерживаемые языки … Википедия

Windows PowerShell — Screenshot of a sample PowerShell session … Wikipedia

Windows Vista — Part of the Microsoft Windows family … Wikipedia

Windows PowerShell — Windows PowerShell … Википедия

Windows Media Player — A component of Microsoft Windows Details … Wikipedia

Модель приложений Windows Runtime

Наша жизнь наполнена абстракциями. Как разработчики мы часто вынуждены бороться со всяческими проблемами, используя абстракции, о которых мы по большому счету ничего не знаем. Абстракции иногда разваливаются и оказываются не в состоянии полностью скрыть нижележащие сложности. Не поймите меня неправильно, абстракции — великая вещь. Они помогают и пользователям, и разработчикам, но вы здорово облегчите себе жизнь, если вникнете в те абстракции, на которые вы регулярно опираетесь в своей работе, и четко поймете, как именно они действуют. Более того, библиотеки, авторы которых приняли эту реальность, зачастую куда успешнее тех, где этого не сделано, и отчасти это связано с тем, что такие библиотеки позволяют входить в абстракцию при пошаговой отладке, если в том возникает необходимость.

Одна из таких абстракций — Windows Runtime (WinRT), и сегодня я собираюсь проиллюстрировать это, рассмотрев базовую модель приложений WinRT. Она построена вокруг класса CoreWindow, экземпляр которого находится внутри каждого «современного» приложения Windows Store и Windows Phone. Тем не менее, сравнительно немногие знают о его существовании, и еще меньше, как он работает. Видимо, это можно считать критерием успеха абстракции.

Со времени первого объявления Windows 8 API в 2011 году многое было сказано и написано о различных языковых проекциях, предоставляющих абстракцию над Windows Runtime. Однако лучший способ понять Windows Runtime — отказаться от языковых проекций, включая C++/CX, и использовать стандартный C++ в сочетании с традиционной COM. Только C++ позволяет раздвинуть плотные шторы и увидеть, что происходит на самом деле (с технической точки зрения, то же самое можно сделать и на C, но это было бы излишне болезненно). Возможно, вы все равно предпочтете использовать ту или иную языковую проекцию (скорее всего, C++/CX), но по крайней мере у вас будет гораздо более четкое понимание происходящего.

Для начала откройте Visual Studio 2012 и создайте новый проект Visual C++ для приложения Windows Store или Windows Phone. Не важно, какой шаблон вы используете. Как только он загрузится, перейдите в Solution Explorer и удалите все, что не существенно. Если вы выбрали шаблон на основе XAML, удалите все XAML-файлы. Вы также можете удалить все файлы исходного кода на C++. Вероятно, вы предпочтете сохранить предкомпилированный заголовочный файл, но обязательно удалите все его содержимое. У вас должны остаться лишь ресурсы пакета, необходимые для развертывания приложения, изображения, сертификата и XML-манифеста.

Читайте также:  Windows 10 steam problems

Затем откройте страницы свойств проекта и выберите свойства компилятора — узел C/C++ в дереве слева. Найдите строку для ключа компилятора /ZW — Consume Windows Runtime Extension — и укажите No, чтобы отключить языковые расширения C++/CX. Тем самым вы будете уверены, что ничего загадочного, помимо мистических чудес стандартного компилятора C++, не происходит. Там же установите уровень предупреждений компилятора /W4.

Если вы попробуете скомпилировать проект, то должны увидеть приветствие от компоновщика, который сообщает об ошибке из-за того, что не удалось найти функцию точки входа в проект — WinMain. Добавьте в проект новый файл исходного кода на C++ и первым делом поместите в него недостающую функцию WinMain:

Как видите, это традиционная функция WinMain для Windows-приложения на основе C Runtime Libraries (CRT). Конечно, HINSTANCE и PWSTR не являются фундаментальными типами C++, поэтому вам придется включить заголовочный файл windows.h:

Если вы сохранили предкомпилированный заголовочный файл проекта, то можете включить его здесь. Я также буду использовать ComPtr из Windows Runtime C++ Template Library (WRL), поэтому сейчас самое время включить и его:

Подробнее о WRL я буду рассказывать в следующих статьях из этой рубрики. А пока я буду просто использовать шаблон класса ComPtr для поддержки указателя на COM-интерфейс. На этом этапе достаточно знать, что WRL ComPtr — это просто смарт-указатель на COM-интерфейс. Хотя он предоставляет некоторые средства, уникальные для Windows Runtime, я не стану использовать их в этот раз. С тем же успехом вы могли бы задействовать CComPtr из Active Template Library (ATL) или любой другой смарт-указатель на COM-интерфейс по своему выбору. WRL ComPtr определен в пространстве имен Microsoft::WRL:

Я также буду использовать макрос ASSERT и функцию HR для обработки ошибок. Об этом я уже говорил, поэтому не буду повторяться. Если вы не уверены в этих этапах, прочитайте мою статью в этой рубрике за май 2013 г. «Introducing Direct2D 1.1» (msdn.microsoft.com/magazine/dn198239).

Наконец, чтобы применять любую из упоминаемых в этой статье WinRT-функций, вы должны передать компоновщику имя файла .lib:

Первое, что ожидает модель приложений, — MTA (multithreaded apartment). Правильно, в ней находится COM-модель изоляции потоков (COM apartment model). Windows Runtime предоставляет функцию RoInitialize, которая является тонкой оболочкой CoInitializeEx:

Несмотря на тот факт, что обычно достаточно CoInitializeEx, я предлагаю вам использовать RoInitialize. Эта функция позволит поддерживать будущие усовершенствования в Windows Runtime без потенциальной угрозы поломать традиционную COM. Она аналогична OleInitialize, которая тоже вызывает CoInitializeEx и кое-что еще. Смысл в том, чтобы в основном потоке вашего приложения не было ничего загадочного. Единственное, что может слегка удивить, — это не STA (single-threaded apartment). Не волнуйтесь, окно вашего приложения по-прежнему будет выполняться в STA-потоке, но создавать его будет Windows Runtime. Эта STA — на самом деле Application STA (ASTA), и она немного отличается от чистой STA, но об этом позже.

Следующая часть посложнее. В Windows Runtime отказались от традиционной модели активации COM, в которой применяются идентификаторы классов на основе GUID, в пользу модели, где активация происходит по текстовым идентификаторам классов. Текстовые имена базируются на именах классов с областью видимости в пределах пространств имен, ставших столь популярными благодаря Java и Microsoft .NET Framework, но, прежде чем вы попытаетесь распрощаться с реестром, учтите, что эти новые идентификаторы классов по-прежнему хранятся в реестре. С технической точки зрения, в реестре регистрируются только основные типы (first-party types), тогда как сторонние типы (third-party types) регистрируются лишь в манифесте конкретного приложения. У этого изменения есть свои преимущества и недостатки. Один из недостатков в том, что описывать идентификатор класса при вызове WinRT-функции немного труднее. В Windows Runtime определен новый строковый тип, поддерживающий удаленное взаимодействие (remotable string type), который заменил традиционный строковый тип BSTR, и любые идентификаторы классов нужно предоставлять, используя этот новый «носитель». HSTRING (так он называется) гораздо меньше подвержен ошибкам, чем BSTR, — главным образом потому, что он является неизменяемым (immutable). Простейший способ создать HSTRING — вызвать функцию WindowsCreateString:

WindowsCreateString выделяет достаточно памяти для хранения копии исходной строки и null-символа, завершающего строку, а затем копирует исходную строку в этот буфер. Чтобы освободить этот вспомогательный буфер, вы должны вызвать WindowsDeleteString, если только владелец строки не возвращается в вызвавшую функцию:

Располагая HSTRING, вы можете получить указатель на вспомогательный буфер этой строки с помощью функции WindowsGetStringRawBuffer:

Необязательный второй параметр возвращает длину строки. Длина хранится вместе со строкой, избавляя вас от необходимости сканировать строку, чтобы определить ее размер. Прежде чем вы начнете строчить класс-оболочку для C++, стоит отметить, что компилятор C++/CX не возится с WindowsCreateString и WindowsDeleteString при генерации кода для строкового литерала или массива const. Вместо них он использует так называемую быстро передаваемую строку (fast-pass string), позволяющую избегать дополнительных операций выделения памяти и копирования, о которых недавно упоминал. Кроме того, это исключает риск утечки памяти. Создается быстро передаваемая строка функцией WindowsCreateStringReference:

Она использует передаваемый вызвавшим кодом HSTRING_HEADER, чтобы избежать выделения памяти из кучи. В этом случае вспомогательный буфер для HSTRING — это сама исходная строка, поэтому вы должны гарантировать, что исходная строка (равно как и заголовок) останется неизменной в течение срока существования HSTRING. Очевидно, что этот подход бесполезен, когда нужно вернуть строку вызвавшей функции, но отличная оптимизация, если требуется передать строку как входной параметр другой функции, чей срок жизни ограничен стеком (т. е. это не относится к асинхронным функциям). WRL также предоставляет оболочки для HSTRING и быстро передаваемых строк.

Читайте также:  Checkpoint capsule workspace mac os

RoGetActivationFactory — как раз такая функция, и она используется для получения фабрики активации или статического интерфейса для данного класса. Она аналогична COM-функции CoGetClassObject. Учитывая, что эта функция обычно применяется с массивом const, генерируемым компилятором MIDL, имеет смысл написать простой шаблон-функцию, предоставляющий оболочку быстро передаваемой строки. Как он может выглядеть, показано на рис. 1.

Рис. 1. Шаблон функции GetActivationFactory

Шаблон функции GetActivationFactory автоматически распознает длину строки, исключая необходимость передачи аргумента с длиной буфера (а здесь легко ошибиться) или весьма дорогостоящего сканирования строки в период выполнения. Затем перед вызовом функции RoGetActivationFactory подготавливает быстро передаваемую строку. И здесь шаблон функции вновь логически распознает идентификатор интерфейса и безопасно возвращает конечный указатель на COM-интерфейс, обернутый в WRL ComPtr.

Теперь вы можете использовать эту вспомогательную функцию для получения интерфейса ICoreApplication:

Интерфейс ICoreApplication — это то, что приводит в действие ваше приложение. Чтобы использовать этот COM-интерфейс, вам потребуется включить заголовочный файл модели приложений:

Этот заголовочный файл определяет ICoreApplication в пространстве имен ABI::Windows::ApplicationModel::Core, а также текстовый идентификатор класса CoreApplication. Единственный метод интерфейса, над которым вам придется хорошенько подумать, — это Run.

Прежде чем продолжить, было бы полезно оценить, как Windows Runtime выводит ваше приложение в свет, если так можно выразиться. Как уже упоминалось, Windows Runtime считает вас просто гостем в вашем процессе. Тут полная аналогия с тем, как годами работали Windows-службы. В случае Windows-службы Windows Service Control Manager (SCM) запускает ее, используя функцию CreateProcess или одну из ее вариаций. Затем ждет, когда процесс вызовет функцию StartServiceCtrlDispatcher. Эта функция устанавливает обратную связь с SCM, благодаря чему служба и SCM могут взаимодействовать друг с другом. Если, например, службе не удастся своевременно вызвать StartServiceCtrlDispatcher, SCM будет считать, что возникла какая-то ошибка, и уничтожит процесс. Функция StartServiceCtrlDispatcher возвращает управление только по окончании работы службы, поэтому SCM нужно создавать дополнительный поток для службы, чтобы принимать уведомления об обратных вызовах. Служба просто реагирует на события и находится полностью во власти SCM. Как вы увидите, это во многом напоминает модель приложений WinRT.

Windows Runtime ждет от процесса получения интерфейса ICoreApplication и вызова его метода Run. Если процессу не удается своевременно сделать это, Windows Runtime подобно SCM считает, что что-то пошло не так и завершает процесс. К счастью, если к процессу подключен отладчик, Windows Runtime обнаруживает это и отключает тайм-аут — в отличие от SCM. Однако модель та же. Windows Runtime контролирует процесс и, когда происходят какие-то события, вызывает приложение в потоке, созданном исполняющей средой. Конечно, Windows Runtime основана на COM, поэтому вместо функции обратного вызова (как в случае SCM) эта исполняющая среда (которая в этом деле опирается на Process Lifetime Manager [PLM]) ожидает, что приложение предоставит метод Run с COM-интерфейсом, который можно использовать для вызова приложения.

Ваше приложение должно предоставить реализацию IFrameworkViewSource, который также находится в пространстве имен ABI::Windows::ApplicationModel::Core, и тогда CoreApplication вызовет его единственный метод CreateView, как только создаст UI-поток вашего приложения. На самом деле в IFrameworkViewSource содержится не только метод CreateView. Этот интерфейс наследует от IInspectable, базового интерфейса WinRT. В свою очередь IInspectable наследует от IUnknown, базового интерфейса COM.

WRL обеспечивает обширную поддержку реализации COM-классов, но об этом мы поговорим в следующей статье. А пока я хочу подчеркнуть, что корни Windows Runtime уходят в COM и что нет лучшего способа показать это, чем реализовать IUnknown. Для моих целей будет полезным отметить, что срок жизни C++-класса, который реализует IFrameworkViewSource и несколько других интерфейсов, определяется стеком. По сути, функция WinMain приложения сводится к следующему:

Остается лишь написать класс SampleWindow так, чтобы он должным образом реализовал интерфейс IFrameworkViewSource. Хотя CoreApplication безразлично, где реализуются интерфейсы, ваше приложение, как минимум, должно реализовать не только IFrameworkViewSource, но и интерфейсы IFrameworkView и IActivatedEventHandler. В данном случае класс SampleWindow может просто реализовать их всех:

Интерфейс IFrameworkView также определен в пространстве имен ABI::Windows::ApplicationModel::Core, а с IActivatedEventHandler дело обстоит несколько сложнее. Я определил его сам таким образом:

Если у вас есть некоторый опыт работы с COM, вы могли подумать, что это выглядит весьма не ортодоксально, — и были бы правы. Как и следовало бы ожидать, ITypedEventHandler — это просто шаблон класса, и довольно странно так определять COM-интерфейс; самая очевидная проблема в том, что вы, по-видимому, не смогли бы узнать, каким идентификатором интерфейса нужно его пометить. К счастью, все эти интерфейсы генерируются компилятором MIDL, который берет на себя задачу специализации каждого из них, и этим специализациям он назначает GUID, представляющий идентификатор интерфейса. Каким бы сложным ни выглядело предыдущее выражение typedef, оно определяет COM-интерфейс, который наследует непосредственно от IUnknown и предоставляет единственный метод — Invoke.

Я должен реализовать несколько методов интерфейсов, поэтому займемся делом. Первым идет IUnknown и его могущественный метод QueryInterface. Я не хочу тратить здесь слишком много времени на IUnknown и IInspectable, так как подробно опишу их в следующей статье. На рис. 2 приведена простая реализация QueryInterface для класса, основанного на стеке.

Читайте также:  Способы загрузки приложения windows

Рис. 2. Метод QueryInterface в SampleWindow

В этой реализации стоит отметить несколько моментов. Прежде всего, метод проверяет, что его аргументы допустимы. Более политкорректная реализация могла бы возвращать E_POINTER, но предполагается, что такие ошибки являются дефектами, которые можно устранить на этапе разработки, поэтому незачем тратить на них лишние процессорные ресурсы в период выполнения. Это обеспечивает наилучшее из возможных поведение, немедленно вызывая ошибку доступа к памяти и создавая аварийный дамп, который довольно легко проанализировать. Если бы вы возвращали E_POINTER, вызвавший дефектный код скорее всего просто проигнорировал бы это. Поэтому лучшая политика — провал на раннем этапе. По сути, такой позиции придерживаются во многих реализациях, включая DirectX и Windows Runtime. Корректная реализация QueryInterface требует уймы усилий. Спецификация COM весьма требовательна к тому, чтобы COM-классы всегда корректно и согласованно обеспечивали определенные гарантии идентификации объектов. Не волнуйтесь, если цепочка выражений if кажется вам устрашающей. В свое время я расскажу и об этом.

И последнее, на что хотелось бы обратить внимание в этой реализации, — она не вызывает AddRef. Обычно перед возвратом управления QueryInterface должен вызывать AddRef применительно к полученному указателю на интерфейс IUnknown. Однако, так как класс SampleWindow находится в стеке, смысла в учете ссылок нет. По той же причине реализация IUnknown-методов AddRef и Release предельно проста:

Результаты этих методов имеют лишь информационный характер, поэтому вы можете использовать преимущество этого факта, и вас устроит любое ненулевое значение. Здесь я должен предупредить вас: возможно, вам понадобится переопределить операторы new и delete, чтобы явным образом указывать на то, что данный класс рассчитан на работу только в стеке. В качестве альтернативы вы могли бы реализовать учет ссылок — так, на всякий случай.

Теперь мне нужно реализовать IInspectable, но, поскольку он не будет использоваться в этом простом приложении, я схитрю и оставлю его методы нереализованными, как показано на рис. 3. Это нерекомендуемая реализация, и нет никаких гарантий, что она будет работать в других случаях. И вновь описание IInspectable я отложу до следующей статьи, а пока замечу лишь, что этого достаточно для подготовки и работы интерфейсов, производных от IInspectable, в классе SampleWindow.

Рис. 3. IInspectable-методы в SampleWindow

Далее я должен реализовать IFrameworkViewSource и его метод CreateView. Поскольку класс SampleWindow тоже реализует IFrameworkView, реализация проста. И вновь заметьте, что обычно перед возвратом управления вы должны были бы вызывать AddRef применительно к полученному указателю на интерфейс, производный от IUnknown. Возможно, вы предпочтете на всякий случай вызывать AddRef в теле этой функции:

Интерфейс IFrameworkView — то место, где наконец начинают происходить интересные вещи. После вызова CreateView из приложения для получения указателя на этот интерфейс Windows Runtime вызывает большинство его методов в быстрой последовательности. Важно так же быстро реагировать на эти вызовы, так как все они засчитываются в тот период времени, в течение которого пользователь ожидает запуска вашего приложения. Первым вызывается Initialize, и в нем приложение должно регистрироваться на событие Activated. Это событие уведомляет, что приложение активировано, но вы сами должны активировать его CoreWindow. Метод Initialize довольно прост:

Затем вызывается метод SetWindow, который предоставляет приложению реализацию ICoreWindow, который просто моделирует обычный HWND рабочего стола в Windows Runtime. В отличие от остальных интерфейсов модели приложений ICoreWindow определен в пространстве имен ABI::Windows::UI::Core. В методе SetWindow обязательно делайте копию указателя на интерфейс, так как достаточно скоро он вам понадобится:

Следующий метод — Load; в нем вы должны собрать весь код, отвечающий за подготовку вашего приложения к начальному отображению:

Как минимум, вы должны регистрироваться на события, относящиеся к изменениям размера окна и видимости, а также к изменениям в масштабировании DPI (dots per inch). Кроме того, вы, вероятно, захотите воспользоваться возможностью создать различные объекты фабрики DirectX, загрузить аппаратно-независимые ресурсы и т. д. Это хорошее место для выполнения всех таких операций по той причине, что в этот момент пользователь видит экран-заставку вашего приложения.

Когда метод Load возвращает управление, Windows Runtime считает, что ваше приложение готово к активации, и генерирует событие Activated, которое я буду обрабатывать, реализовав метод Invoke интерфейса IActivatedEventHandler примерно так:

После активации окна приложение наконец готово к выполнению:

Реализовать это можно разными способами. Здесь я просто получаю интерфейс ICoreDispatcher окна, который представляет цикл прокачки сообщений (message pump) для этого окна. Наконец, существует метод Uninitialize, который мог бы вызываться время от времени, но в остальном бесполезен, и его можно безопасно игнорировать:

Вот и все. Теперь вы можете скомпилировать и запустить приложение. Конечно, в данном случае на экране ничего рисоваться не будет. Можете взять копию dx.h с сайта dx.codeplex.com и начать добавлять Direct2D-код для рендеринга (подробности см. в моей статье «A Modern Library for DirectX Programming» в этой рубрике за июнь 2013 г. по ссылке msdn.microsoft.com/magazine/dn201741) или дождаться следующей статьи, где я покажу, как лучше всего интегрировать Direct2D с базовой моделью приложений WinRT.

Кенни Керр (Kenny Kerr) — высококвалифицированный программист. Живет в Канаде. Автор учебных курсов для Pluralsight, обладатель звания Microsoft MVP. Ведет блог kennykerr.ca Кроме того, читайте его заметки в twitter.com/kennykerr.

Выражаю благодарность за рецензирование статьи эксперту Microsoft Джеймсу Макнеллису (James McNellis).

Оцените статью