Code : Tout sélectionner
; http://www.autoitscript.com/forum/index ... t&p=569255
#include <WinApi.au3>
;Prototypes
;BOOL EjectVolume(TCHAR cDriveLetter);
;HANDLE OpenVolume(TCHAR cDriveLetter);
;BOOL LockVolume(HANDLE hVolume);
;BOOL DismountVolume(HANDLE hVolume);
;BOOL PreventRemovalOfVolume(HANDLE hVolume, BOOL fPrevent);
;BOOL AutoEjectVolume(HANDLE hVolume);
;BOOL CloseVolume(HANDLE hVolume);
;StringFormat Output
$szVolumeFormat = "\\\\.\\%s"
$szRootFormat = "%s\\"
$szErrorFormat = "Error %d: %s\n"
;------------------------------------------
;Arbitrary variables
;Global Const $INVALID_HANDLE_VALUE = 0
;------------------------------------------
;DeviceIoControl Contants
Global Const $FSCTL_LOCK_VOLUME = Int(0x090018)
Global Const $FSCTL_DISMOUNT_VOLUME = Int(0x00090020)
Global Const $IOCTL_STORAGE_EJECT_MEDIA = Int(0x002D4808)
Global Const $IOCTL_STORAGE_MEDIA_REMOVAL = Int(0x002D4804)
;------------------------------------------
;Retry Constants
Global Const $LOCK_TIMEOUT = 10000 ; 10 Seconds
Global Const $LOCK_RETRIES = 20
$OpenVolume = InputBox("Ejecting...", "Enter the drive to eject", "")
ConsoleWrite("Trying to Eject the drive " & EjectVolume($OpenVolume) & @CRLF)
Func ReportError($szMsg)
ConsoleWrite(StringFormat($szErrorFormat, _WinAPI_GetLastErrorMessage(), $szMsg) & @CRLF)
Exit
EndFunc ;==>ReportError
Func OpenVolume($cDriveLetter)
;HANDLE hVolume
;UINT uDriveType
;TCHAR szVolumeName[8]
;TCHAR szRootName[5]
;DWORD dwAccessFlags
$szRootName = StringFormat($szRootFormat, $cDriveLetter)
$uDriveType = DriveGetType($szRootName);
ConsoleWrite($szRootName & @TAB & $uDriveType & @CRLF)
Switch $uDriveType
Case "Removable"
$dwAccessFlags = 6
Case "CDROM"
$dwAccessFlags = 2
Case Else
ConsoleWrite("Cannot eject. Drive type is incorrect." & @CRLF)
Return $INVALID_HANDLE_VALUE
EndSwitch
$szVolumeName = StringFormat($szVolumeFormat, $cDriveLetter)
;$szVolumeName = $szVolumeFormat & $cDriveLetter
ConsoleWrite($szVolumeName & @CRLF)
$hVolume = _WinAPI_CreateFile($szVolumeName, 2, $dwAccessFlags, 6)
#cs
hVolume = CreateFile( szVolumeName,
dwAccessFlags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
0,
NULL );
#ce
If ($hVolume == $INVALID_HANDLE_VALUE) Then ReportError("CreateFile");
Return $hVolume;
EndFunc ;==>OpenVolume
Func CloseVolume($hVolume)
Return _WinAPI_CloseHandle($hVolume);
EndFunc ;==>CloseVolume
Func LockVolume($hVolume)
Local $dwBytesReturned
Local $dwSleepAmount
Local $nTryCount
Local $iRead
$dwSleepAmount = $LOCK_TIMEOUT / $LOCK_RETRIES;
; Do this in a loop until a timeout period has expired
For $nTryCount = 0 To $nTryCount < $LOCK_RETRIES
If _Device_Control($hVolume, $FSCTL_LOCK_VOLUME, $iRead) Then
Return True
Else
Sleep($dwSleepAmount);
EndIf
Next
Return False;
EndFunc ;==>LockVolume
Func DismountVolume($hVolume)
ConsoleWrite("Dismount " & $hVolume & @CRLF)
Local $dwBytesReturned, $iRead
Local $aResult = _Device_Control($hVolume, $FSCTL_DISMOUNT_VOLUME, $iRead)
MsgBox(0, "", $aResult)
Return $aResult
;Return $dwBytesReturned
EndFunc ;==>DismountVolume
Func PreventRemovalOfVolume($hVolume, $fPreventRemoval)
Local $dwBytesReturned
Local $aResult
Local $lpInbuffer, $nInBufferSize, $lpOutBuffer, $nOutBufferSize, $lpOverlapped
$PMRBUFFER = DllStructCreate("bool PreventMediaRemoval")
DllStructSetData($PMRBUFFER, "PreventMediaRemoval", $fPreventRemoval)
$lpBytesReturned = DllStructCreate("int Read")
$pRead = DllStructGetPtr($lpBytesReturned, "Read")
$aResult = DllCall("kernel32.dll", "int", "DeviceIoControl", "hwnd", $hVolume, "uint", $IOCTL_STORAGE_MEDIA_REMOVAL, "ptr", DllStructGetPtr($PMRBUFFER), "uint", DllStructGetSize($PMRBUFFER), _
"ptr", $lpOutBuffer, "uint", $nOutBufferSize, "ptr", $pRead, "ptr", $lpOverlapped)
If $aResult = 0 Then MsgBox(0, "", _WinAPI_GetLastErrorMessage())
Return $aResult <> 0
;& PMRBuffer, sizeof (PREVENT_MEDIA_REMOVAL),
;NULL, 0,
; & dwBytesReturned,
;NULL);
EndFunc ;==>PreventRemovalOfVolume
Func AutoEjectVolume($hVolume)
Local $aResult, $iRead;
$aResult = _Device_Control($hVolume, $IOCTL_STORAGE_EJECT_MEDIA, $iRead)
Return $aResult
EndFunc ;==>AutoEjectVolume
Func EjectVolume($cDriveLetter)
Local $hVolume;
Local $fRemoveSafely = False;
Local $fAutoEject = False;
; Open the volume.
$hVolume = OpenVolume($cDriveLetter);
If $hVolume == $INVALID_HANDLE_VALUE Then Return False
; Lock and dismount the volume.
If LockVolume($hVolume) And DismountVolume($hVolume) Then
$fRemoveSafely = True;
ConsoleWrite("Volume Locked and Dismounted, trying to Eject " & @CRLF)
; Set prevent removal to false and Eject the volume.
If PreventRemovalOfVolume($hVolume, False) And AutoEjectVolume($hVolume) Then
$fAutoEject = True;
EndIf
Else
ConsoleWrite("Volume can't be locked or dismounted, please close possible opened files" & @CRLF)
EndIf
; Close the volume so other processes can use the drive.
If CloseVolume($hVolume) = False Then
Return False;
EndIf
If $fAutoEject Then
ConsoleWrite(StringFormat("Media in Drive %s has been ejected safely.\n", $cDriveLetter))
Else
If $fRemoveSafely Then
ConsoleWrite(StringFormat("Media in Drive %s can be safely removed.\n", $cDriveLetter))
EndIf
EndIf
Return True;
EndFunc ;==>EjectVolume
Func _Device_Control($hDevice, $dwIoControlCode, ByRef $iRead)
Local $aResult
Local $lpInbuffer, $nInBufferSize, $lpOutBuffer, $nOutBufferSize, $lpOverlapped
$tRead = DllStructCreate("int Data")
$aResult = DllCall("kernel32.dll", "int", "DeviceIoControl", "hwnd", $hDevice, "uint", $dwIoControlCode, "ptr", $lpInbuffer, "uint", 0, _
"ptr", $lpOutBuffer, "uint", 0, "ptr", DllStructGetPtr($tRead), "ptr", $lpOverlapped)
$iRead = DllStructGetData($tRead, "Data")
ConsoleWrite("Device Control " & $iRead & @CRLF)
Return $aResult <> 0
EndFunc ;==>_Device_Control