[C++/WinRT][Win32][UWP] HidDevice.FromIdAsync() cannot open device in FileAccessMode::ReadWrite mode in Win32 app

Dimitriy Ryazantcev 26 Reputation points
2020-06-01T14:44:13.367+00:00

I trying to use Windows.Devices.HumanInterfaceDevice UWP API to open HID device (gamepad in my case) and send HID output report. But HidDevice.FromIdAsync() method cannot open device in FileAccessMode::ReadWrite mode in my classic console Win32 app:

enter image description here

Here is minimal C++/WinRT repro example:

   cpp  
   #include "pch.h"  
     
   #include <winrt/Windows.Foundation.h>  
   #include <winrt/Windows.Foundation.Collections.h>  
   #include <winrt/Windows.Devices.Enumeration.h>  
   #include <winrt/Windows.Devices.HumanInterfaceDevice.h>  
   #include <winrt/Windows.Storage.h>  
     
   #include <string>  
   #include <iostream>  
   #include <functional>  
     
   using namespace std;  
   using namespace winrt;  
   using namespace Windows::Devices::Enumeration;  
   using namespace Windows::Devices::HumanInterfaceDevice;  
   using namespace Windows::Storage;  
     
   void OnDeviceAdded(const winrt::Windows::Devices::Enumeration::DeviceInformation& deviceInformation)  
   {  
       std::cout << "*****Device Init End*******" << std::endl;  
     
       try {  
           string id = to_string(deviceInformation.Id());  
           string name = to_string(deviceInformation.Name());  
     
           std::cout << "New HID device connected:" << std::endl;  
           std::cout << "Id: " << id << std::endl;  
           std::cout << "Name: " << name << std::endl;  
     
           HidDevice m_Device = HidDevice::FromIdAsync(deviceInformation.Id(), FileAccessMode::ReadWrite).get();  
     
           if (!m_Device)  
           {  
               std::cout << "Cannot open device for writing! Trying read-only..." << std::endl;  
               m_Device = HidDevice::FromIdAsync(deviceInformation.Id(), FileAccessMode::Read).get();  
           }  
     
           if (!m_Device)  
           {  
               std::cout << "Cannot open device for reading!" << std::endl;  
               throw;  
           }  
     
           uint16_t vendorId = m_Device.VendorId();  
           uint16_t productId = m_Device.ProductId();  
           uint16_t version = m_Device.Version();  
           uint16_t usagePage = m_Device.UsagePage();  
           uint16_t usageId = m_Device.UsageId();  
     
           std::cout << "VendorId: " << vendorId << std::endl;  
           std::cout << "ProductId: " << productId << std::endl;  
           std::cout << "Version: " << version << std::endl;  
           std::cout << "UsagePage: " << usagePage << std::endl;  
           std::cout << "UsageId: " << usageId << std::endl;  
       }  
       catch (...)  
       {  
           std::cout << "Something went wrong while device init! :(" << std::endl;  
       }  
     
       std::cout << "*****Device Init End*******" << std::endl;  
   }  
     
   hstring hidDeviceSelector;  
   DeviceWatcher hidDeviceWatcher = nullptr;  
   event_token hidAddedToken;  
     
   int main()  
   {  
       winrt::init_apartment();  
     
       hidDeviceSelector = HidDevice::GetDeviceSelector(0x01 /*HID_USAGE_PAGE_GENERIC*/, 0x05 /*HID_USAGE_GENERIC_GAMEPAD*/);  
       hidDeviceWatcher = DeviceInformation::CreateWatcher(hidDeviceSelector);  
       hidAddedToken = hidDeviceWatcher.Added(std::bind(&OnDeviceAdded, std::placeholders::_2));  
       hidDeviceWatcher.Start();  
     
       while (true)  
       {  
           // wait  
       }  
     
       hidDeviceWatcher.Added(hidAddedToken);  
     
       winrt::uninit_apartment();  
     
       return 0;  
   }  

Similar questions regarding UWP apps mentioning that there should be *.appxmanifest like this:

   xml  
    <Capabilities>  
       <DeviceCapability Name="humaninterfacedevice">  
         <!--SuperMutt Device-->  
         <Device Id="vidpid:045E 0610">  
           <Function Type="usage:FFAA 0001" />  
         </Device>  
       </DeviceCapability>  
     </Capabilities>  

But seems this is only needed for UWP apps.

It worth to mention that HidDevice Class have DualApiPartition attribute and API should be allowed to be called from any desktop app.

This is bug or I'm missing something?

My C++/WinRT demo app code is here:
https://github.com/DJm00n/HidGamepadConsoleApp

Universal Windows Platform (UWP)
{count} votes