Jump to content











Photo

Eject Removable Drives (AHK GUI for Safely Remove Drives)


  • Please log in to reply
7 replies to this topic

#1 robertcollier4

robertcollier4

    Member

  • Members
  • 33 posts
  •  
    United States

Posted 27 January 2013 - 02:27 PM

Here is a AutoHotkey GUI frontend for Window's Safely Remove Hardware that is easier to use and keyboard shortcut friendly. You can just use the up and down arrows and hit "Enter" to eject a removable drive with keyboard only operation. When the dialog no longer shows the drive, the "Esc" key closes the dialog. The GUI display is better than the Windows display which shows your drive labels in nested trees and requires mouse clicking. For more information visit AutoHotkey Forums SKAN's SafelyRemoveUMS function which it is based upon.

 

To use, download the file SafelyRemoveSKAN-GUI.ahk (9 KB) and run with AutoHotkey or use the pre-compiled AutoHotkey binary SafelyRemoveSKAN-GUI.exe (200 KB) if you don't have AutoHotkey. Or manually create the script by manually pasting the below text into a blank .AHK file and run with AutoHotkey:

 

guiaddonsafelyremoveums.gif

 

SafelyRemoveSKAN-GUI.ahk:

;---------------------------------------------------------------
; http://www.autohotkey.com/board/topic/41310-safelyremoveums-safely-remove-usb-mass-storage-drives/page-3#entry567088
; Eject Removable Drives (GUI Addon to SKAN SafelyRemoveUMS)
; This script adds a GUI control ListView to display removable drives and then remove them with SKAN SafelyRemoveUMS
;---------------------------------------------------------------

#NoTrayIcon
Menu Tray, Icon, C:\WINDOWS\system32\hotplug.dll, 0

Gui, Add, ListView, -Multi x6 y6 r6 w488 vDriveListView gProcessDriveList, Drive|Size(MB)|Volume Label|Device
Gui, Add, Button, x6 w241 h60 gProcessDriveList Default, Eject
Gui, Add, Button, xp+247 yp wp h60 gCancelButton, Close

DriveGet, DrvList, List, REMOVABLE
Loop, Parse, DrvList
{
	DriveGet, ThisDrvLabel, Label, %A_Loopfield%:
	DriveGet, ThisDrvSize, Capacity, %A_Loopfield%:
	ThisDrvInfo := SafelyRemoveUMS(A_Loopfield . ":", True, True)
	LV_Add("", A_Loopfield, ThisDrvSize, ThisDrvLabel, ThisDrvInfo)
}

LV_ModifyCol(1, "40")
LV_ModifyCol(2, "60")
LV_ModifyCol(3, "160")
LV_ModifyCol(4, "AutoHdr")
 
Gui, -MinimizeBox -MaximizeBox
Gui, Show, w500, Eject Removable Drives
Return

ProcessDriveList:
RowSelected := LV_GetNext()
If(RowSelected = 0)
	{
		MsgBox, , No selection, No selection
	} 
	Else
	{
		LV_GetText(DriveSelected, RowSelected, 1)
		SafelyRemoveUMS(DriveSelected . ":", True)
		Reload
	}
Return

GuiEscape:
CancelButton:
GuiClose:
ExitApp
Return

;ADD SKAN SafelyRemoveUMS() Function HERE

;---------------------------------------------------------------
; SafelyRemoveUMS v1.00 by SKAN,   CD:01-Sep-2012 / LM:09-Sep-2012
; AutoHotkey Forum Topic :  http://www.autohotkey.com/community/viewtopic.php?t=44873
;SafelyRemoveUMS( DrivePath, Retry=0) { 
SafelyRemoveUMS( DrivePath, Retry=0, InfoOnly=0 ) { ; MODIFIED-robertcollier4 Added InfoOnly Parameter

 hVol  := DllCall( "CreateFile"
                 , Str,  "\\.\" . ( Drive  := SubStr( DrivePath, 1, 1 ) . ":" )
                 , UInt, 0x80000000
                 , UInt, 0x3
                 , UInt, 0
                 , UInt, 0x3
                 , UInt, 0x0
                 , UInt, 0  )

 If ( hvol < 1 )
    Return 0, ErrorLevel := 1             ; Unable to access volume!

 VarSetCapacity( GenBuf, 2080, 0 )        ; General, all-purpose buffer
 
 pSTORAGE_PROPERTY_QUERY    := &GenBuf                       ;  MSDN  http://bit.ly/SvILmx
 pSTORAGE_DESCRIPTOR_HEADER := &GenBuf + 12                  ;  MSDN  http://bit.ly/O8UNiH
 NumPut( StorageDeviceProperty := 0, pSTORAGE_PROPERTY_QUERY + 0 )

 DllCall( "DeviceIoControl"
        , UInt, hVol
        , UInt, 0x2D1400   ; IOCTL_STORAGE_QUERY_PROPERTY    ;  MSDN: http://bit.ly/OdLos0
        , UInt, pSTORAGE_PROPERTY_QUERY
        , UInt, 12
        , UInt, pSTORAGE_DESCRIPTOR_HEADER ;STORAGE_DEVICE_DESCRIPTOR http://bit.ly/O8UNiH
        , UInt, 1024
        , UIntP, BR
        , UInt, 0 )

 BT := NumGet( pSTORAGE_DESCRIPTOR_HEADER + 28 )   ; STORAGE_BUS_TYPE http://bit.ly/T3qt9C
 If ( BT <> 0x7 )                                  ; BusTypeUsb = 0x7
    Return 0,   DllCall( "CloseHandle", UInt,hVol )
  , ErrorLevel := 2                                ; Drive not USB Mass Storage Device!
 

 IOCTL_STORAGE_GET_DEVICE_NUMBER := 0x2D1080
 pSTORAGE_DEVICE_NUMBER          := &GenBuf

 DllCall( "DeviceIoControl"
        , UInt,  hVol
        , UInt,  IOCTL_STORAGE_GET_DEVICE_NUMBER   ; MSDN http://bit.ly/Ssuzfm
        , UInt,  0
        , UInt,  0
        , UInt,  pSTORAGE_DEVICE_NUMBER            ; MSDN http://bit.ly/PF17hX
        , UInt,  12
        , UIntP, BR
        , UInt,  0   )
        
 DllCall( "CloseHandle", UInt,hVol )
 
 If ( BR = 0 )
    Return 0,  ErrorLevel := 3                     ; Unable to ascertain the Device number

 sDevNum := NumGet( pSTORAGE_DEVICE_NUMBER + 4 )

 GUID_DEVINTERFACE_DISK := "{53F56307-B6BF-11D0-94F2-00A0C91EFB8B}" ; http://bit.ly/TXvGlC
 VarSetCapacity( DiskGUID, 16, 0 )
 NumPut( 0x53F56307,   DiskGUID, 0, "UInt"  )  ,  NumPut( 0xB6BF, DiskGUID, 4, "UShort" )
 NumPut( 0x11D0,       DiskGUID, 6, "UShort")  ,  NumPut( 0xF294, DiskGUID, 8, "UShort" )
 NumPut( 0x1EC9A000,   DiskGUID,10, "UInt"  )  ,  NumPut( 0x8BFB, DiskGUID,14, "UShort" )

 hMod := DllCall( "LoadLibrary", Str,"SetupAPI.dll", UInt )

 hDevInfo := DllCall( "SetupAPI\SetupDiGetClassDevs"                ; http://bit.ly/Pf6vHX
                    . ( A_IsUnicode ? "W" : "A" )
                    , UInt,  &DiskGUID
                    , UInt,  0
                    , UInt,  0
                    , UInt,  0x12  ;  DIGCF_PRESENT := 0x2 | DIGCF_DEVICEINTERFACE := 0x10
                          ,  Int )

 If ( hDevInfo < 1 )
    Return 0,  ErrorLevel := 4                    ; No storage class devices were found!


 pSP_DEVICE_INTERFACE_DATA        :=  &GenBuf + 12             ; MSDN http://bit.ly/PJFcbj
 pSP_DEVICE_INTERFACE_DETAIL_DATA :=  &GenBuf + 40             ; MSDN http://bit.ly/SXr3We
 pSP_DEVINFO_DATA                 :=  &GenBuf + 1040           ; MSDN http://bit.ly/Rgp02c


 NumPut( 28, pSP_DEVICE_INTERFACE_DATA + 0 )
 NumPut( 28, pSP_DEVINFO_DATA + 0 )
 NumPut( 4 + ( A_IsUnicode ? 2 : 1 ), pSP_DEVICE_INTERFACE_DETAIL_DATA + 0 )

 DeviceFound := Instance := DeviceNumber := 0
 
 While DllCall( "SetupAPI\SetupDiEnumDeviceInterfaces"
              , UInt,  hDevInfo
              , UInt,  0
              , UInt,  &DiskGUID
              , UInt,  Instance
              , UInt,  pSP_DEVICE_INTERFACE_DATA ) {

       Instance ++
   
       DllCall( "SetupAPI\SetupDiGetDeviceInterfaceDetail"     ; MSDN http://bit.ly/NINIci
            . ( A_IsUnicode ? "W" : "A" )
              , UInt,  hDevInfo
              , UInt,  pSP_DEVICE_INTERFACE_DATA               ; MSDN http://bit.ly/PJFcbj
              , UInt,  0
              , UInt,  0
              , UIntP, nBytes
              , UInt,  pSP_DEVINFO_DATA )                      ; MSDN http://bit.ly/Rgp02c


       DllCall( "SetupAPI\SetupDiGetDeviceInterfaceDetail"     ; MSDN http://bit.ly/NINIci
            . ( A_IsUnicode ? "W" : "A" )
              , UInt,  hDevInfo
              , UInt,  pSP_DEVICE_INTERFACE_DATA               ; MSDN http://bit.ly/PJFcbj
              , UInt,  pSP_DEVICE_INTERFACE_DETAIL_DATA        ; MSDN http://bit.ly/SXr3We
              , UInt,  nBytes
              , UInt,  0
              , UInt,  pSP_DEVINFO_DATA )                      ; MSDN http://bit.ly/Rgp02c

      hVol  := DllCall( "CreateFile"
                      , UInt,  pSP_DEVICE_INTERFACE_DETAIL_DATA + 4
                      , UInt,  0x80000000
                      , UInt,  0x3
                      , UInt,  0
                      , UInt,  0x3
                      , UInt,  0x0
                      , UInt,  0  )

      If ( hVol < 0 )
           Continue

      DllCall( "DeviceIoControl"
             , UInt,  hVol
             , UInt,  IOCTL_STORAGE_GET_DEVICE_NUMBER          ; MSDN http://bit.ly/Ssuzfm
             , UInt,  0
             , UInt,  0
             , UInt,  pSTORAGE_DEVICE_NUMBER                   ; MSDN http://bit.ly/PF17hX
             , UInt,  12
             , UIntP, BR
             , UInt,  0   )

      DllCall( "CloseHandle", UInt,hVol )

      If ( BR = 0   )
           Continue
         
      tDevNum := NumGet( pSTORAGE_DEVICE_NUMBER + 4 )
      If DeviceFound := ( tDevNum == sDevnum )
         Break
 }

 If ( DeviceFound = 0 )
    Return 0,  ErrorLevel := 5                  ; No matching storage class devices found!

 DllCall( "SetupAPI\SetupDiGetDeviceRegistryProperty"
      . ( A_IsUnicode ? "W" : "A" )
        , UInt, hDevInfo
        , UInt, pSP_DEVINFO_DATA
        , UInt, 12 ; SPDRP_FRIENDLYNAME
        , UInt, 0
        , Str,  GenBuf
        , UInt, 1024
        , UInt, 0 )

 FRIENDLY := GenBuf
 DllCall( "SetupAPI\SetupDiDestroyDeviceInfoList", UInt,hDevInfo )  ; http://bit.ly/TWTmsN

If(InfoOnly)					; MODIFIED-robertcollier4 Added InfoOnly Check
	Return FRIENDLY			; MODIFIED-robertcollier4 Added InfoOnly Check

 DllCall( "SetupAPI\CM_Get_Parent"
        , UIntP, hDeviceID
        , UInt,  NumGet( pSP_DEVINFO_DATA + 20 )
        , UInt,  0 )

 If ( hDeviceID = 0 )
    Return 0,  ErrorLevel := 6                  ; Problem IDentifying USB Device!


 DllCall( "SetupAPI\CM_Get_Device_ID"
      . ( A_IsUnicode ? "W" : "A" )
        , UInt,  hDeviceID
        , Str,   GenBuf
        , UInt,  1024
        , UInt,  0 )

 DeviceID := GenBuf
 MAX_PATH := ( A_IsUnicode ? 520 : 260 )

Label_SafelyRemoveUMS:

 Loop 5 {

          DllCall( "SetupAPI\CM_Request_Device_Eject"
               . ( A_IsUnicode ? "W" : "A" )
                 , UInt,  hDeviceID
                 , UIntP, VetoType
                 , Str,   GenBuf
                 , UInt,  MAX_PATH
                 , Int,   0 )

          If ( VetoType = 0 )
             Break

        }
 
 If ( Retry && VetoType == 6 ) {                ; PNP_VetoOutstandingOpen = 6

   MsgBox, 0x1035 ; MB_SYSTEMMODAL=0x1000 | MB_ICONEXCLAMATION=0x30 | MB_RETRYCANCEL=0x5
         , Safely Remove USB Mass Storage Drive %Drive%
         , Unable to Eject Drive due to Open File Handles!`n`n%FRIENDLY%`n%DeviceID%

   IfMsgBox Retry, GoTo Label_SafelyRemoveUMS

 }

Return ( VetoType ? 0 : FRIENDLY "`n" DeviceID  )
      , DllCall( "SetLastError", UInt,VetoType )
      , ErrorLevel := VetoType ? 7 : 0
}

Edited by robertcollier4, 27 January 2013 - 02:33 PM.


#2 robertcollier4

robertcollier4

    Member

  • Members
  • 33 posts
  •  
    United States

Posted 28 January 2013 - 09:04 AM

Utility updated to include "InUse" column through using SKAN EnumDrives(). This utility works very well when loaded through a HUD Start Menu Launcher such as Executor to allow for ejecting a USB through keyboard only.

 

Download: EjectRemovableDrives.ahk (13KB)

Download: EjectRemovableDrives.exe (204 KB)

 

 

ejectremovabledrives.gif



#3 steve6375

steve6375

    Platinum Member

  • Developer
  • 7566 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films
  •  
    United Kingdom

Posted 28 January 2013 - 12:12 PM

With either exe running on Win7 64 bit OS I get error message when I try to run it
 

Error: Can't load icon
Line # 009 Menu,Tray,Icon,C:\Windows\system32\hotplug.dll,0

The file does exist and I am running as Administrator.. It works OK on XP
Anyone else had problems?



#4 roynals

roynals
  • Members
  • 6 posts
  •  
    United States

Posted 28 January 2013 - 02:24 PM

With either exe running on Win7 64 bit OS I get error message when I try to run it
 

The file does exist and I am running as Administrator.. It works OK on XP
Anyone else had problems?

How about using %windir%\system32\hotplug.dll instead of C:\Windows\system32\hotplug.dll ?



#5 robertcollier4

robertcollier4

    Member

  • Members
  • 33 posts
  •  
    United States

Posted 28 January 2013 - 02:34 PM

I don't have a Win7 64bit OS on hand, but I have updated the script to use %windir% instead of C:\Windows. Also wrote hotkeys in parenthesis for the buttons. Redownload from same links:

 

Download: EjectRemovableDrives.ahk (13KB)

Download: EjectRemovableDrives.exe (204 KB)

 

ejectremovabledriveswit.gif

 

Alternatively, you can change that line in the script to use this icon, but I prefer the original Windows one.



#6 steve6375

steve6375

    Platinum Member

  • Developer
  • 7566 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films
  •  
    United Kingdom

Posted 28 January 2013 - 02:36 PM

Same problem. As I said the dll does exist. I don't think that the path is the problem. Could it be that the dll is a 64bit dll?

Do you need to compile the exe for 64-bit?



#7 steve6375

steve6375

    Platinum Member

  • Developer
  • 7566 posts
  • Location:UK
  • Interests:computers, programming (masm,vb6,C,vbs), photography,TV,films
  •  
    United Kingdom

Posted 28 January 2013 - 02:40 PM

If I install AutoHotkey and run the ahk file then it runs - but does not list any USB devices...



#8 robertcollier4

robertcollier4

    Member

  • Members
  • 33 posts
  •  
    United States

Posted 28 January 2013 - 02:48 PM

I don't think this will work on 64-bit as per SKAN's posts 9 and 11 here  and the warning note on the AutoHotkey_L page here saying that "scripts using DllCall require modification to work on x64 versions of AutoHotkey_L".

 

 

This is for AutoHotKey Classic 32-bit (meaning not "_L", more info on Classic vs _L here). I try to avoid the usage of 64-bit systems so am not able to test or adapt the DllCall.

 





0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users