在Windows中,如何确定(使用C#)锁定文件的进程?
第三方工具很有帮助,但不是我想要的.
这个问题有一个原始答案,现在已超过7年.该代码保存在https://gist.github.com/ieb/2290426 如果您出于某种原因需要使用Windows XP,则此旧版本可能适合您.
一个更好的答案是如何检查文件锁定?
我在下面复制了Eric J的答案(using
添加了语句,类和方法名称与此处的旧代码相匹配)请注意,对此答案的评论可能已过时.
使用如下:
Listlocks = Win32Processes.GetProcessesLockingFile(@"C:\Hello.docx");
码:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; namespace FileLockInfo { public static class Win32Processes { ////// Find out what process(es) have a lock on the specified file. /// /// Path of the file. ///Processes locking the file ///See also: /// http://msdn.microsoft.com/en-us/library/windows/desktop/aa373661(v=vs.85).aspx /// http://wyupdate.googlecode.com/svn-history/r401/trunk/frmFilesInUse.cs (no copyright in code at time of viewing) /// public static ListGetProcessesLockingFile(string path) { uint handle; string key = Guid.NewGuid().ToString(); int res = RmStartSession(out handle, 0, key); if (res != 0) throw new Exception("Could not begin restart session. Unable to determine file locker."); try { const int MORE_DATA = 234; uint pnProcInfoNeeded, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone; string[] resources = {path}; // Just checking on one resource. res = RmRegisterResources(handle, (uint) resources.Length, resources, 0, null, 0, null); if (res != 0) throw new Exception("Could not register resource."); //Note: there's a race condition here -- the first call to RmGetList() returns // the total number of process. However, when we call RmGetList() again to get // the actual processes this number may have increased. res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons); if (res == MORE_DATA) { return EnumerateProcesses(pnProcInfoNeeded, handle, lpdwRebootReasons); } else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result."); } finally { RmEndSession(handle); } return new List (); } [StructLayout(LayoutKind.Sequential)] public struct RM_UNIQUE_PROCESS { public int dwProcessId; public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime; } const int RmRebootReasonNone = 0; const int CCH_RM_MAX_APP_NAME = 255; const int CCH_RM_MAX_SVC_NAME = 63; public enum RM_APP_TYPE { RmUnknownApp = 0, RmMainWindow = 1, RmOtherWindow = 2, RmService = 3, RmExplorer = 4, RmConsole = 5, RmCritical = 1000 } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] public struct RM_PROCESS_INFO { public RM_UNIQUE_PROCESS Process; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] public string strAppName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] public string strServiceShortName; public RM_APP_TYPE ApplicationType; public uint AppStatus; public uint TSSessionId; [MarshalAs(UnmanagedType.Bool)] public bool bRestartable; } [DllImport("rstrtmgr.dll", CharSet = CharSet.Unicode)] static extern int RmRegisterResources(uint pSessionHandle, uint nFiles, string[] rgsFilenames, uint nApplications, [In] RM_UNIQUE_PROCESS[] rgApplications, uint nServices, string[] rgsServiceNames); [DllImport("rstrtmgr.dll", CharSet = CharSet.Auto)] static extern int RmStartSession(out uint pSessionHandle, int dwSessionFlags, string strSessionKey); [DllImport("rstrtmgr.dll")] static extern int RmEndSession(uint pSessionHandle); [DllImport("rstrtmgr.dll")] static extern int RmGetList(uint dwSessionHandle, out uint pnProcInfoNeeded, ref uint pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref uint lpdwRebootReasons); private static List EnumerateProcesses(uint pnProcInfoNeeded, uint handle, uint lpdwRebootReasons) { var processes = new List (10); // Create an array to store the process results var processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded]; var pnProcInfo = pnProcInfoNeeded; // Get the list var res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons); if (res != 0) throw new Exception("Could not list processes locking resource."); for (int i = 0; i < pnProcInfo; i++) { try { processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId)); } catch (ArgumentException) { } // catch the error -- in case the process is no longer running } return processes; } } }
我在这里找到的代码, https://vmccontroller.svn.codeplex.com/svn/VmcController/VmcServices/DetectOpenFiles.cs
对我来说比Iain提供的代码更好.伊恩的代码似乎正在获得自己的锁定.这是我上面修改的代码的略微修改版本,以返回锁定文件的字符串路径而不是FileSystemInfo对象,
using System; using System.Collections.Generic; //using System.EnterpriseServices; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; using System.Security.Permissions; using System.Text; using System.Threading; using Microsoft.Win32.SafeHandles; namespace Crmc.Core.BuildTasks { using System.Diagnostics; using System.Linq; #region ENUMs internal enum NT_STATUS { STATUS_SUCCESS = 0x00000000, STATUS_BUFFER_OVERFLOW = unchecked((int)0x80000005L), STATUS_INFO_LENGTH_MISMATCH = unchecked((int)0xC0000004L) } internal enum SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, SystemProcessInformation = 5, SystemProcessorPerformanceInformation = 8, SystemHandleInformation = 16, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45 } internal enum OBJECT_INFORMATION_CLASS { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } [Flags] internal enum ProcessAccessRights { PROCESS_DUP_HANDLE = 0x00000040 } [Flags] internal enum DuplicateHandleOptions { DUPLICATE_CLOSE_SOURCE = 0x1, DUPLICATE_SAME_ACCESS = 0x2 } #endregion [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] internal sealed class SafeObjectHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeObjectHandle() : base(true) { } internal SafeObjectHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { base.SetHandle(preexistingHandle); } protected override bool ReleaseHandle() { return NativeMethods.CloseHandle(base.handle); } } [SecurityPermission(SecurityAction.LinkDemand, UnmanagedCode = true)] internal sealed class SafeProcessHandle : SafeHandleZeroOrMinusOneIsInvalid { private SafeProcessHandle() : base(true) { } internal SafeProcessHandle(IntPtr preexistingHandle, bool ownsHandle) : base(ownsHandle) { base.SetHandle(preexistingHandle); } protected override bool ReleaseHandle() { return NativeMethods.CloseHandle(base.handle); } } #region Native Methods internal static class NativeMethods { [DllImport("ntdll.dll")] internal static extern NT_STATUS NtQuerySystemInformation( [In] SYSTEM_INFORMATION_CLASS SystemInformationClass, [In] IntPtr SystemInformation, [In] int SystemInformationLength, [Out] out int ReturnLength); [DllImport("ntdll.dll")] internal static extern NT_STATUS NtQueryObject( [In] IntPtr Handle, [In] OBJECT_INFORMATION_CLASS ObjectInformationClass, [In] IntPtr ObjectInformation, [In] int ObjectInformationLength, [Out] out int ReturnLength); [DllImport("kernel32.dll", SetLastError = true)] internal static extern SafeProcessHandle OpenProcess( [In] ProcessAccessRights dwDesiredAccess, [In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, [In] int dwProcessId); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool DuplicateHandle( [In] IntPtr hSourceProcessHandle, [In] IntPtr hSourceHandle, [In] IntPtr hTargetProcessHandle, [Out] out SafeObjectHandle lpTargetHandle, [In] int dwDesiredAccess, [In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, [In] DuplicateHandleOptions dwOptions); [DllImport("kernel32.dll")] internal static extern IntPtr GetCurrentProcess(); [DllImport("kernel32.dll", SetLastError = true)] internal static extern int GetProcessId( [In] IntPtr Process); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle( [In] IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] internal static extern int QueryDosDevice( [In] string lpDeviceName, [Out] StringBuilder lpTargetPath, [In] int ucchMax); } #endregion //[ComVisible(true), EventTrackingEnabled(true)] public class DetectOpenFiles// : ServicedComponent { private static DictionarydeviceMap; private const string networkDevicePrefix = "\\Device\\LanmanRedirector\\"; private const int MAX_PATH = 260; private enum SystemHandleType { OB_TYPE_UNKNOWN = 0, OB_TYPE_TYPE = 1, OB_TYPE_DIRECTORY, OB_TYPE_SYMBOLIC_LINK, OB_TYPE_TOKEN, OB_TYPE_PROCESS, OB_TYPE_THREAD, OB_TYPE_UNKNOWN_7, OB_TYPE_EVENT, OB_TYPE_EVENT_PAIR, OB_TYPE_MUTANT, OB_TYPE_UNKNOWN_11, OB_TYPE_SEMAPHORE, OB_TYPE_TIMER, OB_TYPE_PROFILE, OB_TYPE_WINDOW_STATION, OB_TYPE_DESKTOP, OB_TYPE_SECTION, OB_TYPE_KEY, OB_TYPE_PORT, OB_TYPE_WAITABLE_PORT, OB_TYPE_UNKNOWN_21, OB_TYPE_UNKNOWN_22, OB_TYPE_UNKNOWN_23, OB_TYPE_UNKNOWN_24, //OB_TYPE_CONTROLLER, //OB_TYPE_DEVICE, //OB_TYPE_DRIVER, OB_TYPE_IO_COMPLETION, OB_TYPE_FILE }; private const int handleTypeTokenCount = 27; private static readonly string[] handleTypeTokens = new string[] { "", "", "Directory", "SymbolicLink", "Token", "Process", "Thread", "Unknown7", "Event", "EventPair", "Mutant", "Unknown11", "Semaphore", "Timer", "Profile", "WindowStation", "Desktop", "Section", "Key", "Port", "WaitablePort", "Unknown21", "Unknown22", "Unknown23", "Unknown24", "IoCompletion", "File" }; [StructLayout(LayoutKind.Sequential)] private struct SYSTEM_HANDLE_ENTRY { public int OwnerPid; public byte ObjectType; public byte HandleFlags; public short HandleValue; public int ObjectPointer; public int AccessMask; } /// /// Gets the open files enumerator. /// /// The process id. ///public static IEnumerable GetOpenFilesEnumerator(int processId) { return new OpenFiles(processId); } public static List GetProcessesUsingFile(string fName) { List result = new List (); foreach (var p in Process.GetProcesses()) { try { if (DetectOpenFiles.GetOpenFilesEnumerator(p.Id).Contains(fName)) { result.Add(p); } } catch { }//some processes will fail } return result; } private sealed class OpenFiles : IEnumerable { private readonly int processId; internal OpenFiles(int processId) { this.processId = processId; } #region IEnumerable Members public IEnumerator GetEnumerator() { NT_STATUS ret; int length = 0x10000; // Loop, probing for required memory. do { IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees that the address of the allocated // memory is actually assigned to ptr if an // asynchronous exception occurs. ptr = Marshal.AllocHGlobal(length); } int returnLength; ret = NativeMethods.NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out returnLength); if (ret == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { // Round required memory up to the nearest 64KB boundary. length = ((returnLength + 0xffff) & ~0xffff); } else if (ret == NT_STATUS.STATUS_SUCCESS) { int handleCount = Marshal.ReadInt32(ptr); int offset = sizeof(int); int size = Marshal.SizeOf(typeof(SYSTEM_HANDLE_ENTRY)); for (int i = 0; i < handleCount; i++) { SYSTEM_HANDLE_ENTRY handleEntry = (SYSTEM_HANDLE_ENTRY)Marshal.PtrToStructure((IntPtr)((int)ptr + offset), typeof(SYSTEM_HANDLE_ENTRY)); if (handleEntry.OwnerPid == processId) { IntPtr handle = (IntPtr)handleEntry.HandleValue; SystemHandleType handleType; if (GetHandleType(handle, handleEntry.OwnerPid, out handleType) && handleType == SystemHandleType.OB_TYPE_FILE) { string devicePath; if (GetFileNameFromHandle(handle, handleEntry.OwnerPid, out devicePath)) { string dosPath; if (ConvertDevicePathToDosPath(devicePath, out dosPath)) { if (File.Exists(dosPath)) { yield return dosPath; // return new FileInfo(dosPath); } else if (Directory.Exists(dosPath)) { yield return dosPath; // new DirectoryInfo(dosPath); } } } } } offset += size; } } } finally { // CER guarantees that the allocated memory is freed, // if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); //sw.Flush(); //sw.Close(); } } while (ret == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH); } #endregion #region IEnumerable Members System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion } #region Private Members private static bool GetFileNameFromHandle(IntPtr handle, int processId, out string fileName) { IntPtr currentProcess = NativeMethods.GetCurrentProcess(); bool remote = (processId != NativeMethods.GetProcessId(currentProcess)); SafeProcessHandle processHandle = null; SafeObjectHandle objectHandle = null; try { if (remote) { processHandle = NativeMethods.OpenProcess(ProcessAccessRights.PROCESS_DUP_HANDLE, true, processId); if (NativeMethods.DuplicateHandle(processHandle.DangerousGetHandle(), handle, currentProcess, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) { handle = objectHandle.DangerousGetHandle(); } } return GetFileNameFromHandle(handle, out fileName, 200); } finally { if (remote) { if (processHandle != null) { processHandle.Close(); } if (objectHandle != null) { objectHandle.Close(); } } } } private static bool GetFileNameFromHandle(IntPtr handle, out string fileName, int wait) { using (FileNameFromHandleState f = new FileNameFromHandleState(handle)) { ThreadPool.QueueUserWorkItem(new WaitCallback(GetFileNameFromHandle), f); if (f.WaitOne(wait)) { fileName = f.FileName; return f.RetValue; } else { fileName = string.Empty; return false; } } } private class FileNameFromHandleState : IDisposable { private ManualResetEvent _mr; private IntPtr _handle; private string _fileName; private bool _retValue; public IntPtr Handle { get { return _handle; } } public string FileName { get { return _fileName; } set { _fileName = value; } } public bool RetValue { get { return _retValue; } set { _retValue = value; } } public FileNameFromHandleState(IntPtr handle) { _mr = new ManualResetEvent(false); this._handle = handle; } public bool WaitOne(int wait) { return _mr.WaitOne(wait, false); } public void Set() { try { _mr.Set(); } catch{} } #region IDisposable Members public void Dispose() { if (_mr != null) _mr.Close(); } #endregion } private static void GetFileNameFromHandle(object state) { FileNameFromHandleState s = (FileNameFromHandleState)state; string fileName; s.RetValue = GetFileNameFromHandle(s.Handle, out fileName); s.FileName = fileName; s.Set(); } private static bool GetFileNameFromHandle(IntPtr handle, out string fileName) { IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { int length = 0x200; // 512 bytes RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees the assignment of the allocated // memory address to ptr, if an ansynchronous exception // occurs. ptr = Marshal.AllocHGlobal(length); } NT_STATUS ret = NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); if (ret == NT_STATUS.STATUS_BUFFER_OVERFLOW) { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { // CER guarantees that the previous allocation is freed, // and that the newly allocated memory address is // assigned to ptr if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); ptr = Marshal.AllocHGlobal(length); } ret = NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length); } if (ret == NT_STATUS.STATUS_SUCCESS) { fileName = Marshal.PtrToStringUni((IntPtr)((int)ptr + 8), (length - 9) / 2); return fileName.Length != 0; } } finally { // CER guarantees that the allocated memory is freed, // if an asynchronous exception occurs. Marshal.FreeHGlobal(ptr); } fileName = string.Empty; return false; } private static bool GetHandleType(IntPtr handle, int processId, out SystemHandleType handleType) { string token = GetHandleTypeToken(handle, processId); return GetHandleTypeFromToken(token, out handleType); } private static bool GetHandleType(IntPtr handle, out SystemHandleType handleType) { string token = GetHandleTypeToken(handle); return GetHandleTypeFromToken(token, out handleType); } private static bool GetHandleTypeFromToken(string token, out SystemHandleType handleType) { for (int i = 1; i < handleTypeTokenCount; i++) { if (handleTypeTokens[i] == token) { handleType = (SystemHandleType)i; return true; } } handleType = SystemHandleType.OB_TYPE_UNKNOWN; return false; } private static string GetHandleTypeToken(IntPtr handle, int processId) { IntPtr currentProcess = NativeMethods.GetCurrentProcess(); bool remote = (processId != NativeMethods.GetProcessId(currentProcess)); SafeProcessHandle processHandle = null; SafeObjectHandle objectHandle = null; try { if (remote) { processHandle = NativeMethods.OpenProcess(ProcessAccessRights.PROCESS_DUP_HANDLE, true, processId); if (NativeMethods.DuplicateHandle(processHandle.DangerousGetHandle(), handle, currentProcess, out objectHandle, 0, false, DuplicateHandleOptions.DUPLICATE_SAME_ACCESS)) { handle = objectHandle.DangerousGetHandle(); } } return GetHandleTypeToken(handle); } finally { if (remote) { if (processHandle != null) { processHandle.Close(); } if (objectHandle != null) { objectHandle.Close(); } } } } private static string GetHandleTypeToken(IntPtr handle) { int length; NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, IntPtr.Zero, 0, out length); IntPtr ptr = IntPtr.Zero; RuntimeHelpers.PrepareConstrainedRegions(); try { RuntimeHelpers.PrepareConstrainedRegions(); try { } finally { ptr = Marshal.AllocHGlobal(length); } if (NativeMethods.NtQueryObject(handle, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, ptr, length, out length) == NT_STATUS.STATUS_SUCCESS) { return Marshal.PtrToStringUni((IntPtr)((int)ptr + 0x60)); } } finally { Marshal.FreeHGlobal(ptr); } return string.Empty; } private static bool ConvertDevicePathToDosPath(string devicePath, out string dosPath) { EnsureDeviceMap(); int i = devicePath.Length; while (i > 0 && (i = devicePath.LastIndexOf('\\', i - 1)) != -1) { string drive; if (deviceMap.TryGetValue(devicePath.Substring(0, i), out drive)) { dosPath = string.Concat(drive, devicePath.Substring(i)); return dosPath.Length != 0; } } dosPath = string.Empty; return false; } private static void EnsureDeviceMap() { if (deviceMap == null) { Dictionary localDeviceMap = BuildDeviceMap(); Interlocked.CompareExchange >(ref deviceMap, localDeviceMap, null); } } private static Dictionary BuildDeviceMap() { string[] logicalDrives = Environment.GetLogicalDrives(); Dictionary localDeviceMap = new Dictionary (logicalDrives.Length); StringBuilder lpTargetPath = new StringBuilder(MAX_PATH); foreach (string drive in logicalDrives) { string lpDeviceName = drive.Substring(0, 2); NativeMethods.QueryDosDevice(lpDeviceName, lpTargetPath, MAX_PATH); localDeviceMap.Add(NormalizeDeviceName(lpTargetPath.ToString()), lpDeviceName); } localDeviceMap.Add(networkDevicePrefix.Substring(0, networkDevicePrefix.Length - 1), "\\"); return localDeviceMap; } private static string NormalizeDeviceName(string deviceName) { if (string.Compare(deviceName, 0, networkDevicePrefix, 0, networkDevicePrefix.Length, StringComparison.InvariantCulture) == 0) { string shareName = deviceName.Substring(deviceName.IndexOf('\\', networkDevicePrefix.Length) + 1); return string.Concat(networkDevicePrefix, shareName); } return deviceName; } #endregion } }
不是很简单,但在Windows Vista及更高版本上,您可以使用Restart Manager API查看谁在使用文件.Internet Explorer缓存设置包括使用此功能检测哪个进程已iexplore.exe
打开的详细信息.
省略了很多细节:
// Start an RM session RmStartSession(&sessionHandle, 0, sessionKey); // Register the file you are checking RmRegisterResources(sessionHandle, 1, filePathArray, 0, NULL, 0, NULL); // Get all processes that have that file open. RmGetList(sessionHAndle, &nProcInfoNeeded, &nProcInfo, processes, &rebootReason); RmEndSession(sessionHandle);
来自Windows Sysinternals的句柄.这是Microsoft提供的免费命令行实用程序.
您可以运行它,并解析结果.
以下是根据Iain Ballard的代码转储生成的.它已损坏:当您检索句柄名称时,它偶尔会锁定.此代码不包含针对该问题的任何解决方法,并且.NET几乎没有选项:Thread.Abort
不能再中止当前使用本机方法的线程.
因此,有了这个免责声明,这里是检索句柄的代码,这些句柄在32位和64位模式下都适用于工作(除了偶尔的锁定):
using System; using System.Collections.Generic; using System.Linq; using System.Runtime.ConstrainedExecution; using System.Runtime.InteropServices; namespace BrokenHandleRetrieval { class Program { static void Main(string[] args) { Console.WriteLine("Enumerates open handles."); Console.WriteLine("This *will* lock up on calling HandleInfo.Name from time to time. Thread.Abort() won't help."); foreach (var hi in HandleUtil.GetHandles().Where(hi => hi.Type == HandleType.File)) Console.WriteLine("pid: " + hi.ProcessId + ", name: " + hi.Name); } } public enum HandleType { Unknown, Other, File, Directory, SymbolicLink, Key, Process, Thread, Job, Session, WindowStation, Timer, Desktop, Semaphore, Token, Mutant, Section, Event, KeyedEvent, IoCompletion, IoCompletionReserve, TpWorkerFactory, AlpcPort, WmiGuid, UserApcReserve, } public class HandleInfo { public int ProcessId { get; private set; } public ushort Handle { get; private set; } public int GrantedAccess { get; private set; } public byte RawType { get; private set; } public HandleInfo(int processId, ushort handle, int grantedAccess, byte rawType) { ProcessId = processId; Handle = handle; GrantedAccess = grantedAccess; RawType = rawType; } private static Dictionary_rawTypeMap = new Dictionary (); private string _name, _typeStr; private HandleType _type; public string Name { get { if (_name == null) initTypeAndName(); return _name; } } public string TypeString { get { if (_typeStr == null) initType(); return _typeStr; } } public HandleType Type { get { if (_typeStr == null) initType(); return _type; } } private void initType() { if (_rawTypeMap.ContainsKey(RawType)) { _typeStr = _rawTypeMap[RawType]; _type = HandleTypeFromString(_typeStr); } else initTypeAndName(); } bool _typeAndNameAttempted = false; private void initTypeAndName() { if (_typeAndNameAttempted) return; _typeAndNameAttempted = true; IntPtr sourceProcessHandle = IntPtr.Zero; IntPtr handleDuplicate = IntPtr.Zero; try { sourceProcessHandle = NativeMethods.OpenProcess(0x40 /* dup_handle */, true, ProcessId); // To read info about a handle owned by another process we must duplicate it into ours // For simplicity, current process handles will also get duplicated; remember that process handles cannot be compared for equality if (!NativeMethods.DuplicateHandle(sourceProcessHandle, (IntPtr) Handle, NativeMethods.GetCurrentProcess(), out handleDuplicate, 0, false, 2 /* same_access */)) return; // Query the object type if (_rawTypeMap.ContainsKey(RawType)) _typeStr = _rawTypeMap[RawType]; else { int length; NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, IntPtr.Zero, 0, out length); IntPtr ptr = IntPtr.Zero; try { ptr = Marshal.AllocHGlobal(length); if (NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectTypeInformation, ptr, length, out length) != NT_STATUS.STATUS_SUCCESS) return; _typeStr = Marshal.PtrToStringUni((IntPtr) ((int) ptr + 0x58 + 2 * IntPtr.Size)); _rawTypeMap[RawType] = _typeStr; } finally { Marshal.FreeHGlobal(ptr); } } _type = HandleTypeFromString(_typeStr); // Query the object name if (_typeStr != null && GrantedAccess != 0x0012019f && GrantedAccess != 0x00120189 && GrantedAccess != 0x120089) // don't query some objects that could get stuck { int length; NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectNameInformation, IntPtr.Zero, 0, out length); IntPtr ptr = IntPtr.Zero; try { ptr = Marshal.AllocHGlobal(length); if (NativeMethods.NtQueryObject(handleDuplicate, OBJECT_INFORMATION_CLASS.ObjectNameInformation, ptr, length, out length) != NT_STATUS.STATUS_SUCCESS) return; _name = Marshal.PtrToStringUni((IntPtr) ((int) ptr + 2 * IntPtr.Size)); } finally { Marshal.FreeHGlobal(ptr); } } } finally { NativeMethods.CloseHandle(sourceProcessHandle); if (handleDuplicate != IntPtr.Zero) NativeMethods.CloseHandle(handleDuplicate); } } public static HandleType HandleTypeFromString(string typeStr) { switch (typeStr) { case null: return HandleType.Unknown; case "File": return HandleType.File; case "IoCompletion": return HandleType.IoCompletion; case "TpWorkerFactory": return HandleType.TpWorkerFactory; case "ALPC Port": return HandleType.AlpcPort; case "Event": return HandleType.Event; case "Section": return HandleType.Section; case "Directory": return HandleType.Directory; case "KeyedEvent": return HandleType.KeyedEvent; case "Process": return HandleType.Process; case "Key": return HandleType.Key; case "SymbolicLink": return HandleType.SymbolicLink; case "Thread": return HandleType.Thread; case "Mutant": return HandleType.Mutant; case "WindowStation": return HandleType.WindowStation; case "Timer": return HandleType.Timer; case "Semaphore": return HandleType.Semaphore; case "Desktop": return HandleType.Desktop; case "Token": return HandleType.Token; case "Job": return HandleType.Job; case "Session": return HandleType.Session; case "IoCompletionReserve": return HandleType.IoCompletionReserve; case "WmiGuid": return HandleType.WmiGuid; case "UserApcReserve": return HandleType.UserApcReserve; default: return HandleType.Other; } } } public static class HandleUtil { public static IEnumerable GetHandles() { // Attempt to retrieve the handle information int length = 0x10000; IntPtr ptr = IntPtr.Zero; try { while (true) { ptr = Marshal.AllocHGlobal(length); int wantedLength; var result = NativeMethods.NtQuerySystemInformation(SYSTEM_INFORMATION_CLASS.SystemHandleInformation, ptr, length, out wantedLength); if (result == NT_STATUS.STATUS_INFO_LENGTH_MISMATCH) { length = Math.Max(length, wantedLength); Marshal.FreeHGlobal(ptr); ptr = IntPtr.Zero; } else if (result == NT_STATUS.STATUS_SUCCESS) break; else throw new Exception("Failed to retrieve system handle information."); } int handleCount = IntPtr.Size == 4 ? Marshal.ReadInt32(ptr) : (int) Marshal.ReadInt64(ptr); int offset = IntPtr.Size; int size = Marshal.SizeOf(typeof(SystemHandleEntry)); for (int i = 0; i < handleCount; i++) { var struc = (SystemHandleEntry) Marshal.PtrToStructure((IntPtr) ((int) ptr + offset), typeof(SystemHandleEntry)); yield return new HandleInfo(struc.OwnerProcessId, struc.Handle, struc.GrantedAccess, struc.ObjectTypeNumber); offset += size; } } finally { if (ptr != IntPtr.Zero) Marshal.FreeHGlobal(ptr); } } [StructLayout(LayoutKind.Sequential)] private struct SystemHandleEntry { public int OwnerProcessId; public byte ObjectTypeNumber; public byte Flags; public ushort Handle; public IntPtr Object; public int GrantedAccess; } } enum NT_STATUS { STATUS_SUCCESS = 0x00000000, STATUS_BUFFER_OVERFLOW = unchecked((int) 0x80000005L), STATUS_INFO_LENGTH_MISMATCH = unchecked((int) 0xC0000004L) } enum SYSTEM_INFORMATION_CLASS { SystemBasicInformation = 0, SystemPerformanceInformation = 2, SystemTimeOfDayInformation = 3, SystemProcessInformation = 5, SystemProcessorPerformanceInformation = 8, SystemHandleInformation = 16, SystemInterruptInformation = 23, SystemExceptionInformation = 33, SystemRegistryQuotaInformation = 37, SystemLookasideInformation = 45 } enum OBJECT_INFORMATION_CLASS { ObjectBasicInformation = 0, ObjectNameInformation = 1, ObjectTypeInformation = 2, ObjectAllTypesInformation = 3, ObjectHandleInformation = 4 } static class NativeMethods { [DllImport("ntdll.dll")] internal static extern NT_STATUS NtQuerySystemInformation( [In] SYSTEM_INFORMATION_CLASS SystemInformationClass, [In] IntPtr SystemInformation, [In] int SystemInformationLength, [Out] out int ReturnLength); [DllImport("ntdll.dll")] internal static extern NT_STATUS NtQueryObject( [In] IntPtr Handle, [In] OBJECT_INFORMATION_CLASS ObjectInformationClass, [In] IntPtr ObjectInformation, [In] int ObjectInformationLength, [Out] out int ReturnLength); [DllImport("kernel32.dll")] internal static extern IntPtr GetCurrentProcess(); [DllImport("kernel32.dll", SetLastError = true)] public static extern IntPtr OpenProcess( [In] int dwDesiredAccess, [In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, [In] int dwProcessId); [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)] [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] internal static extern bool CloseHandle( [In] IntPtr hObject); [DllImport("kernel32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool DuplicateHandle( [In] IntPtr hSourceProcessHandle, [In] IntPtr hSourceHandle, [In] IntPtr hTargetProcessHandle, [Out] out IntPtr lpTargetHandle, [In] int dwDesiredAccess, [In, MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, [In] int dwOptions); } }