Advertisement
Guest User

CSharp detect process that handle file

a guest
Feb 18th, 2013
2,036
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 15.50 KB | None | 0 0
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.InteropServices;
  4. using System.Diagnostics;
  5. using System.Text;
  6. using System.Threading;
  7.  
  8. namespace FileLockInfo
  9. {
  10.     public class Win32Processes
  11.     {
  12.         /// <summary>
  13.         /// Return a list of processes that hold on the given file.
  14.         /// </summary>
  15.         public static List<Process> GetProcessesLockingFile(string filePath)
  16.         {
  17.             var procs = new List<Process>();
  18.  
  19.             var processListSnapshot = Process.GetProcesses();
  20.             foreach (var process in processListSnapshot)
  21.             {
  22.                 if (process.Id <= 4) { continue; } // system processes
  23.                 var files = GetFilesLockedBy(process);
  24.                 if (files.Contains(filePath)) procs.Add(process);
  25.             }
  26.             return procs;
  27.         }
  28.  
  29.         /// <summary>
  30.         /// Return a list of file locks held by the process.
  31.         /// </summary>
  32.         public static List<string> GetFilesLockedBy(Process process)
  33.         {
  34.             var outp = new List<string>();
  35.  
  36.             ThreadStart ts = delegate
  37.             {
  38.                 try
  39.                 {
  40.                     outp = UnsafeGetFilesLockedBy(process);
  41.                 }
  42.                 catch { Ignore(); }
  43.             };
  44.  
  45.             try
  46.             {
  47.                 var t = new Thread(ts);
  48.                 t.IsBackground = true;
  49.                 t.Start();
  50.                 if (!t.Join(250))
  51.                 {
  52.                     try
  53.                     {
  54.                         t.Interrupt();
  55.                         t.Abort();
  56.                     }
  57.                     catch { Ignore(); }
  58.                 }
  59.             }
  60.             catch { Ignore(); }
  61.  
  62.             return outp;
  63.         }
  64.  
  65.  
  66.         #region Inner Workings
  67.         private static void Ignore() { }
  68.         private static List<string> UnsafeGetFilesLockedBy(Process process)
  69.         {
  70.             try
  71.             {
  72.                 var handles = GetHandles(process);
  73.                 var files = new List<string>();
  74.  
  75.                 foreach (var handle in handles)
  76.                 {
  77.                     var file = GetFilePath(handle, process);
  78.                     if (file != null) files.Add(file);
  79.                 }
  80.  
  81.                 return files;
  82.             }
  83.             catch
  84.             {
  85.                 return new List<string>();
  86.             }
  87.         }
  88.  
  89.         const int CNST_SYSTEM_HANDLE_INFORMATION = 16;
  90.         private static string GetFilePath(Win32API.SYSTEM_HANDLE_INFORMATION systemHandleInformation, Process process)
  91.         {
  92.             var ipProcessHwnd = Win32API.OpenProcess(Win32API.ProcessAccessFlags.All, false, process.Id);
  93.             var objBasic = new Win32API.OBJECT_BASIC_INFORMATION();
  94.             var objObjectType = new Win32API.OBJECT_TYPE_INFORMATION();
  95.             var objObjectName = new Win32API.OBJECT_NAME_INFORMATION();
  96.             var strObjectName = "";
  97.             var nLength = 0;
  98.             IntPtr ipTemp, ipHandle;
  99.  
  100.             if (!Win32API.DuplicateHandle(ipProcessHwnd, systemHandleInformation.Handle, Win32API.GetCurrentProcess(), out ipHandle, 0, false, Win32API.DUPLICATE_SAME_ACCESS))
  101.                 return null;
  102.  
  103.             IntPtr ipBasic = Marshal.AllocHGlobal(Marshal.SizeOf(objBasic));
  104.             Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectBasicInformation, ipBasic, Marshal.SizeOf(objBasic), ref nLength);
  105.             objBasic = (Win32API.OBJECT_BASIC_INFORMATION)Marshal.PtrToStructure(ipBasic, objBasic.GetType());
  106.             Marshal.FreeHGlobal(ipBasic);
  107.  
  108.             IntPtr ipObjectType = Marshal.AllocHGlobal(objBasic.TypeInformationLength);
  109.             nLength = objBasic.TypeInformationLength;
  110.             // this one never locks...
  111.             while ((uint)(Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectTypeInformation, ipObjectType, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
  112.             {
  113.                 if (nLength == 0)
  114.                 {
  115.                     Console.WriteLine("nLength returned at zero! ");
  116.                     return null;
  117.                 }
  118.                 Marshal.FreeHGlobal(ipObjectType);
  119.                 ipObjectType = Marshal.AllocHGlobal(nLength);
  120.             }
  121.  
  122.             objObjectType = (Win32API.OBJECT_TYPE_INFORMATION)Marshal.PtrToStructure(ipObjectType, objObjectType.GetType());
  123.             if (Is64Bits())
  124.             {
  125.                 ipTemp = new IntPtr(Convert.ToInt64(objObjectType.Name.Buffer.ToString(), 10) >> 32);
  126.             }
  127.             else
  128.             {
  129.                 ipTemp = objObjectType.Name.Buffer;
  130.             }
  131.  
  132.             var strObjectTypeName = Marshal.PtrToStringUni(ipTemp, objObjectType.Name.Length >> 1);
  133.             Marshal.FreeHGlobal(ipObjectType);
  134.             if (strObjectTypeName != "File")
  135.                 return null;
  136.  
  137.             nLength = objBasic.NameInformationLength;
  138.  
  139.             var ipObjectName = Marshal.AllocHGlobal(nLength);
  140.  
  141.             // ...this call sometimes hangs. Is a Windows error.
  142.             while ((uint)(Win32API.NtQueryObject(ipHandle, (int)Win32API.ObjectInformationClass.ObjectNameInformation, ipObjectName, nLength, ref nLength)) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
  143.             {
  144.                 Marshal.FreeHGlobal(ipObjectName);
  145.                 if (nLength == 0)
  146.                 {
  147.                     Console.WriteLine("nLength returned at zero! " + strObjectTypeName);
  148.                     return null;
  149.                 }
  150.                 ipObjectName = Marshal.AllocHGlobal(nLength);
  151.             }
  152.             objObjectName = (Win32API.OBJECT_NAME_INFORMATION)Marshal.PtrToStructure(ipObjectName, objObjectName.GetType());
  153.  
  154.             if (Is64Bits())
  155.             {
  156.                 ipTemp = new IntPtr(Convert.ToInt64(objObjectName.Name.Buffer.ToString(), 10) >> 32);
  157.             }
  158.             else
  159.             {
  160.                 ipTemp = objObjectName.Name.Buffer;
  161.             }
  162.  
  163.             if (ipTemp != IntPtr.Zero)
  164.             {
  165.  
  166.                 var baTemp = new byte[nLength];
  167.                 try
  168.                 {
  169.                     Marshal.Copy(ipTemp, baTemp, 0, nLength);
  170.  
  171.                     strObjectName = Marshal.PtrToStringUni(Is64Bits() ? new IntPtr(ipTemp.ToInt64()) : new IntPtr(ipTemp.ToInt32()));
  172.                 }
  173.                 catch (AccessViolationException)
  174.                 {
  175.                     return null;
  176.                 }
  177.                 finally
  178.                 {
  179.                     Marshal.FreeHGlobal(ipObjectName);
  180.                     Win32API.CloseHandle(ipHandle);
  181.                 }
  182.             }
  183.  
  184.             string path = GetRegularFileNameFromDevice(strObjectName);
  185.             try
  186.             {
  187.                 return path;
  188.             }
  189.             catch
  190.             {
  191.                 return null;
  192.             }
  193.         }
  194.  
  195.         private static string GetRegularFileNameFromDevice(string strRawName)
  196.         {
  197.             string strFileName = strRawName;
  198.             foreach (string strDrivePath in Environment.GetLogicalDrives())
  199.             {
  200.                 var sbTargetPath = new StringBuilder(Win32API.MAX_PATH);
  201.                 if (Win32API.QueryDosDevice(strDrivePath.Substring(0, 2), sbTargetPath, Win32API.MAX_PATH) == 0)
  202.                 {
  203.                     return strRawName;
  204.                 }
  205.                 string strTargetPath = sbTargetPath.ToString();
  206.                 if (strFileName.StartsWith(strTargetPath))
  207.                 {
  208.                     strFileName = strFileName.Replace(strTargetPath, strDrivePath.Substring(0, 2));
  209.                     break;
  210.                 }
  211.             }
  212.             return strFileName;
  213.         }
  214.  
  215.         private static IEnumerable<Win32API.SYSTEM_HANDLE_INFORMATION> GetHandles(Process process)
  216.         {
  217.             var nHandleInfoSize = 0x10000;
  218.             var ipHandlePointer = Marshal.AllocHGlobal(nHandleInfoSize);
  219.             var nLength = 0;
  220.             IntPtr ipHandle;
  221.  
  222.             while (Win32API.NtQuerySystemInformation(CNST_SYSTEM_HANDLE_INFORMATION, ipHandlePointer, nHandleInfoSize, ref nLength) == Win32API.STATUS_INFO_LENGTH_MISMATCH)
  223.             {
  224.                 nHandleInfoSize = nLength;
  225.                 Marshal.FreeHGlobal(ipHandlePointer);
  226.                 ipHandlePointer = Marshal.AllocHGlobal(nLength);
  227.             }
  228.  
  229.             var baTemp = new byte[nLength];
  230.             Marshal.Copy(ipHandlePointer, baTemp, 0, nLength);
  231.  
  232.             long lHandleCount;
  233.             if (Is64Bits())
  234.             {
  235.                 lHandleCount = Marshal.ReadInt64(ipHandlePointer);
  236.                 ipHandle = new IntPtr(ipHandlePointer.ToInt64() + 8);
  237.             }
  238.             else
  239.             {
  240.                 lHandleCount = Marshal.ReadInt32(ipHandlePointer);
  241.                 ipHandle = new IntPtr(ipHandlePointer.ToInt32() + 4);
  242.             }
  243.  
  244.             var lstHandles = new List<Win32API.SYSTEM_HANDLE_INFORMATION>();
  245.  
  246.             for (long lIndex = 0; lIndex < lHandleCount; lIndex++)
  247.             {
  248.                 var shHandle = new Win32API.SYSTEM_HANDLE_INFORMATION();
  249.                 if (Is64Bits())
  250.                 {
  251.                     shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
  252.                     ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle) + 8);
  253.                 }
  254.                 else
  255.                 {
  256.                     ipHandle = new IntPtr(ipHandle.ToInt64() + Marshal.SizeOf(shHandle));
  257.                     shHandle = (Win32API.SYSTEM_HANDLE_INFORMATION)Marshal.PtrToStructure(ipHandle, shHandle.GetType());
  258.                 }
  259.                 if (shHandle.ProcessID != process.Id) continue;
  260.                 lstHandles.Add(shHandle);
  261.             }
  262.             return lstHandles;
  263.         }
  264.  
  265.         private static bool Is64Bits()
  266.         {
  267.             return Marshal.SizeOf(typeof(IntPtr)) == 8;
  268.         }
  269.  
  270.         internal class Win32API
  271.         {
  272.             [DllImport("ntdll.dll")]
  273.             public static extern int NtQueryObject(IntPtr ObjectHandle, int
  274.                 ObjectInformationClass, IntPtr ObjectInformation, int ObjectInformationLength,
  275.                 ref int returnLength);
  276.  
  277.             [DllImport("kernel32.dll", SetLastError = true)]
  278.             public static extern uint QueryDosDevice(string lpDeviceName, StringBuilder lpTargetPath, int ucchMax);
  279.  
  280.             [DllImport("ntdll.dll")]
  281.             public static extern uint NtQuerySystemInformation(int
  282.                 SystemInformationClass, IntPtr SystemInformation, int SystemInformationLength,
  283.                 ref int returnLength);
  284.  
  285.             [DllImport("kernel32.dll")]
  286.             public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwProcessId);
  287.             [DllImport("kernel32.dll")]
  288.             public static extern int CloseHandle(IntPtr hObject);
  289.             [DllImport("kernel32.dll", SetLastError = true)]
  290.             [return: MarshalAs(UnmanagedType.Bool)]
  291.             public static extern bool DuplicateHandle(IntPtr hSourceProcessHandle,
  292.                ushort hSourceHandle, IntPtr hTargetProcessHandle, out IntPtr lpTargetHandle,
  293.                uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwOptions);
  294.             [DllImport("kernel32.dll")]
  295.             public static extern IntPtr GetCurrentProcess();
  296.  
  297.             public enum ObjectInformationClass
  298.             {
  299.                 ObjectBasicInformation = 0,
  300.                 ObjectNameInformation = 1,
  301.                 ObjectTypeInformation = 2,
  302.                 ObjectAllTypesInformation = 3,
  303.                 ObjectHandleInformation = 4
  304.             }
  305.  
  306.             [Flags]
  307.             public enum ProcessAccessFlags : uint
  308.             {
  309.                 All = 0x001F0FFF,
  310.                 Terminate = 0x00000001,
  311.                 CreateThread = 0x00000002,
  312.                 VMOperation = 0x00000008,
  313.                 VMRead = 0x00000010,
  314.                 VMWrite = 0x00000020,
  315.                 DupHandle = 0x00000040,
  316.                 SetInformation = 0x00000200,
  317.                 QueryInformation = 0x00000400,
  318.                 Synchronize = 0x00100000
  319.             }
  320.  
  321.             [StructLayout(LayoutKind.Sequential)]
  322.             public struct OBJECT_BASIC_INFORMATION
  323.             { // Information Class 0
  324.                 public int Attributes;
  325.                 public int GrantedAccess;
  326.                 public int HandleCount;
  327.                 public int PointerCount;
  328.                 public int PagedPoolUsage;
  329.                 public int NonPagedPoolUsage;
  330.                 public int Reserved1;
  331.                 public int Reserved2;
  332.                 public int Reserved3;
  333.                 public int NameInformationLength;
  334.                 public int TypeInformationLength;
  335.                 public int SecurityDescriptorLength;
  336.                 public System.Runtime.InteropServices.ComTypes.FILETIME CreateTime;
  337.             }
  338.  
  339.             [StructLayout(LayoutKind.Sequential)]
  340.             public struct OBJECT_TYPE_INFORMATION
  341.             { // Information Class 2
  342.                 public UNICODE_STRING Name;
  343.                 public int ObjectCount;
  344.                 public int HandleCount;
  345.                 public int Reserved1;
  346.                 public int Reserved2;
  347.                 public int Reserved3;
  348.                 public int Reserved4;
  349.                 public int PeakObjectCount;
  350.                 public int PeakHandleCount;
  351.                 public int Reserved5;
  352.                 public int Reserved6;
  353.                 public int Reserved7;
  354.                 public int Reserved8;
  355.                 public int InvalidAttributes;
  356.                 public GENERIC_MAPPING GenericMapping;
  357.                 public int ValidAccess;
  358.                 public byte Unknown;
  359.                 public byte MaintainHandleDatabase;
  360.                 public int PoolType;
  361.                 public int PagedPoolUsage;
  362.                 public int NonPagedPoolUsage;
  363.             }
  364.  
  365.             [StructLayout(LayoutKind.Sequential)]
  366.             public struct OBJECT_NAME_INFORMATION
  367.             { // Information Class 1
  368.                 public UNICODE_STRING Name;
  369.             }
  370.  
  371.             [StructLayout(LayoutKind.Sequential, Pack = 1)]
  372.             public struct UNICODE_STRING
  373.             {
  374.                 public ushort Length;
  375.                 public ushort MaximumLength;
  376.                 public IntPtr Buffer;
  377.             }
  378.  
  379.             [StructLayout(LayoutKind.Sequential)]
  380.             public struct GENERIC_MAPPING
  381.             {
  382.                 public int GenericRead;
  383.                 public int GenericWrite;
  384.                 public int GenericExecute;
  385.                 public int GenericAll;
  386.             }
  387.  
  388.             [StructLayout(LayoutKind.Sequential, Pack = 1)]
  389.             public struct SYSTEM_HANDLE_INFORMATION
  390.             { // Information Class 16
  391.                 public int ProcessID;
  392.                 public byte ObjectTypeNumber;
  393.                 public byte Flags; // 0x01 = PROTECT_FROM_CLOSE, 0x02 = INHERIT
  394.                 public ushort Handle;
  395.                 public int Object_Pointer;
  396.                 public UInt32 GrantedAccess;
  397.             }
  398.  
  399.             public const int MAX_PATH = 260;
  400.             public const uint STATUS_INFO_LENGTH_MISMATCH = 0xC0000004;
  401.             public const int DUPLICATE_SAME_ACCESS = 0x2;
  402.             public const uint FILE_SEQUENTIAL_ONLY = 0x00000004;
  403.         }
  404.         #endregion
  405.     }
  406. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement