EjectUSB

If you are currently developing portable freeware or planning to do so, use this forum to discuss technical implementation, seek out like-minded developers for partnership, or solicit interested users for beta testing.
Post Reply
Message
Author

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#2 Post by Queue »

Ok, so here's my design goal:
Automatically Close Portable Programs and Eject Portable Drive

I'm just using AutoIt3 out of pure laziness. It's sad when I know Delphi and C++ and rely on a scripting language to accomplish things, but it's due to the ridiculously short development time and stability of the various scripting platforms (AI3, NSIS, etc.).

So, for now, I'm just posting the code. If you want to try it yourself, be my guest, and if you are good with AutoIt3, please comment on the script.

Code: Select all

; ----------------------------------------------------------------------------
;
; EjectUSB
; AutoIt Version: 3.0
; Language:       English
; Platform:       Win9x/NT
; Author:         Queue
;
; Script Function:
;  Closes all programs running from Flash Drive then ejects.
;
; ----------------------------------------------------------------------------

; Prepare environment
#NoTrayIcon
$name = "EjectUSB"
$version = "1.0"
$title = "Remove Flash Drive"
$sysdrive = StringLeft(@WindowsDir, 3)

; Check parameters
If $CmdLine[0] = 0 Then
	$file = @ScriptDir
Else
	If $CmdLine[1] = "/help" OR $CmdLine[1] = "/h" OR $CmdLine[1] = "/?" _
						OR $CmdLine[1] = "-h" OR $CmdLine[1] = "-?" Then
		MsgBox(64, $title, "The syntax for this utility is:" & @CRLF & $name & ".exe DriveLetterToEject")
		Exit 0
	Else
		If FileExists($CmdLine[1]) Then
			$file = $CmdLine[1]
		ElseIf StringLen($CmdLine[1]) = 1 Then
			If FileExists($CmdLine[1] & ":") Then
				$file = $CmdLine[1] & ":\"
			Else
				$file = @ScriptDir
			EndIf
		Else
			$file = @ScriptDir
		EndIf
	EndIf
EndIf

; Find current drive letter if not specified
If $file = @ScriptDir Then
	If StringMid(@ScriptDir,2,1)=":" Then
		$file = StringLeft(@ScriptDir, 2) & "\"
	Else
		$file = StringLeft(@ScriptDir, StringInStr(@ScriptDir, "\", 2, 3))
	EndIf
EndIf

; Append backslash if missing
If StringRight($file, 1) <> "\" Then
	$file &= "\"
EndIf

; Prevent system drive eject
If $file = $sysdrive OR StringInStr($file, @WindowsDir, 2) <> 0 Then
	MsgBox(16, $title, "Cannot Eject the System Drive.")
	Exit 0
EndIf

; Read INI settings
$timetowait = IniRead(@ScriptDir & "\" & $name & ".ini", "TimeToWait", "Seconds", "5")
$exceptions = IniReadSection(@ScriptDir & "\" & $name & ".ini", "Exceptions")

; Process exceptions
If @error = 0 Then
If $exceptions[0][0] > 0 Then
	$list = ProcessList()
	For $i = 1 To $list[0][0]
		$loc = _ProcessGetLocation($list[$i][1])
		If StringLeft($loc, StringLen($file)) = $file Then
			If StringInStr($loc, @ScriptName, 2) = 0 Then
				$k = 0
				For $j = 1 To $exceptions[0][0]
					If StringInStr($loc, $exceptions[$j][1], 2) <> 0 Then $k = 1
				Next
				If $k = 0 Then
					If ProcessExists($list[$i][1]) Then ProcessClose($list[$i][1])
				EndIf
			EndIf
		EndIf
	Next

	$list = ProcessList()
	For $i = 1 To $list[0][0]
		$loc = _ProcessGetLocation($list[$i][1])
		If StringLeft($loc, StringLen($file)) = $file Then
			If StringInStr($loc, @ScriptName, 2) = 0 Then
				If ProcessExists($list[$i][1]) Then ProcessWaitClose($list[$i][1], Number($timetowait))
			EndIf
		EndIf
	Next
EndIf
EndIf

; Terminate programs
$list = ProcessList()
For $i = 1 To $list[0][0]
	$loc = _ProcessGetLocation($list[$i][1])
	If StringLeft($loc, StringLen($file)) = $file Then
		If StringInStr($loc, @ScriptName, 2) = 0 Then
			If ProcessExists($list[$i][1]) Then ProcessClose($list[$i][1])
		EndIf
	EndIf
Next

_RefreshSystemTray()

; Run drive ejector
If StringLen($file) = 3 Then
	If StringRight($file, 2) = ":\" Then
		If FileExists(@ScriptDir & "\RemoveDrive.exe") Then
			Run(@ScriptDir & "\RemoveDrive.exe " & StringLeft($file, 2))
		ElseIf FileExists(@ScriptDir & "\USB_Disk_Eject.exe") Then
			Run(@ScriptDir & "\USB_Disk_Eject.exe /REMOVELETTER " & StringLeft($file, 1))
		EndIf
	EndIf
EndIf

Exit 1

; -------------------------- Begin Custom Functions ---------------------------

Func _ProcessGetLocation($iPID)
	Local $aProc = DllCall('kernel32.dll', 'hwnd', 'OpenProcess', 'int', BitOR(0x0400, 0x0010), 'int', 0, 'int', $iPID)
	If $aProc[0] = 0 Then Return SetError(1, 0, '')
	Local $vStruct = DllStructCreate('int[1024]')
	DllCall('psapi.dll', 'int', 'EnumProcessModules', 'hwnd', $aProc[0], 'ptr', DllStructGetPtr($vStruct), 'int', DllStructGetSize($vStruct), 'int*', 0)
	Local $aReturn = DllCall('psapi.dll', 'int', 'GetModuleFileNameEx', 'hwnd', $aProc[0], 'int', DllStructGetData($vStruct, 1), 'str', '', 'int', 2048)
	If StringLen($aReturn[3]) = 0 Then Return SetError(2, 0, '')
	Return $aReturn[3]
EndFunc

; ===================================================================
; _RefreshSystemTray($nDealy = 1000)
;
; Removes any dead icons from the notification area.
; Parameters:
;    $nDelay - IN/OPTIONAL - The delay to wait for the notification area to expand with Windows XP's
;        "Hide Inactive Icons" feature (In milliseconds).
; Returns:
;    Sets @error on failure:
;        1 - Tray couldn't be found.
;        2 - DllCall error.
; ===================================================================
Func _RefreshSystemTray($nDelay = 1000)
; Save Opt settings
    Local $oldMatchMode = Opt("WinTitleMatchMode", 4)
    Local $oldChildMode = Opt("WinSearchChildren", 1)
    Local $error = 0
    Do; Pseudo loop
        Local $hWnd = WinGetHandle("classname=TrayNotifyWnd")
        If @error Then
            $error = 1
            ExitLoop
        EndIf

        Local $hControl = ControlGetHandle($hWnd, "", "Button1")
        
    ; We're on XP and the Hide Inactive Icons button is there, so expand it
        If $hControl <> "" And ControlCommand($hWnd, "", $hControl, "IsVisible") Then 
            ControlClick($hWnd, "", $hControl)
            Sleep($nDelay)
        EndIf
        
        Local $posStart = MouseGetPos()
        Local $posWin = WinGetPos($hWnd)    
        
        Local $y = $posWin[1]
        While $y < $posWin[3] + $posWin[1]
            Local $x = $posWin[0] 
            While $x < $posWin[2] + $posWin[0]
                DllCall("user32.dll", "int", "SetCursorPos", "int", $x, "int", $y)
                If @error Then
                    $error = 2
                    ExitLoop 3; Jump out of While/While/Do
                EndIf
                $x = $x + 8
            WEnd
            $y = $y + 8
        WEnd
        DllCall("user32.dll", "int", "SetCursorPos", "int", $posStart[0], "int", $posStart[1])
    ; We're on XP so we need to hide the inactive icons again.
        If $hControl <> "" And ControlCommand($hWnd, "", $hControl, "IsVisible") Then 
            ControlClick($hWnd, "", $hControl)
        EndIf
    Until 1
    
; Restore Opt settings
    Opt("WinTitleMatchMode", $oldMatchMode)
    Opt("WinSearchChildren", $oldChildMode)
    SetError($error)
EndFunc; _RefreshSystemTray()
With how it's built, you can specify a filter file of programs not to force closed on its first pass; this is to let you NOT force closed registry wrappers, just kill the main programs so the registry wrappers will close on their own (and thus clean up the registry like they're supposed to).

After the first filtered pass, EjectUSB will wait for unfiltered programs to close (5 second maximum wait by default) and then force close everything before calling one of two utilities to eject the portable drive (one is listed in the Portable Freeware database, the other is available at: www.uwe-sieber.de).

Why am I not releasing this fully yet? Well, I want to make the whole ''kill and wait'' process into a proper loop that can run indefinitely until all programs are closed for one, second, I probably need a second set of checks and waits before the drive ejection.

Also, it currently doesn't work on Win9x; I need a function that can get full path info for running programs on Win9x. Even then, the drive ejection won't work on Win9x as neither ejection utility currently supports it.

Queue

---
---
---

Alrighty, time for revision 2. It will run on Win98SE (as opposed to erroring or not starting at all), but it won't really close anything; to compensate I have it close the PStart portable error message that fires when you close PStart on Win98SE, so it's not useless.

It now also closes any explorer windows that are opened to your portable drive; this is probably WinXP only as the titlebar on explorer/folder windows is different between XP and 9x. It can potentially close other windows if their titlebar starts with the path specified.

Code: Select all

; Utility AutoIt3 Script
;
; Prepared by Queue
;
; Last compiled with AutoIt3 version 3.2.10.0
; http://www.autoitscript.com/autoit3/
;
; Uses RefreshSystemTray version 1st Feb 2005
; http://www.autoitscript.com/forum/index.php?showtopic=7404
;
; [QM]
;
; No Copyright. No Company.
; ========================================================================================

;symbols

#NoTrayIcon
$name = "EjectUSB"
$title = "Remove Portable Drive"

;end

; ========================================================================================

;code

; Parse parameters
If $CmdLine[0] = 0 Then
	; Find current drive letter if not specified
	If StringMid(@ScriptDir,2,1) = ":" Then
		$file = StringLeft(@ScriptDir, 2) & "\"
	Else
		$file = StringLeft(@ScriptDir, StringInStr(@ScriptDir, "\", 2, 3))
	EndIf
Else
	If $CmdLine[1] = "/help" OR $CmdLine[1] = "/h" OR $CmdLine[1] = "/?" _
						OR $CmdLine[1] = "-h" OR $CmdLine[1] = "-?" Then
		MsgBox(64, $title, "The syntax for this utility is:" & @CRLF & $name & ".exe DriveLetterToEject")
		Exit 0
	Else
		If FileExists($CmdLine[1]) Then
			$file = $CmdLine[1]
		ElseIf StringLen($CmdLine[1]) = 1 AND FileExists($CmdLine[1] & ":\") Then
			$file = $CmdLine[1] & ":\"
		Else
			; Find current drive letter if invalid value specified
			If StringMid(@ScriptDir,2,1) = ":" Then
				$file = StringLeft(@ScriptDir, 2) & "\"
			Else
				$file = StringLeft(@ScriptDir, StringInStr(@ScriptDir, "\", 2, 3))
			EndIf
		EndIf
	EndIf
EndIf

; Append backslash if missing
If StringRight($file, 1) <> "\" Then
	$file &= "\"
EndIf

; Prevent system drive eject
If $file = StringLeft(@WindowsDir, 3) OR StringInStr($file, @WindowsDir, 2) <> 0 Then
	MsgBox(16, $title, "Cannot Eject the System Drive.")
	Exit 0
EndIf

; Read INI settings
$timetowait = IniRead(@ScriptDir & "\" & $name & ".ini", "TimeToWait", "Seconds", "5")
SetError(0)
$exclusions = IniReadSection(@ScriptDir & "\" & $name & ".ini", "Exclusions")
$excerror = @error
$inclusions = IniReadSection(@ScriptDir & "\" & $name & ".ini", "Inclusions")
$incerror = @error

If $excerror = 0 Then
	If $exclusions[0][0] = 0 Then $excerror = 1
EndIf
If $incerror = 0 Then
	If $inclusions[0][0] = 0 Then $incerror = 1
EndIf

; Process exclusions and inclusions
$list = ProcessList()
For $i = 1 To $list[0][0]
	$loc = _ProcessGetLocation($list[$i][1])
	$k = 0
	If StringLeft($loc, StringLen($file)) = $file Then
		If StringInStr($loc, @ScriptName, 2) = 0 Then
			$k = 1
			If $excerror = 0 Then
				For $j = 1 To $exclusions[0][0]
					If StringInStr($loc, $exclusions[$j][1], 2) <> 0 Then $k = 0
				Next
			EndIf
		EndIf
	EndIf
	; Process inclusions
	If $incerror = 0 Then
		For $j = 1 To $inclusions[0][0]
			If StringInStr($loc, $inclusions[$j][1], 2) <> 0 Then $k = 1
		Next
	EndIf
	; Terminate programs
	If $k = 1 Then
		If ProcessExists($list[$i][1]) Then ProcessClose($list[$i][1])
	EndIf
Next

If $excerror = 0 Then

$list = ProcessList()
For $i = 1 To $list[0][0]
	$loc = _ProcessGetLocation($list[$i][1])
	$k = 0
	If StringLeft($loc, StringLen($file)) = $file Then
		If StringInStr($loc, @ScriptName, 2) = 0 Then
			$k = 1
			For $j = 1 To $exclusions[0][0]
				If StringInStr($loc, $exclusions[$j][1], 2) <> 0 Then $k = 0
			Next
		EndIf
	EndIf
	; Process inclusions
	If $incerror = 0 Then
		For $j = 1 To $inclusions[0][0]
			If StringInStr($loc, $inclusions[$j][1], 2) <> 0 Then $k = 1
		Next
	EndIf
	; Wait for programs to close
	If $k = 1 Then
		If ProcessExists($list[$i][1]) Then ProcessWaitClose($list[$i][1], Number($timetowait))
	EndIf
Next

; Terminate programs
$list = ProcessList()
For $i = 1 To $list[0][0]
	$loc = _ProcessGetLocation($list[$i][1])
	$k = 0
	If StringLeft($loc, StringLen($file)) = $file Then
		If StringInStr($loc, @ScriptName, 2) = 0 Then
			$k = 1
		EndIf
	EndIf
	; Process inclusions
	If $incerror = 0 Then
		For $j = 1 To $inclusions[0][0]
			If StringInStr($loc, $inclusions[$j][1], 2) <> 0 Then $k = 1
		Next
	EndIf
	; Terminate programs
	If $k = 1 Then
		If ProcessExists($list[$i][1]) Then ProcessClose($list[$i][1])
	EndIf
Next

EndIf

; Wait for programs to close
$list = ProcessList()
For $i = 1 To $list[0][0]
	$loc = _ProcessGetLocation($list[$i][1])
	$k = 0
	If StringLeft($loc, StringLen($file)) = $file Then
		If StringInStr($loc, @ScriptName, 2) = 0 Then
			$k = 1
		EndIf
	EndIf
	; Process inclusions
	If $incerror = 0 Then
		For $j = 1 To $inclusions[0][0]
			If StringInStr($loc, $inclusions[$j][1], 2) <> 0 Then $k = 1
		Next
	EndIf
	; Wait for programs to close
	If $k = 1 Then
		If ProcessExists($list[$i][1]) Then
			If ProcessWaitClose($list[$i][1], Number($timetowait)) = 0 Then
				If ProcessExists($list[$i][1]) Then ProcessClose($list[$i][1])
			EndIf
		EndIf
	EndIf
Next

; Close PStart portable Win98SE error window
WinClose("PStart portable")

; Remove dead system tray icons
_RefreshSystemTray()

; Close explorer windows that are viewing the portable drive
Opt("WinTitleMatchMode", -1)
$list = WinList($file)
For $i = 1 To $list[0][0]
	WinClose($list[$i][0])
Next

; Run drive ejector
If StringLen($file) = 3 Then
	If StringRight($file, 2) = ":\" Then
		If FileExists(@ScriptDir & "\RemoveDrive.exe") Then
			Run(@ScriptDir & "\RemoveDrive.exe " & StringLeft($file, 2), "", @SW_HIDE)
		ElseIf FileExists(@ScriptDir & "\USB_Disk_Eject.exe") Then
			Run(@ScriptDir & "\USB_Disk_Eject.exe /REMOVELETTER " & StringLeft($file, 1))
		EndIf
	EndIf
EndIf

Exit 1

; ........................................................................................

Func _ProcessGetLocation($iPID)
	Local $hProc = DllCall("kernel32.dll", "int", "OpenProcess", "int", 0x0410, "int", 0, "int", $iPID)
	If @error OR $hProc[0] = 0 Then
		If $hProc[0] Then DllCall("kernel32.dll", "int", "CloseHandle", "int", $hProc[0])
		Return SetError(1, 0, "")
	EndIf
	Local $stHMod = DllStructCreate("int hMod")
	Local $stCB = DllStructCreate("dword cbNeeded")
	Local $resEnum = DllCall("psapi.dll", "int", "EnumProcessModules", "int", $hProc[0], "ptr", DllStructGetPtr($stHMod), "dword", DllStructGetSize($stHMod), "ptr", DllStructGetPtr($stCB, 1))
	If @error OR $resEnum[0] = 0 Then
		DllCall("kernel32.dll", "int", "CloseHandle", "int", $hProc[0])
		Return SetError(2, 0, "")
	EndIf
	Local $resPath = DllCall("psapi.dll", "int", "GetModuleFileNameEx", "int", $hProc[0], "int", DllStructGetData($stHMod, 1), "str", "", "dword", 32768)
	DllCall("kernel32.dll", "int", "CloseHandle", "int", $hProc[0])
	If @error Then
		Return SetError(3, 0, "")
	EndIf
	SetError(0)
	Return $resPath[3]
EndFunc

; ........................................................................................
; _RefreshSystemTray($nDelay = 1000)
;
; Removes any dead icons from the system tray.
; Parameters:
;    $nDelay - IN/OPTIONAL - The delay to wait for the notification area to expand with
;    Windows XP's "Hide Inactive Icons" feature (In milliseconds).
; Returns:
;    Sets @error on failure:
;        1 - Tray couldn't be found.
;        2 - DllCall error.
; ........................................................................................
Func _RefreshSystemTray($nDelay = 1000)
; Save Opt settings
    Local $oldMatchMode = Opt("WinTitleMatchMode", 4)
    Local $oldChildMode = Opt("WinSearchChildren", 1)
    Local $error = 0
    Do; Pseudo loop
        Local $hWnd = WinGetHandle("classname=TrayNotifyWnd")
        If @error Then
            $error = 1
            ExitLoop
        EndIf

        Local $hControl = ControlGetHandle($hWnd, "", "Button1")
        
    ; We're on XP and the Hide Inactive Icons button is there, so expand it
        If $hControl <> "" And ControlCommand($hWnd, "", $hControl, "IsVisible") Then 
            ControlClick($hWnd, "", $hControl)
            Sleep($nDelay)
        EndIf
        
        Local $posStart = MouseGetPos()
        Local $posWin = WinGetPos($hWnd)    
        
        Local $y = $posWin[1]
        While $y < $posWin[3] + $posWin[1]
            Local $x = $posWin[0] 
            While $x < $posWin[2] + $posWin[0]
                DllCall("user32.dll", "int", "SetCursorPos", "int", $x, "int", $y)
                If @error Then
                    $error = 2
                    ExitLoop 3; Jump out of While/While/Do
                EndIf
                $x = $x + 8
            WEnd
            $y = $y + 8
        WEnd
        DllCall("user32.dll", "int", "SetCursorPos", "int", $posStart[0], "int", $posStart[1])
    ; We're on XP so we need to hide the inactive icons again.
        If $hControl <> "" And ControlCommand($hWnd, "", $hControl, "IsVisible") Then 
            ControlClick($hWnd, "", $hControl)
        EndIf
    Until 1
    
; Restore Opt settings
    Opt("WinTitleMatchMode", $oldMatchMode)
    Opt("WinSearchChildren", $oldChildMode)
    SetError($error)
EndFunc; _RefreshSystemTray()

;end
Queue
Last edited by Queue on Tue Jun 03, 2008 5:16 pm, edited 2 times in total.

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#3 Post by Queue »

Well, revision 3 time. It now can find and close programs running from the specified drive on Win98SE in addition to XP. I presume this means it also works on ME, NT and 2000. No clue about 95 or Vista. I've only personally tested this on 98SE and XP.

If RemoveDrive.exe or USB_Disk_Eject.exe is found in the same folder as EjectUSB.exe, EjectUSB will use it to eject the drive. On Win9x, it will try and eject the drive itself.

EjectUSB can be configured via an INI file (named EjectUSB.ini) placed in the same folder as EjectUSB.exe. Its format is as follows:

[Settings]
TimeToWait=5
DoNotEject=0

[Exclusions]
0=PStart
1=Pocket
2=Portable

[Inclusions]
0=temp\aicon.exe

TimeToWait is the amount of time in seconds to wait for programs to close.

DoNotEject lets you block automatic ejection even if run on Win9x or in the presence of RemoveDrive or USB_Disk_Eject. Any value except 0 (or no entry) will disable automatic ejection.

Exclusions list part of a file name that won't be automatically closed. Registry wrappers and portable launchers should be excluded. Entries should be numbered sequentially and there should be realistically no limit to the number of entries.

Inclusions list part of a file name that will be automatically closed even if they're not running from the removable drive. Entries should be numbered sequentially and there should be realistically no limit to the number of entries.

An example INI file is included in the ZIP along with the AutoIt3 script.

http://localhostr.com/files/66a9f1/EjectUSB.zip

Queue

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#4 Post by Queue »

Revision 4, Release Candidate 1.

Some fairly major improvements including:
- Closing of Explorer windows now happens reliably on both Win98SE and WinXP SP2
- EjectUSB can now eject the drive using the Windows dialogs for removing ejectable hardware on both Win98SE and WinXP and is no longer language dependent
- Small efficiency improvement when closing programs on Win9x

I'd also like to point out you can pass a drive or folder to EjectUSB via a command line argument. For example, you can have PStart launch EjectUSB on exit passing it the %pdrive% value. If no command line argument is specified, EjectUSB will automatically determine the drive letter of the drive it is running on and use that. If you pass EjectUSB a folder name (or network share), it will not attempt to eject a drive, only close programs running from that folder (and its subfolders).

http://localhostr.com/files/6040fd/EjectUSB.zip

I'm mainly after testing feedback to see what other versions of Windows EjectUSB works on and to make sure it works for other people (particularly using other languages) also running Win98SE or WinXP.

Queue

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#5 Post by Queue »

Revision 5, Release Candidate 2.

---

Two new entries are available in the configuration INI file:
[Settings]
DoNotClose=0 or 1
NoExplorer=0 or 1

If set to 1 (or anything besides 0 or false), DoNotClose disables EjectUSB's program closing functionality. This is useful if you simply want EjectUSB to try and eject a drive without closing programs.

If set to 1 (or anything besides 0 or false), NoExplorer disables EjectUSB's Explorer window closing functionality. This works independently of DoNotClose and must also be set if you don't want EjectUSB to close ANYTHING.

---

In addition, Explorer window closing has been improved slightly (it wasn't catching ''Cabinet'' and ''IEFrame'' versions of Explorer).

---

http://localhostr.com/files/676b25/EjectUSB.zip

---

This is looking to be the final version as all functionality has been established and there don't appear to be any bugs left. In general, errors are gracefully and silently handled; the only exception being if shell32.dll doesn't exist on the machine EjectUSB is run on... but what are the odds of that happening? Even then, it just pops up an error message.

Queue

User avatar
guinness
Posts: 4118
Joined: Mon Aug 27, 2007 2:00 am
Contact:

Amazing...I am currently coding in Autoit and have been...

#6 Post by guinness »

looking for something like this! I am currently using TrueCrypt which mounts to a drive letter e.g. X:\, problem is that if a process exists on this drive it wont dismount correctly. I have been using:

Code: Select all

$Temp = ProcessList()
$Snapshot = ""
For $i = 1 to $Temp[0][0]
$Snapshot=$Snapshot&" "&$Temp[$i][1]
Next

;CONTINUE SCRIPT

$Temp = ProcessList()
Dim $Closelist[20]
For $i = 1 to $Temp[0][0]
If StringInStr( $Snapshot,$Temp[$i][1] )=0 Then
ProcessClose( $Temp[$i][1])
ProcessWaitClose( $Temp[$i][1] )
EndIf
Next
which as you can tell deletes the processes that have opened during the start and closed at the end. with your script I take it that if I place TrueCrypt in the exclusion section of the ini it won't dismount the drive, as your app seems to close TrueCrypt and dismount currently. Any ideas on what sections could be used in your script to accomplish the above?

A great app and any coding tips would be much appreciated.

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#7 Post by Queue »

Ah, I get how yours is working.

Well, with how EjectUSB works currently, you should have two options for closing programs run from a TrueCrypt volume (this is assuming you would just use EjectUSB rather than doing more to your script):
1) Put EjectUSB inside the TrueCrypt volume and run it when you want to close anything running from the TrueCrypt volume. You'd want DoNotEject=1 in the EjectUSB INI's [Settings] section. An exclusion for TrueCrypt shouldn't be necessary because it'd be running from a different drive letter.
2) Put EjectUSB anywhere and run it with a command-line switch equalling the letter of the mounted TrueCrypt volume. If TrueCrypt mounts as X:\ you'd run EjectUSB.exe X:

The problem would be that EjectUSB wouldn't close any programs that are running from outside of the mounted TrueCrypt volume that are using a file from within the TrueCrypt volume.

Your script will close any program run after it which means it would close programs running from outside the volume that may (or may not) be using files from the TrueCrypt volume... unless said program was already running before your script was run AND doesn't spawn a new instance (Notepad wouldn't be a problem but Word would, for example) in which case it'd be on the $Snapshot list.

Now that I've typed all of that... I'm not sure I fully understand what your question is. Are you looking to know how you could use EjectUSB in regards to a TrueCrypt volume, or are you asking for help with your script? If the former, what I wrote above should be of some help. If the latter, I'd need clarification on what exactly you're asking for help with. If you simply want to exclude TrueCrypt from your script's closing, you could have your script run TrueCrypt before preparing the $Snapshot value. This way when the $Snapshot value is generated, TrueCrypt would be among the Process IDs saved in $Snapshot.

The exclusions system in EjectUSB is tailored rather specifically to how EjectUSB matches file names. In addition, EjectUSB is using entire file paths for checking programs rather than just the main executable's name (X:\Folder\Program.exe rather than Program.exe).

Queue

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#8 Post by Queue »

Revision 6.

---

Added device ejection via external utility support for:
DevEject http://www.withopf.com/tools/deveject/
USBDeview http://www.nirsoft.net/utils/usb_devices_view.html
and limited support for:
AutoStart / AutoEject http://xpt.nl/products-autostart
(must be run from the removable drive itself)

---

Added new functionality:
Registry cleanup of application most-recently used list. This attempts to increase portable application stealthiness by removing entries from HKEY_CURRENT_USER\Software\Microsoft\Windows\ShellNoRoam\MUICache related to the drive or folder passed to EjectUSB. This is the final step before attempting drive ejection (if not disabled) so any ejection executables started after this cleanup will still show up in the registry (like RemoveDrive.exe does for me with how I use EjectUSB).

---

Added new INI file setting to correspond to registry cleanup:
[Settings]
DoNotClean=0

If set to 1 (or anything besides 0 or false), DoNotClean disables EjectUSB's registry cleanup functionality.

---

http://localhostr.com/files/b16de0/EjectUSB.zip

---

This version should be bug free, however, I hope to expand upon the stealth cleanup functionality in the future as well as adding a snapshot program closing feature similar to the one guinness talked about earlier in this thread.

Queue

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#9 Post by Queue »

Revision 7.

---

Improved functionality:
Registry cleanup. In addition to:
HKCU\Software\Microsoft\Windows\ShellNoRoam\MUICache
EjectUSB now also cleans entries related to the specified drive/folder from:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedMRU
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\OpenSaveMRU
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\RunMRU
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StreamMRU
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\Streams
as well as firewall policy cleanup from:
HKLM\SYSTEM\CurrentControlSet\Services\SharedAccess\Parameters\FirewallPolicy\StandardProfile\AuthorizedApplications\List

---

Added new INI file setting to correspond to firewall policy cleanup:
[Settings]
NoFirewall=0

If set to 1 (or anything besides 0 or false), NoFirewall disables EjectUSB's firewall policy cleanup functionality. This setting works independently of DoNotClean, so both must be set to 1 to completely disable EjectUSB's registry cleanup functionality.

---

http://localhostr.com/files/ecdebf/EjectUSB.zip

---

The registry cleanup for:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\ComDlg32\LastVisitedMRU
needs testing as I used rather simplistic methods to parse the registry values.

The registry cleanup for:
HKCU\Software\Microsoft\Windows\CurrentVersion\Explorer\StreamMRU
is limited to only cleaning entries specific to a certain drive letter (it can't deal with folder structure checks) due to the way the registry entries are formatted.

Queue

User avatar
MiDoJo
Posts: 282
Joined: Thu Apr 17, 2008 2:36 pm

#10 Post by MiDoJo »

Queue,
Howdy,
I just started testing EjectUSB on a Vista. It works Great (to eject I need to regshot to see other stuff). I'm using it, as suggested by you, at the exit of PStart. I Opened a number of progie on my portable and exited Pstart and it closed them all.

1)Keypass Users need to exit keepass to avoid "this database is in use" upon next run.

2)Is it killing the processes or asking them to shut down gracefully? if I have a progie running and doing work when eject runs will I "lose data/corrupt files"?
Thanks for this progie (i probably won't actually use it past the testing phase but that's b/c I don't have much use for it NOT because it's not useful.)
MiDoJo

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#11 Post by Queue »

Right now it's terminating them forcefully. EjectUSB makes several passes through the running programs though so I should be able to make the first pass be ''graceful'' exit requests. I'll look at KeePass in particular and use it as a benchmark for proper closing.

My original intent was just to get everything closed so the drive could be properly ejected; I wasn't concerned about safety other than general safety (don't delete files, don't damage the OS, etc.). But EjectUSB's evolved a little since then and now also encompasses some cleanup routines so safer closing of programs would make perfect sense with its natural progression.

Thanks again for your help and feedback. =)

Queue

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#12 Post by Queue »

Revision 8.

---

Whew, ok, so thanks to MiDoJo and ashghost I was able to improve support for registry cleanup on Vista and so here's Revision 8.

Some of the registry scanning can take a little while (like 5 to 10 seconds in heavily cluttered situations) so I've improved the configuration file settings to give you better control over EjectUSB's functions. While I want to add functionality, I don't want functionality bloat to impair EjectUSB. I've also restructured the beginning of the AutoIt3 script file to allow easy translation if anyone wants to recompile the script for their own use in their native language.

---

The [Settings] section of EjectUSB.ini is now formatted as such:
[Settings]
TimeToWait=5
DoNotClose=0
NoPrograms=0
NoExplorer=0
DoNotClean=0
NoRegistry=0
NoFirewall=0
NoShortcut=0
DoNotEject=0

DoNotClose now supersedes NoPrograms and NoExplorer meaning if it's set to 1, no programs or explorer windows will be closed. If 0, then NoPrograms decides if programs will be closed and NoExplorer will decide if explorer windows will be closed.

DoNotClean now supersedes NoRegistry, NoFirewall and NoShortcut meaning if it's set to 1, no registry cleanup or recent documents shortcut cleanup will be performed. If 0, then NoRegistry decides if registry cleanup will be performed, NoFirewall will decide if Windows Firewall Policy entries will be cleaned and NoShortcut will decide if recent documents shortcut cleanup will be performed

DoNotEject works the same as before (as does TimeToWait).

---

EjectUSB now detects its own executable filename when run, so you can, for example, name EjectUSB.exe and EjectUSB.ini to newname.exe and newname.ini and it'll be able to get its settings out of newname.ini properly.

---

http://localhostr.com/files/bfa7cc/EjectUSB.zip

---

I haven't yet implemented ''graceful'' closing; I need to explore my options with AutoIt3 to see how I want to manage it. Unfortunately it's not as simple as changing ProcessClose() to WinClose().

I still haven't figured out if BagMRU or TrayNotify are within reason to perform cleanup on.

Also, due to how long the cleanup functions can take, I plan to add some sort of busy indicator to let you know things are still going on.

I need to double check that EjectUSB's built-in ejection works on Vista SP1 (I have a suspicion that it doesn't) and to give EjectUSB the ability to copy itself to the local temp folder in the case that it needs to perform a self-ejection (this isn't necessary on Win98SE but it is on WinXP).

I'll likely also add support for a language translation file (named EjectUSB.lng most likely).

Queue

User avatar
MiDoJo
Posts: 282
Joined: Thu Apr 17, 2008 2:36 pm

#13 Post by MiDoJo »

Queue, Vista SP1 is me (hurrah)
Everything seems to go as planned
Should Eject Require Me to click OK on second eject screen? Currently it does. I ran into some problems (drive cannot be eject it is in use type errors, wink (from John Haller) was recording from a different portable drive when I got this message) but they are not repeatable and do not seem to be related to USB Port type/Hub.
I think that the program will be great use for Portie Users :)
Downloading regshot after lunch so I can get you the reg data on the latest release.
My test programs that are running off of my test drive are
Peazip
MMCompView
Unknown Devices
All seem to close fine.
More later.
Fun working with you.

User avatar
Queue
Posts: 197
Joined: Mon Oct 08, 2007 2:41 am
Contact:

#14 Post by Queue »

MiDoJo wrote:Queue, Vista SP1 is me (hurrah)
Great, then I have all major testing environments available (98SE, XPSP3, VistaSP1).
MiDoJo wrote:Everything seems to go as planned
So far no major problems and I'm fairly meticulous so I seriously doubt there will be any. Just some work to get everything functional between OSes.
MiDoJo wrote:Should Eject Require Me to click OK on second eject screen? Currently it does.
It shouldn't, it should do the entire ejection process automatically and that's what I need to get figured out. The Vista SP1 dialog seems to have a different button ID or something because the ejection routine worked when I tried it on a Vista (non-SP1) machine.
MiDoJo wrote:I ran into some problems (drive cannot be eject it is in use type errors, wink (from John Haller) was recording from a different portable drive when I got this message) but they are not repeatable and do not seem to be related to USB Port type/Hub.
That's not too surprising; I plan to have a mechanism in place to account for that. Does the ''in use'' message happen every time you try and eject with EjectUSB? It actually depends upon the speed that Windows copes with trying to eject the drive; on 98SE Windows is so slow that EjectUSB has time to close before Windows finishes ejecting, but on XP (and I presume Vista) Windows is fast enough that the drive can't eject because EjectUSB hasn't closed yet.
MiDoJo wrote:I think that the program will be great use for Portie Users :)
Here's hoping!
MiDoJo wrote:Downloading regshot after lunch so I can get you the reg data on the latest release.
Alrighty.
MiDoJo wrote:My test programs that are running off of my test drive are
Peazip
MMCompView
Unknown Devices
All seem to close fine.
Good. The next time you test can you have an Explorer window open to your portable drive and see if it closes when you run EjectUSB as well? Not sure what happens on Vista in that regard.
MiDoJo wrote:More later.
Fun working with you.
And with you. Thanks for all your help!

Also, I've already implemented a ''busy indicator'' in the next version; during the registry cleanup process a little spinning hourglass appears in the system tray.

---

Edit: Progress update!
Done! - Busy indicator when performing cleanup.
- It's a cute little spinning hourglass in the system tray.
Started - Ability to copy self to temp folder, run, then delete self.
- I've kinda done this backwards; ability to delete itself is implemented but not the stuff to copy itself to the temp folder then run.
Started - ''Graceful'' program closing.
- Option to disable graceful closing is in place and I know how I'm going to implement it, but I haven't yet.
Nothing Yet - Improved Vista compatibility for ejection.
- Need to figure out what info I'm missing about the Vista eject dialogs. It really shouldn't take much to actually get it working.

Scrapping plans for language file support; EjectUSB only has 5 language-related strings and the new version has edited resources so ''recompiling'' would be required for full language adjustments anyway.

Still not sure about BagMRU and TrayNotify. Can anyone provide insight into what BagMRU is even for?

Queue

User avatar
MiDoJo
Posts: 282
Joined: Thu Apr 17, 2008 2:36 pm

#15 Post by MiDoJo »

Hiya I got you some autoit info for the "Stop a Hardware Device" Vista sp1

Code: Select all

>>>> Window <<<<
Title:	Stop a Hardware device
Class:	#32770
Position:	87, 93
Size:	400, 277
Style:	0x94C802C4
ExStyle:	0x00010101
Handle:	0x00180B1C

>>>> Control <<<<
Class:	Button
Instance:	1
ClassnameNN:	Button1
Advanced (Class):	[CLASS:Button; INSTANCE:1]
ID:	1
Text:	OK
Position:	216, 206
Size:	75, 23
ControlClick Coords:	39, 14
Style:	0x50030000
ExStyle:	0x00000004
Handle:	0x00160C68

>>>> Mouse <<<<
Position:	350, 341
Cursor ID:	0
Color:	0x31317A

>>>> StatusBar <<<<

>>>> Visible Text <<<<
Confirm devices to be stopped, Choose OK to continue.
Windows will attempt to stop the following devices. After the devices are stopped they may be removed safely.
OK
Cancel


>>>> Hidden Text <<<<
A'ight so I click Button Instance 1 aka "OK"
and the following autoit info for "The device can now be safely removed from the computer"'s OK Button

Code: Select all

>>>> Window <<<<
Title:	Safe To Remove Hardware
Class:	#32770
Position:	92, 386
Size:	378, 152
Style:	0x94C801C5
ExStyle:	0x00010101
Handle:	0x002B0AF6

>>>> Control <<<<
Class:	Button
Instance:	1
ClassnameNN:	Button1
Advanced (Class):	[CLASS:Button; INSTANCE:1]
ID:	2
Text:	OK
Position:	268, 79
Size:	88, 26
ControlClick Coords:	29, 10
Style:	0x50030001
ExStyle:	0x00000004
Handle:	0x000F08D6

>>>> Mouse <<<<
Position:	397, 503
Cursor ID:	2
Color:	0xDCF1FC

>>>> StatusBar <<<<

>>>> Visible Text <<<<
OK
This device can now be safely removed from the computer.


>>>> Hidden Text <<<<
It actually depends upon the speed that Windows copes with trying to eject the drive
This makes sense; I'm using an older 512 stick and it was reading on a 1.0 USB. Please note: I'm no longer getting this error and was not getting it everytime. Explorer window closes fine.


Ah ha!!!! I get the error when eject successfully presses it's own buttons (I.e. my 2 different infos in this post are now directly related to each other)
yup yup this is now tested and definite

Post Reply