Visual Basic File API Routines

CreateFile: Test if a File is Open by Another Application
     
Posted:   Thursday November 25, 2004
Updated:   Monday December 26, 2011
     
Applies to:   VB4-32, VB5, VB6
Developed with:   VB6, Windows XP
OS restrictions:   None
Author:   VBnet - Randy Birch
     

Related:  

GetLogicalDriveStrings: An API 'DriveExists' Routine
FindFirstFile: An API 'FileExists' Routine
FindFirstFile: An API 'FolderExists' Routine
     
 Prerequisites
None.

Most well-behaved applications open and lock files to prevent inadvertent or deliberate changes to the file contents by other applications while the file is being used. Others, like Notepad, open the file, read the data, then close the file immediately without placing a lock on the file.

This routine is for use with the former access method, and will return True if another application has the file open, or False if not. For files opened with apps like Notepad, it will always return false. For apps like WordPad, it will return True if both the file and app are on the local machine, but False if file is on a remote machine. (Some locks apparently are different than others, and the CreateFile and CreateFileEx APIs does have special flags that can be used by applications to indicate other apps can open files for joint access, both for read and write.)

Assuming then that the application opening the file places a proper lock on the file, this routine will correctly detect if:

  • a local file has been opened and locked by an application running on the local machine
  • a local file has been opened and locked by an application running on a remote machine
  • a remote file has been opened and locked by an application running on the local machine
  • a remote file has been opened and locked by an application running on another remote machine

The remote file to be tested can be specified using either mapped drives (e.g. z:\filename.exe), UNC format (e.g \\server\share\filename.ext), machine name (e.g. \\vbnetdev\share\filename.ext), or IP address within the network (e.g \\192.168.1.102\share\filename.ext).

The routine works by attempting to obtain a handle to the file using the GENERIC_READ and OPEN_EXISTING flags. If the function is unable to obtain a handle because of a file lock (hFile = -1) the IsFileInUse routine returns True. If a handle is obtained (hFile <> 0), the function returns False. 

If you have access to other machines to perform remote tests, use Word to open the app. If Word is not available see the Comments section below for some quick code that will lock a specified file.

 BAS Module Code
None.

 Form Code
Create a new project with a form containing one text box (Text1), one label (Label1) and a command button (Command1). Add the following code:

Option Explicit
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Copyright ©1996-2011 VBnet/Randy Birch, All Rights Reserved.
' Some pages may also contain other copyrights by the author.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' Distribution: You can freely use this code in your own
'               applications, but you may not reproduce 
'               or publish this code on any web site,
'               online service, or distribute as source 
'               on any media without express permission.
''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Private Const GENERIC_READ As Long = &H80000000
Private Const INVALID_HANDLE_VALUE As Long = -1
Private Const OPEN_EXISTING As Long = 3
Private Const FILE_ATTRIBUTE_NORMAL As Long = &H80
Private Const MAX_PATH As Long = 260

'Enum containing values representing
'the status of the file
Private Enum IsFileResults
   FILE_IN_USE = -1  'True
   FILE_FREE = 0     'False
   FILE_DOESNT_EXIST = -999 'arbitrary number, other than 0 or -1
End Enum

Private Type FILETIME
   dwLowDateTime As Long
   dwHighDateTime As Long
End Type

Private Type WIN32_FIND_DATA
   dwFileAttributes As Long
   ftCreationTime As FILETIME
   ftLastAccessTime As FILETIME
   ftLastWriteTime As FILETIME
   nFileSizeHigh As Long
   nFileSizeLow As Long
   dwReserved0 As Long
   dwReserved1 As Long
   cFileName As String * MAX_PATH
   cAlternate As String * 14
End Type

Private Declare Function CreateFile Lib "kernel32" _
   Alias "CreateFileA" _
  (ByVal lpFileName As String, _
   ByVal dwDesiredAccess As Long, _
   ByVal dwShareMode As Long, _
   ByVal lpSecurityAttributes As Long, _
   ByVal dwCreationDisposition As Long, _
   ByVal dwFlagsAndAttributes As Long, _
   ByVal hTemplateFile As Long) As Long
    
Private Declare Function CloseHandle Lib "kernel32" _
  (ByVal hFile As Long) As Long
  
Private Declare Function FindFirstFile Lib "kernel32" _
   Alias "FindFirstFileA" _
  (ByVal lpFileName As String, _
   lpFindFileData As WIN32_FIND_DATA) As Long

Private Declare Function FindClose Lib "kernel32" _
  (ByVal hFindFile As Long) As Long



Private Sub Form_Load()

   Command1.Caption = "IsFileInUse"
   Text1.Text = "d:\test.doc"
   Label1.Caption = ""
   
End Sub


Private Sub Command1_Click()

   Dim bResult As IsFileResults
   
   bResult = IsFileInUse(Text1.Text)

   Select Case bResult
      Case FILE_IN_USE
         Label1.Caption = "File in use"
         
      Case FILE_FREE
         Label1.Caption = "File is available"
         
      Case FILE_DOESNT_EXIST
         Label1.Caption = "File does not exist!"
         
   End Select
   
   Label1.Caption = Label1.Caption & "  (" & bResult & ")"
   
End Sub


Private Function IsFileInUse(sFile As String) As IsFileResults

   Dim hFile As Long
   
   If FileExists(sFile) Then
   
     'note that FILE_ATTRIBUTE_NORMAL (&H80) has
     'a different value than VB's constant vbNormal (0)!
      hFile = CreateFile(sFile, _
                         GENERIC_READ, _
                         0, 0, _
                         OPEN_EXISTING, _
                         FILE_ATTRIBUTE_NORMAL, 0&)

     'this will evaluate to either
     '-1 (FILE_IN_USE) or 0 (FILE_FREE)
      IsFileInUse = hFile = INVALID_HANDLE_VALUE

      CloseHandle hFile
   
   Else
   
     'the value of FILE_DOESNT_EXIST in the Enum
     'is arbitrary, as long as it's not 0 or -1
      IsFileInUse = FILE_DOESNT_EXIST
   
   End If
   
End Function


Private Function FileExists(sSource As String) As Boolean

   Dim WFD As WIN32_FIND_DATA
   Dim hFile As Long
   
   hFile = FindFirstFile(sSource, WFD)
   FileExists = hFile <> INVALID_HANDLE_VALUE
   
   Call FindClose(hFile)
   
End Function
 Comments
This will create a test app you can use to enter a file, remote or local, and have the tool lock the file for testing the code above. Note that the Open method used will create any mistyped filename, so check for stray 0-length files after testing.

Private hFile As Long

Private Sub Form_Load()

   Text1.Text = ""
   Me.Caption = "ready"

End Sub


Private Sub Command1_Click()

   On Local Error GoTo oops
   hFile = FreeFile
   
   Open Text1.Text For Binary Access Read Lock Read As #hFile
   Caption = "file handle: " & hFile
     
oops_out:
   Exit Sub
   
oops:
   MsgBox Err.Number & vbCrLf & Err.Description
   Resume oops_out
End Sub


Private Sub Command2_Click()

   Close
   hFile = 0
   Me.Caption = "ready"
   
End Sub

 
 

PayPal Link
Make payments with PayPal - it's fast, free and secure!

 
 
 
 

Copyright ©1996-2011 VBnet and Randy Birch. All Rights Reserved.
Terms of Use  |  Your Privacy

 

Hit Counter