Как я могу ссылаться на Windows 8 Runtime (в частности, BLE API) в консольном приложении?

Я использую C# в Visual Studio Professional 13 на Windows 8.1 с установленным WDK.

Мне нужно написать настольное приложение, которое взаимодействует с устройством BLE, используя пользовательский UUID службы. Используя образец общего профиля Bluetooth - пример проекта службы сердечного ритма, доступный в MSDN, я могу отредактировать UUID службы, в котором выполняется поиск, и найти свое конкретное устройство.

Тем не менее, образец проекта представляет собой приложение для Магазина Windows (Metro), и мне нужно консольное приложение.

Когда я создаю новый проект типа Visual C# > Store App > Windows AppWindows 8 SDK автоматически включается в проект.

НО при создании Visual C# > Windows Desktop > * Проект, я не могу найти способ включить Windows 8 Runtime И BLE API, к которому мне нужно получить доступ.

Конечно, Microsoft не была так близорука, чтобы ограничить BLE API для хранения приложений? Как создать / изменить свой проект для разработки настольных и консольных приложений, использующих BLE API?

Исследования (и неудачные попытки), которые я провел до сих пор, уже исключили 32feet.net, поскольку библиотека в настоящее время не обеспечивает поддержку низкоэнергетического стека Bluetooth.

Однако, если есть другая сторонняя библиотека (желательно с открытым исходным кодом или, по крайней мере, одна с пробной версией), которая обеспечивает поддержку BLE, я был бы открыт для ее использования вместо среды выполнения Windows 8.

2 ответа

Можно вызывать API WinRT из настольных приложений Win32 в Windows 8.x, но это не проверенный или, что более важно, хорошо документированный сценарий.

В C# вы должны вручную добавить ссылки на проект и время выполнения, чтобы это работало. Этот блог подробно описывает это. Короче говоря, чтобы вкладка "Ядро" появлялась в настройках вашего проекта, вам нужно вручную добавить это в ваш проект Visual Studio для MSDN.

<PropertyGroup>
    <TargetPlatformVersion>8.0</TargetPlatformVersion>
</PropertyGroup>

Затем вручную добавьте ссылку как на System.Runtime.dll, так и на System.Runtime.InteropServices.WindowsRuntime.dll.

Кстати, для C++ вы можете использовать пространства имен ABI для вызова функций WinRT (как я это делал в одном случае в DirectXTK для аудио) или вы можете использовать расширения C++/CX.

#if defined(__cplusplus_winrt)

    // Enumerating with WinRT using C++/CX (Windows Store apps)
    using Windows::Devices::Enumeration::DeviceClass;
    using Windows::Devices::Enumeration::DeviceInformation;
    using Windows::Devices::Enumeration::DeviceInformationCollection;

    auto operation = DeviceInformation::FindAllAsync(DeviceClass::AudioRender);
    while (operation->Status != Windows::Foundation::AsyncStatus::Completed)
        ;

    DeviceInformationCollection^ devices = operation->GetResults();

    for (unsigned i = 0; i < devices->Size; ++i)
    {
        using Windows::Devices::Enumeration::DeviceInformation;

        DeviceInformation^ d = devices->GetAt(i);
...
    }
#else

    // Enumerating with WinRT using WRL (Win32 desktop app for Windows 8.x)
    using namespace Microsoft::WRL;
    using namespace Microsoft::WRL::Wrappers;
    using namespace ABI::Windows::Foundation;
    using namespace ABI::Windows::Foundation::Collections;
    using namespace ABI::Windows::Devices::Enumeration;

    RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
    HRESULT hr = initialize;
    ThrowIfFailed( hr );

    Microsoft::WRL::ComPtr<IDeviceInformationStatics> diFactory;
    hr = ABI::Windows::Foundation::GetActivationFactory( HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(), &diFactory );
    ThrowIfFailed( hr );

    Event findCompleted( CreateEventEx( nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS ) );
    if ( !findCompleted.IsValid() )
        throw std::exception( "CreateEventEx" );

    auto callback = Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection*>>(
        [&findCompleted,list]( IAsyncOperation<DeviceInformationCollection*>* aDevices, AsyncStatus status ) -> HRESULT
    {
        UNREFERENCED_PARAMETER(aDevices);
        UNREFERENCED_PARAMETER(status);
        SetEvent( findCompleted.Get() );
        return S_OK;
    });

    ComPtr<IAsyncOperation<DeviceInformationCollection*>> operation;
    hr = diFactory->FindAllAsyncDeviceClass( DeviceClass_AudioRender, operation.GetAddressOf() );
    ThrowIfFailed( hr );

    operation->put_Completed( callback.Get() );

    (void)WaitForSingleObjectEx( findCompleted.Get(), INFINITE, FALSE );

    ComPtr<IVectorView<DeviceInformation*>> devices;
    operation->GetResults( devices.GetAddressOf() );

    unsigned int count = 0;
    hr = devices->get_Size( &count );
    ThrowIfFailed( hr );

    if ( !count )
        return list;

    for( unsigned int j = 0; j < count; ++j )
    {
        ComPtr<IDeviceInformation> deviceInfo;
        hr = devices->GetAt( j, deviceInfo.GetAddressOf() );
        if ( SUCCEEDED(hr) )
        {
            HString id;
            deviceInfo->get_Id( id.GetAddressOf() );

            HString name;
            deviceInfo->get_Name( name.GetAddressOf() );
...
        }
    }

#endif 

Это, конечно, код, который совместим только с Windows 8.0 или более поздней версии и не будет работать в Windows 7 или более ранней версии.

Создайте Portable Class Library и поместите туда весь свой BLE-код, а затем ссылайтесь на библиотеку в своем настольном / консольном приложении.

Другие вопросы по тегам