Announcement

Collapse
No announcement yet.

Identify USB Drive Letter

Collapse
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

  • Identify USB Drive Letter

    I have a need to find the USB attached to a PC, where I know there will be only one or zero attached USB drives. So I do this ...

    Code:
    Function GetUBSDriveLetter() As String
       Local i As Long, sDrives As String     'buffer to hold return from API
       sDrives = String$(104," ")   'size the buffer - '"c:\" + nul = 4 bytes x 26 possible letter drives = 104
       GetLogicalDriveStrings 1044, ByVal StrPtr(sDrives)
       For i = 65 To 90
          If InStr(sDrives, Chr$(i)) And GetDriveType(Chr$(i)+":\") = %drive_removable Then Function = Chr$(i) : Exit Function
       Next i
    End Function
    If I wanted to open it, I could do this ...
    Code:
    ShellExecute(hDlg,"Open",GetUSBDriveLetter + ":\", $Nul, $Nul, %SW_Restore)
    Nothing original here on my part, just a modification of something I found on the forums.


  • #2
    Hey Gary,
    If you use a GetDriveType() approach then you do not need GetLogicalDriveStrings()...

    Code:
     
    #COMPILE EXE '#Win 9.07#
    #DIM ALL
    #INCLUDE "Win32Api.inc"
    
    '_____________________________________________________________________________
    
    FUNCTION GetFirstRemovableDriveWithMedia() AS STRING
     LOCAL index AS LONG
     LOCAL zDisk AS ASCIIZ * 3
    
     FOR index = 65 TO 90 'A to Z
       zDisk = CHR$(index) & ":"
       IF GetDriveType(zDisk) = %DRIVE_REMOVABLE THEN 'Is this a removable drive
         IF GetVolumeInformation(zDisk, BYVAL 0, 0, 0, 0, 0, BYVAL 0, 0) THEN 'Is there a valid media
           FUNCTION = zDisk
           EXIT FOR
         END IF
       END IF
     NEXT
    
    END FUNCTION
    '_____________________________________________________________________________
    
    FUNCTION PBMAIN() AS LONG
     LOCAL sFirstRemovableDrive AS STRING
    
     sFirstRemovableDrive = GetFirstRemovableDriveWithMedia()
     IF LEN(sFirstRemovableDrive) THEN
       ShellExecute(%HWND_DESKTOP, "Open", sFirstRemovableDrive & "\" , $NUL, $NUL, %SW_SHOWNORMAL )
     END IF
    
    END FUNCTION
    '_____________________________________________________________________________
    '
    Last edited by Pierre Bellisle; 14 Dec 2017, 12:45 AM.

    Comment


    • #3
      Howdy, Pierre!
      Yep, thanks for pointing that out! More minimal!

      Comment


      • #4
        Empty floppy drives also count as removable, so if that's a possibility the check needs to be a bit more involved

        Comment


        • #5
          Howdy, Bob!
          Good point. It doesn't apply for my current situation but I'll keep it in mind.

          Comment


          • #6

            A memory card reader is also seen as a removable, in fact many devices can be. Not to say USB is a type of bus among others. For those who might need it, I added GetVolumeInformation() in the code above as an easy way to check if there is a media inserted in the "drive".

            Comment


            • #7
              While in the subject, but a lil more complex...

              Click image for larger version  Name:	UsbDevices.png Views:	1 Size:	37.0 KB ID:	767727

              Code:
               
              'Get USB device by Pierre Bellisle
              
              #COMPILE EXE '#Win 9.07#
              #DIM ALL
              #INCLUDE "Win32Api.inc"
              
              %USB_STRING_DESCRIPTOR_TYPE = 3
              %USB_REQUEST_GET_DESCRIPTOR = 6
              %MAXIMUM_USB_STRING_LENGTH  = 255
              %DEVICECONNECTED            = 1
              
              %FILE_DEVICE_UNKNOWN        = 34
              %FILE_DEVICE_USB            = %FILE_DEVICE_UNKNOWN
              %METHOD_BUFFERED            = 0
              %FILE_ANY_ACCESS            = 0
              
              %IOCTL_USB_GET_NODE_CONNECTION_NAME            = &H00220414
              %IOCTL_GET_HCD_DRIVERKEY_NAME                  = &H00220424
              %IOCTL_USB_GET_NODE_INFORMATION                = &H00220408
              %IOCTL_USB_GET_ROOT_HUB_NAME                   = &H00220408
              %IOCTL_USB_GET_NODE_CONNECTION_INFORMATION     = &H0022040C
              %IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION = &H00220410
              
              TYPE USB_DEVICE_DESCRIPTOR 'Packet.Data 1 - USB_CONFIGURATION_DESCRIPTOR_TYPE
               bLength            AS BYTE 'Specifies the length, in bytes, of this descriptor.
               bDescriptorType    AS BYTE 'Specifies the descriptor type. Must be set to USB_DEVICE_DESCRIPTOR_TYPE (1).
               bcdUSB             AS WORD 'Identifies the version of the USB specification that this descriptor structure complies with. This value is a binary-coded decimal number.
               bDeviceClass       AS BYTE 'Specifies the class code of the device as assigned by the USB specification group.
               bDeviceSubClass    AS BYTE 'Specifies the subclass code of the device as assigned by the USB specification group.
               bDeviceProtocol    AS BYTE 'Specifies the protocol code of the device as assigned by the USB specification group.
               bMaxPacketSize0    AS BYTE 'Specifies the maximum packet size, in bytes, for endpoint zero of the device. The value must be set to 8, 16, 32, or 64.
               idVendor           AS WORD 'Specifies the vendor identifier for the device as assigned by the USB specification committee.
               idProduct          AS WORD 'Specifies the product identifier. This value is assigned by the manufacturer and is device-specific.
               bcdDevice          AS WORD 'Identifies the version of the device. This value is a binary-coded decimal number.
               iManufacturer      AS BYTE 'Specifies a device-defined index of the string descriptor that provides a string containing the name of the manufacturer of this device.
               iProduct           AS BYTE 'Specifies a device-defined index of the string descriptor that provides a string that contains a description of the device.
               iSerialNumber      AS BYTE 'Specifies a device-defined index of the string descriptor that provides a string that contains a manufacturer-determined serial number for the device.
               bNumConfigurations AS BYTE 'Specifies the total number of possible configurations for the device.
              END TYPE
              
              TYPE USB_ENDPOINT_DESCRIPTOR 'Packet.Data 5 - USB_CONFIGURATION_DESCRIPTOR_TYPE
               bLength          AS BYTE 'Specifies the length, in bytes, of this descriptor.
               bDescriptorType  AS BYTE 'Specifies the descriptor type. Must be set to USB_ENDPOINT_DESCRIPTOR_TYPE.
               bEndpointAddress AS BYTE 'Specifies the USB-defined endpoint address. The four low-order bits specify the endpoint number. The high-order bit specifies the direction of data flow on this endpoint: 1 for in, 0 for out.
               bmAttributes     AS BYTE 'The two low-order bits specify the endpoint type, one of USB_ENDPOINT_TYPE_CONTROL, USB_ENDPOINT_TYPE_ISOCHRONOUS, USB_ENDPOINT_TYPE_BULK, or USB_ENDPOINT_TYPE_INTERRUPT.
               wMaxPacketSize   AS WORD 'Specifies the maximum packet size that can be sent from or to this endpoint.
               bInterval        AS BYTE 'For interrupt endpoints, bInterval contains the polling interval. For other types of endpoint, this value should be ignored. This value reflects the device's configuration in firmware. Drivers cannot change it.
              END TYPE
              
              TYPE USB_COMMON_DESCRIPTOR 'Packet.Data header - USB_CONFIGURATION_DESCRIPTOR_TYPE
               bLength         AS BYTE  'Lenght in bytes of the descriptor.
               bDescriptorType AS BYTE  'The descriptor type. 1 for USB_DEVICE_DESCRIPTOR, 2 for USB_CONFIGURATION_DESCRIPTOR, 4 for USB_INTERFACE_DESCRIPTOR, 5 for USB_ENDPOINT_DESCRIPTOR, 33 for HID_DESCRIPTOR.
              END TYPE
              
              TYPE SETUP_PACKET
               bmRequest AS BYTE 'The type of USB device request, standard, class, or vendor
               bRequest  AS BYTE '0x06 value indicates a request of GET_DESCRIPTOR.
               wValue    AS WORD 'Type of descriptor to retrieve in the high byte of wValue and the descriptor index in the low byte.
               wIndex    AS WORD 'The device-specific index of the descriptor that is to be retrieved.
               wLength   AS WORD 'The length of the data that is transferred during the second phase of the control transfer.
              END TYPE
              
              TYPE USB_DESCRIPTOR_REQUEST
               ConnectionIndex AS LONG                                'The port whose descriptors are retrieved.
               SETUP_PACKET                                           'See SETUP_PACKET type.
               DATA            AS STRING * %MAXIMUM_USB_STRING_LENGTH 'On output from the IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION I/O control request, this member contains the retrieved descriptors.
              END TYPE
              
              TYPE USB_HUB_DESCRIPTOR
               bDescriptorLength   AS BYTE        'The length, in bytes of the descriptor.
               bDescriptorType     AS BYTE        'The descriptor type. For hub descriptors, this value should be 0x29.
               bNumberOfPorts      AS BYTE        'The number of ports on the hub.
               wHubCharacteristics AS WORD        'The hub characteristics. For more information about this member, see Universal Serial Bus Specification.
               bPowerOnToPowerGood AS BYTE        'The time, in 2-millisecond intervals, that it takes the device to turn on completely. For more information about this member, see Universal Serial Bus Specification.
               bHubControlCurrent  AS BYTE        'The maximum current requirements, in milliamperes, of the controller component of the hub.
               bRemoveAndPowerMask AS STRING * 65 'Not currently implemented. Do not use this member. This member implements DeviceRemovable and PortPwrCtrlMask fields of the hub descriptor. For more information about these fields, see Universal Serial Bus
              '                                    Specification.
              END TYPE
              
              TYPE USB_HUB_NODE
               UsbHub      AS WORD 'Indicates that the device is a hub.
               UsbMIParent AS WORD 'Indicates that the device is a composite device with multiple interfaces.
              END TYPE
              
              TYPE USB_HUB_INFORMATION
               HubDescriptor   AS USB_HUB_DESCRIPTOR 'A USB_HUB_DESCRIPTOR structure that contains selected information from the hub descriptor.
               HubIsBusPowered AS LONG               'A Boolean value that indicates whether the hub is powered. If TRUE, the hub is powered. If FALSE, the hub is not powered.
              END TYPE
              
              TYPE USB_MI_PARENT_INFORMATION
               NumberOfInterfaces AS LONG 'The number of interfaces on the composite device.
              END TYPE
              
              UNION USB_NODE_INFORMATION_UNION
               HubInformation      AS USB_HUB_INFORMATION       'A USB_HUB_INFORMATION structure that contains information about a parent hub device.
               MiParentInformation AS USB_MI_PARENT_INFORMATION 'A USB_MI_PARENT_INFORMATION structure that contains information about a parent non-hub, composite device.
              END UNION
              
              TYPE USB_NODE_INFORMATION
               NodeType AS USB_HUB_NODE   'A USB_HUB_NODE enumerator that indicates whether the parent device is a hub or a non-hub composite device.
               USB_NODE_INFORMATION_UNION 'See USB_NODE_INFORMATION_UNION union
              END TYPE
              
              TYPE USB_HCD_DRIVERKEY_NAME
               ActualLength  AS DWORD                               'The length, in bytes, of the string in the DriverKeyName member.
               DriverKeyName AS STRING * %MAXIMUM_USB_STRING_LENGTH 'wChar array, a NULL-terminated Unicode driver key name for the USB host controller.
              END TYPE
              
              TYPE USB_NODE_CONNECTION_NAME
               ConnectionIndex AS LONG                                 'A value that is greater than or equal to 1 that specifies the number of the port to which the hub is attached.
               ActualLength    AS LONG                                 'The length, in bytes, of the attached hub's symbolic link.
               NAME            AS STRING * %MAXIMUM_USB_STRING_LENGTH  'A Unicode symbolic link for the downstream hub that is attached to the port that is indicated by ConnectionIndex.
              END TYPE
              
              TYPE USB_PIPE_INFO
               EndpointDescriptor AS USB_ENDPOINT_DESCRIPTOR 'See USB_ENDPOINT_DESCRIPTOR type
               ScheduleOffset     AS DWORD                   'Indicates the schedule offset assigned to the endpoint for this pipe.
              END TYPE
              
              TYPE USB_NODE_CONNECTION_INFORMATION
               ConnectionIndex           AS LONG                  'A value that is greater than or equal to 1 that specifies the number of the port.
               DeviceDescriptor          AS USB_DEVICE_DESCRIPTOR 'A USB_DEVICE_DESCRIPTOR structure that reports the USB device descriptor that is returned by the attached device during enumeration.
               CurrentConfigurationValue AS BYTE                  'Value used with SetConfiguration request to specify that current configuration of the device that is connected to the indicated port. See Universal Serial Bus Specification.
               LowSpeed                  AS BYTE                  'If TRUE, the port and its connected device are currently operating at a low speed.
               DeviceIsHub               AS BYTE                  'Value that indicates if the device that is attached to the port is a hub. If TRUE, the device that is attached to the port is a hub. If FALSE, the device is not a hub.
               DeviceAddress             AS WORD                  'The USB-assigned, bus-relative address of the device that is attached to the port.
               NumberOfOpenPipes         AS DWORD                 'The number of open USB pipes that are associated with the port.
               ConnectionStatus          AS DWORD                 'A USB_CONNECTION_STATUS-typed enumerator that indicates the connection status.
               PipeList(1 TO 32)         AS USB_PIPE_INFO         'An array of USB_PIPE_INFO structures that describes the open pipes that are associated with the port.
              END TYPE                                            'Pipe descriptions include the schedule offset of the pipe and the associated endpoint descriptor. This information can be used to calculate bandwidth usage.
              
              TYPE USB_LANGUAGE_ID
               bLength         AS BYTE 'Size of Descriptor in Bytes
               bDescriptorType AS BYTE 'Constant, string Descriptor (0x03)
               wLangId(0)      AS WORD 'First of an array of language id
              END TYPE
              '_____________________________________________________________________________
              
              FUNCTION regDosDevidesGet(BYREF sDosDevicesArray() AS STRING) AS LONG
               LOCAL zValueName     AS ASCIIZ * %MAX_PATH
               LOCAL sData          AS STRING * %MAX_PATH
               LOCAL hKey           AS DWORD
               LOCAL ValueLen       AS DWORD
               LOCAL DataLen        AS DWORD
               LOCAL dwRegType      AS DWORD
               LOCAL dwValueCount   AS DWORD
               LOCAL DosDeviceCount AS DWORD
               LOCAL Retval         AS LONG
              
               Retval = RegOpenKeyEx(%HKEY_LOCAL_MACHINE, "SYSTEM\MountedDevices", BYVAL %NULL, %KEY_READ, hKey)
               IF Retval = %ERROR_SUCCESS THEN
                 dwValueCount   = 0
                 DosDeviceCount = 0
                 DO
                   ValueLen = %MAX_PATH
                   DataLen  = %MAX_PATH
                   Retval = RegEnumValue(hKey, dwValueCount, zValueName, ValueLen, _
                                         BYVAL %Null, dwRegType, sData, DataLen)
                   IF Retval = %ERROR_NO_MORE_ITEMS THEN Retval = %ERROR_SUCCESS : EXIT DO
                   IF LCASE$(LEFT$(zValueName, 12)) = "\dosdevices\" THEN
                     IF DataLen > 12 THEN
                       REDIM PRESERVE sDosDevicesArray(0 TO DosDeviceCount) AS STRING
                       sDosDevicesArray(DosDeviceCount) = RIGHT$(zValueName, 2) & ACODE$(LEFT$(sData, DataLen)) 'If unicode
                       INCR DosDeviceCount
                     END IF
                   END IF
                   INCR dwValueCount
                 LOOP WHILE Retval = %ERROR_SUCCESS
                 RegCloseKey(hKey)
               END IF
               FUNCTION = DosDeviceCount
              
              END FUNCTION
              '_____________________________________________________________________________
              
              FUNCTION usbDeviceLanguageId(BYVAL hHub AS DWORD, BYVAL PortIndex AS LONG, BYREF LanguageIdArray() AS WORD)AS LONG
               LOCAL Request         AS USB_DESCRIPTOR_REQUEST
               LOCAL pUsbLanguageId  AS USB_LANGUAGE_ID POINTER
               LOCAL zLanguage       AS ASCIIZ * %MAX_PATH
               LOCAL sBuffer         AS STRING
               LOCAL BytesReturned   AS DWORD
               LOCAL LanguageIdCount AS LONG
               LOCAL Success         AS LONG
               LOCAL Looper          AS LONG
              
               IF LanguageIdArray(1) = 0 THEN 'Get the languages ids
                 Request.ConnectionIndex = PortIndex
                 Request.bmRequest       = &H80
                 Request.bRequest        = %USB_REQUEST_GET_DESCRIPTOR
                 Request.wValue          = MAK(WORD, 0, %USB_STRING_DESCRIPTOR_TYPE) 'No Index here
                 Request.wLength         = %MAXIMUM_USB_STRING_LENGTH '3 * 256 '4 'LanguageIdArray(1) size = 4, 1033
                 Success = DeviceIoControl(hHub, %IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, _
                                           BYVAL VARPTR(Request), SIZEOF(Request), _
                                           BYVAL VARPTR(Request), SIZEOF(Request), BytesReturned, BYVAL %NULL)
                 IF Success THEN
                   pUsbLanguageId = VARPTR(Request.Data)
                   IF @pUsbLanguageId.bDescriptorType = 3 THEN 'Constant, string Descriptor = 3
                     LanguageIdCount = (@pUsbLanguageId.bLength \ 2) - 1
                     DIM LanguageIdArrayFromIo(1 TO LanguageIdCount) AS WORD AT VARPTR(Request.Data) + 2
                     REDIM LanguageIdArray(1 TO LanguageIdCount)
                     CopyMemory(BYVAL VARPTR(LanguageIdArray(1)), BYVAL VARPTR(LanguageIdArrayFromIo(1)), LanguageIdCount * 2)
              
                     FOR Looper = 1 TO LanguageIdCount
                      sBuffer = sBuffer & "0x" & HEX$(LanguageIdArray(Looper), 4) & " (" & FORMAT$(LanguageIdArray(Looper)) & ") "
                       GetLocaleInfo MAK(DWORD, LanguageIdArray(Looper), %SORT_DEFAULT), %LOCALE_SENGLANGUAGE, zLanguage, %MAX_PATH
                       sBuffer = sBuffer & zLanguage & " ("
                       GetLocaleInfo MAK(DWORD, LanguageIdArray(Looper), %SORT_DEFAULT), %LOCALE_SENGCOUNTRY, zLanguage, %MAX_PATH
                       sBuffer = sBuffer & zLanguage &  "), "
                       GetLocaleInfo MAK(DWORD, LanguageIdArray(Looper), %SORT_DEFAULT), %LOCALE_SLANGUAGE, zLanguage, %MAX_PATH
                       sBuffer = sBuffer & zLanguage & $CRLF
                     NEXT
                   END IF
                 END IF
               END IF
              
              END FUNCTION
              '_____________________________________________________________________________
              
              FUNCTION usbDeviceString(BYVAL hHub AS DWORD, BYVAL PortIndex AS LONG, BYVAL Index AS BYTE)AS STRING
               LOCAL Request                 AS USB_DESCRIPTOR_REQUEST
               LOCAL pBuffer                 AS USB_COMMON_DESCRIPTOR POINTER
               LOCAL sBuffer                 AS STRING
               LOCAL BytesReturned           AS DWORD
               LOCAL StringLen               AS LONG
               LOCAL Success                 AS LONG
               DIM   LanguageIdArray(1 TO 1) AS WORD
              
               usbDeviceLanguageId(hHub, PortIndex, LanguageIdArray())
              
               Request.ConnectionIndex = PortIndex
               Request.bmRequest       = &H80
               Request.bRequest        = %USB_REQUEST_GET_DESCRIPTOR
               Request.wValue          = MAK(WORD, Index, %USB_STRING_DESCRIPTOR_TYPE)
               Request.wIndex          = LanguageIdArray(1) 'Use only the first one
               Request.wLength         = %MAXIMUM_USB_STRING_LENGTH
              
               Success = DeviceIoControl(hHub, %IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION, _
                                         BYVAL VARPTR(Request), SIZEOF(Request), _
                                         BYVAL VARPTR(Request), SIZEOF(Request), BytesReturned, BYVAL %NULL)
               IF Success THEN
                 pBuffer = VARPTR(Request.DATA)
                 StringLen = @pBuffer.bLength
                 sBuffer = ACODE$(MID$(Request.DATA, 3, StringLen - 2))
                 sBuffer = RTRIM$(sBuffer, ANY $SPC & $NUL)
                 IF sBuffer = "" THEN sBuffer = "None" 'Descriptor is blank
                 FUNCTION = sBuffer
               ELSE
                 FUNCTION = "None" 'No string descriptor returned
               END IF
              
              END FUNCTION
              '_____________________________________________________________________________
              
              FUNCTION usbDeviceInfo(BYVAL hHub AS DWORD, BYVAL PortIndex AS LONG, _
                                     BYVAL pBuffer AS USB_DEVICE_DESCRIPTOR POINTER, BYREF sDosDevicesArray() AS STRING)AS STRING
               LOCAL sManufacturer   AS STRING
               LOCAL sProduct        AS STRING
               LOCAL sDiskSerial     AS STRING
               LOCAL sTry            AS STRING
               LOCAL sDrive          AS STRING
               LOCAL zVolume         AS ASCIIZ * 50
               LOCAL zVolumeSerial   AS ASCIIZ * 10
               LOCAL zFileSystem     AS ASCIIZ * 10
               LOCAL FileSystemFlags AS DWORD
               LOCAL VolumeSerial    AS DWORD
               LOCAL MaxLenFileName  AS LONG
               LOCAL Looper          AS LONG
               LOCAL CharPos         AS LONG
              
               sManufacturer = usbDeviceString(hHub, PortIndex, @pBuffer.iManufacturer)
               sProduct      = usbDeviceString(hHub, PortIndex, @pBuffer.iProduct)
               sDiskSerial   = usbDeviceString(hHub, PortIndex, @pBuffer.iSerialNumber)
               sDrive        = "None"
              
               FOR Looper = 0 TO UBOUND(sDosDevicesArray())
                 zVolume       = "-"
                 zFileSystem   = "-"
                 zVolumeSerial = "-"
              
                 sTry = LCASE$(sManufacturer)
                 REPLACE $SPC WITH "_" IN sTry
                 IF (sTry = "none") OR (sTry = "generic") OR (sTry = "?") THEN sTry = "&ven_"
                 CharPos = INSTR(LCASE$(sDosDevicesArray(Looper)), sTry)
                 IF CharPos THEN
                   sTry = LCASE$(sProduct)
                   REPLACE $SPC WITH "_" IN sTry
                   IF (sTry = "none") OR (sTry = "mass_storage")  OR (sTry = "usb_mass_storage") THEN sTry = "&prod_"
                   CharPos = INSTR(CharPos, LCASE$(sDosDevicesArray(Looper)), sTry)
                   IF CharPos THEN
                     sTry = LCASE$(sDiskSerial) & "&0"
                     REPLACE $SPC WITH "_" IN sTry
                     CharPos = INSTR(CharPos, LCASE$(sDosDevicesArray(Looper)), sTry)
                     IF CharPos THEN
                       sDrive = LEFT$(sDosDevicesArray(Looper), 2)
                       GetVolumeInformation(BYVAL STRPTR(sDrive), zVolume, SIZEOF(zVolume), VolumeSerial, MaxLenFileName, _
                                            FileSystemFlags, zFileSystem, SIZEOF(zFileSystem))
                       zVolumeSerial = LEFT$(HEX$(VolumeSerial), 4) & "-" & RIGHT$(HEX$(VolumeSerial), 4)
                       IF LEN(zVolume) = 0 THEN zVolume = "None"
                       EXIT FOR
                     END IF
                   END IF
                 END IF
               NEXT
              
               FUNCTION = "id Vendor    " & $TAB & "0x" & HEX$(@pBuffer.idVendor, 4)  & $CRLF & _
                          "id Product   " & $TAB & "0x" & HEX$(@pBuffer.idProduct, 4) & $CRLF & _
                          "Manufacturer " & $TAB & sManufacturer                      & $CRLF & _
                          "Product      " & $TAB & sProduct                           & $CRLF & _
                          "SerialNumber " & $TAB & sDiskSerial                        & $CRLF & _
                          "Drive letter " & $TAB & sDrive                             & $CRLF & _
                          "Volume       " & $TAB & zVolume                            & $CRLF & _
                          "Volume Serial" & $TAB & zVolumeSerial                      & $CRLF & _
                          "FileSystem   " & $TAB & zFileSystem                        & $CRLF & $CRLF
              
              END FUNCTION
              '_____________________________________________________________________________
              
              SUB usbPortEnum(BYVAL hHub AS DWORD, BYVAL PortCount AS BYTE, BYVAL HubDepth AS BYTE, _
                              BYREF sBuffer AS STRING, BYREF sDosDevicesArray() AS STRING)
               LOCAL  ConnectionInformation AS USB_NODE_CONNECTION_INFORMATION
               LOCAL  NodeInformation       AS USB_NODE_INFORMATION
               LOCAL  NodeConnection        AS USB_NODE_CONNECTION_NAME
               LOCAL  SecurityAttr          AS SECURITY_ATTRIBUTES 'Needed for Win2000
               LOCAL  NodeConnectionName    AS ASCIIZ * %MAXIMUM_USB_STRING_LENGTH
               LOCAL  sDeviceInfo           AS STRING
               LOCAL  hNodeConnection       AS DWORD
               LOCAL  BytesReturned         AS DWORD
               LOCAL  Success               AS LONG
               LOCAL  PortIndex             AS LONG
               LOCAL  HubWanted             AS LONG
              
               SecurityAttr.nLength              = SIZEOF(SECURITY_ATTRIBUTES)
               SecurityAttr.lpSecurityDescriptor = 0
               SecurityAttr.bInheritHandle       = %FALSE
              
               FOR PortIndex = 1 TO PortCount 'Iterate each ports and see what is connected
                 ConnectionInformation.ConnectionIndex = PortIndex
              
                 Success = DeviceIoControl(hHub, %IOCTL_USB_GET_NODE_CONNECTION_INFORMATION, _
                                           BYVAL VARPTR(ConnectionInformation), SIZEOF(ConnectionInformation), _
                                           BYVAL VARPTR(ConnectionInformation), SIZEOF(ConnectionInformation), _
                                           BytesReturned, BYVAL %NULL)
                 IF Success THEN
                   IF ConnectionInformation.ConnectionStatus = %DEVICECONNECTED THEN
                     IF ConnectionInformation.DeviceIsHub THEN 'It's a HUB, we need to iterate his ports.
                       NodeConnection.ConnectionIndex = PortIndex
                       Success = DeviceIoControl(hHub, %IOCTL_USB_GET_NODE_CONNECTION_NAME, _
                                                 BYVAL VARPTR(NodeConnection), SIZEOF(NodeConnection), _
                                                 BYVAL VARPTR(NodeConnection), SIZEOF(NodeConnection), _
                                                 BytesReturned, BYVAL %NULL)
                       IF Success THEN
                         NodeConnectionName = ACODE$(LEFT$(NodeConnection.NAME, NodeConnection.ActualLength))
                         NodeConnectionName = "\\.\" & NodeConnectionName
                         hNodeConnection = CreateFile(NodeConnectionName, %GENERIC_READ, %FILE_SHARE_READ, _
                                                      SecurityAttr, %OPEN_EXISTING, 0, BYVAL %NULL)
                         Success = DeviceIoControl(hNodeConnection, %IOCTL_USB_GET_NODE_INFORMATION, _
                                                   BYVAL VARPTR(NodeInformation), SIZEOF(NodeInformation), _
                                                   BYVAL VARPTR(NodeInformation), SIZEOF(NodeInformation), _
                                                   BytesReturned, BYVAL %NULL)
                         IF Success THEN
                           HubWanted = %FALSE
                           IF HubWanted THEN
                             sBuffer = sBuffer & usbDeviceInfo(hHub, PortIndex, VARPTR(ConnectionInformation.DeviceDescriptor), _
                                                               BYREF sDosDevicesArray())
                           ELSE
                             usbDeviceInfo(hHub, PortIndex, VARPTR(ConnectionInformation.DeviceDescriptor), _
                                           BYREF sDosDevicesArray())
                           END IF
                           'Recursive function call
                           usbPortEnum(hNodeConnection, NodeInformation.HubInformation.HubDescriptor.bNumberOfPorts, _
                                       HubDepth + 1, sBuffer, sDosDevicesArray())
                         END IF
                         CloseHandle(hNodeConnection)
                       END IF
                     ELSE
                       sDeviceInfo = usbDeviceInfo(hHub, PortIndex, VARPTR(ConnectionInformation.DeviceDescriptor), _
                                                   BYREF sDosDevicesArray())
                       sBuffer = sBuffer & sDeviceInfo
                     END IF
                   END IF
                 END IF
               NEXT
              
              END SUB
              '_____________________________________________________________________________
              
              SUB usbHostControllerInfo(BYVAL hHostController AS DWORD, BYREF sBuffer AS STRING, BYREF sDosDevicesArray()AS STRING)
               LOCAL SecurityAttr             AS SECURITY_ATTRIBUTES 'Needed for Win2000
               LOCAL NodeInformation          AS USB_NODE_INFORMATION
               LOCAL DriverKeyName            AS USB_HCD_DRIVERKEY_NAME
               LOCAL RootHubName              AS ASCIIZ * %MAXIMUM_USB_STRING_LENGTH
               LOCAL hRootHub                 AS DWORD
               LOCAL BytesReturned            AS LONG
               LOCAL Success                  AS LONG
              
               SecurityAttr.nLength              = SIZEOF(SECURITY_ATTRIBUTES)
               SecurityAttr.lpSecurityDescriptor = 0
               SecurityAttr.bInheritHandle       = %FALSE
              
               Success = DeviceIoControl(hHostController, %IOCTL_GET_HCD_DRIVERKEY_NAME, _
                                         BYVAL VARPTR(DriverKeyName), SIZEOF(DriverKeyName), _
                                         BYVAL VARPTR(DriverKeyName), SIZEOF(DriverKeyName), _
                                         BytesReturned, BYVAL %NULL)
               IF Success THEN
                 Success = DeviceIoControl(hHostController, %IOCTL_USB_GET_ROOT_HUB_NAME, _
                                           BYVAL VARPTR(DriverKeyName), SIZEOF(DriverKeyName), _
                                           BYVAL VARPTR(DriverKeyName), SIZEOF(DriverKeyName), _
                                           BytesReturned, BYVAL %NULL)
                 IF Success THEN
                   RootHubName = ACODE$(LEFT$(DriverKeyName.DriverKeyName, DriverKeyName.ActualLength))
                   RootHubName = "\\.\" & RootHubName
                   hRootHub = CreateFile(RootHubName, %GENERIC_READ, %FILE_SHARE_READ, _
                                         SecurityAttr, %OPEN_EXISTING, BYVAL %NULL, BYVAL %NULL)
                   IF hRootHub <> %INVALID_HANDLE_VALUE THEN
                     Success = DeviceIoControl(hRootHub, %IOCTL_USB_GET_NODE_INFORMATION, _
                                               BYVAL VARPTR(NodeInformation), SIZEOF(NodeInformation), _
                                               BYVAL VARPTR(NodeInformation), SIZEOF(NodeInformation), _
                                               BytesReturned, BYVAL %NULL)
                     IF Success THEN
                       usbPortEnum(hRootHub, NodeInformation.HubInformation.HubDescriptor.bNumberOfPorts, _
                                   0, sBuffer, sDosDevicesArray())
                       CloseHandle(hRootHub)
                     END IF
                   END IF
                 END IF
               END IF
              
              END SUB
              '_____________________________________________________________________________
              
              FUNCTION UsbDeviceSerialNumberGet() AS STRING
               LOCAL SecurityAttr             AS SECURITY_ATTRIBUTES 'Needed for Win2000
               LOCAL HostControllerName       AS ASCIIZ * 12
               LOCAL sBuffer                  AS STRING
               DIM   sDosDevicesArray(0 TO 0) AS STRING
               LOCAL hHostController          AS DWORD
               LOCAL Looper                   AS LONG
               LOCAL DosDeviceCount           AS DWORD
              
               SecurityAttr.nLength              = SIZEOF(SECURITY_ATTRIBUTES)
               SecurityAttr.lpSecurityDescriptor = 0
               SecurityAttr.bInheritHandle       = %FALSE
              
               DosDeviceCount = regDosDevidesGet(sDosDevicesArray())
              
               FOR Looper = 0 TO 25
                 HostControllerName = "\\.\HCD" & FORMAT$(Looper)
                 hHostController    = CreateFile(HostControllerName, %GENERIC_READ, %FILE_SHARE_READ, _
                                                 SecurityAttr, %OPEN_EXISTING, BYVAL %NULL, BYVAL %NULL)
                 IF GetLastError = 0 THEN
                   IF (hHostController <> %INVALID_HANDLE_VALUE) THEN
                     usbHostControllerInfo(hHostController, sBuffer, sDosDevicesArray())
                     CloseHandle(hHostController)
                   END IF
                 END IF
               NEXT
              
               FUNCTION = sBuffer
              
              END FUNCTION
              '_____________________________________________________________________________
              
              FUNCTION PBMAIN
              
               MessageBox(%HWND_DESKTOP, UsbDeviceSerialNumberGet, "USB devices", %MB_OK OR %MB_TOPMOST)
              
              END FUNCTION
              '_____________________________________________________________________________
              '
              Last edited by Pierre Bellisle; 14 Dec 2017, 01:05 PM.

              Comment


              • #8
                Gary

                You could also have a look on the code i posted there
                http://www.jose.it-berater.org/smffo...15749#msg15749
                to perform USB detection, and use the unique USB hardware serial number as a dongle key replacement.
                Patrice Terrier
                www.zapsolution.com
                www.objreader.com
                Addons: GDImage.DLL 32/64-bit (Graphic library), WinLIFT.DLL 32/64-bit (Skin Engine).

                Comment


                • #9
                  Howdy, Patrice!
                  Thanks for the suggestion. I'll go take a look.

                  And, Pierre,
                  I've been seeing a lot of code recently about identifying hardware serial numbers. I need to find something to do with that capability! It's like having an hammer and searching for a nail to hit!

                  Comment

                  Working...
                  X