Runtime что это такое

Objective-C Runtime. Теория и практическое применение

Что такое Runtime?

Objective-C задумывался как надстройка над языком C, добавляющая к нему поддержку объектно-ориентированной парадигмы. Фактически, с точки зрения синтаксиса, Objective-C — это достаточно небольшой набор ключевых слов и управляющих конструкций над обычным C. Именно Runtime, библиотека времени выполнения, предоставляет тот набор функций, которые вдыхают в язык жизнь, реализуя его динамические возможности и обеспечивая функционирование ООП.

Базовые структуры данных

Мы видим, что объект в процессе работы программы представлен обычной C-структурой. Каждый Objective-C объект имеет ссылку на свой класс — так называемый isa-указатель. Думаю, все видели его при просмотре структуры объектов во время отладки приложений. В свою очередь, класс также представляет из себя аналогичную структуру:

Класс в Objective-C — это полноценный объект и у него тоже присутствует isa-указатель на «класс класса», так называемый метакласс в терминах Objective-C. Аналогично, С-структуры определены и для других сущностей языка:

Функции Runtime-библиотеки
Пример 1. Интроспекция объекта

Рассмотрим пример использования Runtime библиотеки. В одном из наших проектов модель данных представляет собой plain old Objective-C объекты с некоторым набором свойств:

2013-05-04 15:54:01.992 Test[40675:11303] COConcreteObject: <
name = Foo;
quantity = 10;
title = bar;
>

Сообщения

Система вызова методов в Objective-C реализована через посылку сообщений объекту. Каждый вызов метода транслируется в соответствующий вызов функции objc_msgSend :

Здесь вы можете динамически указать свою реализацию вызываемого метода. Если же этот механизм по каким-то причнам вас не устраивает — вы можете использовать форвардинг сообщений.

Пример 2. Method Swizzling
Пример 3. Ассоциативные ссылки

Еще одним известным ограничением категорий является невозможность создания в них новых переменных экземпляра. Пусть, например, вам требуется добавить новое свойство к библиотечному классу UITableView — ссылку на «заглушку», которая будет показываться, когда таблица пуста:

«Из коробки» этот код работать не будет, вы получите исключение во время выполнения программы. Эту проблему можно обойти, используя функционал ассоциативных ссылок:

Источник

Что такое рантайм?

Тут у меня, по лоровской терминологии, включено 2 рантайма, сишный и плюсовой?

Runtime что это такое. 73411: 1393452913. Runtime что это такое фото. Runtime что это такое-73411: 1393452913. картинка Runtime что это такое. картинка 73411: 1393452913

Ха. И тема совсем новая. Просмотрел как-то. Но дискуссия там странная и ничего все равно не понятно.

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Ты прав до слов «я прав» включительно. После этого просто два заголовка, включенных в сорец. Рантайм во втором смысле в программе будет независимо от того, что и куда ты включал.

Ну и упоминание рантайма это не царская привилегия, его могут упоминать и не подобные ему.

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Там больше срач о «модели выполнения», зачем-то перемешанной с рантаймом. Тсу, судя по тегам, хватит понятия sequence point, не влезая в эту мышиную возню.

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Самый простой пример: GC.

Runtime что это такое. 82765:1810093561. Runtime что это такое фото. Runtime что это такое-82765:1810093561. картинка Runtime что это такое. картинка 82765:1810093561

чем ближе язык данной машине тем меньше(колмогорова мера вот это вот всё) рантайм.

т.е рантайм бойлерплейт исполнения для данного языка на данной машине.

например для перво компилируемых языков (фортраны там) не нужон стек на целевой машине.

Runtime что это такое. 82765:1810093561. Runtime что это такое фото. Runtime что это такое-82765:1810093561. картинка Runtime что это такое. картинка 82765:1810093561

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Теперь должно быть ясно

Runtime что это такое. 86365: 578490278. Runtime что это такое фото. Runtime что это такое-86365: 578490278. картинка Runtime что это такое. картинка 86365: 578490278

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

В коде ниже, присваиваение переменной x происходит в момент работы программы. Все остальные действия происходят во время компиляции. Если сделать дизассемблирование, то «рантайм» в данном примере это вот эта инструкция:

Runtime что это такое. 109588:158833342. Runtime что это такое фото. Runtime что это такое-109588:158833342. картинка Runtime что это такое. картинка 109588:158833342

после ордер \r сделай

А как вообще можно программировать с такими понятиями? Что значит сишный? Какая разница, какой язык? Ты же сам сначала говоришь

Я знаю, что рантайм это время выполнения программы, как антоним компайлтайм
Я знаю

Если ты это знаешь, то как это сочетается с той ахинеей, про libc и прочую лабуду, которую ты плетешь дальше? Или имеется в виду, знаю, читал, но не понимаю? Ну так надо так писать сразу. Создается ощущение, что си (относительно низкоуровневым же считается, да?) самый синтетический язык, оторванный от реальности из всех возможных, судя по понятиям его адептов. Например, по версии царя, ООП нужно для создания интерфейсов, а интерфейсы — для эргономичности. Может си вообще к программированию отношения не имеет?

Runtime что это такое. 54109: 2054175765. Runtime что это такое фото. Runtime что это такое-54109: 2054175765. картинка Runtime что это такое. картинка 54109: 2054175765

Я знаю, что рантайм это время выполнения программы, как антоним компайлтайм.

Мне кажется, данное слово еще употребляют к стандартным библиотекам ЯП

Это второе значение, сокращение от «run-time libraries». Однако термин включает не только собственно стандартную библиотеку, но и все библиотеки, которые компилятор неявно линкует с твоей программой.

В случае с С++ ситауция немного сложнее, так как значительная часть стандартной библиотеки является header-only и поэтому к рантайму не относится. С другой стороны, посредством рантайма реализуются исключения, которые являются частью core language, а не стандартной библиотеки (см. выше про «все библиотеки. »)

Runtime что это такое. 54109: 2054175765. Runtime что это такое фото. Runtime что это такое-54109: 2054175765. картинка Runtime что это такое. картинка 54109: 2054175765

включающая(но не ограниченная как правило) в себя премайн машинению и машинерию завершения программы и перечу управления обратно в ос

Для простых смертных, не-миллениалов: код, выполняющийся до функции main() и запускающий ее, и код, выполняющийся после возврата из нее.

Runtime что это такое. 45855: 599263969. Runtime что это такое фото. Runtime что это такое-45855: 599263969. картинка Runtime что это такое. картинка 45855: 599263969

Например, к рантайму относится код, который выполняется от точки входа в исполняемом файле до вызова функции main(). Как минимум, он откуда-то достаёт и передаёт значения argc, argv

Runtime что это такое. 82971:1791648203. Runtime что это такое фото. Runtime что это такое-82971:1791648203. картинка Runtime что это такое. картинка 82971:1791648203

+1 Тоже неплохое объяснение на пальцах.

Runtime что это такое. 82971:1791648203. Runtime что это такое фото. Runtime что это такое-82971:1791648203. картинка Runtime что это такое. картинка 82971:1791648203

execution environment = ОС в данном случае.

Runtime что это такое. 52249:1484105682. Runtime что это такое фото. Runtime что это такое-52249:1484105682. картинка Runtime что это такое. картинка 52249:1484105682

Как минимум, он откуда-то достаёт и передаёт значения argc, argv

Если ОПу это интересно, то берёт он (рантайм) их из стека, куда эти данные заботливо положило ядро.

Например, к рантайму относится код, который выполняется от точки входа в исполняемом файле до вызова функции main().

Опять же, если ОП сомневается, то main() это вовсе не тот кусок кода, который первым начинает выполняться при старте процесса.

Runtime что это такое. 52249:1484105682. Runtime что это такое фото. Runtime что это такое-52249:1484105682. картинка Runtime что это такое. картинка 52249:1484105682

Тут у меня, по лоровской терминологии, включено 2 рантайма, сишный и плюсовой?

По ЛОРовской терминологии есть ещё один рантайм: Runtime что это такое. . Runtime что это такое фото. Runtime что это такое-. картинка Runtime что это такое. картинкаruntime

В дополнение рекомендую посмотреть (слегка win/msvc specific но всё равно полезно)

Выше адепт написал верно:

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Please, read last comment with steady attention. Exactly,this is your level. You may watch youself there, just like in a mirror.

Runtime что это такое. 82765:1810093561. Runtime что это такое фото. Runtime что это такое-82765:1810093561. картинка Runtime что это такое. картинка 82765:1810093561

см. Многоуровневая организация ЭВМ.Э.Таненбаум 1979

Structured Computer Organization Andrew S. Tanenbaum 1976

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Открою маленькую тайну, но main() не является истинным entry point в программе.

Для MSVC (то, что я знаю) это mainCRTStartup (или ей подобные, разные для console и GUI, wide и ansi) делающие вот это: http://stackoverflow.com/questions/1583193/what-functions-does-winmaincrtstartup-perform

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Мне интересно, как он этого наркомана парсит, если кто не уловил. Про ентри поинты я узнал, когда начал exe вместо com собирать.

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

У вас очень хорошо получается объяснять (я не шучу)

Runtime что это такое. 45855: 599263969. Runtime что это такое фото. Runtime что это такое-45855: 599263969. картинка Runtime что это такое. картинка 45855: 599263969

надо думать как он, всё просто 🙂

Runtime что это такое. 120248: 1358101685. Runtime что это такое фото. Runtime что это такое-120248: 1358101685. картинка Runtime что это такое. картинка 120248: 1358101685

Пластичность мозга же — когда читаешь много постов кулинксяо, тренируется нейронная сеть и мозг создает парсер, который может переваривать его посты.

А, это. Работа со своеобразными заказчиками/инженерами придает необыкновенную гибкость парсеру

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Не, я в целом это понял, можно просто выкинуть все знаки препинания и прочитать так, как будто не пишешь, а говоришь разговорно, угадывая интонацию. Но иногда она не угадывается и тогда все, reduce-reduce conflict, нерешаемая хрень.

моя после угадывания паттерна (первые 2-3 слова) перепрыгивает сразу на следующий пост =\

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Нет, это crt0.S. То, что инициализирует стек для программы, ставит всякие гарды и обработчики исключений и прочее. А также это то, что помогает работать всяким конструкциям языка в период исполнения (например, сборщик мусора или поддержка блоков)

Runtime что это такое. p. Runtime что это такое фото. Runtime что это такое-p. картинка Runtime что это такое. картинка p

Также crt0.S (или crt1.S, что почти то же самое) заполняют аргументы для main и делают её вызов, а также вызывают exit на выходе из main.

Обычно crt0/1 — это маленькая программа на ассемблере, описывающая функцию _start, куда передаётся исполнение при запуске программы. Она достаёт argc, argv и env из начала стека, как указано тут http://www.x86-64.org/documentation/abi.pdf Во фряхе, ядро копирует %rsp в %rdi, что позволяет написать crt1 на C. Для C это почти весь рантайм, он не такой сложный, как для других языков.

Runtime что это такое. 19195:1777220655. Runtime что это такое фото. Runtime что это такое-19195:1777220655. картинка Runtime что это такое. картинка 19195:1777220655

Тут царь и ему подобные частенько упоминают такую штуку как рантайм. А я из тех, кто не осилил, что это значит. Я знаю, что рантайм это время выполнения программы, как антоним компайлтайм. Например, ошибка может появиться «в рантайме».

Почти. Рантайм языка это всё, что требуется для запуска программы на этом языке. Например для Java рантайм это виртуальная машина (JVM) и стандартная библиотека. Стандартная библиотека многих языков встраивается в конечный бинарник и при запуске ничего не требует, поэтому многие языки не требуют отдельного рантайма.

Формально говоря да. Но по факту практически на любом языке программа использует libc, можно и без неё обойтись, но я таких языков не встречал. Так что его рантаймом можно считать с определённой натяжкой. Рантайм часто это какие-то дополнительные мегабайты. libc есть на любом компьютере, кроме совсем уж встраиваемых, поэтому с какой-то точки зрения у C нет рантайма.

Ну и C в принципе не требует рантайма, т.е. можно писать программы и без него (хотя немножко «поколдовать» придётся). Не со всеми языками так получится.

Тут у меня, по лоровской терминологии, включено 2 рантайма, сишный и плюсовой?

Это общепринятая терминология. Да, в твоём примере два рантайма.

Источник

Runtime

Runtime

В информатике, «runtime» или «run time» описывает срок исполнения компьютерной программы, от её начала до завершения (сравните время компиляции). Термин «Runtime» иногда используется для обозначения Runtime library — библиотеки базового кода, которая используется с особенным компилятором, но когда термин используется в этом стиле, «Runtime Library» является более точным определением.

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

Runtime — [engl.], Laufzeit … Universal-Lexikon

Runtime — In computer science, runtime or run time describes the operation of a computer program, the duration of its execution, from beginning to termination (compare compile time). The term runtime can also refer to a virtual machine to manage a program… … Wikipedia

Runtime — Moteur d exécution Un moteur d exécution, bibliothèque d exécution ou runtime (abréviation de runtime system ou runtime library, runtime signifiant, en anglais, « au moment de l exécution ») est un programme ou une bibliothèque qui… … Wikipédia en Français

Runtime — Der Begriff Laufzeit (engl. runtime) beschreibt in der Informatik im Wesentlichen die Zeitspanne, während der ein Programm von einem Rechner ausgeführt wird, und zwar sowohl im Bezug auf die Zeitdauer, die zur Bewältigung einer Aufgabe benötigt… … Deutsch Wikipedia

runtime — ● ►en /r*n taym/ n. m. ►EXEC version d un langage ne permettant que l exécution des programmes créés avec le langage. Les runtimes sont utilisés pour distribuer les programmes sans les compiler, mais sans non plus donner les sources à tout le… … Dictionnaire d’informatique francophone

runtime — vykdymo laikas statusas T sritis informatika apibrėžtis Laiko tarpas, kada vykdoma programa. atitikmenys: angl. run time; runtime ryšiai: palygink – kompiliavimo laikas palygink – saistymo laikas … Enciklopedinis kompiuterijos žodynas

runtime — vykdymo trukmė statusas T sritis informatika apibrėžtis Laikas, kurį trunka programos vykdymas. atitikmenys: angl. run time; runtime … Enciklopedinis kompiuterijos žodynas

runtime — n. time of operation (of computer software) … English contemporary dictionary

Runtime verification — is a verification technique that combines formal verification and program execution.It is the process of detecting faults in a system under scrutiny by passively observing its input/output behavior during its normal operations. The observed… … Wikipedia

Runtime-Error — en el Salón del Cómic de Barcelona 2011 Nacimiento … Wikipedia Español

Источник

Windows Runtime. Система типов и взаимодействие с CLR

С выходом Windows 8 разработчикам стала доступна новая библиотека классов — Windows Runtime. Компоненты WinRT могут использоваться в приложениях Windows Store и настольных приложениях; в неуправляемом коде C/C++, в JavaScript, а также в C# и Visual Basic.

Метаданные Windows Runtime

Runtime что это такое. image loader. Runtime что это такое фото. Runtime что это такое-image loader. картинка Runtime что это такое. картинка image loader

Тем не менее, метаданные, которые описывают этот тип позволяют CLR получить экземпляр реализации при вызове конструктора класса.
При просмотре Windows Runtime метаданных можно также заметить, что определения типов и сборок используют новое ключевое слово WindowsRuntime.

Runtime что это такое. image loader. Runtime что это такое фото. Runtime что это такое-image loader. картинка Runtime что это такое. картинка image loader

Это ключевое слово является контекстно-зависимым и по разному интерпретируется в зависимости от того, где оно применяется. Например, если ключевым словом помечено определение типа (TypeDef), то этот тип подчиняется правилам системы типов Windows Runtime и вызов этого типа следует рассматривать как вызов WinRT API.

Взаимодействие CLR с компонентами WinRT

CRL поддерживает взаимодействие с COM-компонентами через обертки Runtime Callable Wrapper (RCW) и COM Callable Wrapper (CCW). Таким образом в CLR ссылка на WinRT объект представляет собой ссылку на RCW, которая в свою очередь содержит ссылку на WinRT объект. Соответственно управляемый код взаимодействует с RCW, который по сути является интерфейсом между вашим кодом и WinRT объектом.

Runtime что это такое. image loader. Runtime что это такое фото. Runtime что это такое-image loader. картинка Runtime что это такое. картинка image loader

Аналогичным образом в Windows Runtime ссылка на объект CLR представляет собой ссылку на CCW, которая в свою очередь содержит ссылку на CLR объект. Windows Runtime при этом взаимодействует с CCW для доступа к функциональности управляемого объекта.

WinRT типы и управляемый код

Runtime что это такое. image loader. Runtime что это такое фото. Runtime что это такое-image loader. картинка Runtime что это такое. картинка image loader

Проецирование типов
Базовый тип
Структуры

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

К тому же, структуры WinRT не могут определять конструкторы или содержать вспомогательные методы. Однако, некоторые структуры CLR, для удобства, проецирует на свои собственные, тем самым предоставляя разработчикам вспомогательные методы и конструкторы. К таким относятся, например, структура Windows.Foundation.Point, Windows.Foundation.Size и Windows.Foundation.Rect.

Строки
Null-совместимые типы

то в управляемом коде этот метод будет выглядеть следующим образом:

Делегаты

В качестве типа параметра или возвращаемого значения делегата WinRT могут использовать только WinRT-совместимые типы. Так же делегаты с глобальной (public) областью видимости не могут быть объявлены как вложенные (на самом деле это общие правила для среды выполнения Windows в целом). Когда вы передаете объект делегата компоненту Windows Runtime, этот объект упаковывается в обертку CCW, которая не уничтожается сборщиком мусора до тех пор, пока она не будет освобождена компонентом, который ее использует. Интересен так же тот факт, что делегаты WinRT не имеют методов BeginInvoke и EndInvoke.

События

то при компиляции этой строки кода, компилятор превращает ее в следующие инструкции:

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

Время и дата

В WinRT время и дата представляются в формате UTC структурой Windows.Foundation.DateTime. CLR проецирует данный тип на структуру System.DateTimeOffset, а не на System.DateTime. Стоит заметить, что DateTime не содержит информацию о часовом поясе. Поэтому дата и время, возвращаемые функциями WinRT в формате UTC, CLR преобразует в локальное время. И наоборот, при передаче структуры DateTimeOffset в WinRT функцию, дата и время преобразуются в UTC формат.

Массивы

WinRT API поддерживает только одномерные массивы. Соответственно следующий код вызовет ошибку времени компиляции:

В управляемом коде массивы передаются по ссылке, при этом изменения элементов массива будут видны любому коду, который имеет ссылку на экземпляр этого массива. Однако, для WinRT это не всегда так, потому что содержимое массива маршалируется только в направлении, которое API определяет в своей сигнатуре, используя System.Runtime.InteropServices.InAttribute и System.Runtime.InteropServices.OutAttribute. Оба атрибута применяются к параметрам метода или возвращаемым значениям и определяют направление маршалинга между управляемой и неуправляемой памятью во время выполнения. В Windows Runtime параметры могут быть либо только для чтения [InAttribute], либо только для записи [OutAttribute] и не могут быть отмечены для чтения и записи одновременно [InAttribute], [OutAttribute]. Это означает, что содержимое массива, передаваемого методу, а также сам массив должны быть предназначены для чтения или для записи. Так, содержимое массива, который помечен атрибутом [InAttribute], копируется в вызываемый метод, поэтому все изменения, которые метод применяет к массиву, не видны вызывающему объекту. Аналогично, содержимое массива, который помечен атрибутом [OutAttribute], устанавливается вызываемым методом и копируется в вызывающий объект, поэтому вызываемый метод не должен делать каких-либо предположений о содержимом исходного массива.

Коллекции

При передачи коллекции CLR упаковывает объект коллекции в обертку CCW и передает ссылку на нее в WinRT API. При этом вызовы через обертку пересекают границу взаимодействия, что отрицательно сказывается на производительности. Однако, в отличие от массивов, возможно выполнение операций без копирования элементов.

Источник

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

Runtime что это такое. dn342867.kenny kerr headshot(ru ru,msdn.10). Runtime что это такое фото. Runtime что это такое-dn342867.kenny kerr headshot(ru ru,msdn.10). картинка Runtime что это такое. картинка dn342867.kenny kerr headshot(ru ru,msdn.10)Наша жизнь наполнена абстракциями. Как разработчики мы часто вынуждены бороться со всяческими проблемами, используя абстракции, о которых мы по большому счету ничего не знаем. Абстракции иногда разваливаются и оказываются не в состоянии полностью скрыть нижележащие сложности. Не поймите меня неправильно, абстракции — великая вещь. Они помогают и пользователям, и разработчикам, но вы здорово облегчите себе жизнь, если вникнете в те абстракции, на которые вы регулярно опираетесь в своей работе, и четко поймете, как именно они действуют. Более того, библиотеки, авторы которых приняли эту реальность, зачастую куда успешнее тех, где этого не сделано, и отчасти это связано с тем, что такие библиотеки позволяют входить в абстракцию при пошаговой отладке, если в том возникает необходимость.

Одна из таких абстракций — 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-манифеста.

Затем откройте страницы свойств проекта и выберите свойства компилятора — узел 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).

Первое, что ожидает модель приложений, — 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, но об этом позже.

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

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

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

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

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 для класса, основанного на стеке.

Рис. 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).

Источник

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *