Jump to content

Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate
Photo

EnumDrives() - Enumerate USB Mass Storage Devices


  • Please log in to reply
12 replies to this topic
SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
DriveGet, List, List enumerates all the drives and returns CDEFGIJ for me, in which drives IJ are USB Mass Storage Devices. If I need only UMS drives ( USB Mass Storage ), DriveGet, List, List, REMOVABLE would not help much as some USB-HDD devices are typed 'FIXED'. EnumDrives( True ) will repopulate and return the drive letters for bus type 'USB', which in my case are IJ, and can be used to automate 'Safely Remove UMS Devices'. EnumDrives( False ) is verbose and returns a TSV ( Tab Seperated Values - LineFeed terminated rows ) with info on all available drives.

Here follows a snippet that loads the TSV into a ListView:

Posted Image
#SingleInstance, Force
Gui, Font, S9
Gui, Add, ListView, w550 R10 +Grid
        , Drive|BusType|InUse?|IsRem?|VendorID - ProductID - Description|DosDevice
Gui, Add, Button, Default gRefresh, Refresh
Gui, Show,, EnumDrives()    [ IOCTL_STORAGE_QUERY_PROPERTY ]

Refresh:
 LV_Delete(),  DL := [color=#FF0000]EnumDrives([/color] [color=#FF8000]False[/color] [color=#FF0000])[/color]
 Loop, Parse, DL, `n
 {  StringSplit, F, A_LoopField, %A_Tab%
    LV_Add( "",F1,F2,F3,F4,F5,F6 )
 }  LV_ModifyCol( "AutoHdr" )
Return                                                 ; // End of auto-execute section //

EnumDrives()

EnumDrives( UMS=0 ) { ; Enumerate USB Mass Storage Devices - by SKAN - Created 24-Aug-2012
 Static StrGet="StrGet"               ; www.autohotkey.com/community/viewtopic.php?t=91471
 DriveGet, DriveArray, List
 StringReplace, DriveArray, DriveArray, A
 StringReplace, DriveArray, DriveArray, B

 VarSetCapacity( sPath, 1024 ) ;  DosQueryDevice              ;  MSDN http://bit.ly/Qyl883
 VarSetCapacity( STORAGE_PROPERTY_QUERY, 12, 0 )              ;  MSDN http://bit.ly/SvILmx
 NumPut( 0, STORAGE_PROPERTY_QUERY ) ; 0 is redundant!        ;  MSDN http://bit.ly/O8UNiH
 VarSetCapacity( STORAGE_DESCRIPTOR_HEADER, 1024, 0 )         ;  MSDN http://bit.ly/NNYsSi

[color=#808080]  /*
      STORAGE_DEVICE_DESCRIPTOR {
      00  DWORD            Version;
      04  DWORD            Size;
      08  BYTE             DeviceType;
      09  BYTE             DeviceTypeModifier;
      10  BOOLEAN          RemovableMedia;
      11  BOOLEAN          CommandQueueing;
      12  DWORD            VendorIdOffset;
      16  DWORD            ProductIdOffset;
      20  DWORD            ProductRevisionOffset;
      24  DWORD            SerialNumberOffset;
      28  STORAGE_BUS_TYPE BusType;
      32  DWORD            RawPropertiesLength;
      36  BYTE             RawDeviceProperties[1];
      }

  */
[/color]
 Loop, Parse, DriveArray
  {
    Drive := A_LoopField ,  Device := "\\.\" Drive ":"
    hVol  := DllCall( "CreateFile",  Str,Device,  UInt,0x80000000, UInt,0x0
                    , UInt,0, UInt,0x3, UInt,0x0, UInt,0 )
    If ( InUse := ( hVol < 1 ) )
    hVol  := DllCall( "CreateFile",  Str,Device,  UInt,0x80000000, UInt,0x3
                    , UInt,0, UInt,0x3, UInt,0x0, UInt,0 )

    Res := DllCall( "DeviceIoControl"
      , UInt, hVol
      , UInt, 0x2D1400   ; IOCTL_STORAGE_QUERY_PROPERTY         MSDN: http://bit.ly/OdLos0
      , UInt, &STORAGE_PROPERTY_QUERY
      , UInt, 12
      , UInt, &STORAGE_DESCRIPTOR_HEADER ;> STORAGE_DEVICE_DESCRIPTOR http://bit.ly/O8UNiH
      , UInt, 1024
      , UIntP, BR
      , UInt, 0 )

    DllCall("CloseHandle", UInt,hVol )
    IfEqual,Res,0, Continue

    BT := NumGet( STORAGE_DESCRIPTOR_HEADER, 28 ) ; STORAGE_BUS_TYPE  http://bit.ly/T3qt9C

    If ( UMS<>0 && BT<> 7 )
       Continue
       
    List .= Drive

    If ( UMS=1 )
       Continue

    BT := BT=1 ?  "SCSI"  : BT=2 ? "ATAPI" : BT=3 ? "ATA" : BT=4 ? "1394" : BT=5 ? "SSA"
       :  BT=6 ?  "FIBRE" : BT=7 ? "USB"  : BT=8 ? "RAID" : BT=9 ? "iSCSI" : BT=10 ? "SAS"
       :  BT=11 ? "SATA"  : BT=12 ? "SD"  : BT=13 ? "MMC" : BT=14 ? "Virtual"
       :  BT=15 ? "FileBackedVirtual" :  BT=16 ? "Max" : BT=17 ? "MaxReserved" : "Unknown"

    RM := NumGet( STORAGE_DESCRIPTOR_HEADER, 10, "Char" )                ; RemovableMedia

    S1 := S2 := ""
    If NumGet( STORAGE_DESCRIPTOR_HEADER, 12 )                           ; VendorIdOffset
       Off := &STORAGE_DESCRIPTOR_HEADER + NumGet( STORAGE_DESCRIPTOR_HEADER, 12 )
     , S1  := A_IsUnicode ? %StrGet%( Off, "" )
                          : DllCall( "MulDiv", UInt,Off, Int,1, Int,1, Str )

    If NumGet( STORAGE_DESCRIPTOR_HEADER, 16 )                           ; ProductIdOffset
       Off := &STORAGE_DESCRIPTOR_HEADER + NumGet( STORAGE_DESCRIPTOR_HEADER, 16 )
    ,  S2  := A_IsUnicode ? %StrGet%( Off, "" )
                          : DllCall( "MulDiv", UInt,Off, Int,1, Int,1, Str )

   DllCall( "QueryDosDevice", Str,Drive ":", Str,sPath, Int,1022 )  ; http://bit.ly/Qyl883

   List .= ":" A_Tab BT A_Tab InUse A_Tab RM A_Tab
   . RegExReplace( S1 " " S2, "(^ +| +(?= )| +$)" ) ; Thanks [color=#FF0000]ManaUser[/color] http://bit.ly/P7JkUe
   . A_Tab sPath "`n"
  }

 IfEqual,UMS,0, StringTrimRight,List,List,1
Return List
}

kWo4Lk1.png

MasterFocus
  • Moderators
  • 4323 posts
  • Last active: Jan 28 2016 01:38 AM
  • Joined: 08 Apr 2009
Shouldn't it be Static StrGet:="StrGet" instead of Static StrGet="StrGet" ?
By the way, that is a very nice trick!

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Antonio Fran├ža -- git.io -- github.com -- ahk4.net -- sites.google.com -- ahkscript.org

Member of the AHK community since 08/Apr/2009. Moderator since mid-2012.


SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Shouldn't it be Static StrGet:="StrGet" instead of Static StrGet="StrGet" ?


Both works.. but last time I tried static assignment in AHK 1.0, it threw an error! Must have been due to different problem, I presume.

guest3456
  • Members
  • 1704 posts
  • Last active: Nov 19 2015 11:58 AM
  • Joined: 10 Mar 2011
code readability > code length

i like the change, even if the ternaries make my head spin :)

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Have edited the code to use QueryDosDevice().
Previously, I was using QueryDosDeviceA() as QueryDosDevice() was failing in AHK_Lw 32bit.
Suddenly the problem seems to have disappeared. Somebody else have faced similar problem.
For anyone, if DosDevice column ( actually it is NT Device names ) is empty when run in AHL_Lw, please let me know.

Thanks.

Elderon
  • Members
  • 36 posts
  • Last active: Apr 08 2014 04:16 PM
  • Joined: 17 Aug 2012
Hi SKAN, I wanted to see this work and hopefully adapt it for some unknown future experiment. Anyways, I kept getting an error code: -1073741819
The GUI would appear but it would be an empty table.
I use AutoHotKey_l!
Windows 7 Ultimate x64
I don't like DropBox, try SugarSync instead.
while(!(succeed = try()));

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005
Hello Elderon, may I know your Windows / AHK version ?

Elderon
  • Members
  • 36 posts
  • Last active: Apr 08 2014 04:16 PM
  • Joined: 17 Aug 2012
Windows 7 x64
AHK_L x64 Unicode V1.1.8.1
I use AutoHotKey_l!
Windows 7 Ultimate x64
I don't like DropBox, try SugarSync instead.
while(!(succeed = try()));

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

Windows 7 x64
AHK_L x64 Unicode V1.1.8.1


My code is not compatible with AHK_L 64 bit :(
I do not have the means to run/test 64Bit code.

Elderon
  • Members
  • 36 posts
  • Last active: Apr 08 2014 04:16 PM
  • Joined: 17 Aug 2012
Ahh that would do it!
Would you happen to have an idea of what I would need to change? This coding is a bit above my level but if you have any ideas I would gladly attempt to try them, I've been meaning to learn com anyways...
I use AutoHotKey_l!
Windows 7 Ultimate x64
I don't like DropBox, try SugarSync instead.
while(!(succeed = try()));

SKAN
  • Administrators
  • 9115 posts
  • Last active:
  • Joined: 26 Dec 2005

what I would need to change?


Mainly Varsetcapacity/DllCall()
<!-- m -->http://l.autohotkey....#VarSetCapacity<!-- m -->

Elderon
  • Members
  • 36 posts
  • Last active: Apr 08 2014 04:16 PM
  • Joined: 17 Aug 2012
I will have to look into that, thanks!
I use AutoHotKey_l!
Windows 7 Ultimate x64
I don't like DropBox, try SugarSync instead.
while(!(succeed = try()));

robertcollier4
  • Members
  • 141 posts
  • Last active: Jun 28 2019 01:05 AM
  • Joined: 11 Nov 2012

Why do you have it set to not display any information if UMS=1? If you do the following changes, then it displays the information in "UMS" only mode also.

 

The following lines:

    If ( UMS=1 )
       Continue

 

change to:

;    If ( UMS=1 )
;      Continue

 

The following line:

 IfEqual,UMS,0, StringTrimRight,List,List,1

 

change to:

 StringTrimRight,List,List,1