Я пытаюсь получить Windows::Devices::Usb::UsbDevice
объект, ссылающийся на конкретное USB-устройство, которое я имею, чтобы передать его стороннему плагину. Из-за ограничений проекта я не могу использовать C++/CX
расширение.
Посмотрев на бесчисленные потоки, ответы и ссылки, я придумал начальную реализацию, которая делает некоторую чёрную магию для вызова статических методов в нужных мне классах WinRT. Единственная проблема заключается в том, что, хотя ни один вызов не приводит к провалу HRESULT
, последний звонок FromIdAsync
не работает, давая мне ERROR_INVALID_HANDLE
(6
) как результат GetLastError()
,
Простое чтение имени ошибки делает меня ошибкой в получении идентификатора устройства, поскольку это единственный дескриптор, который я передаю при вызове, но вместо этого я попытался передать константную строку (что, как я знал, было правильно), и это дало те же результаты.
Вот как я призываю 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;
* Multiple if (FAILED(hr)) return nullptr;
удалено для краткости.
GetLastError function
Получает значение кода последней ошибки вызывающего потока.
Код последней ошибки поддерживается для каждого потока.
Несколько потоков не перезаписывают код последней ошибки друг друга.
но вместо этого я попытался передать постоянную строку (что, как я знал, было правильно), и это дало те же результаты.
ERROR_INVALID_HANDLE
Вызывающая сторона передала NULL в параметре InterfaceHandle.
Как уже упоминалось выше, вы должны получить результат от HRESULT
[&openEvent](IAsyncOperation<UsbDevice*> *opHandler, AsyncStatus status) -> HRESULT
Я бы попытался перебрать коллекцию, чтобы выяснить, как получить ошибку от
Других решений пока нет …