Опубликован: 22.12.2012 | Доступ: свободный | Студентов: 480 / 19 | Длительность: 07:20:00
Лекция 5:

Разработка гибридных подсистем. Использование нескольких языков программирования в одном приложении

< Лекция 4 || Лекция 5 || Лекция 6 >
Аннотация: В лекции рассматриваются технологии создания гибридных приложений - то есть использование нескольких языков программирования в одном приложении.

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

В данной лекции рассматривается создание компонентов на C++ для Windows 8, который оформляется библиотекой DLL, вызываемой из приложения для Windows Store, построенного с использованием JavaScrip. Такой подход имеет ряд преимуществ:

  1. Используется производительность C++ в сложных операциях или операциях с большим объемом вычислений.
  2. Повторное использование существующего кода, который уже написан и протестирован.

В среде Windows 8 можно создавать компоненты (фактически DLL) на языках C++, C# и Visual Basic, а затем использовать полученные компоненты в программах для Windows Store, разработанных на языке JavaScript, XAML. При этом имеется возможность в JavaScript обращаться к API функциям Windows. Фактически в Windows 8 реализован механизм, который позволяет выбрать язык для создания оболочки определенной функции, и реализовать интерфейс пользователя для этой функции на JavaScript.

При построении решения, содержащего JavaScript и компонент для Windows, файлы проекта JavaScript и скомпилированная библиотека DLL объединяются в один пакет, который можно отлаживать локально, в имитаторе, или удаленно в связанном устройстве. Также можно распространять только проект компонента как расширение SDK.

При написании кода компонента на C++, как правило, используются обычная библиотека C++ и встроенные типы, за исключением абстрактного двоичного интерфейса (ABI), в котором передаются данные в/из JavaScript. Здесь используются типы Windows и специальный синтаксис, поддерживаемый средой Visual C++ для создания этих типов и управления ими. Кроме того, код Visual C++ будет использовать такие типы, как delegate и event, для реализации событий, которые можно инициировать из компонента и обрабатывать на языке JavaScript.

Создание экземпляра объекта

Через интерфейс ABI можно передавать только типы cреды Windows. Если компонент содержит такой тип, как std::wstring, в качестве возвращаемого типа или параметра открытого метода, компилятор создает ошибку. Если используются встроенные типы C++, такие как int, double и т д., компилятор автоматически преобразует их в соответствующий тип int32 среды исполнения, float64 и т. д. в параметрах и возвращаемых типах открытых методов. Преобразование выполняется только при передаче типа через ABI.

namespace MyComp 
{
    // объявление класса C++
    public ref class LangSample sealed
    {
        // члены класса
    };
}

//использование в JavaScript
var nativeObject = new myComp.LangSample();

Встроенные типы С++, типы библиотек и типы среды Windows

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

Компоненты среды исполняемой среды могут содержать несколько активируемых классов, а также дополнительные классы, которые доступны только для внутреннего использования в компоненте. К типам C++, которые не предназначены для использования на JavaScript, необходимо применить атрибут WebHostHidden.

Активируемый класс должен быть объявлен как public ref class sealed. Ключевые слова класса ref указывают компилятору создать класс как тип, совместимый с исполняемой средой, а ключевое слово sealed запрещает наследование от этого класса. Для использования в JavaScript класс должен иметь модификатор sealed.

Все числовые примитивы определяются в пространстве имен по умолчанию. Platform Namespace - это пространство имен, в котором C++ определяет классы, являющиеся типами среда исполнения Windows. К ним относятся классы: Platform::String и Platform::Object. Конкретные типы коллекций, такие как Platform::Collections::Map и latform::Collections::Vector определяются пространстве имен Platform::Collections. Открытые интерфейсы, реализуемые этими типами, определяются в пространстве имен Windows::Foundation::Collections.

Обмен данными между классами и через ABI осуществляется через стандартные для С++ методы. Некоторые из них рассмотрены ниже.

Метод, возвращающий значение встроенного типа

double LogCalc(double input)
{
    // Use C++ standard library as usual.
    return std::log(input); 
}
//Вызов метода
var num = nativeObject.logCalc(21.5);
document.getElementById('callmethod').innerHTML = num; 

Метод, возвращающий пользовательскую структуру значения

Для передачи определяемых пользователем структур через интерфейс ABI, необходимо определить объект JavaScript, который содержит те же члены, что и структура, определенная в C++. Затем можно передать этот объект в качестве аргумента методу C++, чтобы объект был неявно преобразован в тип C++. Другой способ состоит в определении класса, который реализует интерфейс IPropertySet (не показан).

namespace Test
{
    //пользовательская структура
    public value struct BatterData
    {
        Platform::String^ Name;
        int Number;
        double BattingAverage;
    };

    public ref class Test sealed
    {
    private:
        BatterData m_batter;
    public:
        property BatterData Batter 
        {
            BatterData get(){ return m_batter; }
        }
    };
}

//вызов метода в JavaScript
var myData = nativeObject.batter;
    document.getElementById('myDataResult').innerHTML = myData.name + " ,
      " + myData.number + " , " + myData.battingAverage.toPrecision(3); 

Перегруженные методы

В JavaScript имеется ограниченная возможность различения перегруженных методов. Например, JavaScript может определить различия между следующими сигнатурами:

int GetNumber(int i);
int GetNumber(int i, string str);
double GetNumber(int i, MyData^ d);

Однако, между следующими сигнатурами язык не определит разчилий:

int GetNumber(int i);
double GetNumber(double d);

или этими сигнатурами такого вида:

MyData^ GetData(MyData^ d1, MyData^ d2);
MyData^ GetData(MyData^ d1, TestData^ d2);

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

//C++ header file:
[Windows::Foundation::Metadata::DefaultOverloadAttribute]
int WinRTComponent::GetNumber(int i);

double WinRTComponent::GetNumber(double d);
Этот код JavaScript всегда вызывает перегрузку с атрибутом:
var num = nativeObject.getNumber(9); 

Коллекции и массивы

Коллекции, всегда передаются через интерфейс ABI в качестве дескрипторов типов среды исполнения Windows, таких как Windows::Foundation::Collections::IVector^ и Windows::Foundation::Collections::IMap^. Например, если возвращается дескриптор типа Platform::Collections::Map, он будет неявно преобразован в Windows::Foundation::Collections::IMap^. Интерфейсы коллекций определяются в отдельном пространстве имен, состоящем из классов C++, которые предоставляют конкретные реализации.

Свойства

Открытые элементы данных, такие как свойства, необходимо представлять с помощью ключевого слова property. Тривиальное свойство аналогично элементу данных, поскольку вся его функциональность является неявной. Нетривиальное свойство имеет явные методы доступа get и set и закрытую переменную с именем, которая является "резервным хранилищем" для значения.

Делегаты и события

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

Асинхронные методы

Чтобы использовать асинхронные методы, предоставляемые другими объектами среда исполнения, используйте класс task. Для реализации асинхронных методов в C++ необходимо использовать функцию Create_async(), которая определена в файле ppltasks.h..

Исключения

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

Отладка все компонентов разрабатываемого приложения осуществляется стандартными средствами среды разработки. При отладке решения JavaScript, содержащего библиотеку DLL компонента, можно настроить отладчик для пошагового выполнения скрипта или машинного кода в компоненте, однако нельзя отлаживать эти части одновременно. Чтобы изменить этот параметр, разверните узел проекта JavaScript в обозревателе решений, а затем последовательно выберите пункты Свойства, Отладка, Тип отладчика.

Обязательно установить соответствующие возможности в конструкторе пакетов. Например, если требуется открыть файл с помощью интерфейсов API среда исполнения Windows, необходимо установить флажок Доступ к библиотеке документов в области Возможности конструктора пакетов.

Если коду JavaScript не удается распознавать открытые свойства или методы в компоненте, убедитесь, что в JavaScript используется "верблюжий" стиль имен. Например, метод LogCalc C++ следует вызывать из JavaScript как logCalc.

При удалении проекта компонента Среда выполнения Windows C++ из решения, необходимо также вручную удалить ссылку на проект из проекта JavaScript. Невыполнение этого требования приведет к невозможности последующей отладки и выполнения операций построения. При необходимости можно добавить ссылку на сборку в библиотеку DLL.

Краткие итоги

В лекции рассмотрены приемы создания гибридных приложений. Для создания гибридного приложения необходимо создать проект, в котором связать JavaScript и dll. Взаимодействие между различными компонентами происходит через интерфейс ABI. При этом используются компоненты как сред разработки, так и среды исполнения.

Вопросы

  1. В чем преимущества гибридных приложений?
  2. Какие программные интерфейсы используются для создания гибридных приложений?
  3. Каким образом используются перегруженные методы lzk создания гибридных приложений?
  4. Для чего используются делегаты?
  5. Каково назначение асинхронных методов?
< Лекция 4 || Лекция 5 || Лекция 6 >