Handle system folders event in windows

2019-04-24 14:38发布

问题:

I am writing some C# code and I need to detect if a specific folder on my windows file system has been opened while the application is running. Is there any way to do it? WinAPI maybe?

回答1:

There are three API things I think you should check out:

FindFirstChangeNotification() http://msdn.microsoft.com/en-us/library/aa364417%28VS.85%29.aspx That gives you a handle you can wait on and use to find changes to a file in a particular file, directory, or tree of directories. It won't tell you when a directory is browsed, but it will tell you when a file is saved, renamed, and so on and so forth.

SetWindowsHookEx() http://msdn.microsoft.com/en-us/library/ms644990%28v=VS.85%29.aspx You can set that up to give you a callback when any number of events occur - in fact I'm pretty positive that you CAN get this callback when a directory is opened, but it will probably be inordinately difficult because you'll be intercepting messages to explorer's window. So you'll be rebooting during debugging.

Windows Shells http://msdn.microsoft.com/en-us/library/bb776778%28v=VS.85%29.aspx If that wasn't painful enough, you can try writing a shell program.

If you're trying to write a rootkit, I suppose you don't want me to spoil the details for you. If you're NOT trying to write a rootkit, I suggest you look it up - carefully. There are open source rootkits, and they all basically have to monitor file access this way to hide from the user / OS.



回答2:

Go with the Windows Shell Extensions. You can use Shell Namespace Extensions to make a "virtual" folder that isn't there (or hides a real one), like the GAC (C:\Windows\assembly)

Here are several examples of Shell Extension coding in .Net 4.0.

A Column Handler would let you know when a folder is "Opened", and even let you provide extra data for each of the files (new details columns).



回答3:

Check out the FileSystemWatcher class.



回答4:

The closest thing that I can think of, that may be useful to you, is using the static Directory class. It provides methods to determine the last time a file or directory was accessed. You could setup a BackgroundWorker to monitor if the directory was accessed during a specified interval. Keep track of the start and end of the interval by using DateTime, and if the last access time falls between those, then you can use the BackgroundWorker's ProgressChanged event to notify the application.

 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.
 }


回答5:

You could use the FileSystemInfo's LastAccessProperty. The problem though is that it can be cached.

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

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

As noted that this can be pre-cached.

"The value of the LastAccessTimeUtc property is pre-cached if the current instance of the FileSystemInfo object was returned from any of the following DirectoryInfo methods:

GetDirectories

GetFiles

GetFileSystemInfos

EnumerateDirectories

EnumerateFiles

EnumerateFileSystemInfos

To get the latest value, call the Refresh method."

Therefore call the Refresh method but it still might not be up to date due to Windows caching the value. (This is according to msdn doc "FileSystemInfo.Refresh takes a snapshot of the file from the current file system. Refresh cannot correct the underlying file system even if the file system returns incorrect or outdated information. This can happen on platforms such as Windows 98." - link: http://msdn.microsoft.com/en-us/library/system.io.filesysteminfo.refresh.aspx



回答6:

I think the only way you can reliably achieve this is by monitoring the currently running processes and watch closely for new Explorer.exe instances and/or new Explorer.exe spawned threads (the "Run every window on a separate process" setting gets in the way here).

I admit I don't have a clue about how to code this, but that's what I would look for.