#include "pch.h" #include HRESULT RetrieveDevicePath( _Out_bytecap_(BufLen) LPTSTR DevicePath, _In_ ULONG BufLen, _Out_opt_ PBOOL FailureDeviceNotFound ); HRESULT OpenDevice( _Out_ PDEVICE_DATA DeviceData, _Out_opt_ PBOOL FailureDeviceNotFound ) /*++ Routine description: Open all needed handles to interact with the device. If the device has multiple USB interfaces, this function grants access to only the first interface. If multiple devices have the same device interface GUID, there is no guarantee of which one will be returned. Arguments: DeviceData - Struct filled in by this function. The caller should use the WinusbHandle to interact with the device, and must pass the struct to CloseDevice when finished. FailureDeviceNotFound - TRUE when failure is returned due to no devices found with the correct device interface (device not connected, driver not installed, or device is disabled in Device Manager); FALSE otherwise. Return value: HRESULT --*/ { HRESULT hr = S_OK; BOOL bResult; DeviceData->HandlesOpen = FALSE; hr = RetrieveDevicePath(DeviceData->DevicePath, sizeof(DeviceData->DevicePath), FailureDeviceNotFound); if (FAILED(hr)) { return hr; } DeviceData->DeviceHandle = CreateFile(DeviceData->DevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL); if (INVALID_HANDLE_VALUE == DeviceData->DeviceHandle) { hr = HRESULT_FROM_WIN32(GetLastError()); return hr; } bResult = WinUsb_Initialize(DeviceData->DeviceHandle, &DeviceData->WinusbHandle); if (FALSE == bResult) { hr = HRESULT_FROM_WIN32(GetLastError()); CloseHandle(DeviceData->DeviceHandle); return hr; } DeviceData->HandlesOpen = TRUE; return hr; } VOID CloseDevice( _Inout_ PDEVICE_DATA DeviceData ) /*++ Routine description: Perform required cleanup when the device is no longer needed. If OpenDevice failed, do nothing. Arguments: DeviceData - Struct filled in by OpenDevice Return value: None --*/ { if (FALSE == DeviceData->HandlesOpen) { // // Called on an uninitialized DeviceData // return; } WinUsb_Free(DeviceData->WinusbHandle); CloseHandle(DeviceData->DeviceHandle); DeviceData->HandlesOpen = FALSE; return; } HRESULT RetrieveDevicePath( _Out_bytecap_(BufLen) LPTSTR DevicePath, _In_ ULONG BufLen, _Out_opt_ PBOOL FailureDeviceNotFound ) /*++ Routine description: Retrieve the device path that can be used to open the WinUSB-based device. If multiple devices have the same device interface GUID, there is no guarantee of which one will be returned. Arguments: DevicePath - On successful return, the path of the device (use with CreateFile). BufLen - The size of DevicePath's buffer, in bytes FailureDeviceNotFound - TRUE when failure is returned due to no devices found with the correct device interface (device not connected, driver not installed, or device is disabled in Device Manager); FALSE otherwise. Return value: HRESULT --*/ { CONFIGRET cr = CR_SUCCESS; HRESULT hr = S_OK; PTSTR DeviceInterfaceList = NULL; ULONG DeviceInterfaceListLength = 0; if (NULL != FailureDeviceNotFound) { *FailureDeviceNotFound = FALSE; } // // Enumerate all devices exposing the interface. Do this in a loop // in case a new interface is discovered while this code is executing, // causing CM_Get_Device_Interface_List to return CR_BUFFER_SMALL. // do { cr = CM_Get_Device_Interface_List_Size(&DeviceInterfaceListLength, (LPGUID)&GUID_DEVINTERFACE_$formatteddrivername$, NULL, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); if (cr != CR_SUCCESS) { hr = HRESULT_FROM_WIN32(CM_MapCrToWin32Err(cr, ERROR_INVALID_DATA)); break; } DeviceInterfaceList = (PTSTR)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, DeviceInterfaceListLength * sizeof(TCHAR)); if (DeviceInterfaceList == NULL) { hr = E_OUTOFMEMORY; break; } cr = CM_Get_Device_Interface_List((LPGUID)&GUID_DEVINTERFACE_$formatteddrivername$, NULL, DeviceInterfaceList, DeviceInterfaceListLength, CM_GET_DEVICE_INTERFACE_LIST_PRESENT); if (cr != CR_SUCCESS) { HeapFree(GetProcessHeap(), 0, DeviceInterfaceList); if (cr != CR_BUFFER_SMALL) { hr = HRESULT_FROM_WIN32(CM_MapCrToWin32Err(cr, ERROR_INVALID_DATA)); } } } while (cr == CR_BUFFER_SMALL); if (FAILED(hr)) { return hr; } // // If the interface list is empty, no devices were found. // if (*DeviceInterfaceList == TEXT('\0')) { if (NULL != FailureDeviceNotFound) { *FailureDeviceNotFound = TRUE; } hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); HeapFree(GetProcessHeap(), 0, DeviceInterfaceList); return hr; } // // Give path of the first found device interface instance to the caller. CM_Get_Device_Interface_List ensured // the instance is NULL-terminated. // hr = StringCbCopy(DevicePath, BufLen, DeviceInterfaceList); HeapFree(GetProcessHeap(), 0, DeviceInterfaceList); return hr; }