locked
ReadFile works when handle opened with drive letter/physical drive symlink, but not with device path RRS feed

  • Question

  • I want to open a USB flash drive and read from it on a physical disk level. This works OK when I supply 'CreateFile' with a drive letter ('\\.\G:') or physical device number ('\\.\PhysicalDrive1') type symbolic link. However, what I really want to do, is to open it with a device path:

    hSourceDevice = CreateFile( // ((PUSBDEVICEINFO) sourceDevice->infoItem)->DevicePath,
            _T("\\\\.\\usb#Vid_0781&Pid_5530#4324401b65307a12#{a5dcbf10-6530-11d2-901f-00c04fb951ed}"),
           // _T("\\\\.\\G:"),
           // _T("\\\\.\\PhysicalDrive1"),
                                    GENERIC_READ | GENERIC_WRITE,
                                    FILE_SHARE_READ | FILE_SHARE_WRITE,
                                    NULL,
                                    OPEN_EXISTING,
                                    0,
                                    NULL);

    I get in all 3 cases a valid handle (no INVALID_HANDLE_VALUE)  from 'CreateFile'. Then I want to read from the USB flash drive:
            
    result = ReadFile( hSourceDevice,
         buffer,
         512,
         &bytesRead,
         NULL);
         
    This works for the handles created with a drive letter or physical device number - but not for the device path one. In that case, 'ReadFile' fails with the errorcode 87 (ERROR_INVALID_PARAMETER). Other functions that work in the first 2 cases also fail with the device path one, like IOCTL_STORAGE_GET_DEVICE_NUMBER with errorcode 50 (ERROR_NOT_SUPPORTED).
    When I use the handle with 'GetFileType' I get in the first 2 cases 1 (FILE_TYPE_DISK) as a result, when I use the device path one I get a 0 (FILE_TYPE_UNKNOWN).
    Obviously it is something different that is opened when I use the device path. But what and why?

    There are several reasons why I need to use a device path to open the USB flash drive, the main one that I specifically want to target flash drives plugged in a certain hub. Based on 'UsbView' source code, I do the following to get the device path:

    1. I walk through the USB device tree, until I find and get a handle to the hub that I want (correct VendorId & DeviceId & Serialnumber).
    2. Given the handle of the hub, I iterate with IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX over its ports.
    3. If a port is connected and is not another hub, I supply to IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME the hub handle and the port index and get the driver key name (e.g. '{36FC9E60-C465-11CF-8056-444553540000}\0023').
    4. I walk with CM_ functions through the device nodes, until I have found the one with the correct driver key name.
    5. With the Device Instance Handle of the device node I get through 'CM_Get_Device_ID' the Device Instance ID (e.g. 'USB\VID_0781&PID_5530\4324401B65307A12').
    6. This Device Instance ID is used with SetupDiGetClassDevs:

    deviceInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVINTERFACE_USB_DEVICE,
              deviceID,
              NULL,
              (DIGCF_PRESENT | DIGCF_DEVICEINTERFACE));
              
    SetupDiEnumDeviceInterfaces and SetupDiGetDeviceInterfaceDetail then deliver the device path (e.g. '\\?\usb#vid_0781&pid_5530#4324401b65307a12#{a5dcbf10-6530-11d2-901f-00c04fb951ed}').

    I am currently working with Visual Studio 10 under Windows XP.

    Many thanks in advance for any help.

    Tuesday, July 17, 2012 1:08 PM

Answers