Link to home
Start Free TrialLog in
Avatar of formi
formiFlag for Switzerland

asked on

delphi: check if file is in use

I need to check if an exe-file is in use (started). I can not do this with the process-list because the program may be started from another pc in the network. I worked with the following procedure:

function FileIsInUse(aName : string) : boolean;
var
    HFileRes : HFILE;
begin
  if FileExists(aName) then
  begin
    HFileRes := CreateFile(pchar(aName), GENERIC_READ or
      GENERIC_WRITE,0, nil,
      OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL, 0);
    Result := (HFileRes = INVALID_HANDLE_VALUE);
    _lclose(HFileRes);
  end
  else
    Result := false;
end;

The problem is when the exe-file is write-protected (as it is for non-administrators) I always get "true" for this function. Are there other possibilities to check this?

Thanks in advance, Peter
Avatar of thiagoblimeira
thiagoblimeira
Flag of Brazil image

uses StrUtils;

function IsFileInUse(fName : string) : boolean;
var
  HFileRes : HFILE;
  Res: string[6];

  function CheckAttributes(FileNam: string; CheckAttr: string): Boolean;
  var
    fa: Integer;
  begin
    fa := GetFileAttributes(PChar(FileNam)) ;
    Res := '';

    if (fa and FILE_ATTRIBUTE_NORMAL) <> 0 then
    begin
      Result := False;
      Exit;
    end;

    if (fa and FILE_ATTRIBUTE_ARCHIVE) <> 0 then
Res := Res + 'A';
    if (fa and FILE_ATTRIBUTE_COMPRESSED) <> 0 then
Res := Res + 'C';
    if (fa and FILE_ATTRIBUTE_DIRECTORY) <> 0 then
Res := Res + 'D';
    if (fa and FILE_ATTRIBUTE_HIDDEN) <> 0 then
Res := Res + 'H';
    if (fa and FILE_ATTRIBUTE_READONLY) <> 0 then
Res := Res + 'R';
    if (fa and FILE_ATTRIBUTE_SYSTEM) <> 0 then
Res := Res + 'S';

    Result := AnsiContainsText(Res, CheckAttr) ;
  end; (*CheckAttributes*)

  procedure SetAttr(fName: string) ;
  var
    Attr: Integer;
  begin
    Attr := 0;
    if AnsiContainsText(Res, 'A') then
Attr := Attr + FILE_ATTRIBUTE_ARCHIVE;
    if AnsiContainsText(Res, 'C') then
Attr := Attr + FILE_ATTRIBUTE_COMPRESSED;
    if AnsiContainsText(Res, 'D') then
Attr := Attr + FILE_ATTRIBUTE_DIRECTORY;
    if AnsiContainsText(Res, 'H') then
Attr := Attr + FILE_ATTRIBUTE_HIDDEN;
    if AnsiContainsText(Res, 'S') then
Attr := Attr + FILE_ATTRIBUTE_SYSTEM;

    SetFileAttributes(PChar(fName), Attr) ;
  end; (*SetAttr*)
begin //IsFileInUse
  if CheckAttributes(fName, 'R') then
  begin
  Result := False;

  if not FileExists(fName) then exit;

    if MessageDlg(ExtractFileName(fName) + ' is a READ-ONLY file.' + #13#10 + 'Do you wish to clear the READ-ONLY flag???', mtConfirmation, [mbYes, mbNo], 0) = mrNo then
    beginb
      Result := True;
      Exit;
    end;
  end;

  SetFileAttributes(PChar(fName), FILE_ATTRIBUTE_NORMAL) ;

  SetAttr(fName) ;

  HFileRes := CreateFile(pchar(fName), GENERIC_READ or GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0) ;
  Result := (HFileRes = INVALID_HANDLE_VALUE) ;
  if not Result then CloseHandle(HFileRes) ;
end; //IsFileInUse
Here's a shorter example:

function IsFileInUse(FileName: TFileName): Boolean;
var
  HFileRes: HFILE;
begin
  Result := False;
  if not FileExists(FileName) then Exit;
  HFileRes := CreateFile(PChar(FileName),
                         GENERIC_READ or GENERIC_WRITE,
                         0,
                         nil,
                         OPEN_EXISTING,
                         FILE_ATTRIBUTE_NORMAL,
                         0);
  Result := (HFileRes = INVALID_HANDLE_VALUE);
  if not Result then
    CloseHandle(HFileRes);
end;
 
 
{Example:}
 
procedure TForm1.Button1Click(Sender: TObject);
begin
  if IsFileInUse('c:\windows\notepad.exe') then
    ShowMessage('Notepad is in use.');
  else
    ShowMessage('Notepad not in use.');
end;
Avatar of formi

ASKER

@Johnices: that is the procedure I have problems with ...

@thiagoblimeira: I didn't test it but if I don't have the rights to write to the file I have no chance to change the attribute! So this can't be the solution.
@formi,

I should learn to read an entire post before I jump in with some solution. Sorry about that!

My guess is that you are using Vista or Windows 7?

You may have to get around UAC if that is the case and run your app as an administrator or request privilege elevations by using a proper manifest.

If this is XP or under.... no other way that I know of other than to ensure your application has and runs under admin privileges.

John
ASKER CERTIFIED SOLUTION
Avatar of Mahdi78
Mahdi78
Flag of Algeria image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of formi

ASKER

Ok, I think there is no better solution, but I'll do it another way: I'll open a tempoary textfile if I start program x. If I start program y I'll try to delete this file. If this is not possible I know that program x is running. With your solution if program x crashes I'll never be able to start program y.