Using C#, how does one figure out what process locked a file?

前端 未结 9 2069
死守一世寂寞
死守一世寂寞 2020-11-22 13:03

In Windows, how do I determine (using C#) what process locked a file?

Third-party tools are helpful, but not what I\'m looking for.

9条回答
  •  时光取名叫无心
    2020-11-22 13:34

    This question had an original answer that is now over 7 years old. That code is preserved at https://gist.github.com/i-e-b/2290426 This old version might work for you if you need to use Windows XP for some reason.

    A much better answer is at How to check for file lock?

    I've replicated Eric J's answer below (with using statements added, and class & method names to match the old code that was here) Please note that the comments to this answer may be out-of-date.

    Research by user 'Walkman' is ongoing to improve the older code, as there are some conditions where the Restart Manager does not list all locks. See Github repo: https://github.com/Walkman100/FileLocks

    Use like:

    List locks = Win32Processes.GetProcessesLockingFile(@"C:\Hello.docx");
    

    Code:

    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 List 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();
            }
    
    
            [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;
            }
        }
    }
    

提交回复
热议问题