Вызов сборки .NET из Delphi / C ++ Builder - PullRequest
0 голосов
/ 28 ноября 2018

Я пытался использовать компонент TBluetoothLE в многоплатформенном приложении.Код прекрасно работает на iOS.Требуется некоторая настройка для правильной работы на Android.Но я не могу заставить его работать в Windows.

Я смотрел во время отладки исходный код на платформе Windows, и он, похоже, использует WinRT API.Я знаю, что написание (и тестирование) универсального компонента, который хорошо работает на нескольких платформах, не так просто.Но мне интересно, можем ли мы использовать WinRT непосредственно из приложения, не используя компонент, предоставленный Embarcadero.

В C # есть много рабочих примеров, которые я тестировал на Windows. BluetoothLEExplorer - очень хорошее приложение, которое показывает использование WinRT для обнаружения и связи с устройствами BLE.

Delphi также предоставляет файлы интерфейса для использования WinRT, но нет примера приложения, показывающего, какиспользуй это.

Я хотел бы исследовать очень простой пример вызова функции внутри сборки .NET из C ++ Builder.

В C # простым примером является вызов FromBluetoothAddressAsync для определения возможности подключения устройства BLE с данным адресом:

C # пример в 3 строки кода:

1 - создать Watcher для обнаружения устройств BLE

BluetoothLEAdvertisementWatcher advWatcher;
// then call its Received method 
advWatcher.Received(some_callback_function_to_be_called_when_the_watcher_detect_adevice);
//the discovered BLE device address is saved in variable uint_t64 deviceAddr by the callback_function

2 - получить объект BluetoothLEDevice для устройства, используя FromBluetoothAddressAsync():

BluetoothLEDevice dev = BluetoothLEDevice::FromBluetoothAddressAsync(deviceAddr).get(); 

в сборке .NET Windows.Device.Bluetooth, подпись функции FromBluetoothAddressAsync():

inline Windows::Foundation::IAsyncOperation<Windows::Devices::Bluetooth::BluetoothLEDevice> BluetoothLEDevice::FromBluetoothAddressAsync(uint64_t bluetoothAddress)

Delphi предоставляет интерфейсы для классов BluetoothLEAdvertisementWatcher и BluetoothLEDevice и методов Received() и FromBluetoothAddressAsync() внутри WinAPI.Devices.Bluetooth.pas.

Со стороны C ++ Builder у нас есть заголовочные файлы для определений.В Winapi.Devices.Bluetooth.Advertisement.hpp у нас есть:

__interface DELPHIINTERFACE IBluetoothLEAdvertisementWatcher;
typedef System::DelphiInterface<IBluetoothLEAdvertisementWatcher> _di_IBluetoothLEAdvertisementWatcher;

, а в WinAPI.Devices.Bluetooth.hpp у нас есть:

  class PASCALIMPLEMENTATION TBluetoothDevice : public System::Win::Winrt::TWinRTGenericImportS2__2<_di_IBluetoothDeviceStatics,_di_IBluetoothDeviceStatics2>
{
    typedef System::Win::Winrt::TWinRTGenericImportS2__2<_di_IBluetoothDeviceStatics,_di_IBluetoothDeviceStatics2> inherited;

public:
    ...
    static _di_IAsyncOperation_1__IBluetoothDevice __fastcall FromBluetoothAddressAsync(unsigned __int64 address);

public:
    /* TObject.Create */ inline __fastcall TBluetoothDevice() : System::Win::Winrt::TWinRTGenericImportS2__2<_di_IBluetoothDeviceStatics,_di_IBluetoothDeviceStatics2>() { }
    /* TObject.Destroy */ inline __fastcall virtual ~TBluetoothDevice() { }

};

Мой вопрос: как создавать экземпляры объектов .NET в C ++ Builder?

Я понимаю, что утверждение типа:

_di_IBluetoothLEAdvertisementWatcher MyWatacher;

в C ++ Builder - это просто объявление.Это означает, что MyWatcher является указателем NULL.Но как создать экземпляр нового (реального) BluetoothLEAdvertisementWatcher объекта перед вызовом его методов?

Update # 1

Насколько я понимаю, для каждого вызываемого класса_X в сборке .NET, delphi сгенерирует два определения: интерфейс I_X и объект T_X.Мы можем «Создать / выделить» экземпляры T_X, но не I_X.В C ++ Builder мы получаем другое имя для интерфейса _di_I_X.

Создание объекта выглядит нормально:

    TBluetoothLEAdvertisementWatcher *inst =
    new TBluetoothLEAdvertisementWatcher();
    _di_IBluetoothLEAdvertisementWatcher intf;

Я пробовал несколько подходов, чтобы типизировать созданные T_X to _di_I_X:

// Первый метод:

inst->GetInterface(__uuidof(IBluetoothLEAdvertisementWatcher), (void*)&intf);

// Второй метод:

intf = interface_cast<TBluetoothLEAdvertisementWatcher>(inst);

// Третий метод:

bool trans_ok = Supports(inst,__uuidof(IBluetoothLEAdvertisementWatcher),(void*)&intf);     

Все они возвращают NULL для intf.

Я заметил, что TBluetoothLEAdvertisementWatcher объявлено:

TBluetoothLEAdvertisementWatcher= class(TWinRTGenericImportFI<IBluetoothLEAdvertisementWatcherFactory, IBluetoothLEAdvertisementWatcher>)

Как вы думаете, "проблема приведения типа" связана смножественное наследование в TBluetoothLEAdvertisementWatcher?

Обновление № 2:

Я использовал delphi для создания экземпляра для себя.Я создал unit2.pas с помощью:

unit Unit2;

interface
uses
  System.SysUtils, System.Bluetooth,  Winapi.Devices.Bluetooth.Advertisement;

function CreateADelphiInstance() : IBluetoothLEAdvertisementWatcher;
implementation

  function CreateADelphiInstance() : IBluetoothLEAdvertisementWatcher;
begin
  Result := TBluetoothLEAdvertisementWatcher.Create;
end;
end.

Затем в C ++ Builder я называю его следующим образом:

_di_IBluetoothLEAdvertisementWatcher intf = CreateADelphiInstance();
if (intf) 
    intf->ScanningMode = Winapi::Commontypes::BluetoothLEScanningMode::Active;

Но я надеюсь, что смогу сделать это непосредственно в C ++ Builder.

...