简体   繁体   English

监视文件夹并查找Windows应用程序中是否打开了文件

[英]Monitor a folder and find if a file is open in windows app

Edit: So apparently there is no simple or convenient way of knowing if a file is open / being held by a process . 编辑:因此,显然没有简单或方便的方法来知道文件是否已打开/由进程保存 I think this is a problem or design decision of Windows OS itself because even programs like Process Explorer can't tell when I have "mytext.txt" file is open in notepad right besides it's window :) further research also showed only way to get this information reliably is to dvelve into system drivers. 我认为这是Windows OS本身的问题或设计决定,因为即使像Process Explorer这样的程序也无法告知我何时在窗口旁的记事本中打开了“ mytext.txt”文件:)进一步的研究也仅显示了获取方法可靠地将此信息深入系统驱动程序。 My question still stands and if anyone can show me a path to this driver solution that is also appreciated. 我的问题仍然存在,是否有人可以向我展示此驱动程序解决方案的路径,这一点也值得赞赏。

ps: I sincerely think there should be a simple solution to this answer. ps:我真诚地认为应该为这个答案提供一个简单的解决方案。 I mean, it feels like it's a feature missing in a whole OS - can't tell if a file is open? 我的意思是,感觉它是整个操作系统中都缺少的功能-无法确定文件是否打开? Really? 真? Not even an API method? 甚至没有API方法? This doesn't feel right to me. 这对我来说不合适。

-- Original Question -- -原始问题-

I've been searching all around the web to find an answer to this. 我一直在网上搜索以找到答案。 Apparently after Windows Vista there is a feature called Restart Manager was added and we can invoke that dll's methods to check if a file locked or not. 显然,在Windows Vista之后,添加了一个称为“重新启动管理器”的功能,我们可以调用该dll的方法来检查文件是否已锁定。

However, when I try this in a simple console app (inspired by this article: https://blogs.msdn.microsoft.com/oldnewthing/20120217-00/?p=8283 and this SO answer https://stackoverflow.com/a/20623311/1858013 ) it can tell if an office file (xls, doc etc...) is locked / open but not when I open a .txt file in Notepad, or a .sln file when I have a project open in Visual Studio. 但是,当我在一个简单的控制台应用程序中尝试此操作(受本文启发: https : //blogs.msdn.microsoft.com/oldnewthing/20120217-00/?p=8283且此答案为https://stackoverflow.com / a / 20623311/1858013 ),它可以判断办公文件(xls,doc等...)是否已锁定/打开,但当我在记事本中打开.txt文件或打开项目时却显示.sln文件时却无法锁定在Visual Studio中。

My program is monitoring a preset folder in user's system (say, Documents folder) and I want to trigger an event when any file is opened in that folder. 我的程序正在监视用户系统中的预设文件夹(例如,Documents文件夹),并且要在该文件夹中打开任何文件时触发事件。 The program itself won't modify the file or do work with that file so locking or unlocking is not a problem, I simply want to be notified when a file is opened in any program in the monitored folder. 该程序本身不会修改文件或不使用该文件,因此锁定或解锁不是问题,我只是想在受监视的文件夹中的任何程序中打开文件时得到通知。

Right now, I'm using this code to find which processes are locking a file but I feel there is an easier way to know when a file is opened than using Win32 apis. 现在,我正在使用此代码来查找哪些进程正在锁定文件,但是与使用Win32 API相比,我觉得有一种更容易知道何时打开文件的方法。

static public class FileUtil
{
    [StructLayout(LayoutKind.Sequential)]
    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;

    enum RM_APP_TYPE
    {
        RmUnknownApp = 0,
        RmMainWindow = 1,
        RmOtherWindow = 2,
        RmService = 3,
        RmExplorer = 4,
        RmConsole = 5,
        RmCritical = 1000
    }

    [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
    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,
                                          UInt32 nFiles,
                                          string[] rgsFilenames,
                                          UInt32 nApplications,
                                          [In] RM_UNIQUE_PROCESS[] rgApplications,
                                          UInt32 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);

    /// <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>
    static public List<Process> WhoIsLocking(string path)
    {
        uint handle;
        string key = Guid.NewGuid().ToString();
        List<Process> processes = new List<Process>();

        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 ERROR_MORE_DATA = 234;
            uint pnProcInfoNeeded = 0,
                 pnProcInfo = 0,
                 lpdwRebootReasons = RmRebootReasonNone;

            string[] resources = new string[] { 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 == ERROR_MORE_DATA)
            {
                // Create an array to store the process results
                RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded];
                pnProcInfo = pnProcInfoNeeded;

                // Get the list
                res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons);
                if (res == 0)
                {
                    processes = new List<Process>((int)pnProcInfo);

                    // Enumerate all of the results and add them to the 
                    // list to be returned
                    for (int i = 0; i < pnProcInfo; i++)
                    {
                        try
                        {
                            processes.Add(Process.GetProcessById(processInfo[i].Process.dwProcessId));
                        }
                        // catch the error -- in case the process is no longer running
                        catch (ArgumentException) { }
                    }
                }
                else throw new Exception("Could not list processes locking resource.");
            }
            else if (res != 0) throw new Exception("Could not list processes locking resource. Failed to get size of result.");
        }
        finally
        {
            RmEndSession(handle);
        }

        return processes;
    }
}

Any help would be appreciated. 任何帮助,将不胜感激。

Do you need to know who opened a file or do you just need to know if it is locked. 您是否需要知道是谁打开了文件,还是只需要知道文件是否已锁定。

In case you just need to know if it is locked you can use FileSystemWatcher. 如果您只需要知道它是否被锁定,则可以使用FileSystemWatcher。 This component will monitor a certain folder for various changes. 该组件将监视某个文件夹的各种更改。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM