I'd like to programmatically find out which process is responsible for locking a certain file/folder.
Much like the Resource monitor does under CPU/Associated Handles.
Has anyone done this before? Any idea what would be the quickest way to find it?
Do you just "scan" every process for all their handles, resolve them and check if they contain the filename or how would this be done?
And if so, how would I get all the handles of a process?
Find the process that is locking a file/folder
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
I found an interesting piece of code on the Internet that might do what I want. It's written in C++ though and I don't understand the crucial parts.
Here's what I got figured out for now. Using my functions RunAsAdmin(), OpenProcess(), SetPrivilege() and EnumProcesses() I managed to get the handles of every process... well sort of... I get a handle on most of them, but I always get a LastError=5 or 6 which is "ERROR_ACCESS_DENIED" and "ERROR_INVALID_HANDLE".
No idea what I'm doing wrong here tbh. But even if I got this figured out, I'm completely lost where it starts with "if (NT::ZwDuplicateObject [...]" in the C++ code.
Code: Select all
//SOURCE: http://forums.codeguru.com/showthread.php?176997.html
#include "ntdll.h"
#include <stdlib.h>
#include <stdio.h>
#include "ntddk.h"
#define DUPLICATE_SAME_ATTRIBUTES 0x00000004
#pragma comment(lib,"ntdll.lib")
BOOL EnablePrivilege(PCSTR name)
{
TOKEN_PRIVILEGES priv = {1, {0, 0, SE_PRIVILEGE_ENABLED}};
LookupPrivilegeValue(0, name, &priv.Privileges[0].Luid);
HANDLE hToken;
OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken);
AdjustTokenPrivileges(hToken, FALSE, &priv, sizeof priv, 0, 0);
BOOL rv = GetLastError() == ERROR_SUCCESS;
CloseHandle(hToken);
return rv;
}
int main(int argc, char *argv[])
{
if (argc == 1) return 0;
ULONG pid = strtoul(argv[1], 0, 0);
EnablePrivilege(SE_DEBUG_NAME);
HANDLE hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, pid);
ULONG n = 0x1000;
PULONG p = new ULONG[n];
while (NT::ZwQuerySystemInformation(NT::SystemHandleInformation, p, n * sizeof *p, 0)
== STATUS_INFO_LENGTH_MISMATCH)
delete [] p, p = new ULONG[n *= 2];
NT::PSYSTEM_HANDLE_INFORMATION h = NT::PSYSTEM_HANDLE_INFORMATION(p + 1);
for (ULONG i = 0; i < *p; i++) {
if (h[i].ProcessId == pid) {
HANDLE hObject;
if (NT::ZwDuplicateObject(hProcess, HANDLE(h[i].Handle), NtCurrentProcess(), &hObject,
0, 0, DUPLICATE_SAME_ATTRIBUTES)
!= STATUS_SUCCESS) continue;
NT::OBJECT_BASIC_INFORMATION obi;
NT::ZwQueryObject(hObject, NT::ObjectBasicInformation, &obi, sizeof obi, &n);
printf("%p %04hx %6lx %2x %3lx %3ld %4ld ",
h[i].Object, h[i].Handle, h[i].GrantedAccess,
int(h[i].Flags), obi.Attributes,
obi.HandleCount - 1, obi.PointerCount - 2);
n = obi.TypeInformationLength + 2;
NT::POBJECT_TYPE_INFORMATION oti = NT::POBJECT_TYPE_INFORMATION(new CHAR[n]);
NT::ZwQueryObject(hObject, NT::ObjectTypeInformation, oti, n, &n);
printf("%-14.*ws ", oti[0].Name.Length / 2, oti[0].Name.Buffer);
n = obi.NameInformationLength == 0
? MAX_PATH * sizeof (WCHAR) : obi.NameInformationLength;
NT::POBJECT_NAME_INFORMATION oni = NT::POBJECT_NAME_INFORMATION(new CHAR[n]);
NTSTATUS rv = NT::ZwQueryObject(hObject, NT::ObjectNameInformation, oni, n, &n);
if (NT_SUCCESS(rv))
printf("%.*ws", oni[0].Name.Length / 2, oni[0].Name.Buffer);
printf("\n");
CloseHandle(hObject);
}
}
delete [] p;
CloseHandle(hProcess);
return 0;
}
No idea what I'm doing wrong here tbh. But even if I got this figured out, I'm completely lost where it starts with "if (NT::ZwDuplicateObject [...]" in the C++ code.
Code: Select all
RunAsAdmin() ; Run elevated
thisHProcess := OpenProcess() ; Get handle to this ahk process
SetPrivilege(thisHProcess, "SeDebugPrivilege", True) ; Set SeDebugPrivilege on this process
pidList := EnumProcesses() ; Get all process IDs
Loop % pidList.MaxIndex() { ; Loop through all the PIDs
pid := pidList[A_Index] ; Store current process ID in pid
hProcess := OpenProcess(pidList[A_Index]) ; Store current process handle in hProcess
If A_LastError ; If an error occured print it out:
MsgBox % "PID: " pid "`nHandle: " hProcess "`nLastError: " A_LastError
CloseHandle(hProcess) ; Close the handle again
}
WinGetPid(winTitle := "A") {
WinGet, pid, PID, %winTitle%
Return pid
}
OpenProcess(pid := 0, privileges := -1) {
Return DllCall("OpenProcess", "Uint", (privileges = -1) ? 0x1F0FFF|0x0400 : privileges, "Uint", False, "Uint", pid ? pid : DllCall("GetCurrentProcessId"))
}
CloseHandle(handle) {
Return DllCall("CloseHandle", "Ptr", handle)
}
SetPrivilege(hProcess, privilegeName := "SeDebugPrivilege", enable := True) {
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", hProcess, "UInt", 32, "PtrP", tokenHandle)
VarSetCapacity(newState, 16, 0)
NumPut(1, newState, 0, "UInt")
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", privilegeName, "Int64P", luid)
NumPut(luid, newState, 4, "Int64")
If enable
NumPut(2, newState, 12, "UInt")
returnValue := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", tokenHandle, "Int", False, "Ptr", &newState, "UInt", 0, "Ptr", 0, "Ptr", 0)
CloseHandle(tokenHandle)
CloseHandle(hProcess)
Return returnValue
}
EnumProcesses() {
pidList := []
VarSetCapacity(pProcessIds, 4096)
DllCall("Psapi.dll\EnumProcesses", "Ptr", &pProcessIds, "UInt", 4096, "UIntP", pBytesReturned)
Loop % pBytesReturned // 4
If pid := NumGet(pProcessIds, A_Index*4, "UInt") ;pProcessIds = DWORD array (DWORD = 4 bytes)
pidList.Insert(pid)
Return pidList
}
RunAsAdmin() {
If !A_IsAdmin {
Run *runAs "%A_ScriptFullPath%"
ExitApp
}
}
Re: Find the process that is locking a file/folder
That is not that simple, you owe me a beer
Requires AutoHotkey_H v1 or v2:
Requires AutoHotkey_H v1 or v2:
Code: Select all
; http://forums.codeguru.com/showthread.php?176997.html
RunAsAdmin()
Gui,+Resize
Gui,Add,ListView,w640 r30 aw ah, Process Name|Process ID|File Handle|GrantedAccess|Flags|Attributes|HandleCount|File Name
FILETIME :="DWORD dwLowDateTime;DWORD dwHighDateTime"
OBJECT_BASIC_INFORMATION:="
(
// Information Class 0
int Attributes;
int GrantedAccess;
int HandleCount;
int PointerCount;
int PagedPoolUsage;
int NonPagedPoolUsage;
int Reserved1;
int Reserved2;
int Reserved3;
int NameInformationLength;
int TypeInformationLength;
int SecurityDescriptorLength;
FILETIME CreateTime;
)"
GENERIC_MAPPING :="
(
DWORD GenericRead;
DWORD GenericWrite;
DWORD GenericExecute;
DWORD GenericAll;
)"
OBJECT_TYPE_INFORMATION:="
(
// Information Class 2
UNICODE_STRING Name;
int ObjectCount;
int HandleCount;
int Reserved1;
int Reserved2;
int Reserved3;
int Reserved4;
int PeakObjectCount;
int PeakHandleCount;
int Reserved5;
int Reserved6;
int Reserved7;
int Reserved8;
int InvalidAttributes;
GENERIC_MAPPING GenericMapping;
int ValidAccess;
byte Unknown;
byte MaintainHandleDatabase;
int PoolType;
int PagedPoolUsage;
int NonPagedPoolUsage;
)"
UNICODE_STRING := "WORD Length;WORD MaximumLength;WORD *Buffer"
OBJECT_NAME_INFORMATION:="UNICODE_STRING Name"
SYSTEM_HANDLE_INFORMATION :="
(
// Information Class 16
int ProcessID;
byte ObjectTypeNumber;
byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
ushort Handle;
int Object_Pointer;
int GrantedAccess;
)"
EnablePrivilege()
obi := Struct(OBJECT_BASIC_INFORMATION), oti := Struct("OBJECT_TYPE_INFORMATION[100]"), oni := Struct("OBJECT_NAME_INFORMATION[65]")
ObjectBasicInformation:=0, ObjectNameInformation:=1,ObjectTypeInformation:=2
VarSetCapacity(p,A_PtrSize*n:=0x1000)
SystemHandleInformation:=16
While 0xc0000004 = DllCall("ntdll\ZwQuerySystemInformation","UInt", SystemHandleInformation, "PTR", &p, "UInt", n*A_PtrSize, "UInt*", sz,"CDecl UInt") ;STATUS_INFO_LENGTH_MISMATCH:=0xc0000004
VarSetCapacity(p, A_PtrSize * (n := n * 2))
h:=Struct("SYSTEM_HANDLE_INFORMATION", (&p) + A_PtrSize)
hCurrentProc:=GetCurrentProcess()
VarSetCapacity(procName,520)
i:=0
Loop % NumGet(&p,"UInt"){
if !hProc:=OpenProcess(0x40|0x400, false, h[A_Index].ProcessID) ;PROCESS_DUP_HANDLE:=0x40, PROCESS_QUERY_INFORMATION:=0x400
continue
if (ZwDuplicateObject(hProc, h[A_Index].Handle, hCurrentProc, getvar(hObject:=0), 0, 0, 0x4)){ ;DUPLICATE_SAME_ATTRIBUTES := 0x4
CloseHandle(hProc)
continue
}
ZwQueryObject(hObject, ObjectBasicInformation, obi[], sizeof(obi))
ZwQueryObject(hObject, ObjectTypeInformation, oti[], obi.TypeInformationLength + 2)
if ("File" !=StrGet(oti.Name.Buffer["",""],oti.Name.Length // 2,"UTF-16") || GetFileType(hObject)!=1)
{
CloseHandle(hObject),CloseHandle(hProc)
continue
}
DllCall("QueryFullProcessImageName","Ptr", hProc, "Uint", 0, "Str", procName, "UInt*", sz:=520)
data:= [procName,h[A_Index].ProcessID, h[A_Index].Handle, h[A_Index].GrantedAccess, h[A_Index].flags, obi.Attributes, (obi.HandleCount - 1)]
i++
if ZwQueryObject(hObject, ObjectNameInformation, oni[], obi.NameInformationLength = 0 ? 520 : obi.NameInformationLength)<0x7FFFFFFF ; MAX_PATH*2:=520
data.Push(StrGet(oni.Name.Buffer["",""],oni.Name.Length // 2,"UTF-16"))
CloseHandle(hObject),CloseHandle(hProc)
LV_Add("",data*)
}
Gui,Show, , % "Showing " i " File Handles"
return
GuiClose:
ExitApp
#DllImport, ZwDuplicateObject,ntdll\ZwDuplicateObject,PTR,,PTR,,PTR,,PTR,,UInt,,UInt,,UInt,,UInt
#DllImport, ZwQuerySystemInformation, ntdll\ZwQuerySystemInformation,UInt,,PTR,,UInt,,UInt,,UInt
#DllImport, ZwQueryObject, ntdll\ZwQueryObject,PTR,,UInt,,PTR,,UInt,,UInt,,UInt
#DllImport, ZwQueryInformationFile, ntdll\ZwQueryInformationFile,PTR,,PTR,,PTR,,UInt,,UInt,
RunAsAdmin() {
If !A_IsAdmin {
Run *runAs %A_AhkPath% "%A_ScriptFullPath%"
ExitApp
}
}
EnablePrivilege(name:="SeDebugPrivilege"){
static LUID:="DWORD LowPart;LONG HighPart",LUID_AND_ATTRIBUTES:="EnablePrivilege(LUID) Luid;DWORD Attributes;",TOKEN_PRIVILEGES:="DWORD PrivilegeCount;EnablePrivilege(LUID_AND_ATTRIBUTES) Privileges[1]"
,priv:=Struct(TOKEN_PRIVILEGES,{PrivilegeCount:1}),init:=priv.Privileges.Attributes:=2 ;SE_PRIVILEGE_ENABLED
LookupPrivilegeValue(0, name, priv.Privileges.Luid[""])
OpenProcessToken(GetCurrentProcess(), 32, getvar(hToken:=0)) ; TOKEN_ADJUST_PRIVILEGES:=32
AdjustTokenPrivileges(hToken, FALSE, priv[], sizeof(priv), 0, 0)
rv := !A_LastError
CloseHandle(hToken)
return rv
}
Re: Find the process that is locking a file/folder
HotKeyIt wrote:That is not that simple, you owe me a beer
Requires AutoHotkey_H v1 or v2:Code: Select all
; http://forums.codeguru.com/showthread.php?176997.html RunAsAdmin() Gui,+Resize Gui,Add,ListView,w640 r30 aw ah, Process Name|Process ID|File Handle|GrantedAccess|Flags|Attributes|HandleCount|File Name FILETIME :="DWORD dwLowDateTime;DWORD dwHighDateTime" OBJECT_BASIC_INFORMATION:=" ( // Information Class 0 int Attributes; int GrantedAccess; int HandleCount; int PointerCount; int PagedPoolUsage; int NonPagedPoolUsage; int Reserved1; int Reserved2; int Reserved3; int NameInformationLength; int TypeInformationLength; int SecurityDescriptorLength; FILETIME CreateTime; )" GENERIC_MAPPING :=" ( DWORD GenericRead; DWORD GenericWrite; DWORD GenericExecute; DWORD GenericAll; )" OBJECT_TYPE_INFORMATION:=" ( // Information Class 2 UNICODE_STRING Name; int ObjectCount; int HandleCount; int Reserved1; int Reserved2; int Reserved3; int Reserved4; int PeakObjectCount; int PeakHandleCount; int Reserved5; int Reserved6; int Reserved7; int Reserved8; int InvalidAttributes; GENERIC_MAPPING GenericMapping; int ValidAccess; byte Unknown; byte MaintainHandleDatabase; int PoolType; int PagedPoolUsage; int NonPagedPoolUsage; )" UNICODE_STRING := "WORD Length;WORD MaximumLength;WORD *Buffer" OBJECT_NAME_INFORMATION:="UNICODE_STRING Name" SYSTEM_HANDLE_INFORMATION :=" ( // Information Class 16 int ProcessID; byte ObjectTypeNumber; byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT ushort Handle; int Object_Pointer; int GrantedAccess; )" EnablePrivilege() obi := Struct(OBJECT_BASIC_INFORMATION), oti := Struct("OBJECT_TYPE_INFORMATION[100]"), oni := Struct("OBJECT_NAME_INFORMATION[65]") ObjectBasicInformation:=0, ObjectNameInformation:=1,ObjectTypeInformation:=2 VarSetCapacity(p,A_PtrSize*n:=0x1000) SystemHandleInformation:=16 While 0xc0000004 = DllCall("ntdll\ZwQuerySystemInformation","UInt", SystemHandleInformation, "PTR", &p, "UInt", n*A_PtrSize, "UInt*", sz,"CDecl UInt") ;STATUS_INFO_LENGTH_MISMATCH:=0xc0000004 VarSetCapacity(p, A_PtrSize * (n := n * 2)) h:=Struct("SYSTEM_HANDLE_INFORMATION", (&p) + A_PtrSize) hCurrentProc:=GetCurrentProcess() VarSetCapacity(procName,520) i:=0 Loop % NumGet(&p,"UInt"){ if !hProc:=OpenProcess(0x40|0x400, false, h[A_Index].ProcessID) ;PROCESS_DUP_HANDLE:=0x40, PROCESS_QUERY_INFORMATION:=0x400 continue if (ZwDuplicateObject(hProc, h[A_Index].Handle, hCurrentProc, getvar(hObject:=0), 0, 0, 0x4)){ ;DUPLICATE_SAME_ATTRIBUTES := 0x4 CloseHandle(hProc) continue } ZwQueryObject(hObject, ObjectBasicInformation, obi[], sizeof(obi)) ZwQueryObject(hObject, ObjectTypeInformation, oti[], obi.TypeInformationLength + 2) if ("File" !=StrGet(oti.Name.Buffer["",""],oti.Name.Length // 2,"UTF-16") || GetFileType(hObject)!=1) { CloseHandle(hObject),CloseHandle(hProc) continue } DllCall("QueryFullProcessImageName","Ptr", hProc, "Uint", 0, "Str", procName, "UInt*", sz:=520) data:= [procName,h[A_Index].ProcessID, h[A_Index].Handle, h[A_Index].GrantedAccess, h[A_Index].flags, obi.Attributes, (obi.HandleCount - 1)] i++ if ZwQueryObject(hObject, ObjectNameInformation, oni[], obi.NameInformationLength = 0 ? 520 : obi.NameInformationLength)<0x7FFFFFFF ; MAX_PATH*2:=520 data.Push(StrGet(oni.Name.Buffer["",""],oni.Name.Length // 2,"UTF-16")) CloseHandle(hObject),CloseHandle(hProc) LV_Add("",data*) } Gui,Show, , % "Showing " i " File Handles" return GuiClose: ExitApp #DllImport, ZwDuplicateObject,ntdll\ZwDuplicateObject,PTR,,PTR,,PTR,,PTR,,UInt,,UInt,,UInt,,UInt #DllImport, ZwQuerySystemInformation, ntdll\ZwQuerySystemInformation,UInt,,PTR,,UInt,,UInt,,UInt #DllImport, ZwQueryObject, ntdll\ZwQueryObject,PTR,,UInt,,PTR,,UInt,,UInt,,UInt #DllImport, ZwQueryInformationFile, ntdll\ZwQueryInformationFile,PTR,,PTR,,PTR,,UInt,,UInt, RunAsAdmin() { If !A_IsAdmin { Run *runAs %A_AhkPath% "%A_ScriptFullPath%" ExitApp } } EnablePrivilege(name:="SeDebugPrivilege"){ static LUID:="DWORD LowPart;LONG HighPart",LUID_AND_ATTRIBUTES:="EnablePrivilege(LUID) Luid;DWORD Attributes;",TOKEN_PRIVILEGES:="DWORD PrivilegeCount;EnablePrivilege(LUID_AND_ATTRIBUTES) Privileges[1]" ,priv:=Struct(TOKEN_PRIVILEGES,{PrivilegeCount:1}),init:=priv.Privileges.Attributes:=2 ;SE_PRIVILEGE_ENABLED LookupPrivilegeValue(0, name, priv.Privileges.Luid[""]) OpenProcessToken(GetCurrentProcess(), 32, getvar(hToken:=0)) ; TOKEN_ADJUST_PRIVILEGES:=32 AdjustTokenPrivileges(hToken, FALSE, priv[], sizeof(priv), 0, 0) rv := !A_LastError CloseHandle(hToken) return rv }
great job
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
Hey, thank you so much! Man AHK_H is so cool!! I'll have to translate it into AHK_L code for now though.
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
Is there a way to resolve `\Device\HarddiskVolumeX` to the drive letter?
Re: Find the process that is locking a file/folder
Can you show what you got so far?
Just found a way to convert C: DriveLetters to "\Device\HardDiskVolumeX"
Ref: Displaying Volume Paths
FindFirst / NextVolume gives you Volume names GUID \?\\...
QueryDosDevice gives you a Device name \Device\HarddiskVolume from a GUID or DriveLetter
GetVolumePathNamesForVolumeName gives you the Drive letter C: from a GUID
So what you can do is loop all drives with DriveGet and QueryDosDevice and store them in an array and later you can recheck them.
Just found a way to convert C: DriveLetters to "\Device\HardDiskVolumeX"
Code: Select all
MsgBox % QueryDosDevice("C:")
QueryDosDevice(DeviceName := "C:")
{
size := VarSetCapacity(TargetPath, 260 * (A_IsUnicode ? 2 : 1)) + 1
DllCall("QueryDosDevice", "str", DeviceName, "str", TargetPath, "uint", size)
return TargetPath
}
FindFirst / NextVolume gives you Volume names GUID \?\\...
QueryDosDevice gives you a Device name \Device\HarddiskVolume from a GUID or DriveLetter
GetVolumePathNamesForVolumeName gives you the Drive letter C: from a GUID
So what you can do is loop all drives with DriveGet and QueryDosDevice and store them in an array and later you can recheck them.
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
Well, I don't really have anything so far. I found that the Diskpart could be parsed for that.
But that wouldn't be very elegant.
I really like your way and I think it's good enough.
I just tried it on HotkeyIt's example and it works like a charm:
Code: Select all
DISKPART> list volume
Volume ### Ltr Label Fs Type Size Status Info
---------- --- ----------- ----- ---------- ------- --------- --------
Volume 0 H DVD-ROM 0 B No Media
Volume 1 NTFS Partition 350 MB Healthy System
Volume 2 C NTFS Partition 232 GB Healthy Boot
Volume 3 D Samsung USB NTFS Removable 59 GB Healthy
I really like your way and I think it's good enough.
Code: Select all
devicePathObj := GetDevicePaths()
For devicePath, filePath in devicePathObj
MsgBox, %devicePath% - %filePath%
MsgBox % devicePathObj["\Device\HarddiskVolume2"]
GetDevicePaths() {
DriveGet, driveLetters, List
driveLetters := StrSplit(driveLetters)
devicePaths := {}
Loop % driveLetters.MaxIndex()
devicePaths[QueryDosDevice(driveLetters[A_Index] ":")] := driveLetters[A_Index] ":"
Return devicePaths
}
QueryDosDevice(DeviceName := "C:") {
size := VarSetCapacity(TargetPath, 1023) + 1
DllCall("QueryDosDevice", "str", DeviceName, "str", TargetPath, "uint", size)
return TargetPath
}
Code: Select all
; http://forums.codeguru.com/showthread.php?176997.html
RunAsAdmin()
SetGlobals()
EnablePrivilege()
Gui, +Resize
Gui, Add, ListView, w640 r30 aw ah, Process Name|Process ID|File Handle|GrantedAccess|Flags|Attributes|HandleCount|Device Path|File Path|Drive
Gui, Show,, % "Showing " i " File Handles"
obi := Struct(OBJECT_BASIC_INFORMATION), oti := Struct("OBJECT_TYPE_INFORMATION[100]"), oni := Struct("OBJECT_NAME_INFORMATION[65]")
ObjectBasicInformation:=0, ObjectNameInformation:=1,ObjectTypeInformation:=2
VarSetCapacity(p,A_PtrSize*n:=0x1000)
SystemHandleInformation:=16
While 0xc0000004 = DllCall("ntdll\ZwQuerySystemInformation","UInt", SystemHandleInformation, "PTR", &p, "UInt", n*A_PtrSize, "UInt*", sz,"CDecl UInt") ;STATUS_INFO_LENGTH_MISMATCH:=0xc0000004
VarSetCapacity(p, A_PtrSize * (n := n * 2))
h:=Struct("SYSTEM_HANDLE_INFORMATION", (&p) + A_PtrSize)
hCurrentProc:=GetCurrentProcess()
VarSetCapacity(procName,520)
i:=0
devicePathsObj := GetDevicePaths()
Loop % NumGet(&p,"UInt") {
If !hProc:=OpenProcess(0x40|0x400, false, h[A_Index].ProcessID) ;PROCESS_DUP_HANDLE:=0x40, PROCESS_QUERY_INFORMATION:=0x400
Continue
If (ZwDuplicateObject(hProc, h[A_Index].Handle, hCurrentProc, getvar(hObject:=0), 0, 0, 0x4)){ ;DUPLICATE_SAME_ATTRIBUTES := 0x4
CloseHandle(hProc)
Continue
}
ZwQueryObject(hObject, ObjectBasicInformation, obi[], sizeof(obi))
ZwQueryObject(hObject, ObjectTypeInformation, oti[], obi.TypeInformationLength + 2)
If ("File" !=StrGet(oti.Name.Buffer["",""],oti.Name.Length // 2,"UTF-16") || GetFileType(hObject)!=1) {
CloseHandle(hObject),CloseHandle(hProc)
Continue
}
DllCall("QueryFullProcessImageName","Ptr", hProc, "Uint", 0, "Str", procName, "UInt*", sz:=520)
data:= [procName,h[A_Index].ProcessID, h[A_Index].Handle, h[A_Index].GrantedAccess, h[A_Index].flags, obi.Attributes, (obi.HandleCount - 1)]
i++
If ZwQueryObject(hObject, ObjectNameInformation, oni[], obi.NameInformationLength = 0 ? 520 : obi.NameInformationLength)<0x7FFFFFFF { ; MAX_PATH*2:=520
devicePath := StrGet(oni.Name.Buffer["",""],oni.Name.Length // 2,"UTF-16")
RegexMatch(devicePath, "S)(^\\.+?\\.+?)(\\|$)", matches)
filePath := StrReplace(devicePath,matches[1],devicePathsObj[matches[1]],o,1)
drive := SubStr(filePath,1,1)
data.Push(devicePath, filePath, drive)
}
CloseHandle(hObject),CloseHandle(hProc)
LV_Add("",data*)
}
GuiClose(){
ExitApp
}
#DllImport, ZwDuplicateObject,ntdll\ZwDuplicateObject,PTR,,PTR,,PTR,,PTR,,UInt,,UInt,,UInt,,UInt
#DllImport, ZwQuerySystemInformation, ntdll\ZwQuerySystemInformation,UInt,,PTR,,UInt,,UInt,,UInt
#DllImport, ZwQueryObject, ntdll\ZwQueryObject,PTR,,UInt,,PTR,,UInt,,UInt,,UInt
#DllImport, ZwQueryInformationFile, ntdll\ZwQueryInformationFile,PTR,,PTR,,PTR,,UInt,,UInt,
RunAsAdmin() {
If !A_IsAdmin {
Run % "*runAs " (A_IsCompiled?"":A_AhkPath " ") "`"" A_ScriptFullPath "`""
ExitApp
}
}
EnablePrivilege(name:="SeDebugPrivilege"){
static LUID:="DWORD LowPart;LONG HighPart",LUID_AND_ATTRIBUTES:="EnablePrivilege(LUID) Luid;DWORD Attributes;",TOKEN_PRIVILEGES:="DWORD PrivilegeCount;EnablePrivilege(LUID_AND_ATTRIBUTES) Privileges[1]"
,priv:=Struct(TOKEN_PRIVILEGES,{PrivilegeCount:1}),init:=priv.Privileges.Attributes:=2 ;SE_PRIVILEGE_ENABLED
LookupPrivilegeValue(0, name, priv.Privileges.Luid[""])
OpenProcessToken(GetCurrentProcess(), 32, getvar(hToken:=0)) ; TOKEN_ADJUST_PRIVILEGES:=32
AdjustTokenPrivileges(hToken, FALSE, priv[], sizeof(priv), 0, 0)
rv := !A_LastError
CloseHandle(hToken)
return rv
}
GetDevicePaths() {
DriveGet, driveLetters, List
driveLetters := StrSplit(driveLetters)
devicePaths := {}
Loop % driveLetters.MaxIndex()
devicePaths[QueryDosDevice(driveLetters[A_Index] ":")] := driveLetters[A_Index] ":"
Return devicePaths
}
QueryDosDevice(DeviceName := "C:") {
size := VarSetCapacity(TargetPath, 1023) + 1
DllCall("QueryDosDevice", "str", DeviceName, "str", TargetPath, "uint", size)
return TargetPath
}
SetGlobals() {
Global
FILETIME :="DWORD dwLowDateTime;DWORD dwHighDateTime"
OBJECT_BASIC_INFORMATION:="
(
// Information Class 0
int Attributes;
int GrantedAccess;
int HandleCount;
int PointerCount;
int PagedPoolUsage;
int NonPagedPoolUsage;
int Reserved1;
int Reserved2;
int Reserved3;
int NameInformationLength;
int TypeInformationLength;
int SecurityDescriptorLength;
FILETIME CreateTime;
)"
GENERIC_MAPPING :="
(
DWORD GenericRead;
DWORD GenericWrite;
DWORD GenericExecute;
DWORD GenericAll;
)"
OBJECT_TYPE_INFORMATION:="
(
// Information Class 2
UNICODE_STRING Name;
int ObjectCount;
int HandleCount;
int Reserved1;
int Reserved2;
int Reserved3;
int Reserved4;
int PeakObjectCount;
int PeakHandleCount;
int Reserved5;
int Reserved6;
int Reserved7;
int Reserved8;
int InvalidAttributes;
GENERIC_MAPPING GenericMapping;
int ValidAccess;
byte Unknown;
byte MaintainHandleDatabase;
int PoolType;
int PagedPoolUsage;
int NonPagedPoolUsage;
)"
UNICODE_STRING := "WORD Length;WORD MaximumLength;WORD *Buffer"
OBJECT_NAME_INFORMATION:="UNICODE_STRING Name"
SYSTEM_HANDLE_INFORMATION :="
(
// Information Class 16
int ProcessID;
byte ObjectTypeNumber;
byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
ushort Handle;
int Object_Pointer;
int GrantedAccess;
)"
}
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
Okay this is getting really nice and usable. I'm still on AHK_H for now, but I still think it's worth sharing.
It's much nicer and way faster than the resource monitor garbage. I even got icons to work, which makes it way easier to spot certain files and it just looks nice.
It might also be a cool idea to show which process is using/blocking which port.
I'm also wondering if we could close the handles that are locking a file without closing the process responsible. That would be pretty neat.
It's much nicer and way faster than the resource monitor garbage. I even got icons to work, which makes it way easier to spot certain files and it just looks nice.
Code: Select all
; http://forums.codeguru.com/showthread.php?176997.html
; credits to HotkeyIt for the super complicated handle retrievement!
; credits to jNizM for the neat QueryDosDevice function!
RunAsAdmin()
SetGlobals()
EnablePrivilege()
Gui, +Resize
Gui, Add, Edit, w640 r1 aw gGui_FilterList vGui_Filter
Gui, Add, ListView, w640 r30 aw ah, Potentially locked|By
LV_ModifyCol(1,300)
LV_ModifyCol(2,300)
Gui, Add, Button, w640 aw ay gGui_Reload, Reload
Gui, Add, Progress, w640 aw ay vGui_Progress
Gui, Show,, % "Showing " i " File Handles"
Gui_Reload()
Gui_FilterList(ctrlHwnd:="", guiEvent:="", eventInfo:="", errLvl:=0) {
Global
GuiControlGet, Gui_Filter
LV_Delete()
Loop % dataArray.MaxIndex() {
data := dataArray[A_Index]
If (InStr(data.filePath,Gui_Filter))
LV_Add("Icon" A_Index, data.filePath, data.procFullPath)
}
}
Gui_Reload() {
Global ;let's make life a bit more easy
obi := Struct(OBJECT_BASIC_INFORMATION), oti := Struct("OBJECT_TYPE_INFORMATION[100]"), oni := Struct("OBJECT_NAME_INFORMATION[65]")
ObjectBasicInformation:=0, ObjectNameInformation:=1,ObjectTypeInformation:=2
VarSetCapacity(p,A_PtrSize*n:=0x1000)
SystemHandleInformation:=16
While 0xc0000004 = DllCall("ntdll\ZwQuerySystemInformation","UInt", SystemHandleInformation, "PTR", &p, "UInt", n*A_PtrSize, "UInt*", sz,"CDecl UInt") ;STATUS_INFO_LENGTH_MISMATCH:=0xc0000004
VarSetCapacity(p, A_PtrSize * (n := n * 2))
h:=Struct("SYSTEM_HANDLE_INFORMATION", (&p) + A_PtrSize)
hCurrentProc:=GetCurrentProcess()
VarSetCapacity(procName,520)
dataArray := []
i:=0
numgetRes := NumGet(&p,"UInt")
LV_Delete()
ImageList := IL_Create(numgetRes)
LV_SetImageList(ImageList)
GuiControl,, Gui_Progress, 0
devicePathsObj := GetDevicePaths()
Loop % numgetRes {
GuiControl,, Gui_Progress, % A_Index/numgetRes*100
If !hProc:=OpenProcess(0x40|0x400, false, h[A_Index].ProcessID) ;PROCESS_DUP_HANDLE:=0x40, PROCESS_QUERY_INFORMATION:=0x400
Continue
If (ZwDuplicateObject(hProc, h[A_Index].Handle, hCurrentProc, getvar(hObject:=0), 0, 0, 0x4)){ ;DUPLICATE_SAME_ATTRIBUTES := 0x4
CloseHandle(hProc)
Continue
}
ZwQueryObject(hObject, ObjectBasicInformation, obi[], sizeof(obi))
ZwQueryObject(hObject, ObjectTypeInformation, oti[], obi.TypeInformationLength + 2)
If ("File" !=StrGet(oti.Name.Buffer["",""],oti.Name.Length // 2,"UTF-16") || GetFileType(hObject)!=1) {
CloseHandle(hObject),CloseHandle(hProc)
Continue
}
DllCall("QueryFullProcessImageName","Ptr", hProc, "Uint", 0, "Str", procName, "UInt*", sz:=520)
data := {}
data.procFullPath := procName
data.pid := h[A_Index].ProcessID
data.handle := h[A_Index].Handle
data.grantedAccess := h[A_Index].GrantedAccess
data.flags := h[A_Index].flags
data.attributes := obi.Attributes
data.handleCount := (obi.HandleCount - 1)
i++
If ZwQueryObject(hObject, ObjectNameInformation, oni[], obi.NameInformationLength = 0 ? 520 : obi.NameInformationLength)<0x7FFFFFFF { ; MAX_PATH*2:=520
devicePath := StrGet(oni.Name.Buffer["",""],oni.Name.Length // 2,"UTF-16")
RegexMatch(devicePath, "S)(^\\.+?\\.+?)(\\|$)", matches)
filePath := StrReplace(devicePath,matches[1],devicePathsObj[matches[1]],o,1)
drive := SubStr(filePath,1,1)
data.devicePath := devicePath
data.filePath := filePath
data.drive := drive
data.isfolder := InStr(FileExist(data.filePath), "D") ? True : False
SplitPath, % data.filePath,,, fileExt
If (data.isfolder)
IL_Add(ImageList, "shell32.dll", 5)
Else If (fileExt = "exe")
IL_Add(ImageList, data.filePath, 0)
Else {
icon := GetIconByExt(fileExt)
If (icon.file)
IL_Add(ImageList, icon.file, icon.index)
Else
IL_Add(ImageList, "imageres.dll", 3)
}
dataArray.Push(data)
}
CloseHandle(hObject),CloseHandle(hProc)
}
Gui_FilterList()
}
GuiClose(){
ExitApp
}
#DllImport, ZwDuplicateObject,ntdll\ZwDuplicateObject,PTR,,PTR,,PTR,,PTR,,UInt,,UInt,,UInt,,UInt
#DllImport, ZwQuerySystemInformation, ntdll\ZwQuerySystemInformation,UInt,,PTR,,UInt,,UInt,,UInt
#DllImport, ZwQueryObject, ntdll\ZwQueryObject,PTR,,UInt,,PTR,,UInt,,UInt,,UInt
#DllImport, ZwQueryInformationFile, ntdll\ZwQueryInformationFile,PTR,,PTR,,PTR,,UInt,,UInt,
RunAsAdmin() {
If !A_IsAdmin {
Run % "*runAs " (A_IsCompiled?"":A_AhkPath " ") "`"" A_ScriptFullPath "`""
ExitApp
}
}
EnablePrivilege(name:="SeDebugPrivilege"){
static LUID:="DWORD LowPart;LONG HighPart",LUID_AND_ATTRIBUTES:="EnablePrivilege(LUID) Luid;DWORD Attributes;",TOKEN_PRIVILEGES:="DWORD PrivilegeCount;EnablePrivilege(LUID_AND_ATTRIBUTES) Privileges[1]"
,priv:=Struct(TOKEN_PRIVILEGES,{PrivilegeCount:1}),init:=priv.Privileges.Attributes:=2 ;SE_PRIVILEGE_ENABLED
LookupPrivilegeValue(0, name, priv.Privileges.Luid[""])
OpenProcessToken(GetCurrentProcess(), 32, getvar(hToken:=0)) ; TOKEN_ADJUST_PRIVILEGES:=32
AdjustTokenPrivileges(hToken, FALSE, priv[], sizeof(priv), 0, 0)
rv := !A_LastError
CloseHandle(hToken)
return rv
}
GetIconByExt(ext) {
from := RegRead("HKEY_CLASSES_ROOT\." ext)
defaultIcon := RegRead("HKEY_CLASSES_ROOT\" from "\DefaultIcon")
defaultIcon := StrReplace(defaultIcon, "`"", "") ;"
defaultIcon := StrReplace(defaultIcon, "`%SystemRoot`%", A_WinDir)
defaultIcon := StrReplace(defaultIcon, "`%ProgramFiles`%", A_ProgramFiles)
defaultIcon := StrReplace(defaultIcon, "`%windir`%", A_WinDir)
defaultIconSplit := StrSplit(defaultIcon,",")
resFile := defaultIconSplit[1]
index := defaultIconSplit[2]
;index := (index < 0 ? abs(index)-4 : index)
Return {file: resFile, index: index}
}
GetDevicePaths() {
DriveGet, driveLetters, List
driveLetters := StrSplit(driveLetters)
devicePaths := {}
Loop % driveLetters.MaxIndex()
devicePaths[QueryDosDevice(driveLetters[A_Index] ":")] := driveLetters[A_Index] ":"
Return devicePaths
}
QueryDosDevice(DeviceName := "C:") {
size := VarSetCapacity(TargetPath, 1023) + 1
DllCall("QueryDosDevice", "str", DeviceName, "str", TargetPath, "uint", size)
return TargetPath
}
SetGlobals() {
Global
FILETIME :="DWORD dwLowDateTime;DWORD dwHighDateTime"
OBJECT_BASIC_INFORMATION:="
(
// Information Class 0
int Attributes;
int GrantedAccess;
int HandleCount;
int PointerCount;
int PagedPoolUsage;
int NonPagedPoolUsage;
int Reserved1;
int Reserved2;
int Reserved3;
int NameInformationLength;
int TypeInformationLength;
int SecurityDescriptorLength;
FILETIME CreateTime;
)"
GENERIC_MAPPING :="
(
DWORD GenericRead;
DWORD GenericWrite;
DWORD GenericExecute;
DWORD GenericAll;
)"
OBJECT_TYPE_INFORMATION:="
(
// Information Class 2
UNICODE_STRING Name;
int ObjectCount;
int HandleCount;
int Reserved1;
int Reserved2;
int Reserved3;
int Reserved4;
int PeakObjectCount;
int PeakHandleCount;
int Reserved5;
int Reserved6;
int Reserved7;
int Reserved8;
int InvalidAttributes;
GENERIC_MAPPING GenericMapping;
int ValidAccess;
byte Unknown;
byte MaintainHandleDatabase;
int PoolType;
int PagedPoolUsage;
int NonPagedPoolUsage;
)"
UNICODE_STRING := "WORD Length;WORD MaximumLength;WORD *Buffer"
OBJECT_NAME_INFORMATION:="UNICODE_STRING Name"
SYSTEM_HANDLE_INFORMATION :="
(
// Information Class 16
int ProcessID;
byte ObjectTypeNumber;
byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
ushort Handle;
int Object_Pointer;
int GrantedAccess;
)"
}
It might also be a cool idea to show which process is using/blocking which port.
I'm also wondering if we could close the handles that are locking a file without closing the process responsible. That would be pretty neat.
Re: Find the process that is locking a file/folder
Looks nice, thanks for sharing =)
Maybe someone (like just me) can assist you to translate it into pure ahk_l.
Do you want to create a "Scripts and Functions" Topic? So I can add a Process Explorer like tool into your Topic too.
(or creatinging 1 big one together - maybe on github or something like this)
Maybe someone (like just me) can assist you to translate it into pure ahk_l.
Do you want to create a "Scripts and Functions" Topic? So I can add a Process Explorer like tool into your Topic too.
(or creatinging 1 big one together - maybe on github or something like this)
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
Re: Find the process that is locking a file/folder
For closing handles you can maybe use CloseHandle function (Ref: Kernel Objects)
And with GetHandleInformation function you can check if the handle is protected from closing
with SetHandleInformation function you can (maybe) set a handle protection or remove a protection
The CloseHandle function closes handles to the following objects:
Access token
Communications device
Console input
Console screen buffer
Event
File
File mapping
I/O completion port
Job
Mailslot
Memory resource notification
Mutex
Named pipe
Pipe
Process <======
Semaphore
Thread <======
Transaction
Waitable timer
Code: Select all
CloseHandle(handle)
{
if !(DllCall("CloseHandle", "ptr", handle))
return A_LastError
return 1
]
Code: Select all
GetHandleInformation(handle)
{
static FLAG := {1: "INHERIT", 2: "PROTECT_FROM_CLOSE"}
if !(DllCall("GetHandleInformation", "ptr", handle, "uint*", flags))
return A_LastError
return flags
}
Code: Select all
SetHandleInformation(handle, mask := 1, flags := 1)
{
if !(DllCall("SetHandleInformation", "ptr", handle, "uint", mask, "uint", flags))
return A_LastError
return 1
}
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
https://autohotkey.com/boards/viewtopic.php?f=6&t=15857
That process explorer looks pretty cool. But your tool shows a list of processes that can be filtered, while my tool shows a list of handles that can be filtered. I guess we could add a new window that opens when you doubleclick a process to show all of its handles. The use-case would be a different one though.
I will, however, try to abstract the code into useful functions or classes so that you can easily add it to your process explorer.
EDIT:
Thanks, the handle functions look promising.
That process explorer looks pretty cool. But your tool shows a list of processes that can be filtered, while my tool shows a list of handles that can be filtered. I guess we could add a new window that opens when you doubleclick a process to show all of its handles. The use-case would be a different one though.
I will, however, try to abstract the code into useful functions or classes so that you can easily add it to your process explorer.
EDIT:
Thanks, the handle functions look promising.
Re: Find the process that is locking a file/folder
Hello Bruttosozialprodukt,
I'm wondering about some structure definitions and offsets. Did you run it on x64 with AHK 64?
I'm wondering about some structure definitions and offsets. Did you run it on x64 with AHK 64?
Last edited by just me on 13 Apr 2016, 03:44, edited 1 time in total.
Re: Find the process that is locking a file/folder
If you finished the translation to ahk_l i will pm you the code from the process explorer (rewrite it a bit atm) and we can create a big process / handles / ... tool.
Welcome just me =)
[ot]
since we are german speaking guys we should move the follow communication for this into german help subforum, so its easier for all.
[/ot]
Welcome just me =)
[ot]
since we are german speaking guys we should move the follow communication for this into german help subforum, so its easier for all.
[/ot]
[AHK] v2.0.5 | [WIN] 11 Pro (Version 22H2) | [GitHub] Profile
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
I ran it on Window 8.1 x64. I think I used AHK_H v2 32bit version, but I can't remember.
Edit:
Yes, I used AHK_H v2 Win32w. Using the x64w version it doesn't work, no errors, but the list stays empty. So you're probably right with your suspicion.
Edit:
Yes, I used AHK_H v2 Win32w. Using the x64w version it doesn't work, no errors, but the list stays empty. So you're probably right with your suspicion.
Re: Find the process that is locking a file/folder
If you have time, please try this:
Code: Select all
SYSTEM_HANDLE_INFORMATION :="
(
// Information Class 16
int ProcessID;
byte ObjectTypeNumber;
byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
ushort Handle;
pvoid Object_Pointer; // <<<<< changed int to pvoid
int GrantedAccess;
)"
-
- Posts: 463
- Joined: 24 Jan 2014, 22:28
Re: Find the process that is locking a file/folder
Just the same. It still works with AHK_H 32 bit and the list is empty using the 64 bit version.
Re: Find the process that is locking a file/folder
Hmmm, seems to need more. See you later!
Re: Find the process that is locking a file/folder
This is already available in Flags, see SYSTEM_HANDLE_INFORMATION.jNizM wrote:And with GetHandleInformation function you can check if the handle is protected from closingCode: Select all
GetHandleInformation(handle) { static FLAG := {1: "INHERIT", 2: "PROTECT_FROM_CLOSE"} if !(DllCall("GetHandleInformation", "ptr", handle, "uint*", flags)) return A_LastError return flags }
For 64-bit change A_PtrSize to 4: h:=Struct("SYSTEM_HANDLE_INFORMATION", (&p) + 4)
Who is online
Users browsing this forum: FanaticGuru and 149 guests