Eject() - For CD/DVD and USB Mass Storage devices

Post your working scripts, libraries and tools
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Eject() - For CD/DVD and USB Mass Storage devices

06 Sep 2014, 15:22

Eject( DriveLetter ) - Returns True on success and False on failure.
Compatibility: XP and greater ( x86/x64 ), Autohotkey 1.1 and 2.0

Usage example: Eject( "D:" ). Drive letter passed can be like "D" or "D:" or "D:\" or "D:\\". Only the first letter matters.

ErrorLevel:
  • -1 Invalid drive letter.
  • -2 Neither a CD/DVD drive, nor a USB Mass Storage device.
  • -3 Eject failed. Refer A_LastError ( range 1 - 13 ) to identify the reason. The most common will be A_LastError = 6 which is
    PNP_VetoOutstandingOpen The requested operation was rejected because of outstanding open handles.
Edit 13/Sep/2014: Code updated to eject 'FIXED' typed USB drives ( External HDD ). Thanks to user jantom

Code: Select all

Eject( DRV  ) {                       ;  By SKAN,  http://goo.gl/pUUGRt,  CD:01/Sep/2014 | MD:13/Sep/2014
Local hMod, hVol, queryEnum, VAR := "", sPHDRV := "", nDID := 0, nVT := 1, nTC := A_TickCount 
Local IOCTL_STORAGE_GET_DEVICE_NUMBER := 0x2D1080, STORAGE_DEVICE_NUMBER,  FILE_DEVICE_DISK := 0x00000007 

  DriveGet, VAR, Type, % DRV := SubStr( DRV, 1, 1 ) ":"
  If ( VAR = "" )
     Return  ( ErrorLevel := -1 ) + 1
        
  If ( VAR = "CDROM" ) {
     Drive, Eject, %DRV%  
     If ( nTC + 1000 > A_Tickcount ) 
        Drive, Eject, %DRV%, 1
     Return  ( ErrorLevel ? 0 : 1 )
  } 

; Find physical drive number from drive letter.   
  hVol := DllCall( "CreateFile", "Str","\\.\" DRV, "Int",0, "Int",0, "Int",0, "Int",3, "Int",0, "Int",0 )

  VarSetcapacity( STORAGE_DEVICE_NUMBER, 12, 0 )
  DllCall( "DeviceIoControl", "Ptr",hVol, "UInt",IOCTL_STORAGE_GET_DEVICE_NUMBER
         , "Int",0, "Int",0, "Ptr",&STORAGE_DEVICE_NUMBER, "Int",12, "PtrP",0, "Ptr",0 )  

  DllCall( "CloseHandle", "Ptr",hVol )

  If (  NumGet( STORAGE_DEVICE_NUMBER, "UInt" ) = FILE_DEVICE_DISK  ) 
     sPHDRV := "\\\\.\\PHYSICALDRIVE" NumGet( STORAGE_DEVICE_NUMBER, 4, "UInt" )
  
; Find PNPDeviceID = USBSTOR for given physical drive
  queryEnum := ComObjGet( "winmgmts:" ).ExecQuery( "Select * from Win32_DiskDrive "
                      . "where DeviceID='" sPHDRV "' and InterfaceType='USB'" )._NewEnum()
  If not queryEnum[ DRV ]
     Return ( ErrorLevel := -2 ) + 2
     
  hMod := DllCall( "LoadLibrary", "Str","SetupAPI.dll", "UPtr" )
  
; Locate USBSTOR node and move up to its parent
  DllCall( "SetupAPI\CM_Locate_DevNode", "PtrP",nDID, "Str",DRV.PNPDeviceID, "Int",0 )
  DllCall( "SetupAPI\CM_Get_Parent", "PtrP",nDID, "UInt",nDID, "Int",0 )

  VarSetCapacity( VAR, 520, 0 )
  While % ( nDID and nVT and A_Index < 4 ) 
    DllCall( "SetupAPI\CM_Request_Device_Eject", "UInt",nDID, "PtrP",nVT, "Str",VAR, "Int",260, "Int",0 )
  
  DllCall("FreeLibrary", "Ptr",hMod ),    DllCall( "SetLastError", "UInt",nVT )     

Return ( nVT ? ( ErrorLevel := -3 ) + 3 : 1 )  
}
guest3456
Posts: 2528
Joined: 09 Oct 2013, 10:31

Re: Eject() - For CD/DVD and USB Mass Storage devices

06 Sep 2014, 17:51

You should probably state what the DRV parameter expects.. is it "D", "D:", "D:\" etc

Skrell
Posts: 163
Joined: 23 Jan 2014, 12:05

Re: Eject() - For CD/DVD and USB Mass Storage devices

07 Sep 2014, 10:13

isn't the last line missing a ")" ?
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

07 Sep 2014, 14:52

Skrell wrote:isn't the last line missing a ")" ?
Last few chars go missing when downloaded. Some forum quirk, I guess. I have appended a ; end eject.ahk at the end of the code.
Thanks for reporting this.
:)
Skrell
Posts: 163
Joined: 23 Jan 2014, 12:05

Re: Eject() - For CD/DVD and USB Mass Storage devices

08 Sep 2014, 08:17

SKAN wrote:
Skrell wrote:isn't the last line missing a ")" ?
Last few chars go missing when downloaded. Some forum quirk, I guess. I have appended a ; end eject.ahk at the end of the code.
Thanks for reporting this.
:)
No prob Skan, thank YOU for all the scripts you've contributed!!!!
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

11 Sep 2014, 11:48

I get A_LastError = 1.
I'm trying to safely remove a portable USB drive (2.5 inch, 1TB).
It works clicking the standard Win 7 tray icon ('Safely Remove Hardware').
Any suggestion?
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

11 Sep 2014, 14:08

Hi jantom,
Welcome to the forum. :)
jantom wrote:I get A_LastError = 1
What about ErrorLevel ? Is it -3 ?

Edit:
Can you insert a MsgBox in Eject() as follows and let me know what sDID is? ( sDID = strDeviceID )

Code: Select all

sDID  := Split[1] "\" Split[2] "\" Split[3]
MsgBox % Clipboard := sDID
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 02:15

Here's the content of Msgbox:

---------------------------
Eject.ahk
---------------------------
\\
---------------------------
OK
---------------------------
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 02:17

yes, ErrorLevel is -3
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 09:40

jantom wrote:yes, ErrorLevel is -3
Thanks. ErrorLevel should have been -2. A different problem, fixed now.

Just one more help:
Set the correct drive and post the hex.

Code: Select all

DRV := "H:" 
RegRead, Hex, HKLM, SYSTEM\MountedDevices, \DosDevices\%DRV%
MsgBox % Hex
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 10:14

Hex is:

B14CB7010000100000000000
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 10:38

I get this message:
---------------------------
Eject.ahk
---------------------------
Error at line 19.

Line Text: Local sHex, Split, sDID, nDID := 0, nVT := 1, nTC := A_TickCount, VAR, nLen := VarSetCapacity( VAR,1...
Error: Local variables must not be declared in this function.

The program will exit.
---------------------------
OK
---------------------------
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 11:05

jantom wrote:Hex is:

B14CB7010000100000000000
As expected, your drive is typed as "FIXED". Allow me sometime please, I will update the code to handle "FIXED" typed USB Mass Storage Devices.

:)
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 11:09

Great. Thank you so much.
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 14:02

jantom, I do not have external HDD drive to test the new code.
Please try and let me know, so that I can update my code in the first post.
Ejectv2 - WMI based enumeration
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 14:12

Thank you. Unfortunately, I can't make it work.
Can you suggest how to debug?
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

12 Sep 2014, 19:13

jantom wrote:Can you suggest how to debug?
Insert MsgBox after hVol := and sPHDRV :=
hVol should not be -1
sPHDRV should not be blank and should be like: \\\\.\\PHYSICALDRIVE1

The following will list all your drives. Please let me know the properties for the drive in question.

Code: Select all

List := ""
for ObjItem in ComObjGet("winmgmts:").ExecQuery( "Select * from Win32_DiskDrive" )
List .= "`nCaption: "         . objItem.Caption
     .  "`nDescription: "     . objItem.Description
     .  "`nDeviceID: "        . objItem.DeviceID
     .  "`nInterfaceType: "   . objItem.InterfaceType
     .  "`nMediaLoaded: "     . objItem.MediaLoaded
     .  "`nMediaType: "       . objItem.MediaType
     .  "`nModel: "           . objItem.Model
     .  "`nName: "            . objItem.Name
     .  "`nPartitions: "      . objItem.Partitions
     .  "`nPNPDeviceID: "     . objItem.PNPDeviceID
     .  "`nSectorsPerTrack: " . objItem.SectorsPerTrack
     .  "`nStatus: "          . objItem.Status 
     .  "`n----------------------------------------------`n"

MsgBox % Clipboard := List
jantom
Posts: 12
Joined: 21 Feb 2014, 10:49

Re: Eject() - For CD/DVD and USB Mass Storage devices

13 Sep 2014, 03:21

hVol = 248
sPHDRV = (blank)
ErrorLevel = -2


The drive in question is:
----------------------------------------------

Caption: Seagate Expansion USB Device
Description: Disk drive
DeviceID: \\.\PHYSICALDRIVE1
InterfaceType: USB
MediaLoaded: -1
MediaType: External hard disk media
Model: Seagate Expansion USB Device
Name: \\.\PHYSICALDRIVE1
Partitions: 1
PNPDeviceID: USBSTOR\DISK&VEN_SEAGATE&PROD_EXPANSION&REV_060E\NA481WBG&0
SectorsPerTrack: 63
Status: OK
----------------------------------------------
User avatar
SKAN
Posts: 363
Joined: 29 Sep 2013, 16:58

Re: Eject() - For CD/DVD and USB Mass Storage devices

13 Sep 2014, 04:35

Last piece of info required. ( I promise )
Set the correct drive and post the info:

Code: Select all

DRV := "H:"

hVol := DllCall( "CreateFile", "Str","\\.\" DRV, "Int",0, "Int",0, "Int",0, "Int",3, "Int",0, "Int",0 )

VarSetcapacity( STORAGE_DEVICE_NUMBER, 12, 0 )
DllCall( "DeviceIoControl", "Ptr",hVol, "UInt",IOCTL_STORAGE_GET_DEVICE_NUMBER := 0x2D1080
       , "Int",0, "Int",0, "Ptr",&STORAGE_DEVICE_NUMBER, "Int",12, "PtrP",0, "Ptr",0 )  
       
DllCall( "CloseHandle", "Ptr",hVol )

MsgBox % Clipboard := "DeviceType:`t"      NumGet( STORAGE_DEVICE_NUMBER, 0, "Int" ) "`n"
                    . "DeviceNumber:`t"    NumGet( STORAGE_DEVICE_NUMBER, 4, "Int" ) "`n" 
                    . "PartitionNumber:`t" NumGet( STORAGE_DEVICE_NUMBER, 8, "Int" ) 

Return to “Scripts and Functions”

Who is online

Users browsing this forum: No registered users and 28 guests