【问题标题】:Open UsbDevice using C++ WRL - ERROR_INVALID_HANDLE使用 C++ WRL 打开 UsbDevice - ERROR_INVALID_HANDLE
【发布时间】:2016-08-13 04:40:09
【问题描述】:

我正在尝试获取一个引用特定 USB 设备的 Windows::Devices::Usb::UsbDevice 对象,以便将其传递给第 3 方插件。由于项目限制,我无法使用C++/CX 扩展。

在查看了无数线程、答案和参考资料后,我想出了一个初始实现,它使用一些黑魔法来调用我需要的 WinRT 类上的静态方法。唯一的问题是,即使没有调用导致失败的HRESULT,最后一次调用FromIdAsync 也不起作用,由于GetLastError(),给了我ERROR_INVALID_HANDLE (6)。

仅仅读取错误名称就让我觉得错误在于获取设备的 ID,因为这是我传递该调用的唯一句柄,但我尝试传递一个常量字符串(我知道这是正确的),它产生了结果相同。

这就是我调用FromIdAsync* 的方式:

// Retrieves static methods for UsbDevice class
ComPtr<IUsbDeviceStatics> usbDevSt;
hr = GetActivationFactory(
    HStringReference(RuntimeClass_Windows_Devices_Usb_UsbDevice).Get(),
    &usbDevSt
);

// Creates an event to work as a 'semaphore', for waiting for the 'FromIdAsync'
// call to be completed
Event openEvent(CreateEventEx(
    nullptr,
    nullptr,
    CREATE_EVENT_MANUAL_RESET,
    WRITE_OWNER | EVENT_ALL_ACCESS
));
if (!openEvent.IsValid()) return nullptr;

// Setups a callback for when the device enumeration is done
auto asyncOpenCb = Callback<IAsyncOperationCompletedHandler<UsbDevice*>>(
    [&openEvent](IAsyncOperation<UsbDevice*> *opHandler, AsyncStatus status) -> HRESULT {
        if (!opHandler || status != AsyncStatus::Completed) {
            DWORD x = GetLastError(); // ERROR_INVALID_HANDLE (6)
        }

        SetEvent(openEvent.Get());
        return S_OK;
    }
);

// Invokes the 'asyncOpenOp' method, equivalent to UsbDevice::FromIdAsync(String)
ComPtr<IAsyncOperation<UsbDevice*>> asyncOpenOp;
hr = usbDevSt->FromIdAsync(
    devId.Get(),
    asyncOpenOp.GetAddressOf()
);

// Registers completed callback
hr = asyncOpenOp->put_Completed(asyncOpenCb.Get());

// Waits for open operation to complete before continuing
WaitForSingleObjectEx(openEvent.Get(), INFINITE, false);

// Retrieves the result from the asynchronous call
ComPtr<IUsbDevice> dev;
hr = asyncOpenOp->GetResults(dev.GetAddressOf());

这就是我得到devId*的方式:

// Retrieve static methods for DeviceInformation class
ComPtr<IDeviceInformationStatics> devInfoSt;
HRESULT hr = GetActivationFactory(
    HStringReference(RuntimeClass_Windows_Devices_Enumeration_DeviceInformation).Get(),
    &devInfoSt
);

// Create an event to work as a 'semaphore', for waiting for the 'FindAllAsyncAqsFilter' call to be completed
Event findEvent(CreateEventEx(
    nullptr,
    nullptr,
    CREATE_EVENT_MANUAL_RESET,
    WRITE_OWNER | EVENT_ALL_ACCESS
));
if (!findEvent.IsValid()) return nullptr;

// Setup a callback for when the device enumeration is done
auto asyncFindCb = Callback<IAsyncOperationCompletedHandler<DeviceInformationCollection*>>(
    [&findEvent](IAsyncOperation<DeviceInformationCollection*> *opHandler, AsyncStatus status) -> HRESULT {
        SetEvent(findEvent.Get());
        return S_OK;
    }
);

// Invoke the 'FindAllAsyncAqsFilter' method, equivalent to DeviceInformation::FindAllAsync(String)
ComPtr<IAsyncOperation<DeviceInformationCollection*>> asyncFindOp;
hr = devInfoSt->FindAllAsyncAqsFilter(
    HStringReference(DEVICE_FILTER).Get(),
    asyncFindOp.GetAddressOf()
);

// Registers completed callback
hr = asyncFindOp->put_Completed(asyncFindCb.Get());

// Waits for enumeration to complete before continuing
WaitForSingleObjectEx(findEvent.Get(), INFINITE, FALSE);

// Retrieves the result from the asynchronous call
ComPtr<IVectorView<DeviceInformation*>> devColl;
hr = asyncFindOp->GetResults(devColl.GetAddressOf());

// Checks for collection size
unsigned int collSize;
hr = devColl->get_Size(&collSize);

if (collSize == 0) {
    return nullptr;
}

// Retrieves the first DeviceInformation object from the collection
ComPtr<IDeviceInformation> devInfo;
hr = devColl->GetAt(0, devInfo.GetAddressOf());

// Retrieves the device's id
HString devId;
hr = devInfo->get_Id(devId.GetAddressOf());

另外,我确实以这种方式初始化 WinRT:

RoInitializeWrapper initialize(RO_INIT_MULTITHREADED);
if (FAILED(initialize)) return nullptr;

*为简洁起见,删除了多个 if (FAILED(hr)) return nullptr;

【问题讨论】:

  • 您无法从 GetLastError() 获得诊断信息,您必须使用 HRESULT。
  • @HansPassant 我认为可能是这样。但是在这种情况下是哪一个?因为除了最后一个(asyncOpenOp-&gt;getResults(...))之外,所有这些都返回S_OK,这给了我0x8000000E(在意外时间调用了一个方法),这完全有道理,因为操作已经失败.

标签: c++ visual-c++ windows-runtime windows-store-apps wrl


【解决方案1】:

GetLastError function

检索调用线程的最后一个错误代码值。
每个线程都维护最后一个错误代码
多个线程不会覆盖彼此的最后一个错误代码。


但我尝试传递一个常量字符串(我知道这是正确的),它产生了相同的结果。

ERROR_INVALID_HANDLE
调用者在 InterfaceHandle 参数中传递了 NULL。

如上所述,您必须从HRESULT获取结果

[&openEvent](IAsyncOperation<UsbDevice*> *opHandler, AsyncStatus status) -> HRESULT 

我会尝试遍历集合以找出如何从中获取错误

https://msdn.microsoft.com/en-us/library/windows/apps/windows.devices.enumeration.deviceinformationcollection.indexof

【讨论】:

  • 收藏似乎不是问题。我可以成功检索到 DeviceInformation 对象,并且它的属性似乎非常有效。我不太明白你的建议。
猜你喜欢
  • 1970-01-01
  • 2015-11-12
  • 1970-01-01
  • 1970-01-01
  • 2017-12-29
  • 1970-01-01
  • 2012-12-10
  • 2017-04-26
  • 2012-09-15
相关资源
最近更新 更多