Replicate Computer / Disk Management eject procedure (in script)

Within Disk Management (of Computer Management), I'd like to write a script, .bat, .vbs, visual basic etc, that will replicate the eject feature.

Ejecting via Windows Explorer won't work. The USB cartridge for backups that I'm using, will only eject via the computer management eject procedure, so I'd like to script this.

Using windows 2008... and have VB6.

Can anyone help?
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

I am pretty syre they both perform the same routine.

Here is how you would eject a removable device using API.

1) Open a (volume) handle to the device using CreateFile()
2) Try to lock the volume using FSCTL_LOCK_VOLUME
3) If the call above succeeds it's safe to dismount the volume using FSCTL_DISMOUNT_VOLUME
4) You want to make sure there is no (prevent removal locks) on the volume so you call IOCTL_STORAGE_MEDIA_REMOVAL and set the structure parameter to False.
5) Use IOCTL_STORAGE_EJECT_MEDIA to eject the device.
6) Close the volume handle.

This is how all of them work but I will take a wild guess and say that maybe explorer doesn't go as far to disable any ejection locks but the disk managment eject option does.
Here is an example I wrote that should eject a removable device just like explorer or disk managment. This is an interesting question and I want to know myself if there is any difference between them. Give this a try and keep me updated! :)

Add code to a (module.bas)
Usage: SafeEject "e:\"
Option Explicit
' safe eject media vb6.
' author's name
PreventMediaRemoval As Long
End Type
Private Const INVALID_HANDLE_VALUE As Long = (-1)
Private Const FSCTL_LOCK_VOLUME As Long = &H90018
Private Const FSCTL_UNLOCK_VOLUME As Long = &H9001C
Private Const FSCTL_DISMOUNT_VOLUME As Long = &H90020
Private Const IOCTL_STORAGE_MEDIA_REMOVA<wbr ></wbr>L As Long = &H2D4804
Private Const IOCTL_STORAGE_EJECT_MEDIA As Long = &H2D4808
Private Const OPEN_EXISTING As Long = 3
Private Const GENERIC_READ As Long = &H80000000
Private Const GENERIC_WRITE As Long = &H40000000
Private Const FILE_SHARE_READ As Long = &H1
Private Const FILE_SHARE_WRITE As Long = &H2
Private Const DRIVE_REMOVABLE As Long = 2
Private Const DRIVE_CDROM As Long = 5
Private Declare Function DeviceIoControl Lib "kernel32.dll" (ByVal hDevice As Long, ByVal dwIoControlCode As Long, ByVal lpInBuffer As Long, ByVal nInBufferSize As Long, ByVal lpOutBuffer As Long, ByVal nOutBufferSize As Long, lpBytesReturned As Long, ByVal lpOverlapped As Long) As Long
Private Declare Function CreateFileW Lib "kernel32.dll" (ByVal lpFileName As Long, ByVal dwDesiredAccess As Long, ByVal dwShareMode As Long, ByVal lpSecurityAttributes As Long, ByVal dwCreationDisposition As Long, ByVal dwFlagsAndAttributes As Long, ByVal hTemplateFile As Long) As Long
Private Declare Function GetDriveTypeW Lib "kernel32.dll" (ByVal nDrive As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" (ByVal hObject As Long) As Long
Sub SafeEject(ByVal szDrive As String)
Dim dwAccess As Long
Dim dwDriveType As Long
Dim hDrive As Long
Dim cb As Long
' Check if trailing backslash exists.
If InStr(szDrive, "\") = 0 Then
  Debug.Print "Please specify a full drive letter. ex. X:\"
  Exit Sub
End If
' Backslash is required for this call.
dwDriveType = GetDriveTypeW(StrPtr(szDri<wbr ></wbr>ve))
' Check if this type of drive is removable.
Select Case dwDriveType
    dwAccess = GENERIC_READ
  Case Else
    Debug.Print "This type of volume is not a removable device."
    Exit Sub
End Select
' Remove backslash.
szDrive = Replace$(szDrive, "\", vbNullString)
' This must not have a backslash.(open volume for direct access might need admin rights on vista/win7)
hDrive = CreateFileW(StrPtr("\\.\" & szDrive), dwAccess, FILE_SHARE_READ Or FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0)
' checksum
  Debug.Print "Bad handle. (try:run as admin)"
  Exit Sub
End If
' Attempt to lock the volume for safe ejection.
If DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, 0, 0, 0, 0, cb, 0) Then
  ' DISMOUNT the volume and flush cache and any associations on the systems.
  Call DeviceIoControl(hDrive, FSCTL_DISMOUNT_VOLUME, 0, 0, 0, 0, cb, 0)
  ' Make sure there is no prevent removal locks.
  udtPMR.PreventMediaRemoval<wbr ></wbr> = 0
  Call DeviceIoControl(hDrive, IOCTL_STORAGE_MEDIA_REMOVA<wbr ></wbr>L, VarPtr(udtPMR), Len(udtPMR), 0, 0, cb, 0)
  ' Eject the media.
  Call DeviceIoControl(hDrive, IOCTL_STORAGE_EJECT_MEDIA,<wbr ></wbr> 0, 0, 0, 0, cb, 0)
  ' You could still force the ejection here but any
  ' data in process would get corrupted.
  Debug.Print "It's not safe to eject this media."
End If
' Close volume handle.
CloseHandle hDrive
End Sub

Open in new window


Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
gary_slandAuthor Commented:
Hi. Many thanks for your help. This worked! I really thought I'd be stuck with this problem. There does seem to be some difference between explorer and disk management, perhaps as you say it's to do the locks.
Many thanks though!
Great. So it seems that the computer managment is doing some additional work than explorer thats interesting.

I was messing around with the (Safe Remove Hardware option) and I noticed that it actually updates explorer and removes the drive from the explorer list. Which the code above doesn't do so in addition the safely remove hardware goes even one step further and updates explorer.

Here is how it works.

Option Explicit
Private Const SHCNE_DRIVEREMOVED As Long = &H80
Private Const SHCNF_PATHW As Long = 5
Private Declare Function SHChangeNotify Lib "shell32.dll" (ByVal wEventId As Long, _
  ByVal uFlags As Long, ByVal dwItem1 As Long, ByVal dwItem2 As Long) As Long
Private Sub Update(ByVal szDrive As String)
' Do some magic here.(must have trailing backslash)
Call SHChangeNotify(SHCNE_DRIVEREMOVED, SHCNF_PATHW, StrPtr(szDrive), 0)
End Sub

Open in new window

Just to make sure, you would call the above method after you call the eject part.
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Microsoft Development

From novice to tech pro — start learning today.