Jump to content

Recommended Posts

Posted

Hello,

I have to update data on a huge quantity of usb keys.

The goal is > when a usb key is detected, the script must erase the data on this key, and copy *.* from a specified directory to the key, eject the key and wait for the next key.

I made a script, witch is a merge of ptrex's 'USB drive Monitor Example' and the arcker's 'AutoEjectIt'.

Here is the script:

; #FUNCTION# ====================================================================================================
; Description ...: Eject an USB Key or a CD-ROM safely
; Parameters ....: $$cDriveLetter - Drive to eject (ex : E: )

; Return values .: Success      - True
;                  Failure      - False
; Author ........: Yoan Roblet (Arcker)
; Remarks .......:
; Requirements...: AutoIt3Lib
; Related .......: http://support.microsoft.com/kb/165721
; ====================================================================================================


#include <A3LWinApi.au3>
#include <Misc.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

   
           

$chemin="c:\usbee\"
$strComputer = "."
 $objWMIService = ObjGet("winmgmts:\\" & $strComputer & "\root\cimv2")

 $colEvents = $objWMIService.ExecNotificationQuery _
    ("Select * From __InstanceOperationEvent Within 5 Where " _
        & "TargetInstance isa 'Win32_LogicalDisk' and " _
           & "TargetInstance.DriveType = 2" )
           
HotKeySet("{ESC}", "Terminer")
;~ ==========================================================
;~                          ACTION
;~ ==========================================================
While 1
    $objEvent = $colEvents.NextEvent
    If $objEvent.TargetInstance.DriveType = 2 Then ;~ detecte les cles usb (2 = usb)
        Select
            Case $objEvent.Path_.Class()="__InstanceCreationEvent" ;~ detecte la creation d'un disque
                Consolewrite("Disque " & $objEvent.TargetInstance.DeviceId & "ajouté." & @CR)
                FileDelete($objEvent.TargetInstance.DeviceId &"\*.*") ;~ efface le contenu de la clé
                FileCopy($chemin &"*.*", $objEvent.TargetInstance.DeviceId &"\") ;~ copie les nouveaux fichiers
                $OpenVolume = $objEvent.TargetInstance.DeviceId
                ConsoleWrite("Trying to Eject the drive " & EjectVolume($OpenVolume) & @crlf) ; <=== use of the autoejectit
                
            Case $objEvent.Path_.Class()="__InstanceDeletionEvent"
                Consolewrite("Disque " & $objEvent.TargetInstance.DeviceId & "supprimé."& @CR)
        EndSelect
    EndIf
    
WEnd
;~ ==========================================================

Func Terminer()
    Exit 0
EndFunc




Func ReportError($szMsg)
    ConsoleWrite(StringFormat($szErrorFormat, _API_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 = _API_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 _API_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,"",_API_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

- The problem is i don't know where to put the HotKey to quit the program when i launch the program, it works, but when i press 'ESC' it only quit when a usb change has been detected. I would like to quit exactly when i want. i don't specialy need a hotkey, even a gui with a button is better but i don't know gui creation for the moment.

- Does a script already exist for copying data on usb keys with shorter code?

Thank you for your help and suggests,

Loris

Posted

  symadis said:

Any ideas for the place of the hotkey?

Add this to the top of the script: Opt("TrayIconDebug", 1)

And when you hit ESC and nothing happens, check what line of the script it's hung up on.

<_<

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Posted

What happens if you insert a sleep(1000) statement into the while loop? Don't think that the while loop is some kind of blocking function but it's worth the try...

Posted

  Sundance said:

What happens if you insert a sleep(1000) statement into the while loop? Don't think that the while loop is some kind of blocking function but it's worth the try...

A While/WEnd loop is not blocking, but can slam your CPU usage. A shorter sleep, i.e. Sleep(20) or Sleep(100), is usually better to free up the CPU while still making the script responsive to events. A full second is slow enough to be perceptible lag to the user.

<_<

Valuater's AutoIt 1-2-3, Class... Is now in Session!For those who want somebody to write the script for them: RentACoder"Any technology distinguishable from magic is insufficiently advanced." -- Geek's corollary to Clarke's law
Posted

I know that 1 sec is to much to go productive with a program. It was only for testing purpose. In our domain we use some AutoItscripts with GUI's. I think the users would allready killed me if i used a sleep(1000) <_<

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...