В этом разделе показано, как выполнять преобразование между объектами двоичного интерфейса приложений SDK (ABI) и C++/WinRT. Эти методики можно использовать для взаимодействия между кодом, который использует эти два способа программирования, и средой выполнения Windows, или для постепенного переноса кода с ABI на C++/WinRT.
В общем случае C++/WinRT предоставляет типы ABI, как void*, поэтому файлы заголовков для платформы добавлять не нужно.
Что такое ABI среды выполнения Windows и что такое типы ABI?
Класс среды выполнения Windows (класс среды выполнения) — это, на самом деле, абстракция. Такая абстракция определяет двоичный интерфейс (двоичный интерфейс приложения или ABI), позволяющий различным языкам программирования взаимодействовать с объектом. Независимо от языка программирования, взаимодействие клиентского кода с объектом среды выполнения Windows происходит на самом низком уровне, при этом языковые конструкции клиента преобразуются в вызовы ABI объекта.
Аба терапия Урок 1. Как усадить ребенка. Смотрит в глаза
Заголовки пакета Windows SDK в папке «%WindowsSdkDir%Include10.0.17134.0winrt» (при необходимости измените номер версии пакета SDK на используемый), представляют собой файлы заголовков ABI среды выполнения Windows. Они были созданы с помощью компилятора MIDL. Далее приведен пример включения одного из таких заголовков.
#include
А также упрощенный пример одного из типов ABI, которые можно найти в этом конкретном заголовке SDK. Обратите внимание, что пространство имен ABI, Windows::Foundation и все остальные пространства имен Windows объявляются заголовками SDK внутри пространства имен ABI.
namespace ABI::Windows::Foundation < IUriRuntimeClass : public IInspectable < public: /* [propget] */ virtual HRESULT STDMETHODCALLTYPE get_AbsoluteUri(/* [retval, out] */__RPC__deref_out_opt HSTRING * value) = 0; . >>
IUriRuntimeClass представляет собой COM-интерфейс. К тому же, он основан на IInspectable, IUriRuntimeClass, поэтому относится к интерфейсу среды выполнения Windows. Обратите внимание на тип возврата HRESULT, а не на вызов исключений, а также на использование таких артефактов, как дескриптор HSTRING (рекомендуется снова задать значение nullptr для этого дескриптора после окончания работы с ним). Это дает понять, как выглядит среда выполнения Windows на двоичном уровне приложения; другими словами, на уровне в COM-программирования.
Среда выполнения Windows основывается на API-интерфейсы модели COM. Доступ к среде выполнения Windows можно получить таким образом или через языковые проекции. Использование проекции позволяет скрывать подробности COM и обеспечить более естественный подход к программированию на используемом языке.
Например, в папке «%WindowsSdkDir%Include10.0.17134.0cppwinrtwinrt» (при необходимости можно изменить номер версии пакета SDK на используемый) вы обнаружите заголовки проекции языка C++/WinRT. Для каждого пространства имен Windows существует заголовок, так же, как для каждого пространства имен Windows есть один заголовок ABI. Пример включения одного из заголовков C++/WinRT.
Функции. Передача параметров. Возврат результата. ABI.
#include
А вот (из этого заголовка) упрощенный эквивалент C++/WinRT типа ABI, который мы только что видели.
namespace winrt::Windows::Foundation < struct Uri : IUriRuntimeClass, . < winrt::hstring AbsoluteUri() const < . >. >; >
Интерфейс здесь представляет собой современный стандартный C++. Он избавляет от необходимости в HRESULT (при необходимости C++/WinRT вызывает исключения). Функция доступа возвращает простой строковый объект, который очищается в конце его области видимости.
Этот раздел предназначен для тех случаев, когда вам требуется взаимодействие с кодом, который работает на уровне двоичного интерфейса приложения (ABI), и необходимо портировать этот код.
Преобразование в типы ABI и обратно в коде
Для безопасности и простоты во время преобразования в обоих направлениях можно использовать winrt::com_ptr, com_ptr::as и winrt::Windows::Foundation::IUnknown::as. Далее приведен пример кода (на основе шаблона проекта Консольное приложение), в котором также показано, как использовать псевдонимы пространств имен для различных островов, чтобы разрешить конфликты пространств имен между проекцией C++/WinRT и ABI.
// pch.h #pragma once #include #include #include «winrt/Windows.Foundation.h» // main.cpp #include «pch.h» namespace winrt < using namespace Windows::Foundation; >namespace abi < using namespace ABI::Windows::Foundation; >; int main() < winrt::init_apartment(); winrt::Uri uri(L»http://aka.ms/cppwinrt»); // Convert to an ABI type. winrt::com_ptrptr< uri.as() >; // Convert from an ABI type. uri = ptr.as(); winrt::IStringable uriAsIStringable< ptr.as() >; >
Реализации функций as вызывают QueryInterface. Если вам нужны преобразования более низкого уровня, которые вызывают только AddRef, вы можете использовать вспомогательные функции winrt::copy_to_abi и winrt::copy_from_abi. В следующем примере кода эти преобразования более низкого уровня добавлены к примеру, приведенному выше.
При взаимодействии с типами ABI очень важно предусмотреть, чтобы используемый тип ABI соответствовал интерфейсу по умолчанию объекта C++/WinRT. В противном случае вызовы методов типа ABI фактически приводят к вызову методов в том же слоте vtable в интерфейсе по умолчанию с непредвиденными результатами. Обратите внимание, что использование winrt::copy_to_abi не защищает от этой проблемы во время компиляции, так как используется void* для всех типов ABI и предполагается, что вызывающий объект правильно сопоставил типы. Это позволяет избежать ситуации, когда заголовки C++/WinRT должны ссылаться на заголовки ABI, когда типы ABI могут никогда не использоваться.
int main() < // The code in main() already shown above remains here. // Lower-level conversions that only call AddRef. // Convert to an ABI type. ptr = nullptr; winrt::copy_to_abi(uriAsIStringable, *ptr.put_void()); // Convert from an ABI type. uri = nullptr; winrt::copy_from_abi(uriAsIStringable, ptr.get()); ptr = nullptr; >
Ниже приведены другие методы преобразования аналогично низкого уровня, но на этот раз в них используются необработанные указатели типов интерфейса ABI (определенные заголовками Windows SDK).
// The code in main() already shown above remains here. // Copy to an owning raw ABI pointer with copy_to_abi. abi::IStringable* owning< nullptr >; winrt::copy_to_abi(uriAsIStringable, *reinterpret_cast( // Copy from a raw ABI pointer. uri = nullptr; winrt::copy_from_abi(uriAsIStringable, owning); owning->Release();
Для преобразований самого низкого уровня, которые копируют только адреса, можно использовать вспомогательные функции winrt::get_abi, winrt::detach_abi и winrt::attach_abi.
WINRT_ASSERT — это макроопределение, которое передается в _ASSERTE.
// The code in main() already shown above remains here. // Lowest-level conversions that only copy addresses // Convert to a non-owning ABI object with get_abi. abi::IStringable* non_owning< static_cast(winrt::get_abi(uriAsIStringable)) >; WINRT_ASSERT(non_owning); // Avoid interlocks this way. owning = static_cast(winrt::detach_abi(uriAsIStringable)); WINRT_ASSERT(!uriAsIStringable); winrt::attach_abi(uriAsIStringable, owning); WINRT_ASSERT(uriAsIStringable);
Функция convert_from_abi
Эта вспомогательная функция преобразует необработанный указатель интерфейса ABI в эквивалентный объект C++/WinRT с минимальными затратами.
template T convert_from_abi(::IUnknown* from) < T to< nullptr >; // `T` is a projected type. winrt::check_hresult(from->QueryInterface(winrt::guid_of(), winrt::put_abi(to))); return to; >
Эта функция просто вызывает QueryInterface, чтобы запросить интерфейс по умолчанию запрошенного типа C++/WinRT.
Как мы уже выяснили для преобразования объекта C++/WinRT в эквивалентный указатель интерфейса ABI вспомогательной функции не требуется. Просто используйте функцию-член winrt::Windows::Foundation::IUnknown::as (или try_as) для запроса нужного интерфейса. Функции as и try_as возвращают объект winrt::com_ptr, в который упакован запрошенный тип ABI.
Пример кода, в котором используется convert_from_abi
Ниже приведен пример кода, показывающий работу этой вспомогательной функции на практике.
// pch.h #pragma once #include #include #include «winrt/Windows.Foundation.h» // main.cpp #include «pch.h» #include using namespace winrt; using namespace Windows::Foundation; namespace winrt < using namespace Windows::Foundation; >namespace abi < using namespace ABI::Windows::Foundation; >; namespace sample < template T convert_from_abi(::IUnknown* from) < T to< nullptr >; // `T` is a projected type. winrt::check_hresult(from->QueryInterface(winrt::guid_of(), winrt::put_abi(to))); return to; > inline auto put_abi(winrt::hstring return reinterpret_cast(winrt::put_abi(object)); > > int main() < winrt::init_apartment(); winrt::Uri uri(L»http://aka.ms/cppwinrt»); std::wcout ptr = uri.as(); winrt::hstring domain; winrt::check_hresult(ptr->get_Domain(sample::put_abi(domain))); std::wcout (ptr.get()); WINRT_ASSERT(uri.Domain() == uri_from_abi.Domain()); WINRT_ASSERT(uri == uri_from_abi); >
Взаимодействие с указателями интерфейса СОМ ABI
Показанный ниже шаблон вспомогательной функции демонстрирует, как скопировать указатель интерфейса COM ABI заданного типа в его эквивалент C++/WinRT, представляющий собой смарт-указатель типа проекции.
template To to_winrt(From* ptr) < To result< nullptr >; winrt::check_hresult(ptr->QueryInterface(winrt::guid_of(), winrt::put_abi(result))); return result; > . ID2D1Factory1* com_ptr< . >; auto cppwinrt_ptr >(com_ptr)>;
Следующий шаблон вспомогательной функции аналогичен предыдущему, за исключением того, что он копирует тип смарт-указателя из библиотек реализации Windows (WIL).
template To to_winrt(wil::com_ptr_t const To result< nullptr >; if constexpr (std::is_same_v) < ptr.query_to(winrt::guid_of(), winrt::put_abi(result)); > else < winrt::check_result(ptr.query_to(winrt::guid_of(), winrt::put_abi(result))); > return result; >
Небезопасное взаимодействие с указателями интерфейса СОМ ABI
В таблице ниже показаны (наряду с другими операциями) небезопасные преобразования указателя интерфейса COM ABI заданного типа и его эквивалента C++/WinRT, представляющего собой смарт-указатель типа проекции. Предполагается, что в коде используются следующие объявления.
winrt::Sample s; ISample* p; void GetSample(_Out_ ISample** pp);
Также предполагается, что ISample — это интерфейс по умолчанию для Sample.
Сделать это можно во время компиляции этого кода.
static_assert(std::is_same_v, winrt::ISample>);
Извлечение ISample* из winrt::Sample | p = reinterpret_cast(get_abi(s)); | s по-прежнему является владельцем объекта. |
Отсоединение ISample* от winrt::Sample | p = reinterpret_cast(detach_abi(s)); | s больше не является владельцем объекта. |
Передача ISample* в новый объект winrt::Sample | winrt::Sample s< p, winrt::take_ownership_from_abi >; | s становится владельцем объекта. |
Указание ISample* в winrt::Sample | *put_abi(s) = p; | s становится владельцем объекта. Высвобождается любой объект, которые ранее принадлежал s (происходит при отладке). |
Получение ISample* в winrt::Sample | GetSample(reinterpret_cast(put_abi(s))); | s становится владельцем объекта. Высвобождается любой объект, которые ранее принадлежал s (происходит при отладке). |
Замена ISample* в winrt::Sample | attach_abi(s, p); | s становится владельцем объекта. Высвобождается объект, который ранее принадлежал s. |
Копирование ISample* в winrt::Sample | copy_from_abi(s, p); | s создает новую ссылку на объект. Высвобождается объект, который ранее принадлежал s. |
Копирование winrt::Sample в ISample* | copy_to_abi(s, reinterpret_cast(p)); | p получает копию объекта. Высвобождается любой объект, который ранее принадлежал p. |
Взаимодействие со структурой GUID ABI
GUID ( /previous-versions/aa373931(v%3Dvs.80) ) теперь проецируется как winrt::guid. Для API-интерфейсов, которые вы реализуете, необходимо использовать winrt::guid для параметров GUID. В противном случае выполняется автоматическое преобразование winrt::guid и GUID, если добавлено unknwn.h (добавлено неявно с помощью < >или других файлов заголовков) до добавления заголовков C++/WinRT.
Но вы также можете использовать reinterpret_cast . Предполагается, что в коде используются следующие объявления.
winrt::guid winrtguid; GUID abiguid;
Из winrt::guid в GUID | abiguid = winrtguid; | abiguid = reinterpret_cast(winrtguid); |
Из GUID в winrt::guid | winrtguid = abiguid; | winrtguid = reinterpret_cast(abiguid); |
Вы можете создать winrt::guid следующим образом.
winrt::guid myGuid < 0xC380465D, 0x2271, 0x428C, < 0x9B, 0x83, 0xEC, 0xEA, 0x3B, 0x4A, 0x85, 0xC1>>;
Сведения о том, как создать winrt::guid из строки, см. в разделе make_guid.cpp.
Взаимодействие с HSTRING ABI
В следующей таблице показано, как выполнять преобразования winrt::hstring и HSTRING, а также другие операции. Предполагается, что в коде используются следующие объявления.
winrt::hstring s; HSTRING h; void GetString(_Out_ HSTRING* value);
Извлечение HSTRING из hstring | h = static_cast(get_abi(s)); | s по-прежнему является владельцем строки. |
Отсоединение HSTRING от hstring | h = reinterpret_cast(detach_abi(s)); | s больше не является владельцем строки. |
Указание HSTRING в hstring | *put_abi(s) = h; | s становится владельцем строки. Высвобождается любая строка, которая ранее принадлежала s (происходит при отладке). |
Получение HSTRING в hstring | GetString(reinterpret_cast(put_abi(s))); | s становится владельцем строки. Высвобождается любая строка, которая ранее принадлежала s (происходит при отладке). |
Замена HSTRING в hstring | attach_abi(s, h); | s становится владельцем строки. Высвобождается строка, которая ранее принадлежала s. |
Копирование HSTRING в hstring | copy_from_abi(s, h); | s создает закрытую копию строки. Высвобождается строка, которая ранее принадлежала s. |
Копирование hstring в HSTRING | copy_to_abi(s, reinterpret_cast(h)); | h получает копию строки. Высвобождается любая строка, которая ранее принадлежала h. |
Кроме того, вспомогательные приложения строк в библиотеках реализации Windows (WIL) выполняют базовые операции со строками. Чтобы использовать вспомогательные приложения строк WIL, включите и см. таблицу ниже. Для получения подробных сведений перейдите по ссылкам, приведенным в таблице.
Предоставление необработанного указателя строки Юникода или ANSI и дополнительной длины; получение специализированной оболочки unique_any. | wil::make_something_string |
Развертывание смарт-объекта до тех пор, пока не будет найден необработанный указатель строки Юникода с символом NULL в конце. | wil::str_raw_ptr |
Получение строки, упакованной с помощью объекта смарт-указателя, или пустой строки L»» , если смарт-указатель пустой. | wil::string_get_not_null |
Объединение любого количества строк. | wil::str_concat |
Получение строки из строки формата printf-style и соответствующего списка параметров. | wil::str_printf |
Важные API
- IUnknown::AddRef method (Метод IUnknown::AddRef)
- IUnknown::QueryInterface method (Метод IUnknown::QueryInterface)
- winrt::attach_abi function (C++/WinRT) (Функция winrt::attach_abi (C++/WinRT))
- winrt::com_ptr struct template (C++/WinRT) (Шаблон структуры winrt::com_ptr (C++/WinRT))
- winrt::copy_from_abi function (C++/WinRT) (Функция winrt::copy_from_abi (C++/WinRT))
- winrt::copy_to_abi function (C++/WinRT) (Функция winrt::copy_to_abi (C++/WinRT))
- winrt::detach_abi function (C++/WinRT) (Функция winrt::detach_abi (C++/WinRT))
- winrt::get_abi function (C++/WinRT) (Функция winrt::get_abi (C++/WinRT))
- winrt::Windows::Foundation::IUnknown struct (C++/WinRT) (Структура winrt::Windows::Foundation::IUnknown)
- winrt::Windows::Foundation::IUnknown struct (C++/WinRT) (Структура winrt::Windows::Foundation::IUnknown (C++/WinRT))
Источник: learn.microsoft.com
Русские Блоги
Полное название ABI: Application binary interface (двоичный интерфейс приложения), определяет набор правил, которые позволяют скомпилированным двоичным кодам объектов работать во всех операционных системах, совместимых с ABI, без изменений.
В разных телефонах Android используются разные процессоры, поэтому для взаимодействия необходимо предоставить соответствующие правила взаимодействия с двоичным интерфейсом (то есть соответствующие файлы ABI).
Некоторые процессоры могут поддерживать несколько правил взаимодействия, но это совместимо за счет производительности.
Основная архитектура ABI
- armeabiv-v7a: процессоры ARM 7-го поколения и выше. Его используют большинство устройств Android, выпущенных после 2011 года.
- arm64-v8a: 8-е поколение, 64-битный процессор ARM, несколько устройств, Samsung Galaxy S6 — одно из них.
- armeabi: 5-е и 6-е поколения процессоров ARM в основном используются в первых мобильных телефонах.
- x86: Больше используются планшеты и симуляторы.
- x86_64: 64-битный планшет.
Связь между ABI и CPU
Когда приложение установлено на устройстве, будет установлен только файл .so, соответствующий архитектуре ЦП, поддерживаемой устройством. Если поддерживается несколько архитектур ABI, он будет следовать приоритету
Конкретные типы поддержки следующие:
ARMv5(CPU):armeabi(ABI)
ARMv7:armeabi,armeabi-v7a
ARMv8:armeabi,armeabi-v7a,arm64-v8a
MIPS:mips
MIPS64:mips,mips64
x86:x86(1),armeabi(2),armeabi-v7a(3)
x86_64:armeabi,x86,x86_64
Видно, что большинство процессоров имеют прямую совместимость, но при выборе ABI будет приоритет.
Например, для процессоров X86 предпочтительнее использовать пакет .so в каталоге x86. Если он существует, другие поддерживаемые архитектуры ABI не будут установлены; если нет каталога x86, будет выбран .so в каталоге armeabi-v7a, и будет выбран последний. Выберите файл .so в каталоге armeabi.
ps: Хотя устройства X86 могут запускать библиотеку so под armeabi, производительность может быть потеряна, и нет гарантии, что сбоев не произойдет, особенно если есть библиотеки, созданные небольшими компаниями.
Проблемы при использовании
.so файл, поместите в каталог ABI с низким приоритетом
Архитектура процессора устройства — ARMv7, а файл ABI — armeabi-v7a, но он помещается в каталог armeabi.
1. Если в проекте есть каталог armeabi-v7a и в нем нет библиотеки so, ARMv7 сначала загружает каталог armeabi-v7a, а если нет соответствующей библиотеки so, будет сообщено об ошибке.
Caused by: java.lang.UnsatisfiedLinkError
2. В проекте есть только каталог armeabi. ARMv7 одновременно загрузит каталог armeabi и библиотеку so в каталог, что эквивалентно загрузке библиотеки armeabi rule so. Из-за функции прямой совместимости он не будет сообщать об ошибке и может работать, но Производительность будет потеряна.
Файлы .so помещаются в каталог ABI с высоким приоритетом.
Архитектура ЦП устройства — ARMv7, а файл ABI — armeabi, но он помещается в каталог armeabi-v7a.
Может загружаться, но можно ли пользоваться? Я тоже не уверен. Поскольку библиотека so armeabi может не обязательно поддерживать правила взаимодействия с интерфейсом, установленные armeabi-v7a.
Приоритет файлов ABI в нескольких сторонних SDK различается.
Приоритет файлов ABI в двух сторонних SDK различается. Когда мобильный телефон загружен и работает, библиотека с низким приоритетом не загружается.
Архитектура процессора моего мобильного телефона — ARMv7, и в проекте используются два сторонних SDK: Enterprise A и Enterprise B.
Предприятие A: ABI-файл — это armeabi-v7a, поместите его в каталог armeabi-v7a.
Предприятие B: файл ABI — это armeabi-v5te, поместите его в каталог armeabi.
При запуске вы обнаружите, что после запуска происходит сбой, и появляется следующая информация журнала.
Caused by: java.lang.UnsatisfiedLinkError
Это связано с тем, что низкий приоритет, то есть пакет so предприятия B, не загружен, и его нельзя использовать в обычном режиме, что приводит к ошибке.
Решение:
1. Используйте файлы ABI с одинаковым приоритетом и поместите файлы ABI в каталог ABI с тем же приоритетом.
Предприятие A: ABI-файл — это armeabi-v5te, он находится в каталоге armeabi.
Предприятие B: файл ABI — это armeabi-v5te, поместите его в каталог armeabi.
или
Предприятие A: ABI-файл — это armeabi-v7a, поместите его в каталог armeabi-v7a.
Предприятие B: файл ABI — armeabi-v7a, поместите его в каталог armeabi-v7a.
2. Используйте файлы ABI с разными приоритетами и помещайте файлы ABI в каталоги ABI с одинаковым приоритетом. Обычно это не рекомендуется.
Предприятие A: ABI-файл — это armeabi-v7a, но он находится в каталоге armeabi.
Предприятие B: файл ABI — это armeabi-v5te, поместите его в каталог armeabi.
или
Предприятие A: ABI-файл — это armeabi-v7a, поместите его в каталог armeabi-v7a.
Предприятие B: файл ABI — это armeabi-v5te, но он помещается в каталог armeabi-v7a.
Важные правила so файлов
При работе с файлами .so существует простое, но неизвестное важное правило.
Вы должны предоставить как можно больше файлов .so, оптимизированных для каждого ABI.
Совместимость с NDK
При использовании NDK выберите платформу компиляции, соответствующую minsdkVersion приложения, поскольку NDK имеет обратную совместимость.
Меры предосторожности
Таким образом, все папки ABI должны быть согласованы
Если наше приложение решает поддерживать несколько ABI, мы должны обратить особое внимание: для этого в каждом ABI поддерживается либо все, либо ни один. Он не должен смешиваться, но должен предоставлять соответствующий файл .so для каждого каталога ABI.
Источник: russianblogs.com
Робот Abi для торговли на бинарных опционах
Впервые о роботе бинарных опционов Abi стало известно в 2014 году, который также известен в спекулятивной среде, как BinRobot Lady.
- Что собой представляет робот Abi
- В чем особенность торговой стратегии
- Как настроить робота для автоматической торговли
- Преимущества и недостатки стратегии робота
-
Источник: finswin.com