Jump to content

Recommended Posts

I have used the following function for checking if a file is in use for many years (it is recommended on numerous sites):

function IsFileInUse(FileName: String): Boolean;
var
  HFileRes: HFILE;
  hdl:THandle;
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;

It still works fine for 32Bit, but not 64 bit. On 64 bit It always returns a valid handle even when the file is in use and thus reports that the file is not in use even when it is.

 

Also, when run from the IDE in 64 bit it crashes with an EExternalException: "External exception C0000008" when trying to close the handle. I have found some posts on this via Google and it seems to be a known issue, the answer being to switch off some debug options.

 

But I am not particularly troubled by the IDE bug. I am majorly concerned by the failure to detect that a file is in use!

 

I've tried with CreateFileA and CreateFileW, but with the exactly the same result.

Share this post


Link to post
Posted (edited)

HFileRes should be a THandle instead of HFILE (which is a LongWord).  In 64bit CreateFile returns a 64bit value and you are assigning it to a 32bit one.  On a side note I just checked Delphi RIO and still no compiler hint for this type of thing...  Seems like that would be useful.

 

-Mark

Edited by MarkShark

Share this post


Link to post
5 minutes ago, MarkShark said:

HFileRes should be a THandle instead of HFILE (which is a LongWord).  In 64bit CreateFile returns a 64bit value and you are assigning it to a 32bit one.

Noted and thanks, but still returns false when the file is actually in use in 64 bit. Any idea why?

Share this post


Link to post
Posted (edited)

Why do you call FileExists? A single call to CreateFile can tell you what you need. The code as it stands won't tell you whether or not the file is in use. What is hdl? Use THandle as stated above. 

 

As for the problem, debug it! Use GetLastError if CreateFile fails. If CreateFile succeeds then there's presumably something wrong with your logic. 

Edited by David Heffernan

Share this post


Link to post
Posted (edited)
1 hour ago, David Heffernan said:

Why do you call FileExists? A single call to CreateFile can tell you what you need. The code as it stands won't tell you whether or not the file is in use. What is hdl? Use THandle as stated above. 

I copied the code from I believe Mike Lischke's site and found it worked exactly as I wanted in 32 bit.

Never thought about the reason for the fileExists, but I suppose if the file doesn't exist then the answer to isFileInUse is "No". If it doesn't exist why bother creating it? So to my mind, it makes sense. However, it certainly isn't the cause of the problem.

 

As for using THandle, please read my post to which you have responded where I say "Noted and thanks, but still returns false...". I was unaware of the problem with FileHdl in64 bit, but I have now changed it and it makes no difference whatsoever. In 64 bit when I run the function, it creates the file even though it is in use in another process and returns no error at least not on the CreateFile process. The only error it returns is on the call to CloseHandle, but that only happens in the IDE so, as I stated in my original post, I don't particularly care. Anyway, It's not hard to imagine that the reason CloseHandle bugs out is because the file is open in another process already and the handle should never have been created.

 

But ignoring the CloseHandle problem, which would not exist if the function worked as expected (and as it does work in 32 bit), why doesn't it work in 64 bit?

 

It would be helpful if someone else tried it in a 64 bit app. All you need is a button and an openDialog, the above function (obviously with HFileRes, changed to THandle) and the following code in your button's onClick:

if OpenDialog1.Execute then
  if isFileInUse(openDialog1.FileName) then
    Showmessage('in use')
  else
   Showmessage('not in use');

 

Edited by Mark Williams

Share this post


Link to post

The reason you don't call FileExists is that CreateFile will fail and GetLastError will tell you that the file does not exist.

 

You have tell us why you believe that CreateFile should fail in the scenario that concerns you. Another program already opened the file? With what flags? 

 

Rather than have us spend time trying to guess how to recreate the problem, can you provide a complete console app that reproduces the issue. 

Share this post


Link to post
6 minutes ago, David Heffernan said:

The reason you don't call FileExists is that CreateFile will fail and GetLastError will tell you that the file does not exist.

Ok. Noted, but not really my issue.

 

However, for some reason the function is now working as expected in 64 bit and I have no idea why. 

 

Thanks anyway.

Share this post


Link to post
Posted (edited)

I would suggest rewriting the function to something more like this:

function IsFileInUse(const FileName: String): Boolean;
var
  hf: THandle;
begin
  hf := CreateFile(PChar(FileName),
    GENERIC_READ or GENERIC_WRITE,
    0,
    nil,
    OPEN_EXISTING,
    FILE_ATTRIBUTE_NORMAL,
    0);
  if hf <> INVALID_HANDLE_VALUE then begin
    CloseHandle(hf);
    Result := False;
  end else begin
    Result := (GetLastError() = ERROR_SHARING_VIOLATION);
  end;
end;

 

Edited by Remy Lebeau
  • Like 1

Share this post


Link to post
3 hours ago, Remy Lebeau said:

I would suggest rewriting the function to something more like this:

Thanks. Will do.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×