NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device) { SP_DEVINFO_DATA Data; UNICODE_STRING nameW; NTSTATUS status; HDEVINFO devinfo; GUID hidGuid; BASE_DEVICE_EXTENSION *ext; HidD_GetHidGuid(&hidGuid); ext = device->DeviceExtension; RtlInitUnicodeString( &nameW, ext->device_name); devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_HIDCLASS, NULL, NULL, DIGCF_DEVICEINTERFACE); if (!devinfo) { FIXME( "failed to get ClassDevs %x\n", GetLastError()); return STATUS_UNSUCCESSFUL; } Data.cbSize = sizeof(Data); if (!SetupDiCreateDeviceInfoW(devinfo, ext->instance_id, &GUID_DEVCLASS_HIDCLASS, NULL, NULL, DICD_INHERIT_CLASSDRVS, &Data)) { if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS) { SetupDiDestroyDeviceInfoList(devinfo); return STATUS_SUCCESS; } FIXME( "failed to Create Device Info %x\n", GetLastError()); goto error; } if (!SetupDiRegisterDeviceInfo( devinfo, &Data, 0, NULL, NULL, NULL )) { FIXME( "failed to Register Device Info %x\n", GetLastError()); goto error; } SetupDiDestroyDeviceInfoList(devinfo); status = IoRegisterDeviceInterface(device, &hidGuid, NULL, &ext->link_name); if (status != STATUS_SUCCESS) { FIXME( "failed to register device interface %x\n", status ); return status; } return STATUS_SUCCESS; error: SetupDiDestroyDeviceInfoList(devinfo); return STATUS_UNSUCCESSFUL; }
HRESULT xDiEnumDriverFiles( __in_opt HWND Owner, __in LPCWSTR OemInfFullPath, __in DWORD Flags, __in XDI_ENUM_DRIVER_FILE_CALLBACK EnumCallback, __in LPVOID EnumContext) { HRESULT hr; BOOL success; WCHAR infFullPath[MAX_PATH]; DWORD n = GetFullPathNameW(OemInfFullPath, MAX_PATH, infFullPath, NULL); if (0 == n) { hr = HRESULT_FROM_WIN32(GetLastError()); hr = (SUCCEEDED(hr)) ? E_FAIL : hr; goto error0; } HDEVINFO devInfoSet = SetupDiCreateDeviceInfoList(NULL, Owner); if (INVALID_HANDLE_VALUE == devInfoSet) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error0; } SP_DEVINFO_DATA devInfoData = { sizeof(SP_DEVINFO_DATA) }; success = SetupDiCreateDeviceInfoW( devInfoSet, L"XDI_Temporary_Enumerator", &GUID_NULL, NULL, NULL, DICD_GENERATE_ID, &devInfoData); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error1; } HSPFILEQ fileQueueHandle = SetupOpenFileQueue(); if (INVALID_HANDLE_VALUE == fileQueueHandle) { // Error from SetupOpenFileQueue is only from out-of-memory situation // without the last error set hr = E_OUTOFMEMORY; goto error2; } SP_DEVINSTALL_PARAMS devInstallParams = {sizeof(SP_DEVINSTALL_PARAMS)}; success = SetupDiGetDeviceInstallParamsW( devInfoSet, &devInfoData, &devInstallParams); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error3; } // // Specify the search path // hr = StringCchCopyW( devInstallParams.DriverPath, MAX_PATH, infFullPath); if (FAILED(hr)) { goto error3; } devInstallParams.FlagsEx |= DI_FLAGSEX_ALLOWEXCLUDEDDRVS; devInstallParams.FileQueue = fileQueueHandle; devInstallParams.Flags |= DI_NOVCP; devInstallParams.Flags |= DI_ENUMSINGLEINF; success = SetupDiSetDeviceInstallParamsW( devInfoSet, &devInfoData, &devInstallParams); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error3; } // // use DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE if possible // to ensure we look at duplicate nodes (which is broken in itself) // #ifndef DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE #define DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE 0x08000000L // Don't remove identical driver nodes from the class list #endif if (xDipWindowsXPOrLater()) { devInstallParams.FlagsEx |= DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE; success = SetupDiSetDeviceInstallParamsW( devInfoSet, &devInfoData, &devInstallParams); if (!success) { devInstallParams.FlagsEx &= ~DI_FLAGSEX_NO_CLASSLIST_NODE_MERGE; } } // // Build a class driver list with every driver // success = SetupDiBuildDriverInfoList( devInfoSet, &devInfoData, SPDIT_CLASSDRIVER); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error3; } SP_DRVINFO_DATA drvInfoData = { sizeof(SP_DRVINFO_DATA) }; for (DWORD index = 0; ; ++index) { success = SetupDiEnumDriverInfoW( devInfoSet, &devInfoData, SPDIT_CLASSDRIVER, index, &drvInfoData); if (!success) { break; } SP_DRVINFO_DETAIL_DATA drvInfoDetail = { sizeof(SP_DRVINFO_DETAIL_DATA) }; success = SetupDiGetDriverInfoDetailW( devInfoSet, &devInfoData, &drvInfoData, &drvInfoDetail, sizeof(SP_DRVINFO_DETAIL_DATA), NULL); if (!success && ERROR_INSUFFICIENT_BUFFER != GetLastError()) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error4; } success = SetupDiSetSelectedDriverW( devInfoSet, &devInfoData, &drvInfoData); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error4; } if (Flags & XDI_EDF_NO_CLASS_INSTALLER) { success = SetupDiInstallDriverFiles( devInfoSet, &devInfoData); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error4; } } else { success = SetupDiCallClassInstaller( DIF_INSTALLDEVICEFILES, devInfoSet, &devInfoData); if (!success) { hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error4; } } } // // SPQ_SCAN_USE_CALLBACK_EX checks the digital signature of the file // We do not want to check the signature here. // // SPQ_SCAN_FILE_PRESENCE avoids checking the digital signature of the file // in Windows XP or later. (Not in Windows 2000) when used // with SPQ_SCAN_USE_CALLBACK_EX // XDI_ENUM_FQS_CONTEXT fqsContext = {0}; fqsContext.Callback = EnumCallback; fqsContext.CallbackContext = EnumContext; DWORD scanResult; success = SetupScanFileQueueW( fileQueueHandle, SPQ_SCAN_USE_CALLBACK, // SPQ_SCAN_USE_CALLBACKEX | SPQ_SCAN_FILE_PRESENCE, Owner, xDipEnumFileQueueScanCallback, &fqsContext, &scanResult); if (!success) { // // SetupScanFileQueue may fail using SPQ_SCAN_FILE_PRESENSE flag // Try again without SPQ_SCAN_FILE_PRESENSE // (when using SPQ_SCAN_USE_CALLBACKEX) // hr = HRESULT_FROM_SETUPAPI(GetLastError()); goto error4; } hr = S_OK; #pragma warning(disable: 4533) // to use goto in cpp error4: SetupDiDestroyDriverInfoList( devInfoSet, &devInfoData, SPDIT_CLASSDRIVER); error3: SetupCloseFileQueue(fileQueueHandle); error2: SetupDiDeleteDeviceInfo(devInfoSet, &devInfoData); error1: SetupDiDestroyDeviceInfoList(devInfoSet); error0: #pragma warning(default: 4533) return hr; }
NTSTATUS HID_LinkDevice(DEVICE_OBJECT *device, LPCWSTR serial, LPCWSTR index) { WCHAR regname[255]; WCHAR dev_link[255]; SP_DEVINFO_DATA Data; UNICODE_STRING nameW, linkW; NTSTATUS status; HDEVINFO devinfo; GUID hidGuid; BASE_DEVICE_EXTENSION *ext; HidD_GetHidGuid(&hidGuid); ext = device->DeviceExtension; sprintfW(dev_link, device_link_fmtW, ext->information.VendorID, ext->information.ProductID, index, ext->information.VersionNumber, serial, class_guid); struprW(dev_link); RtlInitUnicodeString( &nameW, ext->device_name); RtlInitUnicodeString( &linkW, dev_link ); TRACE("Create link %s\n", debugstr_w(dev_link)); ext->link_name = HeapAlloc(GetProcessHeap(), 0, sizeof(WCHAR) * (lstrlenW(dev_link) + 1)); lstrcpyW(ext->link_name, dev_link); status = IoCreateSymbolicLink( &linkW, &nameW ); if (status) { FIXME( "failed to create link error %x\n", status ); return status; } sprintfW(regname, device_regname_fmtW, ext->information.VendorID, ext->information.ProductID, index, ext->information.VersionNumber, serial); devinfo = SetupDiGetClassDevsW(&GUID_DEVCLASS_HIDCLASS, NULL, NULL, DIGCF_DEVICEINTERFACE); if (!devinfo) { FIXME( "failed to get ClassDevs %x\n", GetLastError()); return GetLastError(); } Data.cbSize = sizeof(Data); if (!SetupDiCreateDeviceInfoW(devinfo, regname, &GUID_DEVCLASS_HIDCLASS, NULL, NULL, DICD_INHERIT_CLASSDRVS, &Data)) { if (GetLastError() == ERROR_DEVINST_ALREADY_EXISTS) { SetupDiDestroyDeviceInfoList(devinfo); return ERROR_SUCCESS; } FIXME( "failed to Create Device Info %x\n", GetLastError()); return GetLastError(); } if (!SetupDiRegisterDeviceInfo( devinfo, &Data, 0, NULL, NULL, NULL )) { FIXME( "failed to Register Device Info %x\n", GetLastError()); return GetLastError(); } if (!SetupDiCreateDeviceInterfaceW( devinfo, &Data, &hidGuid, NULL, 0, NULL)) { FIXME( "failed to Create Device Interface %x\n", GetLastError()); return GetLastError(); } SetupDiDestroyDeviceInfoList(devinfo); return S_OK; }
static void create_ramdisk_device(std::string full_inf_file_path, std::string hardware_id) { GUID class_guid; WCHAR class_name_w[MAX_CLASS_NAME_LEN]; auto success = SetupDiGetINFClassW(w32util::widen(full_inf_file_path).c_str(), &class_guid, class_name_w, safe::numelementsf(class_name_w), nullptr); if (!success) w32util::throw_windows_error(); /* don't install device if it already exists */ auto create_device = true; { HDEVINFO device_info_set = SetupDiGetClassDevsEx(&class_guid, nullptr, nullptr, 0, nullptr, nullptr, nullptr); if (device_info_set == INVALID_HANDLE_VALUE) { w32util::throw_setupapi_error(); } SP_DEVINFO_DATA device_info_data; zero_object(device_info_data); device_info_data.cbSize = sizeof(device_info_data); for (DWORD idx = 0; create_device && SetupDiEnumDeviceInfo(device_info_set, idx, &device_info_data); ++idx) { /* first get hardware id reg key for this device info */ CHAR buffer[1024]; BOOL success_prop = SetupDiGetDeviceRegistryPropertyA(device_info_set, &device_info_data, SPDRP_HARDWAREID, nullptr, (PBYTE) buffer, sizeof(buffer), nullptr); if (!success_prop) w32util::throw_setupapi_error(); PCHAR bp = buffer; while(*bp) { if (!strcmp(bp, hardware_id.c_str())) { create_device = false; break; } bp += strlen(bp) + 1; } } } // device already exists, no need to create it if (!create_device) return; auto device_info_set = SetupDiCreateDeviceInfoList(&class_guid, NULL); if (device_info_set == INVALID_HANDLE_VALUE) w32util::throw_setupapi_error(); auto _destroy_device_info_set = safe::create_deferred(SetupDiDestroyDeviceInfoList, device_info_set); SP_DEVINFO_DATA device_info_data; zero_object(device_info_data); device_info_data.cbSize = sizeof(device_info_data); auto success_create_device_info = SetupDiCreateDeviceInfoW(device_info_set, class_name_w, &class_guid, nullptr, 0, DICD_GENERATE_ID, &device_info_data); if (!success_create_device_info) w32util::throw_setupapi_error(); // TODO: runtime stack array is a GCC extension auto reg_hardware_id_len = hardware_id.size() + 2; auto reg_hardware_id_size = reg_hardware_id_len * sizeof(WCHAR); auto reg_hardware_id = std::unique_ptr<WCHAR[]>(new WCHAR[reg_hardware_id_len]); memset(reg_hardware_id.get(), 0, reg_hardware_id_size); memcpy(reg_hardware_id.get(), w32util::widen(hardware_id).data(), hardware_id.size() * sizeof(WCHAR)); auto success_set_hardware_id = SetupDiSetDeviceRegistryPropertyW(device_info_set, &device_info_data, SPDRP_HARDWAREID, (BYTE *) reg_hardware_id.get(), reg_hardware_id_size); if (!success_set_hardware_id) w32util::throw_setupapi_error(); auto success_class_installer = SetupDiCallClassInstaller(DIF_REGISTERDEVICE, device_info_set, &device_info_data); if (!success_class_installer) w32util::throw_setupapi_error(); create_ramdisk_hardware_keys(device_info_set, &device_info_data); }