Jump to content
Sign in to follow this  
SlackerAl

Getting file handles from non-AutoIt files

Recommended Posts

I have an application (external, commercial, no source, non-AutoIt) that applies a file lock to data files that it opens and then holds this lock until the application closes, preventing the files from being deleted. There is no need for this (it reads the file once then ignores it) and I often want to delete the files without closing the other application. I've been using process explorer to find file handles from these files to force a close on them - this works well, but I would like to simplify the process using AutoIt.

Is it possible to find file handles being used by another non-AutoIt application and force them to close?

Can I write this capability in AutoIt, without requiring an installation of process explorer?


Problem solving step 1: Write a simple, self-contained, running, replicator of your problem.

Share this post


Link to post
Share on other sites

I doubt it will work In native AutoIt without an external exe file. But I'd simply use the "handle.exe" from the sysinternals suite.

Given the filename as parameter, you'll get the name of the executable and process ID which owns the handle.

Using the -c parameter and the process ID, you can close the handle and then delete the file.


Any of my own codes posted on the forum are free for use by others without any restriction of any kind. (WTFPL)

Share this post


Link to post
Share on other sites

Hi.

 

I faced a simmilar issue for my compiled scripts, that are stored on a Windows Server Share and are used by quite a lot of users continuously and simultaneously.

 

So the users are throughout the Network (LAN), the Server the files are stored on is a remote machine (view of my PC), that's why I remotely Close "Network file handles"

 

 

Net-GetOpenFileHandles-CloseAndReplace.au3

#include <GUIConstantsEx.au3>
#include <NetShare.au3>
#include <WindowsConstants.au3>
#include <Array.au3>
#include <EditConstants.au3>
; Enumerate open files on the server


$DragDropOpenFile = "<drag drop the opened file on a server share here>"
$DragDropNewFile = "<drag drop the file supposed to replace the above one here>"
$NewFile = ""
$Gui_h = 250
$Gui_w = 800
$vDist = 7
; GUICreate($GuiTitle, $w, $h, @DesktopWidth - $w - 100, @DesktopHeight - $h - 60, -1, $WS_EX_ACCEPTFILES) ; generally enable drag-drop for files into other GUI controls
$myGui = GUICreate("Tool to forcibly close & replace open files on server shares", $Gui_w, $Gui_h, 100, 100, -1, $WS_EX_ACCEPTFILES)

$InputFileToClose = GUICtrlCreateInput($DragDropOpenFile, 20, $vDist, $Gui_w - 40, 20)
GUICtrlSetState(-1, $GUI_DROPACCEPTED) ; allow drag-droping files for this control, $InputFile
Opt("Guicoordmode", 2)
$InputFileNew = GUICtrlCreateInput($DragDropNewFile, -1, $vDist)
GUICtrlSetState(-1, $GUI_DROPACCEPTED) ; allow drag-droping files for this control, $InputFile
GUICtrlSetState(-1, $GUI_DISABLE)
$lServer = GUICtrlCreateLabel("<server>", -1, $vDist)
$lShare = GUICtrlCreateLabel("<share-mapping>", -1, $vDist)
$lPath = GUICtrlCreateLabel("<sub-path>", -1, $vDist)
$lFile = GUICtrlCreateLabel("<file>", -1, $vDist)

$doit = GUICtrlCreateButton("Search and close for open file handles", -1, $vDist)
GUICtrlSetState(-1, $GUI_DISABLE)
$exit = GUICtrlCreateButton("Cancel", -1, $vDist)



GUISetState()



$FN = False
$FNnew = ""
$FNmatch = False
$ToolTitle = ""
$ToolTxt = ""


$RegExA2E = "(?i)^(?:.*?Problem copying file from: )(.*?)(?: To :)(.*$)" ; $1 = compiled local TEMP file, $2 = not replacable destination file
; Examle Replacement failed output: !>11:19:15 Problem copying file from: C:\Users\USERNAME\AppData\Local\AutoIt v3\Aut2exe\~AU98E6.tmp.exe To :z:\MyAutoitExeForTheUsers.exe

While 1
    $Clip = ClipGet()
    If StringRegExp($Clip, $RegExA2E) Then
        $Src = StringRegExpReplace($Clip, $RegExA2E, "$2")
        GUICtrlSetData($InputFileToClose, $Src)
        $Dst = StringRegExpReplace($Clip, $RegExA2E, "$1")
        GUICtrlSetData($InputFileNew, $Dst)
    EndIf

    $input = GUICtrlRead($InputFileToClose)
    If $input <> $DragDropOpenFile Then ; da wurde was reingezogen
        $DragDropOpenFile = $input
        If StringLeft($input, 2) = "\\" Then
            $Type = "UNC"
            $ServerShareUNC = StringLeft($input, StringInStr($input, "\", 0, 4) - 1)
            $fRelPathFN = StringReplace($input, $ServerShareUNC, "")
            $fPath = StringLeft($fRelPathFN, StringInStr($fRelPathFN, "\", 0, -1))
            $FN = StringTrimLeft($fRelPathFN, StringInStr($fRelPathFN, "\", 0, -1))
        ElseIf StringMid($input, 2, 1) = ":" Then ; Pfad mit Laufwerksbuchstabe, evtl. Netzwerk Mapping (erforderlich)
            $drive = StringLeft($input, 2)
            $Type = DriveGetType($drive)
            If $Type = "Network" Then
                $ServerShareUNC = DriveMapGet($drive)
                $foo = StringReplace($input, $drive, $ServerShareUNC) ; Laufwerkspfad in UNC Pfad umwandeln
                $fRelPathFN = StringReplace($foo, $ServerShareUNC, "")
                $fPath = StringLeft($fRelPathFN, StringInStr($fRelPathFN, "\", 0, -1))
                $FN = StringTrimLeft($fRelPathFN, StringInStr($fRelPathFN, "\", 0, -1))
            Else
                MsgBox(48, @ScriptLineNumber, "This script can *ONLY* close remotely handles for files open on server shares!" & @CRLF & _
                        $input & @CRLF & _
                        $drive & " = " & $Type)
                ContinueLoop 2
            EndIf
        EndIf
        $Server = StringLeft($ServerShareUNC, StringInStr($ServerShareUNC, "\", 0, 3) - 1)
        $Share = StringTrimLeft($ServerShareUNC, StringInStr($ServerShareUNC, "\", 0, 3) - 1)
        GUICtrlSetData($lServer,"Server  = '" &  $Server& "'")
        GUICtrlSetData($lShare, "Mapping = '" & $Share & "'")
        GUICtrlSetData($lPath,  "SubPath = '" &$fPath & "'")
        GUICtrlSetData($lFile,  "FileName= '" & $FN &"'")
        GUICtrlSetState($doit, $GUI_ENABLE)
        GUICtrlSetState($InputFileNew, $GUI_ENABLE)
    EndIf

    If $NewFile <> GUICtrlRead($InputFileNew) Then
        $NewFile = GUICtrlRead($InputFileNew)
        If $NewFile <> $DragDropNewFile Then
            If StringInStr($NewFile, $DragDropNewFile) Then
                $NewFile = StringReplace($NewFile, $DragDropNewFile, "")
                GUICtrlSetData($InputFileNew, $NewFile)
            EndIf
            $FNnew = StringTrimLeft($NewFile, StringInStr($NewFile, "\", 0, -1))
            If $FN = $FNnew Then
                If $FNmatch = False Then
                    $FNmatch = True
                    GUICtrlSetData($doit, "Search for & Close open file handles, then replace file")
                EndIf
            Else
                If $FNmatch Then
                    $FNmatch = False
                    GUICtrlSetData($doit, "Search for & Close open file handles, then replace file")
                    GUICtrlSetData($InputFileNew, $DragDropNewFile)
                EndIf
            EndIf
        EndIf
    EndIf
    Switch GUIGetMsg()
        Case $exit, $GUI_EVENT_CLOSE
            GUIDelete($myGui)
            Exit
        Case $doit
            AbArbeiten($Server, $Share, $fPath, $FN)
    EndSwitch
WEnd





Func AbArbeiten($_Srv, $_Shr, $_fPth, $_fNme)

    Local $iID = 0
    Local $iRights = 1
    Local $iLckCount = 2
    Local $iFPFN = 3
    Local $iUser = 4

    ConsoleWrite($_fPth & $_fNme & @CRLF)

    Local $aFile = _Net_Share_FileEnum($_Srv)
    If IsArray($aFile) Then
        ; _ArrayDisplay($aFile)
        Local $x
        $ToolTxt = "Open File Handles:"
        $ToolTitle = "Handles to be checked total: " & $aFile[0][0]
        UpdateToolTip()
        AdlibRegister(UpdateToolTip, 1000)
        For $x = $aFile[0][0] To 1 Step -1
            $ToolTitle = $x & " handles remaining for checking..."

            If Not StringInStr($aFile[$x][$iFPFN], $_fPth & $_fNme) Then
                ; ConsoleWrite("Nix Enthalten in: " & $aFile[$x][$iFPFN] & @CRLF)
                _ArrayDelete($aFile, $x)
            Else
                $ToolTxt &= @CRLF & $aFile[$x][$iFPFN] & ", User = " & $aFile[$x][$iUser]
                ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $ToolTxt = ' & $ToolTxt & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
            EndIf
        Next
        $aFile[0][0] = UBound($aFile) - 1
        _ArraySort($aFile, 0, 1, 0, $iUser)
        ; _ArrayDisplay($aFile, $aFile[0][0] & " FileLocks found.")
        If $aFile[0][0] = 0 Then
            $ToolTitle = "Done, no open file handles were found"
            $ToolTxt &= @CRLF & ", no handles to be closed for this file!"
            Sleep(2000)
            $ToolTxt = ""
            ReplaceFile()
        Else
            $ToolTitle =  $aFile[0][0] & " open file handles were found..."
            $CloseErr = 0
            For $x = 1 To $aFile[0][0]
                If _Net_Share_FileClose($Server, $aFile[$x][$iID]) Then
                    $ToolTxt &= @CRLF & @TAB & "Handle closed: " & $aFile[$x][$iID]
                Else
                    $ToolTxt &= @CRLF & "ERROR: Handle Close Failed! --> " & $aFile[$x][$iFPFN] & ", User = " & $aFile[$x][$iUser]
                    $CloseErr += 1
                EndIf
            Next
            ConsoleWrite('@@ Debug(' & @ScriptLineNumber & ') : $CloseErr = ' & $CloseErr & @CRLF & '>Error code: ' & @error & @CRLF) ;### Debug Console
            If $CloseErr = 0 Then
                $ToolTitle = "All found open file handles could be closed."
                ReplaceFile()
            Else
                $ToolTitle = $CloseErr & " Handles could *NOT* be closed!"
                Sleep(2000)
            EndIf
            Sleep(1000)
            $ToolTxt = ""
            $ToolTitle = ""
        EndIf
    Else
        MsgBox(0, "not an array", $aFile & @CRLF & @error & @CRLF & @extended & @CRLF & _
                "Unable to retrieve the array of open file handles for " & $Share)
    EndIf
EndFunc   ;==>AbArbeiten


Func UpdateToolTip()
    ToolTip($ToolTxt, MouseGetPos(0) + 20, MouseGetPos(1) + 20, $ToolTitle)
    ; ConsoleWrite( $ToolTxt & @CRLF & $ToolTitle & @CRLF & "-------------------" & @CRLF)
EndFunc   ;==>UpdateToolTip


Func ReplaceFile()
    If FileExists($NewFile) Then
        If FileCopy($NewFile, $input, 1 + 8) Then
            $ToolTitle = "File successfully replaced."
            $ToolTxt = "Done"
        Else
            $ToolTitle = "File could *NOT* be replaced."
            $ToolTxt = "Possibly another open file handle spawned while this script was running." & @CRLF & _
                    "Simply start over again, please."
            MsgBox(48, $ToolTitle, $ToolTxt)
        EndIf
    EndIf
EndFunc   ;==>ReplaceFile

 

Edited by rudi

Earth is flat, pigs can fly, and Nuclear Power is SAFE!

Share this post


Link to post
Share on other sites

Thanks Rudi, I was looking at file enumerating in the _winapi section yesterday, but ran out of time - this looks like just the thing I'm after. Also thanks to Adam who put me on to _WinAPI_EnumProcessHandles (not what I wanted, but made me look in the right part of the help file!).


Problem solving step 1: Write a simple, self-contained, running, replicator of your problem.

Share this post


Link to post
Share on other sites

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
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...