Click here to Skip to main content
Rate this: bad
good
Please Sign up or sign in to vote.
See more: C#3.0
how to check file is used by another process in c# framework 3.5 pls help me out..
Posted 20-Jan-13 19:55pm
Comments
Savy17 at 23-Oct-13 11:24am
   
I am using Solution 3 to find the word process that has been used to open the particular word document. Once process is found, I kill the process using process.kill() method. It kills the process and I can see the process disappears from task manager. However if I try to open the same document again, it pops up the dialog saying file is locked for editing by 'abc'.
If I close the app and restart, it works fine. Please suggest how to get away with this issue.
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 3

Please check if you can find the process using your file. Replace the file name in Main
 
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using System.Threading;
 
namespace FileLockInfo
{
    public class Win32Processes
    {
        /// <summary>
        /// Return a list of processes that hold on the given file.
        /// </summary>
        /// 

        static void Main()
        {
            Console.WriteLine("C:\\Users\\Rupam\\Desktop\\Transaction Details.pdf");
 
            GetProcessesLockingFile("C:\\Users\\Rupam\\Desktop\\Transaction Details - PayPal.pdf");
            Console.Read();
         
        }
        public static List<Process> GetProcessesLockingFile(string filePath)
        {
            var procs = new List<Process>();
 
            var processListSnapshot = Process.GetProcesses();
            foreach (var process in processListSnapshot)
            {
                Console.WriteLine( process.ProcessName);
                if (process.Id <= 4) { continue; } // system processes
                var files = GetFilesLockedBy(process);
                if (files.Contains(filePath))
                {
                    
                    Console.WriteLine("--------------->"+process.ProcessName);
                    procs.Add(process);
                }
            }
            return procs;
        }
 
        /// <summary>
        /// Return a list of file locks held by the process.
        /// </summary>
        public static List<string> GetFilesLockedBy(Process process)
        {
            var outp = new List<string>();
 
            ThreadStart ts = delegate
            {
                try
                {
                    outp = UnsafeGetFilesLockedBy(process);
                }
                catch { Ignore(); }
            };
 
            try
            {
                var t = new Thread(ts);
                t.IsBackground = true;
                t.Start();
                if (!t.Join(250))
                {
                    try
                    {
                        t.Interrupt();
                        t.Abort();
                    }
                    catch { Ignore(); }
                }
            }
            catch { Ignore(); }
 
            return outp;
        }
 

        #region Inner Workings
        private static void Ignore() { }
        private static List<string> UnsafeGetFilesLockedBy(Process process)
        {
            try
            {
                var handles = GetHandles(process);
                var files = new List<string>();
 
                foreach (var handle in handles)
                {
                    var file = GetFilePath(handle, process);
                    if (file != null) files.Add(file);
                }
 
                return files;
            }
            catch
            {
                return new List<string>();
            }
        }
 
        const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
        private static string GetFilePath(Win32API.SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process)
        {
            var ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
            var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
            var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
            var objObjectName = new Win32API.OBJECT_NAME_INFORMATION();
            var strObjectName = "";
            var nLength = 0;
            IntPtr ipTemp, ipHandle;
 
            if (!Win32API.DuplicateHandle(ipProcessHwnd, systemHandleInformation.Handle, Win32API.GetCurrentProcess(), out ipHandle, 0, false, Win32API.DUPLICATE_SAME_ACCESS))
                return null;
 
            IntPtr ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
            Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength);
            objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
            Marshal.FreeHGlobal(ipBasic);
 
            IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
            nLength = objBasic.TypeInformationLength;
            // this one never locks...
            while ((uint)(Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
            {
                if (nLength == 0)
                {
                    Console.WriteLine("nLength returned at zero! ");
                    return null;
                }
                Marshal.FreeHGlobal(ipObjectType);
                ipObjectType = Marshal.AllocHGlobal(nLength);
            }
 
            objObjectType = (Win32API.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
            if (Is64Bits())
            {
                ipTemp = new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32);
            }
            else
            {
                ipTemp = objObjectType.Name.Buffer;
            }
 
            var strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
            Marshal.FreeHGlobal(ipObjectType);
            if (strObjectTypeName != "File")
                return null;
 
            nLength = objBasic.NameInformationLength;
 
            var ipObjectName = Marshal.AllocHGlobal(nLength);
 
            // ...this call sometimes hangs. Is a Windows error.
            while ((uint)(Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectNameInformation, ipObjectName, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
            {
                Marshal.FreeHGlobal(ipObjectName);
                if (nLength == 0)
                {
                    Console.WriteLine("nLength returned at zero! " + strObjectTypeName);
                    return null;
                }
                ipObjectName = Marshal.AllocHGlobal(nLength);
            }
            objObjectName = (Win32API.OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(ipObjectName, objObjectName.GetType());
 
            if (Is64Bits())
            {
                ipTemp = new IntPtr(Convert.ToInt64(objObjectName.Name.Buffer.ToString(), 10) >> 32);
            }
            else
            {
                ipTemp = objObjectName.Name.Buffer;
            }
 
            if (ipTemp != IntPtr.Zero)
            {
 
                var baTemp = new byte[nLength];
                try
                {
                    Marshal.Copy(ipTemp, baTemp, 0, nLength);
 
                    strObjectName = Marshal.PtrToStringUni(Is64Bits() ? new IntPtr(ipTemp.ToInt64()) : new IntPtr(ipTemp.ToInt32()));
                }
                catch (AccessViolationException)
                {
                    return null;
                }
                finally
                {
                    Marshal.FreeHGlobal(ipObjectName);
                    Win32API.CloseHandle(ipHandle);
                }
            }
 
            string path = GetRegularFileNameFromDevice(strObjectName);
            try
            {
                return path;
            }
            catch
            {
                return null;
            }
        }
 
        private static string GetRegularFileNameFromDevice(string strRawName)
        {
            string strFileName = strRawName;
            foreach (string strDrivePath in Environment.GetLogicalDrives())
            {
                var sbTargetPath = new StringBuilder(Win32API.MAX_PATH);
                if (Win32API.QueryDosDevice(strDrivePath.Substring(0, 2), sbTargetPath, Win32API.MAX_PATH) == 0)
                {
                    return strRawName;
                }
                string strTargetPath = sbTargetPath.ToString();
                if (strFileName.StartsWith(strTargetPath))
                {
                    strFileName = strFileName.Replace(strTargetPath, strDrivePath.Substring(0, 2));
                    break;
                }
            }
            return strFileName;
        }
 
        private static IEnumerable<Win32API.SYSTEM_HANDLE_INFORMATION> GetHandles(Process process)
        {
            var nHandleInfoSize = 0x10000;
            var ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
            var nLength = 0;
            IntPtr ipHandle;
 
            while (Win32API.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
            {
                nHandleInfoSize = nLength;
                Marshal.FreeHGlobal(ipHandlePointer);
                ipHandlePointer = Marshal.AllocHGlobal(nLength);
            }
 
            var baTemp = new byte[nLength];
            Marshal.Copy(ipHandlePointer, baTemp, 0, nLength);
 
            long lHandleCount;
            if (Is64Bits())
            {
                lHandleCount = Marshal.ReadInt64(ipHandlePointer);
                ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
            }
            else
            {
                lHandleCount = Marshal.ReadInt32(ipHandlePointer);
                ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
            }
 
            var lstHandles = new List<Win32API.SYSTEM_HANDLE_INFORMATION>();
 
            for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
            {
                var shHandle = new Win32API.SYSTEM_HANDLE_INFORMATION();
                if (Is64Bits())
                {
                    shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
                    ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 8);
                }
                else
                {
                    ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle));
                    shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
                }
                if (shHandle.ProcessID != process.Id) continue;
                lstHandles.Add(shHandle);
            }
            return lstHandles;
        }
 
        private static bool Is64Bits()
        {
            return Marshal.SizeOf(typeof(IntPtr)) == 8;
        }
 
        internal class Win32API
        {
            [DllImport("ntdll.dll")]
            public static extern int NtQueryObject(IntPtr ObjectHandle, int
                ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength,
                ref int returnLength);
 
            [DllImport("kernel32.dll", SetLastError = true)]
            public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);
 
            [DllImport("ntdll.dll")]
            public static extern uint NtQuerySystemInformation(int
                SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength,
                ref int returnLength);
 
            [DllImport("kernel32.dll")]
            public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
            [DllImport("kernel32.dll")]
            public static extern int CloseHandle(IntPtr hObject);
            [DllImport("kernel32.dll", SetLastError = true)]
            [return: MarshalAs(UnmanagedType.Bool)]
            public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
               ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
               uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
            [DllImport("kernel32.dll")]
            public static extern IntPtr GetCurrentProcess();
 
            public enum ObjectInformationClass
            {
                ObjectBasicInformation = 0,
                ObjectNameInformation = 1,
                ObjectTypeInformation = 2,
                ObjectAllTypesInformation = 3,
                ObjectHandleInformation = 4
            }
 
            [Flags]
            public enum ProcessAccessFlags : uint
            {
                All = 0x001F0FFF,
                Terminate = 0x00000001,
                CreateThread = 0x00000002,
                VMOperation = 0x00000008,
                VMRead = 0x00000010,
                VMWrite = 0x00000020,
                DupHandle = 0x00000040,
                SetInformation = 0x00000200,
                QueryInformation = 0x00000400,
                Synchronize = 0x00100000
            }
 
            [StructLayout(LayoutKind.Sequential)]
            public struct OBJECT_BASIC_INFORMATION
            { // Information Class 0
                public int Attributes;
                public int GrantedAccess;
                public int HandleCount;
                public int PointerCount;
                public int PagedPoolUsage;
                public int NonPagedPoolUsage;
                public int Reserved1;
                public int Reserved2;
                public int Reserved3;
                public int NameInformationLength;
                public int TypeInformationLength;
                public int SecurityDescriptorLength;
                public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
            }
 
            [StructLayout(LayoutKind.Sequential)]
            public struct OBJECT_TYPE_INFORMATION
            { // Information Class 2
                public UNICODE_STRING Name;
                public int ObjectCount;
                public int HandleCount;
                public int Reserved1;
                public int Reserved2;
                public int Reserved3;
                public int Reserved4;
                public int PeakObjectCount;
                public int PeakHandleCount;
                public int Reserved5;
                public int Reserved6;
                public int Reserved7;
                public int Reserved8;
                public int InvalidAttributes;
                public GENERIC_MAPPING GenericMapping;
                public int ValidAccess;
                public byte Unknown;
                public byte MaintainHandleDatabase;
                public int PoolType;
                public int PagedPoolUsage;
                public int NonPagedPoolUsage;
            }
 
            [StructLayout(LayoutKind.Sequential)]
            public struct OBJECT_NAME_INFORMATION
            { // Information Class 1
                public UNICODE_STRING Name;
            }
 
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct UNICODE_STRING
            {
                public ushort Length;
                public ushort MaximumLength;
                public IntPtr Buffer;
            }
 
            [StructLayout(LayoutKind.Sequential)]
            public struct GENERIC_MAPPING
            {
                public int GenericRead;
                public int GenericWrite;
                public int GenericExecute;
                public int GenericAll;
            }
 
            [StructLayout(LayoutKind.Sequential, Pack = 1)]
            public struct SYSTEM_HANDLE_INFORMATION
            { // Information Class 16
                public int ProcessID;
                public byte ObjectTypeNumber;
                public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
                public ushort Handle;
                public int Object_Pointer;
                public UInt32 GrantedAccess;
            }
 
            public const int MAX_PATH = 260;
            public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
            public const int DUPLICATE_SAME_ACCESS = 0x2;
            public const uint FILE_SEQUENTIAL_ONLY = 0x00000004;
        }
        #endregion
    }
}
  Permalink  
Comments
Sergey Alexandrovich Kryukov at 21-Jan-13 1:39am
   
And the problem of this solution is totally lost platform compatibility. This time, I did not vote, as it might work, but I would not agree to use such a system-dependent method...
—SA
Grasshopper.iics at 21-Jan-13 1:54am
   
This works fine under Windows 7, does not require to open another process ( handle.exe). All you be doing is using GetProcessesLockingFile() method. Solution to Non trivial problems can not be trivial. Even handle.exe shoots up loads of problems !
Sergey Alexandrovich Kryukov at 21-Jan-13 2:37am
   
I understand the benefit of such solution, but I explained some drawbacks. The major thing: this is not really needed.
You try to discourage using exception handling, but there is nothing better than that, I'm very much sure.
—SA
Grasshopper.iics at 21-Jan-13 3:17am
   
I am sorry, but I really don't get you here SA. I considered member to be relatively new in coding as he seems to be relatively new to cp. So I offered an easy way out. You voted me 1, stamping the answer not suitable. I pulled out some work from another project which I found some times back in stackoverflow. This solution works best, no matter what your file type is.
 
But you are now saying that the solution is complicated. By the mean time OP has not come back to comment on any solutions or clarifying any point.
 
Should we consider
1. To check if a file is locked, my first solution
2. To find the exact process and the name with file handle, my second method.
 
Where I used it?
 
I have controlled power point slide through some stuff like lasser , voice, hand movement, eye blink. I use this technique to find out the Handle (Int32 pointer to process) and then I pass the keys through Sendkey(). So please clarify if I am wrong in my either cases.
Sergey Alexandrovich Kryukov at 21-Jan-13 3:34am
   
You are right, to certain extent. Here are my arguments:
I also mentioned that you kill the platform compatibility. OP is the novice, but the code created now, can be used later, and these days I can see more and more used of different platforms, and non-Microsoft ones, via Mono. Incompatible.
 
I can see that you provide a lot more information on the file lock. But OP only needs to know: to work with the file or not. I'm pretty much sure this is the case. The goal is not writing a utility like HANDLE.EXE your know.
 
So, not that your solution is bad: I will strongly discourage using it. And I even stronger disagree with your assessment of exception approach. Nevertheless, after some thinking, I up-voted this solution, but by my 4. After all, you have serious knowledge on the subject; and the code is pretty impressive. I still cannot agree with your judgement.
 
—SA
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 1

First check if the file exists (File.Exists) if so try to open for write within try and catch block, if exception is generated then it is used by another process. However finding something through exception is not the best way!
  Permalink  
Comments
Sergey Alexandrovich Kryukov at 21-Jan-13 1:12am
   
You apparently have no idea of the essence of this problem. This is not as trivial. I voted 1, sorry.
—SA
Grasshopper.iics at 21-Jan-13 1:33am
   
As par your question, it was meant to be "if a file is being used by another process". Do let me understand if your question suggest anything in particular which is not answered? Say if you needed an information about "which process is currently accessing a file?"
 
If you had, I would have given you following solution which will display the process that is actually holding your file access ( Somethimes back I had done similar stuff, ref stackoverflow.com)
 
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Diagnostics;
using System.Text;
using System.Threading;
 
namespace FileLockInfo
{
public class Win32Processes
{
///
/// Return a list of processes that hold on the given file.
///

///
 
static void Main()
{
Console.WriteLine("C:\\Users\\Rupam\\Desktop\\Transaction Details.pdf");
 
GetProcessesLockingFile("C:\\Users\\Rupam\\Desktop\\Transaction Details - PayPal.pdf");
Console.Read();

}
public static List<Process> GetProcessesLockingFile(string filePath)
{
var procs = new List<Process>();
 
var processListSnapshot = Process.GetProcesses();
foreach (var process in processListSnapshot)
{
Console.WriteLine( process.ProcessName);
if (process.Id <= 4) { continue; } // system processes
var files = GetFilesLockedBy(process);
if (files.Contains(filePath))
{

Console.WriteLine("--------------->"+process.ProcessName);
procs.Add(process);
}
}
return procs;
}
 
///
/// Return a list of file locks held by the process.
///

public static List GetFilesLockedBy(Process process)
{
var outp = new List();
 
ThreadStart ts = delegate
{
try
{
outp = UnsafeGetFilesLockedBy(process);
}
catch { Ignore(); }
};
 
try
{
var t = new Thread(ts);
t.IsBackground = true;
t.Start();
if (!t.Join(250))
{
try
{
t.Interrupt();
t.Abort();
}
catch { Ignore(); }
}
}
catch { Ignore(); }
 
return outp;
}
 

#region Inner Workings
private static void Ignore() { }
private static List UnsafeGetFilesLockedBy(Process process)
{
try
{
var handles = GetHandles(process);
var files = new List();
 
foreach (var handle in handles)
{
var file = GetFilePath(handle, process);
if (file != null) files.Add(file);
}
 
return files;
}
catch
{
return new List();
}
}
 
const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
private static string GetFilePath(Win32API.SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process)
{
var ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
var objObjectName = new Win32API.OBJECT_NAME_INFORMATION();
var strObjectName = "";
var nLength = 0;
IntPtr ipTemp, ipHandle;
 
if (!Win32API.Duplicate
Rate this: bad
good
Please Sign up or sign in to vote.

Solution 2

By default, the file is opened for exclusive use, though only one file handle. If some other process opens it, you will have exception on the attempt to open it again. There is an option to open a file for multiple access, but this is rarely the case, and this is not the case you described.
 
You won't be able to close the file unless you terminate the "offending" process.
 
First of all, the similar question was asked here many times, and from this experience I know: in most cases the blocking process is your own process. You could have forgotten to dispose/close something in the same application. So, first of all, check it up. To explore this possibility, please see my past answer:
Clearing a Handle in C#[^].
 
In same cases, you really need to investigate which process holds which file. For this, I recommend using one utility from the Sysinternals Suite. This set of utilities (formerly from Winternals company, presently at Microsoft) is a must-have for any developer, please see:
http://technet.microsoft.com/en-us/sysinternals/bb842062[^],
http://technet.microsoft.com/en-us/sysinternals/bb545027[^].
 
The utility you need is "handle.exe", please see:
http://technet.microsoft.com/en-us/sysinternals/bb896655[^].
 
In your case, you use it with file name parameter:
handle.exe <file_name>
 
This utility will scan all kinds of handles, not just file handles. For file, it will scan all file handles matching the file name (so it does not have to be a full path name) and return information sufficient to identify each process, including its pid. So, if you need more information on a process in question, you can also use other Sysinternals utilities, in particular, its Process Explorer:
http://technet.microsoft.com/en-us/sysinternals/bb896653[^].
 
[EDIT #1]
 
Now, if you simply want to check is the file is already open by some process at the given moment (but why?), I usually advise a very simple thing. It's a good idea to use offensive programming instead of defensive. You can simply work with the file as if it is not blocked. Sandwich this part of code in try-catch-finally block. If the block throws the code into catch part, it means the file was used by another process. Doing so is absolutely safe.
 
Doing something else is very difficult and hardly can justify the effort. Besides, it is heavily system-dependent and, of course, will require P/Invoke. You will totally kill the platform independence of your code it you try to do it.
 
[EDIT #2]
 
In principle, another option could be running handle.exe via System.Diagnostics.Process.Start. You will also need to redirect StandardOutput of your process, to capture is and extract the result of diagnostics. The redirection sample can be found here: http://msdn.microsoft.com/en-us/library/system.diagnostics.process.standardoutput.aspx[^].
 
However, this approach is far from being elegant. And if you need to deploy your product, it would be some problem (legal, technical… third-party is third-party).
 
Good luck,
—SA
  Permalink  
v3

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

  Print Answers RSS
0 Maciej Los 315
1 OriginalGriff 273
2 Aajmot Sk 224
3 Marcin Kozub 210
4 Richard MacCutchan 200
0 OriginalGriff 7,853
1 Sergey Alexandrovich Kryukov 7,107
2 DamithSL 5,604
3 Manas Bhardwaj 4,986
4 Maciej Los 4,790


Advertise | Privacy | Mobile
Web02 | 2.8.1411023.1 | Last Updated 21 Jan 2013
Copyright © CodeProject, 1999-2014
All Rights Reserved. Terms of Service
Layout: fixed | fluid

CodeProject, 503-250 Ferrand Drive Toronto Ontario, M3C 3G8 Canada +1 416-849-8900 x 100