С помощью C#, как выяснить, какой процесс заблокировал файл?
в Windows, Как определить (с помощью C#) какой процесс заблокировал файл?
сторонние инструменты полезны, но не то, что я ищу.
9 ответов:
этот вопрос был оригинальный ответ, который уже более 7 лет. Этот код сохраняется в https://gist.github.com/i-e-b/2290426 Эта старая версия может работать для вас, если вам нужно использовать Windows XP по какой-то причине.
гораздо лучший ответ на Как проверить блокировку файла?
я воспроизвел ответ Эрика J ниже (с
using
добавлены операторы, а имена классов и методов соответствуют старому коду, который был здесь) обратите внимание, что комментарии к этому ответу могут быть устаревшими.как использовать:
List<Process> locks = Win32Processes.GetProcessesLockingFile(@"C:\Hello.docx");
код:
using System; using System.Collections.Generic; using System.Diagnostics; using System.Runtime.InteropServices; namespace FileLockInfo { public static class Win32Processes { /// <summary> /// Find out what process(es) have a lock on the specified file. /// </summary> /// <param name="path">Path of the file.</param> /// <returns>Processes locking the file</returns> /// <remarks>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) /// </remarks> public static List<Process> GetProcessesLockingFile(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<Process>(); } [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<Process> EnumerateProcesses(uint pnProcInfoNeeded, uint handle, uint lpdwRebootReasons) { var processes = new List<Process>(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 Dictionary<string, string> deviceMap; 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; } /// <summary> /// Gets the open files enumerator. /// </summary> /// <param name="processId">The process id.</param> /// <returns></returns> public static IEnumerable<String> GetOpenFilesEnumerator(int processId) { return new OpenFiles(processId); } public static List<Process> GetProcessesUsingFile(string fName) { List<Process> result = new List<Process>(); 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<String> { private readonly int processId; internal OpenFiles(int processId) { this.processId = processId; } #region IEnumerable<FileSystemInfo> Members public IEnumerator<String> 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<string, string> localDeviceMap = BuildDeviceMap(); Interlocked.CompareExchange<Dictionary<string, string>>(ref deviceMap, localDeviceMap, null); } } private static Dictionary<string, string> BuildDeviceMap() { string[] logicalDrives = Environment.GetLogicalDrives(); Dictionary<string, string> localDeviceMap = new Dictionary<string, string>(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 и выше вы можете использовать Перезапустить 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);
Handle С Windows Sysinternals. Это бесплатная утилита командной строки, предоставляемая корпорацией Майкрософт.
вы можете запустить его и проанализировать результат.
следующее было произведено на основе дампа кода 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<byte, string> _rawTypeMap = new Dictionary<byte, string>(); 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<HandleInfo> 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); } }
попробовать Unlocker. Если вы попытаетесь удалить файл, заблокированный другим процессом, он будет содержать список процессов, которые заблокировали файл. Затем вы можете разблокировать файл, выключив эти процессы.
Я считаю, что вам нужен код, работающий в режиме ядра, чтобы полностью ответить на вопрос (но я не смотрел на API менеджера перезапуска).
вы можете перечислить все процессы и их модули - так что если файл, который вы ищете, является модулем (DLL, EXE, OCX...), вы хорошо идти. Но если это текстовый файл, например, вы должны посмотреть на таблицу дескрипторов ядра, которую вы не можете видеть из пользовательского режима. Ручка.exe имеет драйвера ядра для того, чтобы сделать это.
вам абсолютно не нужно работать в режиме ядра (!!!)
Это Win32 FAQ с Windows 95 (!) (в C, Google groups, Win32) : прочитайте таблицу дескриптора, из пользовательского режима, конечно, и получите PID из дескриптора файла ...
я переписываю метод GetProcessesLockingFile () в решении. Код не работал. Например, у вас есть папка
"C:\folder1\folder2"
и процесс в folder2 (process1). Если процесс был запущен, GetProcessesLockingFile () возвращал мне"C:\folder1\folder2"
. Так что условиеif (files.Contains(filePath))
=>if ("C:\folder1\folder2".contains("C:\folder1\folder2\process1"))
никогда не было правдой.так вот мое решение:
public static List<Process> GetProcessesLockingFile(FileInfo file) { var procs = new List<Process>(); var processListSnapshot = Process.GetProcesses(); foreach (var process in processListSnapshot) { if (process.Id <= 4) { continue; } // system processes List<string> paths = GetFilesLockedBy(process); foreach (string path in paths) { string pathDirectory = path; if (!pathDirectory.EndsWith(Constants.DOUBLE_BACKSLASH)) { pathDirectory = pathDirectory + Constants.DOUBLE_BACKSLASH; } string lastFolderName = Path.GetFileName(Path.GetDirectoryName(pathDirectory)); if (file.FullName.Contains(lastFolderName)) { procs.Add(process); } } } return procs; }
или со строковым параметром:
public static List<Process> GetProcessesLockingFile(string filePath) { var procs = new List<Process>(); var processListSnapshot = Process.GetProcesses(); foreach (var process in processListSnapshot) { if (process.Id <= 4) { continue; } // system processes List<string> paths = GetFilesLockedBy(process); foreach (string path in paths) { string pathDirectory = path; if (!pathDirectory.EndsWith(Constants.DOUBLE_BACKSLASH)) { pathDirectory = pathDirectory + Constants.DOUBLE_BACKSLASH; } string lastFolderName = Path.GetFileName(Path.GetDirectoryName(pathDirectory)); if (filePath.Contains(lastFolderName)) { procs.Add(process); } } } return procs; }