unit fFileUnlock;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs, StdCtrls,
  Grids, uFileUnlock;

type

  { TfrmFileUnlock }

  TfrmFileUnlock = class(TForm)
    btnUnlockAll: TButton;
    btnUnlock: TButton;
    btnClose: TButton;
    btnTerminate: TButton;
    stgFileHandles: TStringGrid;
    procedure btnTerminateClick(Sender: TObject);
    procedure btnUnlockAllClick(Sender: TObject);
    procedure btnUnlockClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure stgFileHandlesDblClick(Sender: TObject);
    procedure stgFileHandlesSelection(Sender: TObject; aCol, aRow: Integer);
  private
    procedure ShowThread;
    procedure UnlockRow(Index: Integer);
  public

  end;

function ShowUnlockForm(ProcessInfo: TProcessInfoArray): Boolean;

implementation

{$R *.lfm}

uses
  Windows, Math, LCLStrConsts, DCConvertEncoding, fMain, uMyWindows, uLng;

function ShowUnlockForm(ProcessInfo: TProcessInfoArray): Boolean;
var
  Index: Integer;
  UnlockEnabled: Boolean = False;
begin
  with TfrmFileUnlock.Create(frmMain) do
  try
    stgFileHandles.RowCount:= Length(ProcessInfo) + 1;

    for Index:= 1 to stgFileHandles.RowCount - 1 do
    begin
      if (ProcessInfo[Index - 1].FileHandle <> 0) then begin
        UnlockEnabled:= True;
        stgFileHandles.Cells[0, Index]:= IntToStr(ProcessInfo[Index - 1].FileHandle);
      end;
      stgFileHandles.Cells[1, Index]:= IntToStr(ProcessInfo[Index - 1].ProcessId);
      stgFileHandles.Cells[2, Index]:= ProcessInfo[Index - 1].ExecutablePath;
    end;
    btnUnlockAll.Enabled:= UnlockEnabled;
    btnTerminate.Enabled:= Length(ProcessInfo) > 0;
    stgFileHandles.Row:= IfThen(UnlockEnabled, 1, 0);
    btnUnlock.Enabled:= UnlockEnabled and (Length(stgFileHandles.Cells[0, 1]) > 0);

    TThread.Synchronize(nil, @ShowThread);

    Result:= (ModalResult = mrOK);
  finally
    Free;
  end;
end;

{ TfrmFileUnlock }

procedure TfrmFileUnlock.stgFileHandlesSelection(Sender: TObject; aCol, aRow: Integer);
begin
  btnUnlock.Enabled:= (aRow > 0) and (Length(stgFileHandles.Cells[0, aRow]) > 0);
end;

procedure TfrmFileUnlock.btnUnlockClick(Sender: TObject);
begin
  UnlockRow(stgFileHandles.Row);
  if (stgFileHandles.RowCount = 1) then
  begin
    Close;
    ModalResult:= mrOK;
  end;
end;

procedure TfrmFileUnlock.FormShow(Sender: TObject);
var
  Index: Integer;
begin
  for Index:= 0 to stgFileHandles.Columns.Count - 1 do
  begin
    stgFileHandles.Columns[Index].Width:= stgFileHandles.Canvas.TextWidth(stgFileHandles.Columns[Index].Title.Caption + 'W');
  end;
end;

procedure TfrmFileUnlock.stgFileHandlesDblClick(Sender: TObject);
var
  AHandle: HWND;
  ProcessId: DWORD;
begin
  if (stgFileHandles.Row > 0) then
  begin
    ProcessId:= StrToDWord(stgFileHandles.Cells[1, stgFileHandles.Row]);
    AHandle:= FindMainWindow(ProcessId);
    if AHandle <> 0 then ShowWindowEx(AHandle);
  end;
end;

procedure TfrmFileUnlock.btnUnlockAllClick(Sender: TObject);
var
  Index: Integer;
begin
  for Index:= stgFileHandles.RowCount - 1 downto 1 do
  begin
    UnlockRow(Index);
  end;
  if (stgFileHandles.RowCount = 1) then
  begin
    Close;
    ModalResult:= mrOK;
  end;
end;

procedure TfrmFileUnlock.btnTerminateClick(Sender: TObject);
var
  Index: Integer;
  ProcessId: DWORD;
begin
  if (stgFileHandles.Row > 0) then
  begin
    if MessageBoxW(Handle, PWideChar(CeUtf8ToUtf16(rsMsgTerminateProcess)), PWideChar(CeUtf8ToUtf16(rsMtWarning)), MB_YESNO or MB_ICONWARNING) = IDYES then
    begin
      ProcessId:= StrToDWord(stgFileHandles.Cells[1, stgFileHandles.Row]);
      if uFileUnlock.TerminateProcess(ProcessId) then
      begin
        for Index:= stgFileHandles.RowCount - 1 downto 1 do
        begin
          if (ProcessId = StrToDWord(stgFileHandles.Cells[1, Index])) then
            stgFileHandles.DeleteRow(Index);
        end;
        if (stgFileHandles.RowCount = 1) then
        begin
          Close;
          ModalResult:= mrOK;
        end;
      end;
    end;
  end;
end;

procedure TfrmFileUnlock.ShowThread;
begin
  ShowModal;
end;

procedure TfrmFileUnlock.UnlockRow(Index: Integer);
var
  ProcessId: DWORD;
  FileHandle: HANDLE;
begin
  ProcessId:= StrToDWord(stgFileHandles.Cells[1, Index]);
  FileHandle:= StrToQWord(stgFileHandles.Cells[0, Index]);
  if FileUnlock(ProcessId, FileHandle) then stgFileHandles.DeleteRow(Index);
end;

end.

