У меня есть одно приложение MFC, которое использует BLE DLL. Библиотека BLE позаботится о сканировании устройства, подключении и т. д.
Я попытался динамически связать BLE DLL. Сканирование устройства Bluetooth завершается без каких-либо проблем. Когда я попытался вызвать API ConnectToDevice из BLE DLL, возникла проблема.
API работает в других платформах C++, кроме MFC. Я только что создал диалоговое базовое приложение MFC и вызываю API библиотеки BLE из простого события нажатия кнопки.
Это пример кода
fire_and_forget SensorDeviceInfo::ConnectToDevice(condition_variable& signal, bool& bConnected)
{
// Returns a BluetoothLEDevice object for the given Id and initiate a connection
m_BluetoothLEDevice = co_await BluetoothLEDevice::FromIdAsync(GetId());
if (m_BluetoothLEDevice == nullptr)
{
LogError(m_Log, __func__, "Failed to connect to device.");
}
if (m_BluetoothLEDevice != nullptr)
{
m_ConnectionStatusEventToken = m_BluetoothLEDevice.ConnectionStatusChanged({ this,
&SensorDeviceInfo::ConnectionStatusChangeHandler });
}
signal.notify_one();
}
Поскольку это асинхронный вызов, я использовал условную переменную, чтобы заблокировать поток до завершения функции.
mutex mtxConnect;
unique_lock lockConnect(mtxConnect);
condition_variable cvConnect;
// Connect to the sensor ble device
m_CurrentDevice->ConnectToDevice(cvConnect, bConnected);
cvConnect.wait(lockConnect);
Во время отладки приложения вызов поступает в место FromIdAsync, но через некоторое время он зависает, и стек вызовов исчезает.
Я использую VS2019 и последний распространяемый пакет (2019).
При проверке инструмента "Зависимости" я обнаружил, что в папке Windows\System32 отсутствуют некоторые библиотеки DLL.
Отсутствующие библиотеки DLL: api-ms-win-core-wow64-l1-1-0.dll, api-ms-win-core-wow64-l1-1-1.dll, api-ms-win-core -winrt-string-l1-1-0.dll. Здесь api-ms-win-core-wow64-l1-1-0.dll, api-ms-win-core-winrt-string-l1-1-0.dll доступны в других местах Windows.
Но DLL api-ms-win-core-wow64-l1-1-1.dll отсутствует в системе.
Ниже приведены проблемы с зависимостями, заданные инструментом Зависимости
Я проверил mfc140.dll с машины другого коллеги. Проблема зависимости присутствует и на их машинах.
Я не знаю, является ли эта проблема с отсутствующей DLL основной причиной нашего библиотечного API ConnectToDevice.
Это неудобный код по многим причинам. Он запускает асинхронную задачу, а затем решает дождаться завершения синхронно. Синхронизация тоже избыточна. Я имею в виду, что если вы do хотите выполнить
ConnectToDevice
синхронно, просто верните ему IAsyncAction и вызовите для него функцию расширения C++/WinRTget()
. Хотя, на самом деле, вы, конечно же, никогда не захотите блокировать поток пользовательского интерфейса.Кроме того, передача ссылок в сопрограммы — это всегда ошибка, которая просто ждет своего часа.
Да вы правы. Я пробовал так же, как вы сказали. Я пробовал IAsyncAction и IAsyncOperation. Теперь API работают, и теперь я также могу заблокировать рабочий поток. Большое спасибо.
Проблема все еще возникает в моем исходном приложении MFC. В образце приложения MFC он работал без проблем.
Кажется, я припоминаю, что API BLE несколько привередлив, когда дело доходит до того, какой поток выполняет какой вызов. Хотя можно разгрузить вызов
FromIdAsync
в поток пула потоков, вы должны вернуться к исходному потоку до установки обратного вызова события. Второй пример в этом разделе объясняет, как вернуться к вызывающему потоку.Поскольку мне нечего отображать в потоке пользовательского интерфейса, я использую сценарий разгрузки.
co_await winrt::resume_background();
Приведенный выше код фактически решил мою проблему. Спасибо за немедленную помощь.Я настроен скептически, но если у вас нет причин делать
ConnectToDevice
асинхронным, то просто не делайте этого. Превратите его в обычную функцию и замените операторco_await
наFromIdAsync(GetId()).get()
. Нет никаких других точек приостановки, с которыми нужно иметь дело, и после этого изменения все просто работает в одном потоке. Хотя вы, вероятно, делаете асинхронную реализацию, чтобы не замораживать пользовательский интерфейс.О Боже! Почему я не подумал об этом раньше. Спасибо @IInspectable за все ценные комментарии. Я просто удалил
co_await
и просто использовал.get()
с самим WinRT API.