Со времени последнего обновления Windows 10 1809 мы больше не можем открывать USB-устройства, похожие на HID, с помощью CreateFile
. Мы сократили проблему до этого минимального примера:
#include <windows.h>
#include <setupapi.h>
#include <stdio.h>
#include <hidsdi.h>
void bad(const char *msg) {
DWORD w = GetLastError();
fprintf(stderr, "bad: %s, GetLastError() == 0x%08x\n", msg, (unsigned)w);
}
int main(void) {
int i;
GUID hidGuid;
HDEVINFO deviceInfoList;
const size_t DEVICE_DETAILS_SIZE = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA) + MAX_PATH;
SP_DEVICE_INTERFACE_DETAIL_DATA *deviceDetails = alloca(DEVICE_DETAILS_SIZE);
deviceDetails->cbSize = sizeof(*deviceDetails);
HidD_GetHidGuid(&hidGuid);
deviceInfoList = SetupDiGetClassDevs(&hidGuid, NULL, NULL,
DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if(deviceInfoList == INVALID_HANDLE_VALUE) {
bad("SetupDiGetClassDevs");
return 1;
}
for (i = 0; ; ++i) {
SP_DEVICE_INTERFACE_DATA deviceInfo;
DWORD size = DEVICE_DETAILS_SIZE;
HIDD_ATTRIBUTES deviceAttributes;
HANDLE hDev = INVALID_HANDLE_VALUE;
fprintf(stderr, "Trying device %d\n", i);
deviceInfo.cbSize = sizeof(deviceInfo);
if (!SetupDiEnumDeviceInterfaces(deviceInfoList, 0, &hidGuid, i,
&deviceInfo)) {
if (GetLastError() == ERROR_NO_MORE_ITEMS) {
break;
} else {
bad("SetupDiEnumDeviceInterfaces");
continue;
}
}
if(!SetupDiGetDeviceInterfaceDetail(deviceInfoList, &deviceInfo,
deviceDetails, size, &size, NULL)) {
bad("SetupDiGetDeviceInterfaceDetail");
continue;
}
fprintf(stderr, "Opening device %s\n", deviceDetails->DevicePath);
hDev = CreateFile(deviceDetails->DevicePath, 0,
FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
OPEN_EXISTING, 0, NULL);
if(hDev == INVALID_HANDLE_VALUE) {
bad("CreateFile");
continue;
}
deviceAttributes.Size = sizeof(deviceAttributes);
if(HidD_GetAttributes(hDev, &deviceAttributes)) {
fprintf(stderr, "VID = %04x PID = %04x\n", (unsigned)deviceAttributes.VendorID, (unsigned)deviceAttributes.ProductID);
} else {
bad("HidD_GetAttributes");
}
CloseHandle(hDev);
}
SetupDiDestroyDeviceInfoList(deviceInfoList);
return 0;
}
Он перечисляет все устройства HID, пытаясь получить идентификатор поставщика/идентификатор продукта для каждого, используя CreateFile
по пути, SetupDiGetDeviceInterfaceDetail
а затем вызывая HidD_GetAttributes
.
Этот код работает без проблем в предыдущих версиях Windows (протестирован в Windows 7, Windows 10 1709 и 1803, и оригинальный код, из которого он был извлечен, работает всегда начиная с XP и далее), но с последним обновлением (1809) для всех клавиатурных устройств ( в том числе и наш) не может быть открыт, так как CreateFile
завершается ошибкой с отказом в доступе (GetLastError()
== 5). Запуск программы от имени администратора не имеет никакого эффекта.
Сравнивая выходные данные до и после обновления, я заметил, что устройства, которые теперь не могут быть открыты, получили конечный \kbd
в пути устройства, то есть то, что ранее было
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}
сейчас
\\?\hid#vid_24d6&pid_8000&mi_00#7&294a3305&0&0000#{4d1e55b2-f16f-11cf-88cb-001111000030}\kbd
Это ошибка/новое ограничение безопасности в последней версии Windows 10? Был ли этот код всегда неправильным, и раньше он работал случайно? Это можно исправить?
Обновить
В качестве отчаянной попытки мы попытались удалить \kbd
из возвращенной строки... и CreateFile
теперь работает! Итак, теперь у нас есть обходной путь, но было бы интересно понять, если это ошибка в SetupDiGetDeviceInterfaceDetail
, если он намеренный, и если этот обходной путь на самом деле правильный.