在Windows中处理系统文件夹事件

8

我正在编写一些 C# 代码,需要在应用程序运行时检测 Windows 文件系统上的特定文件夹是否已被打开。有没有什么方法可以做到?也许可以使用 WinAPI?


嗯 - FileWatcher 类,但那只是用于监测变化... - bryanmac
1
定义打开?在目录中的文件句柄?通过Windows资源管理器浏览? - Josh
1
你能描述一下你的情境吗?为什么需要知道用户何时通过资源管理器查看你的目录?使用ExplorerBrowser是否是你应用程序更好的设计选择? - Raymond Chen
@raymond:我需要这样做是因为我的应用程序需要查看用户打开了哪些文件夹。我想在这里创建一些安全性措施。资源管理器浏览器是最好的选择,因为每个人都知道如何使用它。 - Gabriel Solitario
1
如果你试图通过黑客方式进入资源管理器来实现安全性(唯一的方法是通过Shell扩展),那么你会遇到麻烦。换句话说,你想要实现什么?你必须比“安全性东西”更具体。 - Stu
显示剩余3条评论
6个回答

2
有三个API我认为你应该了解一下:
FindFirstChangeNotification() http://msdn.microsoft.com/en-us/library/aa364417%28VS.85%29.aspx 这个函数可以提供一个句柄,你可以等待它并用它来查找特定文件、目录或目录树中的更改。它不会告诉你何时浏览目录,但它会告诉你何时保存、重命名文件等。
SetWindowsHookEx() http://msdn.microsoft.com/en-us/library/ms644990%28v=VS.85%29.aspx 你可以设置这个函数,在任何事件发生时给你回调 - 实际上我非常肯定当打开一个目录时,你可以得到这个回调,但这可能会非常困难,因为你将拦截到资源管理器窗口的消息。所以在调试期间你需要重启。
Windows Shells http://msdn.microsoft.com/en-us/library/bb776778%28v=VS.85%29.aspx 如果那还不够痛苦,你可以尝试编写一个shell程序。
如果你试图编写一个rootkit,我想你不希望我为你泄漏细节。如果你不打算编写rootkit,我建议你仔细查阅资料。有一些开源的rootkits,它们基本上都必须通过这种方式来监视文件访问以从用户/操作系统中隐藏。

1

使用Windows Shell扩展。您可以使用Shell Namespace扩展来创建一个“虚拟”文件夹(或隐藏实际文件夹),例如GAC(C:\ Windows \ assembly)

这里有几个在Net 4.0中编写Shell扩展的例子

列处理程序会在打开文件夹时通知您,并且甚至让您为每个文件提供额外的数据(新的详细信息列)。


0
我能想到的最接近你需求的方法,可能是使用静态目录类(Directory Class)。它提供了一些方法来确定文件或目录上次访问时间。你可以设置一个BackgroundWorker线程在指定的时间间隔内监视是否有人访问该目录。通过使用 DateTime 记录时间间隔的开始和结束,并且如果上次访问时间落在这之间,则可以使用 BackgroundWorker 的 ProgressChanged 事件来通知应用程序。
 BackgroundWorker folderWorker = new BackgroundWorker();
 folderWorker.WorkerReportsProgress = true;
 folderWorker.WorkerSupportsCancellation = true;
 folderWorker.DoWork += FolderWorker_DoWork;
 folderWorker.ProgressChanged += FolderWorker_ProgressChanged;

 folderWorker.RunWorkerAsync();

 void FolderWorker_DoWork(object sender, DoWorkEventArgs e)
 {
      BackgroundWorker worker = (BackgroundWorker)sender;

      while(!worker.CancellationPending)
      {
           DateTime lastAccess = Directory.GetLastAccessTime(DIRECTORY_PATH);

           //Check to see if lastAccess falls between the last time the loop started
           //and came to end.
           if(/*your check*/)
           {
                object state;  //Modify this if you need to send back data.
                worker.ReportProgress(0, state);
           }
      }
 }

 void FolderWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
 {
      //Take action here from the worker.ReportProgress being invoked.
 }

也许我错了,但是我尝试过打开一个文件夹时LastAccessTime并没有改变。这对我不起作用。 - Gabriel Solitario
LastAccessTime() 实际上返回操作系统记录的文件夹或其内容修改的最后时间。我相信你能做的就是使用FileSystemWatcher监视文件夹的变化,然后获取最后访问时间。 - Dubs
谢谢@Dubs。但是我只需要在从Windows资源管理器打开文件夹时处理一个事件。以这种方式没有对文件夹进行更改。 - Gabriel Solitario

0

您可以使用FileSystemInfo的LastAccessProperty。但问题在于它可能会被缓存。

FileSystemInfo: http://msdn.microsoft.com/en-us/library/975xhcs9.aspx

LastAccessTime Property: http://msdn.microsoft.com/en-us/library/system.io.filesysteminfo.lastaccesstimeutc.aspx

请注意,这可能会被预缓存。

"如果FileSystemInfo对象的当前实例是从以下任何DirectoryInfo方法返回的,则LastAccessTimeUtc属性的值将被预缓存:

GetDirectories

GetFiles

GetFileSystemInfos

EnumerateDirectories

EnumerateFiles

EnumerateFileSystemInfos

要获取最新值,请调用Refresh方法。"

因此,调用Refresh方法可能仍然无法更新到最新值,因为Windows缓存该值。根据msdn文档所述:“FileSystemInfo.Refresh从当前文件系统中获取文件的快照。即使文件系统返回不正确或过时的信息,Refresh也无法更正底层文件系统。这在诸如Windows 98之类的平台上可能会发生。”- 链接:http://msdn.microsoft.com/en-us/library/system.io.filesysteminfo.refresh.aspx

0

请查看FileSystemWatcher类。


正如bryanmac所告诉我们的那样,不幸的是FileSystemWatcher仅适用于更改(删除,更改,重命名,创建...)。 - Gabriel Solitario

-2

我认为你可靠地实现这一点的唯一方法是监视当前运行的进程,并密切关注新的Explorer.exe实例和/或新的Explorer.exe生成的线程(“在单独的进程中运行每个窗口”设置会妨碍此处)。

我承认我不知道如何编写代码,但这就是我要寻找的。


您有许多其他编程方式可以监视文件系统(如FileSystemWatcher和Directory以及BackgroundWorker),可以通过自运行文件进行操作,当通过Windows资源管理器访问文件夹时会自动运行等。 - Moshe Bixenshpaner

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接