Usage example: Eject( "D:" ). Drive letter passed can be like "D" or "D:" or "D:\" or "D:\\". Only the first letter matters.
ErrorLevel will be blank when eject() was successful or contain an error text explaining what went wrong.
The other 2 parameters exist only for debug purposes.
DontCheck : When true will skip MediaType check. I used this to try ejecting my C: drive and Internal DVD drive.
DontEject : When true, returns the class without ejecting the drive. Useful for populating a removable drives list.
What has changed in this new version?
Win32_DiskDrive->MediaType values for a physical drive are as follows:
- Fixed hard disk media : Any drive directly plugged into mainboard. HDD/CDD/DVD etc
- Removable Media : Flash/Pen drives, card readers, external HDD etc. plugged via USB port
- External hard disk media : UAS - USB Attached SCSI
- Unknown ; Probably a Floppy disk drive. I don't have the hardware to test
A UAS drive identifies itself as USB in Windows 7 but as SCSI in Windows 8 and upwards so the old approach is now no more useful
The new rewritten version now checks Win32_DiskDrive->MediaType and proceeds with eject if media type is either Removable Media or External hard disk media
If you have a eject supported drive but the new Eject() fails, Please run
Code: Select all
MsgBox % Clipboard := Eject("X:",,True ).MediaType ; Replace X: with your drive
The function along with code for testing
Explore/Eject Drives
Run script and use as follows:
Hotkey Ctrl+Win+<DriveLetter> to explore the drive
Hotkey Ctrl+Win+Alt+<DriveLetter> to eject the drive.
Hotkey Win+E to open My Computer/Computer/This PC maximized
Code: Select all
Eject(DRV, DontCheck:=0, DontEject:=0) { ; By SKAN on CT91/D29R @ goo.gl/pUUGRt
Local STORAGE_DEVICE_NUMBER, IOCTL_STORAGE_GET_DEVICE_NUMBER:=0x2D1080
Local OPEN_EXISTING:=3, hVol:=0, sPHDRV:="", qStr:="", qEnum:= "", nDID:=0, nVT:=1
Local AMT := "[Removable Media][External hard disk media]", dObj:={}, VT, VAR
hVol := DllCall("CreateFile", "Str","\\.\" . (DRV:=SubStr(DRV,1,1) . ":"), "UInt",0
,"UInt",0, "Ptr",0,"UInt",OPEN_EXISTING, "UInt",0, "Ptr",0, "Ptr")
If (hVol = -1 )
{
ErrorLevel := FileExist(DRV) ? "Mapped/substitute drive" : "Invalid drive letter"
Return dObj
}
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 )
sPHDRV := "\\\\.\\PHYSICALDRIVE" . NumGet(STORAGE_DEVICE_NUMBER,4,"UInt")
qStr := "Select * from Win32_DiskDrive where DeviceID='$$$'"
qEnum := ComObjGet("winmgmts:").ExecQuery(StrReplace(qStr,"$$$",sPHDRV))._NewEnum()
qEnum[dObj]
If ( DontEject )
{
ErrorLevel := ""
Return dObj
}
If ! ( DontCheck || InStr(AMT, "[" . dObj.MediaType . "]", True) )
{
ErrorLevel := (dObj.MediaType=="Fixed hard disk media"
? "Media is a Fixed hard disk" : "Media type Unknown")
Return dObj
}
If ! ( DllCall("GetModuleHandle", "Str","SetupAPI.dll", "Ptr") )
{
DllCall("LoadLibrary", "Str","SetupAPI.dll", "Ptr")
}
DllCall("SetupAPI\CM_Locate_DevNode", "PtrP",nDID, "Str",dObj.PNPDeviceID, "Int",0)
DllCall("SetupAPI\CM_Get_Parent", "PtrP",nDID, "UInt",nDID, "Int",0)
VarSetCapacity(VAR,520,0)
DllCall("SetupAPI\CM_Request_Device_Eject"
,"UInt",nDID, "PtrP",nVT,"Str",VAR, "Int",260, "Int",0)
ErrorLevel := ( nVT=0 ? 0 : ["PNP_VetoTypeUnknown`nThe specified operation was reje"
. "cted for an unknown reason.","PNP_VetoLegacyDevice`nThe device does not support "
. "the specified PnP operation.","PNP_VetoPendingClose`nThe specified operation can"
. "not be completed because of a pending close operation.","PNP_VetoWindowsApp`nA M"
. "icrosoft Win32 application vetoed the specified operation.","PNP_VetoWindowsServ"
. "ice`nA Win32 service vetoed the specified operation.","PNP_VetoOutstandingOpen`n"
. "The requested operation was rejected because of outstanding open handles.","PNP_"
. "VetoDevice`nThe device supports the specified operation, but the device rejected"
. " the operation.","PNP_VetoDriver`nThe driver supports the specified operation, b"
. "ut the driver rejected the operation.","PNP_VetoIllegalDeviceRequest`nThe device"
. " does not support the specified operation.","PNP_VetoInsufficientPower`nThere is"
. " insufficient power to perform the requested operation.","PNP_VetoNonDisableable"
. "`nThe device cannot be disabled.","PNP_VetoLegacyDriver`nThe driver does not sup"
. "port the specified PnP operation.","PNP_VetoInsufficientRights`nThe caller has i"
. "nsufficient privileges to complete the operation.","PNP_VetoAlreadyRemoved`nThe "
. "device has been already removed"][nVT] )
Return dObj
}
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
; DEMO SCRIPT FOLLOWS:
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
#NoEnv
#SingleInstance, Force
; If ! FileExist( "T:\" )
; Run subst T: "%A_TEMP%",,Hide ; Substitute drive T: for temp folder
Loop 26
{
HotKey % "^#" . Chr(A_Index+64), ExploreDrive
HotKey % "^!#" . Chr(A_Index+64), EjectDrive
}
Return
#E::Run ::{20d04fe0-3aea-1069-a2d8-08002b30309d},,Max
F1::ListVars
ExploreDrive:
TrayTip
DRV := SubStr(A_ThisHotkey,0) . ":\"
If FIleExist( DRV )
{
Run %Drv%,, Max
Return
}
TrayTip, Explore drive, Drive %Drv%: does not exist,, 0x22
SetTimer, TrayTipClose, -3000
Return
EjectDrive:
TrayTip
DRV := SubStr(A_ThisHotkey,0) . ":\"
dObj := Eject(DRV)
If ! ( ErrorLevel )
{
TrayTip, Eject drive %DRV%, % dObj.Model "`nsafely removed",,0x21
SetTimer, TrayTipClose, -4000
Return
}
TrayTip, Eject Drive %DRV%, % "`n" . ErrorLevel,, 0x23
SetTimer, TrayTipClose, -4000
Return
TrayTipClose:
TrayTip
Return
;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -