ADD: Delete operation - show which process has locked file (Windows >= 2000)

This commit is contained in:
Alexander Koblov 2018-10-21 16:27:31 +00:00
commit c5e8537ccb
2 changed files with 183 additions and 17 deletions

View file

@ -332,7 +332,9 @@ begin
if Length(ProcessInfo) > 0 then
begin
sQuestion+= LineEnding + LineEnding + Format(rsMsgProcessId, [ProcessInfo[0].ProcessId]) + LineEnding;
sQuestion+= Format(rsMsgApplicationName, [ProcessInfo[0].ApplicationName]) + LineEnding;
if (Length(ProcessInfo[0].ApplicationName) > 0) then begin
sQuestion+= Format(rsMsgApplicationName, [ProcessInfo[0].ApplicationName]) + LineEnding;
end;
sQuestion+= Format(rsMsgExecutablePath, [ProcessInfo[0].ExecutablePath]) + LineEnding;
end;
end;

View file

@ -21,7 +21,7 @@ function GetFileInUseProcess(const FileName: String; LastError: Integer; out Pro
implementation
uses
Windows;
JwaWinType, JwaNative, JwaNtStatus, JwaPsApi, Windows, DCWindows;
const
RstrtMgr = 'RstrtMgr.dll';
@ -62,6 +62,12 @@ type
bRestartable: BOOL;
end;
PSystemHandleInformationEx = ^TSystemHandleInformationEx;
TSystemHandleInformationEx = record
Count: ULONG;
Handle: array[0..0] of TSystemHandleInformation;
end;
var
RmStartSession: function (pSessionHandle: LPDWORD; dwSessionFlags: DWORD; strSessionKey: LPWSTR): DWORD; stdcall;
RmEndSession: function (dwSessionHandle: DWORD): DWORD; stdcall;
@ -71,32 +77,150 @@ var
QueryFullProcessImageNameW: function(hProcess: HANDLE; dwFlags: DWORD; lpExeName: LPWSTR; lpdwSize: PDWORD): BOOL; stdcall;
GetFinalPathNameByHandleW: function(hFile: HANDLE; lpszFilePath: LPWSTR; cchFilePath: DWORD; dwFlags: DWORD): DWORD; stdcall;
var
RstrtMgrLib: HMODULE = 0;
GetFileName: function(hFile: HANDLE): UnicodeString;
procedure Initialize;
function _wcsnicmp(const s1, s2: pwidechar; count: ptruint): integer; cdecl; external 'msvcrt.dll';
function GetFileHandleList(out SystemInformation : PSystemHandleInformationEx): Boolean;
const
MEM_SIZE = SizeOf(TSystemHandleInformationEx);
var
SystemDirectory: UnicodeString;
Status: NTSTATUS;
SystemInformationLength : ULONG = MEM_SIZE;
begin
if CheckWin32Version(6, 0) then
begin
SetLength(SystemDirectory, maxSmallint + 1);
SetLength(SystemDirectory, GetSystemDirectoryW(Pointer(SystemDirectory), maxSmallint));
RstrtMgrLib:= LoadLibraryW(PWideChar(SystemDirectory + PathDelim + RstrtMgr));
if RstrtMgrLib <> 0 then
begin
@RmStartSession := GetProcAddress(RstrtMgrLib, 'RmStartSession');
@RmEndSession := GetProcAddress(RstrtMgrLib, 'RmEndSession');
SystemInformation:= GetMem(MEM_SIZE);
repeat
Status:= NtQuerySystemInformation(SystemHandleInformation, SystemInformation,
SystemInformationLength, @SystemInformationLength);
if Status = STATUS_INFO_LENGTH_MISMATCH then begin
ReAllocMem(SystemInformation, SystemInformationLength + SizeOf(TSystemHandleInformation) * 100)
end;
until Status <> STATUS_INFO_LENGTH_MISMATCH;
Result:= (Status = STATUS_SUCCESS);
if not Result then FreeMem(SystemInformation);
end;
@RmRegisterResources := GetProcAddress(RstrtMgrLib, 'RmRegisterResources');
@RmGetList := GetProcAddress(RstrtMgrLib, 'RmGetList');
function GetFileNameOld(hFile: HANDLE): UnicodeString;
const
MAX_SIZE = SizeOf(TObjectNameInformation) + MAXWORD;
var
ReturnLength : ULONG;
ObjectInformation : PObjectNameInformation;
begin
ObjectInformation:= GetMem(MAX_SIZE);
if (NtQueryObject(hFile, ObjectNameInformation, ObjectInformation, MAXWORD, @ReturnLength) <> STATUS_SUCCESS) then
Result:= EmptyWideStr
else begin
SetLength(Result, ObjectInformation^.Name.Length div SizeOf(WideChar));
Move(ObjectInformation^.Name.Buffer^, Result[1], ObjectInformation^.Name.Length);
end;
FreeMem(ObjectInformation);
end;
function GetFileNameNew(hFile: HANDLE): UnicodeString;
begin
SetLength(Result, maxSmallint + 1);
SetLength(Result, GetFinalPathNameByHandleW(hFile, PWideChar(Result), maxSmallint, 0));
end;
var
FileHandleType: ULONG;
function GetFileHandleType: ULONG;
var
Index: DWORD;
Handle: THandle;
ProcessId: DWORD;
SystemInformation : PSystemHandleInformationEx;
begin
Handle:= FileOpen('NUL', fmOpenRead or fmShareDenyNone);
if Handle <> feInvalidHandle then
begin
if GetFileHandleList(SystemInformation) then
begin
ProcessId:= GetCurrentProcessId;
for Index:= 0 to SystemInformation^.Count - 1 do
begin
if (SystemInformation^.Handle[Index].Handle = USHORT(Handle)) and (SystemInformation^.Handle[Index].ProcessId = ProcessId) then
begin
Result:= SystemInformation^.Handle[Index].ObjectTypeNumber;
Break;
end;
end;
FreeMem(SystemInformation);
end;
@QueryFullProcessImageNameW:= GetProcAddress(GetModuleHandleW(Kernel32), 'QueryFullProcessImageNameW');
FileClose(Handle);
end;
end;
function GetFileInUseProcess(const FileName: String; LastError: Integer; out
ProcessInfo: TProcessInfoArray): Boolean;
function GetModuleFileName(hProcess: HANDLE): UnicodeString;
begin
SetLength(Result, maxSmallint + 1);
SetLength(Result, GetModuleFileNameExW(hProcess, 0, PWideChar(Result), maxSmallint));
end;
function GetNativeName(const FileName: String; out NativeName: UnicodeString): Boolean;
var
hFile: HANDLE;
begin
hFile := CreateFileW(PWideChar(UTF16LongName(FileName)), FILE_READ_ATTRIBUTES,
FILE_SHARE_READ or FILE_SHARE_WRITE or FILE_SHARE_DELETE,
nil, OPEN_EXISTING, 0, 0);
Result:= (hFile <> INVALID_HANDLE_VALUE);
if Result then begin
NativeName:= GetFileName(hFile);
CloseHandle(hFile);
end;
end;
function GetFileInUseProcessOld(const FileName: String; var ProcessInfo: TProcessInfoArray): Boolean;
var
hFile: HANDLE;
Index: Integer;
hProcess: HANDLE;
AFileName, AOpenName: UnicodeString;
SystemInformation : PSystemHandleInformationEx;
begin
if GetNativeName(FileName, AFileName) and GetFileHandleList(SystemInformation) then
begin
for Index:= 0 to SystemInformation^.Count - 1 do
begin
if (SystemInformation^.Handle[Index].ObjectTypeNumber = FileHandleType) then
begin
{ Query the object name (unless it has an access of
0x0012019f, on which NtQueryObject could hang. }
if (SystemInformation^.Handle[Index].GrantedAccess = $0012019f) then
begin
Continue;
end;
hProcess:= OpenProcess(PROCESS_DUP_HANDLE or PROCESS_QUERY_INFORMATION or PROCESS_VM_READ, False, SystemInformation^.Handle[Index].ProcessId);
if (hProcess <> 0) then
begin
if DuplicateHandle(hProcess, SystemInformation^.Handle[Index].Handle, GetCurrentProcess, @hFile, 0, False, DUPLICATE_SAME_ACCESS) then
begin
AOpenName:= GetFileName(hFile);
if (_wcsnicmp(PWideChar(AOpenName), PWideChar(AFileName), Length(AFileName)) = 0) then
begin
SetLength(ProcessInfo, Length(ProcessInfo) + 1);
ProcessInfo[High(ProcessInfo)].ProcessId:= SystemInformation^.Handle[Index].ProcessId;
ProcessInfo[High(ProcessInfo)].ExecutablePath:= UTF8Encode(GetModuleFileName(hProcess));
end;
CloseHandle(hFile);
end;
CloseHandle(hProcess);
end;
end;
end;
FreeMem(SystemInformation);
end;
Result:= (Length(ProcessInfo) > 0);
end;
function GetFileInUseProcessNew(const FileName: String; out ProcessInfo: TProcessInfoArray): Boolean;
const
MAX_CNT = 5;
var
@ -114,7 +238,6 @@ var
rgAffectedApps: array[0..MAX_CNT - 1] of TRMProcessInfo;
begin
if (RstrtMgrLib = 0) then Exit(False);
if (LastError <> ERROR_SHARING_VIOLATION) then Exit(False);
FillChar(szSessionKey, SizeOf(szSessionKey), 0);
Result:= (RmStartSession(@dwSession, 0, szSessionKey) = ERROR_SUCCESS);
if Result then
@ -154,6 +277,47 @@ begin
end;
end;
function GetFileInUseProcess(const FileName: String; LastError: Integer; out
ProcessInfo: TProcessInfoArray): Boolean;
begin
if (LastError <> ERROR_SHARING_VIOLATION) then Exit(False);
if Win32MajorVersion < 6 then
Result:= GetFileInUseProcessOld(FileName, ProcessInfo)
else begin
Result:= GetFileInUseProcessNew(FileName, ProcessInfo)
end;
end;
procedure GetFileHandleTypeThread(Parameter : Pointer);
begin
FileHandleType:= GetFileHandleType;
end;
procedure Initialize;
var
SystemDirectory: UnicodeString;
begin
if Win32MajorVersion < 6 then
GetFileName:= @GetFileNameOld
else begin
SetLength(SystemDirectory, maxSmallint + 1);
SetLength(SystemDirectory, GetSystemDirectoryW(Pointer(SystemDirectory), maxSmallint));
RstrtMgrLib:= LoadLibraryW(PWideChar(SystemDirectory + PathDelim + RstrtMgr));
if RstrtMgrLib <> 0 then
begin
@RmStartSession := GetProcAddress(RstrtMgrLib, 'RmStartSession');
@RmEndSession := GetProcAddress(RstrtMgrLib, 'RmEndSession');
@RmRegisterResources := GetProcAddress(RstrtMgrLib, 'RmRegisterResources');
@RmGetList := GetProcAddress(RstrtMgrLib, 'RmGetList');
end;
GetFileName:= @GetFileNameNew;
@QueryFullProcessImageNameW:= GetProcAddress(GetModuleHandleW(Kernel32), 'QueryFullProcessImageNameW');
@GetFinalPathNameByHandleW:= GetProcAddress(GetModuleHandleW(Kernel32), 'GetFinalPathNameByHandleW');
end;
TThread.ExecuteInThread(@GetFileHandleTypeThread, nil);
end;
initialization
Initialize;