1

Good Morning,

I have a native C++ DLL managing BLE (Bluetooth Low Energy) connection who use the internal Bluetooth card of the computer. All works fine on Win10, I never had any problem connecting or reconnecting a device since 2019.

Then I pass under Win11 and none of the function used after discover services seems to work. I never received the callback of the function:

  • GetCharacteristicsWithCacheModeAsync
  • GetDescriptorsWithCacheModeAsync
  • WriteClientCharacteristicConfigurationDescriptorAsync

So I change the two first function to the equivalent function without cache mode and it works fine:

  • GetCharacteristicsWithCacheModeAsync -> GetCharacteristicsAsync
  • GetDescriptorsWithCacheModeAsync -> GetDescriptorsAsync

I still don't know why the cache mode version doesn't work correctly.

In other hand, the last function to write on the descriptor to active the "Notify" or "Indicate" doesn't raise the callback whether I use "WriteClientCharacteristicConfigurationDescriptorAsync" or "WriteClientCharacteristicConfigurationDescriptorWithResultAsync".

Here is my code for writing on the descriptor:

//Try to write the correct "value" on the descripton  
ComPtr<IAsyncOperation<enum GattCommunicationStatus>> writeOp;
HRESULT hr = charac->getChar()->WriteClientCharacteristicConfigurationDescriptorAsync(value, &writeOp);
        
if (ifFailedPrintErrorMessage(hr, "Can't write descriptor async")) {
     return E_FAIL;  
}
        
//Create event to simulate "await"
Event asyncCompletedWriteDescri(CreateEventEx(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, WRITE_OWNER | EVENT_ALL_ACCESS));  
HRESULT resultAsyncActionWriteDescri = S_OK;  
        
//Callback    
hr = writeOp->put_Completed(Callback<IAsyncOperationCompletedHandler<GattCommunicationStatus>>([this, charac, &resultAsyncActionWriteDescri, &asyncCompletedWriteDescri](IAsyncOperation<GattCommunicationStatus> *op, AsyncStatus status) {
        
     //Get Result
     GattCommunicationStatus result;
     HRESULT hr = op->GetResults(&result);  
     if (ifFailedPrintErrorMessage(hr, "Can't get writeDescriptor result")) {
        resultAsyncActionWriteDescri = E_FAIL;
        SetEvent(asyncCompletedWriteDescri.Get());
        return E_FAIL;
     }

     //Check if it's a success
     if (result != GattCommunicationStatus_Success) {
         std::cout << "Can't open pipe" << endl;
         resultAsyncActionWriteDescri = E_FAIL;
         SetEvent(asyncCompletedWriteDescri.Get());
         return E_FAIL;
     }
        
     //Register characteristic to ValueChanged
     if (registrerCharToValueChanged(charac) == E_FAIL) {
         resultAsyncActionWriteDescri = E_FAIL;
         SetEvent(asyncCompletedWriteDescri.Get());
         return E_FAIL;
     }
            
     resultAsyncActionWriteDescri = S_OK;
     SetEvent(asyncCompletedWriteDescri.Get());
     return S_OK;
}).Get());
                
//If the put_Completed function failed
if (ifFailedPrintErrorMessage(hr, "Can't call put_Completed for write descriptor async")) {
     return E_FAIL;
}
                
//Wait until the callback IAsyncOperationCompletedHandler is raised
WaitForSingleObject(asyncCompletedWriteDescri.Get(), INFINITE);
return resultAsyncActionWriteDescri;

I have see in MS example, that it uses the keyword "co_await" but I can't use it here because there is no ComPtr in MS example and the definition of the funtion isn't the same. The MS example works fine and I can write on descriptor. GattCommunicationStatus status = co_await selectedChar.WriteClientCharacteristicConfigurationDescriptorAsync(cccdValue);

Perhaps some security feature have changes?

I have try on Win11: Version 21H2 (build: 22000.856).

Thank you in advance for taking my problem into account :)

Best Regards

Julien

Jiu
  • 11
  • 1
  • IAsyncOperation->QueryInterface(IAsyncInfo). IAsyncInfo->GetStatus() and wait when status changed in simple loop (emulate co_await). Thsi works without any problem. We use this way in our Bluetooth Framework (https://www.btframework.com) – Mike Petrichenko Aug 17 '22 at 10:11
  • Hello, thank you for your answer. It works. :) But I don't understand how we pass from waiting a callback to a call to QueryInterface because as I understand, QueryInterface only gives a pointer on the interface. The other "put_completed(Callback<>)" that I have in my code, still works great without using QueryInterface. – Jiu Aug 22 '22 at 13:48
  • Its different things: callbacks and waiting on IAsyncInfo completion status. Callbacks in WINRT have lot of bugs (sometime they work, sometime does not) so I prefer to stay with waiting on completion status changing with AsyncInfo. – Mike Petrichenko Aug 22 '22 at 15:17

0 Answers0