|
-
Mar 12th, 2009, 09:22 PM
#1
Thread Starter
Addicted Member
Find and close all open handles to a drive
Have you ever tried to run chkdsk on a drive or format it or eject a usb drive when other programs are still accessing it or running from it? The operation will fail... This code shows how to enumerate all open handles pointing to the drive letter you specify (in the Form_Load event) and lets you close them. If a program is running from the drive then closing the handle isn't enough so the process itself has to be terminated.
WARNING! Do NOT specify the drive letter of your SYSTEM (C drive or you'll find yourself pressing the "reset" button on the front of your computer. Yes, curiosity got the best of me and I just had to try it
How to test this code:
Open a few Explorer windows and command promt windows displaying the contents of your USB drive and maybe even run an exe or two from the drive then change "H:" in the Form_Load event to match your USB drive letter and run this program and it should find all open handles and display them in the listbox. Click the command button to have all handles closed for you and if the handle points to a process running from the USB drive then the process itself will be closed.
Create a new project:
Add a Listbox (List1)
Add a Command button (Command1)
Add a Timer (Timer1 set to 2000)
Here's the code:
Code:
Option Explicit
'/////////////////////////////////////////////////////////////////////////
' This code were explicitly developed for PSC(Planet Source Code) Users,
' as Open Source Project. This code are property of their author.
'
' You may use any of this code in you're own application(s).
'
' (c) Luprix 2004
' [email protected]
'/////////////////////////////////////////////////////////////////////////
'///////////////////////////// Constants and Types ////////////////////////
Private Const DUPLICATE_CLOSE_SOURCE = &H1
Private Const PROCESS_ALL_ACCESS As Long = &H1F0FFF
Private Const MAX_PATH As Long = 260
Private Const SE_DEBUG_NAME As String = "SeDebugPrivilege"
Private Const TOKEN_ADJUST_PRIVILEGES As Long = &H20
Private Const TOKEN_QUERY As Long = &H8
Private Const SE_PRIVILEGE_ENABLED As Long = &H2
Private Const PROCESS_VM_READ = &H10
Private Const PROCESS_DUP_HANDLE = &H40
Private Const PROCESS_QUERY_INFORMATION = &H400
Private Const STANDARD_RIGHTS_ALL = &H1F0000
Private Const GENERIC_ALL = &H10000000
Private Const INVALID_HANDLE_VALUE = -1
Private Const SystemHandleInformation = 16&
Private Const ObjectNameInformation = 1&
Private Const STATUS_INFO_LENGTH_MISMATCH = &HC0000004
Private Type LUID
LowPart As Long
HighPart As Long
End Type
Private Type LUID_AND_ATTRIBUTES
pLuid As LUID
Attributes As Long
End Type
Private Type TOKEN_PRIVILEGES
PrivilegeCount As Long
TheLuid As LUID
Attributes As Long
End Type
Private Type SECURITY_ATTRIBUTES
nLength As Long
lpSecurityDescriptor As Long
bInheritHandle As Long
End Type
Private Type SYSTEM_HANDLE_TABLE_ENTRY_INFO
UniqueProcessId As Integer
CreatorBackTraceIndex As Integer
ObjectTypeIndex As Byte
HandleAttributes As Byte
HandleValue As Integer
Object As Long
GrantedAccess As Long
End Type
Private Type SYSTEM_HANDLE_INFORMATION
NumberOfHandles As Long
Handles() As SYSTEM_HANDLE_TABLE_ENTRY_INFO
End Type
Private Type OBJECT_NAME_PRIVATE
Length As Integer
MaximumLength As Integer
Buffer As Long
ObjName(1023) As Byte
End Type
'///////////////////////////// Declarations ///////////////////////////////
'Undocumented Native API
Private Declare Function NtDuplicateObject Lib "NTDLL.DLL" (ByVal _
hSourceProcess As Long, _
ByVal hSourceHandle As Long, _
ByVal hCopyProcess As Long, _
CopyHandle As Long, _
ByVal DesiredAccess As Long, _
ByVal Attributes As Long, _
ByVal Options As Long) As Long
Private Declare Function NtClose Lib "NTDLL.DLL" (ByVal ObjectHandle As Long) As Long
Private Declare Function NtQuerySystemInformation Lib "NTDLL.DLL" ( _
ByVal dwInfoType As Long, _
ByVal lpStructure As Long, _
ByVal dwSize As Long, _
dwReserved As Long) As Long
Private Declare Function NtQueryObject Lib "NTDLL.DLL" ( _
ByVal ObjectHandle As Long, _
ByVal ObjectInformationClass As Long, _
ObjectInformation As OBJECT_NAME_PRIVATE, _
ByVal Length As Long, _
ResultLength As Long) As Long
'Win32 API
Private Declare Function LookupPrivilegeValue Lib "advapi32.dll" _
Alias "LookupPrivilegeValueA" ( _
ByVal lpSystemName As String, _
ByVal lpName As String, _
lpLuid As LUID) As Long
Private Declare Function AdjustTokenPrivileges Lib "advapi32.dll" ( _
ByVal TokenHandle As Long, _
ByVal DisableAllPrivileges As Long, _
ByRef NewState As TOKEN_PRIVILEGES, _
ByVal BufferLength As Long, _
ByRef PreviousState As TOKEN_PRIVILEGES, _
ByRef ReturnLength As Long) As Long
Private Declare Function OpenProcessToken Lib "advapi32.dll" ( _
ByVal ProcessHandle As Long, _
ByVal DesiredAccess As Long, _
ByRef TokenHandle As Long) As Long
Private Declare Function CloseHandle Lib "kernel32.dll" ( _
ByVal hObject As Long) As Long
Private Declare Function GetCurrentProcess Lib "kernel32.dll" () As Long
Private Declare Function GetLastError Lib "kernel32.dll" () As Long
Private Declare Function OpenProcess Lib "kernel32.dll" ( _
ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwProcessId As Long) As Long
Private Declare Function DuplicateHandle Lib "kernel32" ( _
ByVal hSourceProcessHandle As Long, _
ByVal hSourceHandle As Long, _
ByVal hTargetProcessHandle As Long, _
lpTargetHandle As Long, _
ByVal dwDesiredAccess As Long, _
ByVal bInheritHandle As Long, _
ByVal dwOptions As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" _
Alias "RtlMoveMemory" ( _
Destination As Any, _
Source As Any, _
ByVal Length As Long)
Private Declare Function EnumProcessModules Lib "psapi.dll" ( _
ByVal hProcess As Long, _
ByRef lphModule As Long, _
ByVal cb As Long, _
ByRef cbNeeded As Long) As Long
Private Declare Function GetModuleFileNameExA Lib "psapi.dll" ( _
ByVal hProcess As Long, _
ByVal hModule As Long, _
ByVal ModuleName As String, _
ByVal nSize As Long) As Long
Private Declare Function TerminateProcess Lib "kernel32" (ByVal hProcess As Long, ByVal uExitCode As Long) As Long
Private Declare Function GetWindowThreadProcessId Lib "user32" (ByVal hwnd As Long, lpdwProcessId As Long) As Long
Private Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ByVal lpClassName As String, ByVal lpWindowName As String) As Long
Private Declare Function QueryDosDevice Lib "kernel32" Alias _
"QueryDosDeviceA" ( _
ByVal lpDeviceName As String, _
ByVal lpTargetPath As String, _
ByVal ucchMax As Long) As Long
'Global Vars
Dim Privilege As Boolean
Dim ResultPorts(1, 65535) As Long
Dim DriveLetter As String
-
Mar 12th, 2009, 09:25 PM
#2
Thread Starter
Addicted Member
Re: Find and close all open handles to a drive
It didn't all fit in one post...
Code:
Function OpenPort() As Boolean
Dim i As Long, Status As Long
Dim Ret As Long, NumHandles As Long
Dim HandleInfo As SYSTEM_HANDLE_INFORMATION
Dim RequiredLength As Long
Dim Buffer() As Byte
Do
ReDim Buffer(0 To 19)
RequiredLength = 20 'len SYSTEM_HANDLE_INFORMATION
'first, find the RequiredLength for the SYSTEM_HANDLE_INFORMATION array
Status = NtQuerySystemInformation(SystemHandleInformation, _
ByVal VarPtr(Buffer(0)), ByVal RequiredLength, 0&)
If Status = 0 Then
Exit Do
End If
'obtain, RequiredLength
CopyMemory ByVal VarPtr(NumHandles), ByVal VarPtr(Buffer(0)), 4
RequiredLength = NumHandles * 16 + 4
ReDim Buffer(0 To RequiredLength)
'Native API NTDLL. Find system information
Status = NtQuerySystemInformation(SystemHandleInformation, _
ByVal VarPtr(Buffer(0)), ByVal RequiredLength, 0&)
ReDim HandleInfo.Handles(NumHandles)
CopyMemory ByVal VarPtr(HandleInfo.Handles(0)), _
ByVal VarPtr(Buffer(4)), RequiredLength - 4
Loop While Status = STATUS_INFO_LENGTH_MISMATCH
If Status = STATUS_INFO_LENGTH_MISMATCH Then
MsgBox "STATUS_INFO_LENGTH_MISMATCH"
End If
Dim MyPID As Long
Dim MyName As String
MyName = "Unknown"
List1.Clear
For i = 0 To NumHandles - 1
MyPID = CLng(HandleInfo.Handles(i).UniqueProcessId)
If Hex(HandleInfo.Handles(i).GrantedAccess) <> "12019F" And Hex(HandleInfo.Handles(i).GrantedAccess) <> "100000" And Hex(HandleInfo.Handles(i).GrantedAccess) <> "120089" Then
MyName = GetObjectName(HandleInfo.Handles(i).UniqueProcessId, HandleInfo.Handles(i).HandleValue)
Else
MyName = "Skipped..."
End If
If InStr(1, MyName, DriveLetterToVolumeName(DriveLetter), vbTextCompare) Then
List1.AddItem ProcessPathByPID(MyPID) & " PID = " & HandleInfo.Handles(i).UniqueProcessId & " Handle = 0x" & Hex(HandleInfo.Handles(i).HandleValue)
End If
Next i
OpenPort = True
End Function
Function LoadPrivilege(ByVal Privilege As String) As Boolean
'The access
Dim hToken As Long
Dim SEDebugNameValue As LUID
Dim tkp As TOKEN_PRIVILEGES
Dim hProcessHandle As Long
Dim tkpNewButIgnored As TOKEN_PRIVILEGES
Dim lbuffer As Long
hProcessHandle = GetCurrentProcess()
If GetLastError <> 0 Then
MsgBox "GetCurrentProcess, Error: " & GetLastError()
Exit Function
End If
OpenProcessToken hProcessHandle, (TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY), hToken
If GetLastError <> 0 Then
MsgBox "OpenProcessToken, Error: " & GetLastError()
Exit Function
End If
LookupPrivilegeValue "", Privilege, SEDebugNameValue
If GetLastError <> 0 Then
MsgBox "LookupPrivilegeValue, Error: " & GetLastError()
Exit Function
End If
With tkp
.PrivilegeCount = 1
.TheLuid = SEDebugNameValue
.Attributes = SE_PRIVILEGE_ENABLED
End With
AdjustTokenPrivileges hToken, False, tkp, Len(tkp), tkpNewButIgnored, lbuffer
If GetLastError <> 0 Then
MsgBox "AdjustTokenPrivileges, Error: " & GetLastError()
Exit Function
End If
LoadPrivilege = True
End Function
Function ProcessPathByPID(PID As Long) As String
'Return path to the executable from PID
'http://support.microsoft.com/default.aspx?scid=kb;en-us;187913
Dim cbNeeded As Long
Dim Modules(1 To 200) As Long
Dim Ret As Long
Dim ModuleName As String
Dim nSize As Long
Dim hProcess As Long
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION _
Or PROCESS_VM_READ, 0, PID)
If hProcess <> 0 Then
Ret = EnumProcessModules(hProcess, Modules(1), _
200, cbNeeded)
If Ret <> 0 Then
ModuleName = Space(MAX_PATH)
nSize = 500
Ret = GetModuleFileNameExA(hProcess, _
Modules(1), ModuleName, nSize)
ProcessPathByPID = Left(ModuleName, Ret)
End If
End If
Ret = CloseHandle(hProcess)
If ProcessPathByPID = "" Then
ProcessPathByPID = "SYSTEM"
End If
End Function
Function GetObjectName(ProcessId As Integer, hCurrent As Integer) As String
Dim hPort As Long, Port As Long
Dim RequiredLength As Long
Dim ResultLength As Long
Dim Status As Long
Dim hProc As Long
Dim Ret As Long
Dim pObjName As OBJECT_NAME_PRIVATE
If ProcessId = 0 Then
Exit Function
End If
hProc = OpenProcess(PROCESS_DUP_HANDLE, 0&, ProcessId)
If hProc = INVALID_HANDLE_VALUE Then
Exit Function
End If
Ret = DuplicateHandle(hProc, hCurrent, -1, hPort, STANDARD_RIGHTS_ALL Or GENERIC_ALL, 0&, &H2)
RequiredLength = LenB(pObjName)
Status = NtQueryObject(hPort, ObjectNameInformation, pObjName, RequiredLength, ResultLength)
Ret = CloseHandle(hPort)
Ret = CloseHandle(hProc)
GetObjectName = Trim(pObjName.ObjName)
End Function
Private Sub CloseHandleEx(ByVal lPID As Long, ByVal lHandle As Long)
Dim hProcess As Long
hProcess = OpenProcess(PROCESS_ALL_ACCESS, 0, lPID)
Call NtDuplicateObject(hProcess, lHandle, 0, ByVal 0, 0, 0, DUPLICATE_CLOSE_SOURCE)
Call NtClose(hProcess)
End Sub
-
Mar 12th, 2009, 09:26 PM
#3
Thread Starter
Addicted Member
Re: Find and close all open handles to a drive
It didn't all fit in two posts!
Code:
Private Sub Command1_Click()
Dim i As Long, Status As Long
Dim Ret As Long, NumHandles As Long
Dim HandleInfo As SYSTEM_HANDLE_INFORMATION
Dim RequiredLength As Long
Dim Buffer() As Byte
Screen.MousePointer = vbHourglass
Do
ReDim Buffer(0 To 19)
RequiredLength = 20 'len SYSTEM_HANDLE_INFORMATION
'first, find the RequiredLength for the SYSTEM_HANDLE_INFORMATION array
Status = NtQuerySystemInformation(SystemHandleInformation, _
ByVal VarPtr(Buffer(0)), ByVal RequiredLength, 0&)
If Status = 0 Then
Exit Do
End If
'obtain, RequiredLength
CopyMemory ByVal VarPtr(NumHandles), ByVal VarPtr(Buffer(0)), 4
RequiredLength = NumHandles * 16 + 4
ReDim Buffer(0 To RequiredLength)
'Native API NTDLL. Find system information
Status = NtQuerySystemInformation(SystemHandleInformation, _
ByVal VarPtr(Buffer(0)), ByVal RequiredLength, 0&)
ReDim HandleInfo.Handles(NumHandles)
CopyMemory ByVal VarPtr(HandleInfo.Handles(0)), _
ByVal VarPtr(Buffer(4)), RequiredLength - 4
Loop While Status = STATUS_INFO_LENGTH_MISMATCH
Dim MyPID As Long
Dim MyName As String
MyName = "Unknown"
For i = 0 To NumHandles - 1
MyPID = CLng(HandleInfo.Handles(i).UniqueProcessId)
If Hex(HandleInfo.Handles(i).GrantedAccess) <> "12019F" And Hex(HandleInfo.Handles(i).GrantedAccess) <> "100000" And Hex(HandleInfo.Handles(i).GrantedAccess) <> "120089" Then
MyName = GetObjectName(HandleInfo.Handles(i).UniqueProcessId, HandleInfo.Handles(i).HandleValue)
Else
MyName = "Skipped..."
End If
If InStr(1, MyName, DriveLetterToVolumeName(DriveLetter), vbTextCompare) Then
CloseHandleEx HandleInfo.Handles(i).UniqueProcessId, HandleInfo.Handles(i).HandleValue
If StrComp(Left(ProcessPathByPID(CLng(HandleInfo.Handles(i).UniqueProcessId)), 2), DriveLetter, vbTextCompare) = 0 Then
ProcessTerminate CLng(HandleInfo.Handles(i).UniqueProcessId)
End If
End If
Next i
End Sub
Private Sub Form_Activate()
'If List1.ListCount <= 0 Then Unload Me
End Sub
Private Sub Form_Load()
Dim PathBuf As String
Dim txtBuffer As String
Dim i As Long
DriveLetter = "H:"
Me.Caption = "*** ATTENTION ***"
Me.Left = Screen.Width / 2 - Me.Width / 2
Me.Top = Screen.Height / 2 - Me.Width / 2
If Not Privilege Then
'Require Admin privileges
If Not (LoadPrivilege(SE_DEBUG_NAME)) Then
End
End If
End If
Privilege = True
OpenPort
End Sub
Private Sub Timer1_Timer()
OpenPort
If List1.ListCount = 0 Then
'Unload Me
End If
Screen.MousePointer = vbNormal
End Sub
Private Function DriveLetterToVolumeName(DriveLetter As String) As String
Dim sBuff As String, iLen As Integer
Const MAX_PATH As Integer = 260
sBuff = String$(MAX_PATH, Chr$(0))
iLen = QueryDosDevice(DriveLetter, sBuff, MAX_PATH)
' Return just the first NULL-terminated string in the return value
sBuff = Left$(sBuff, InStr(sBuff, Chr$(0)) - 1)
DriveLetterToVolumeName = sBuff & "\"
End Function
Function ProcessTerminate(Optional lProcessID As Long, Optional lHwndWindow As Long) As Boolean
Dim lhwndProcess As Long
Dim lExitCode As Long
Dim lRetVal As Long
Dim lhThisProc As Long
Dim lhTokenHandle As Long
Dim tLuid As LUID
Dim tTokenPriv As TOKEN_PRIVILEGES, tTokenPrivNew As TOKEN_PRIVILEGES
Dim lBufferNeeded As Long
Const PROCESS_ALL_ACCESS = &H1F0FFF, PROCESS_TERMINATE = &H1
Const ANYSIZE_ARRAY = 1, TOKEN_ADJUST_PRIVILEGES = &H20
Const TOKEN_QUERY = &H8, SE_DEBUG_NAME As String = "SeDebugPrivilege"
Const SE_PRIVILEGE_ENABLED = &H2
On Error Resume Next
If lHwndWindow Then
'Get the process ID from the window handle
lRetVal = GetWindowThreadProcessId(lHwndWindow, lProcessID)
End If
If lProcessID Then
'Give Kill permissions to this process
lhThisProc = GetCurrentProcess
OpenProcessToken lhThisProc, TOKEN_ADJUST_PRIVILEGES Or TOKEN_QUERY, lhTokenHandle
LookupPrivilegeValue "", SE_DEBUG_NAME, tLuid
'Set the number of privileges to be change
tTokenPriv.PrivilegeCount = 1
tTokenPriv.TheLuid = tLuid
tTokenPriv.Attributes = SE_PRIVILEGE_ENABLED
'Enable the kill privilege in the access token of this process
AdjustTokenPrivileges lhTokenHandle, False, tTokenPriv, Len(tTokenPrivNew), tTokenPrivNew, lBufferNeeded
'Open the process to kill
lhwndProcess = OpenProcess(PROCESS_TERMINATE, 0, lProcessID)
If lhwndProcess Then
'Obtained process handle, kill the process
ProcessTerminate = CBool(TerminateProcess(lhwndProcess, lExitCode))
Call CloseHandle(lhwndProcess)
End If
End If
On Error GoTo 0
End Function
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|