I have browsed around but cannot find any information on what I am seeking, if there is another post that already goes over this then I apologize.
I am seeking help
it does not throw an event even when I add LastAccessed.
Because NotifyFilters.LastAccessed
specifies that you wish to retreive that property, not the event to subscribe to. The available events are Changed
, Created
, or Deleted
, none of which does what you want.
You should take a look at the ReadDirectoryChangesW Win32 function, documented here. It can be passed a FILE_NOTIFY_CHANGE_LAST_ACCESS
flag, which seems to deliver what you want:
Any change to the last access time of files in the watched directory or subtree causes a change notification wait operation to return.
Edit: disregard this, the FileSystemWatcher
does internally pass NotifyFilters.LastWrite
as int 32, which is the same as FILE_NOTIFY_CHANGE_LAST_ACCESS
, to ReadDirectoryChangesW
. That function then still does not notify on file access, I've tried.
Perhaps this is caused by this:
Last Access Time has a loose granularity that only guarantees that the time is accurate to within one hour. In Windows Vista, we've disabled updates to Last Access Time to improve NTFS performance. If you are using an application that relies on this value, you can enable it using the following command:
fsutil behavior set disablelastaccess 0
You must restart the computer for this change to take effect.
If you execute that on the command prompt, perhaps then the LastAccess
will be written and the event will fire. I'm not going to try in on my SSD and don't have a VM ready, but on Windows 7 disablelastaccess
seems to be enabled out-of-the-box.
If it still doesn't work when you disable that behavior, wait for Raymond Chen's suggestion box (or himself) to come by, usually there's a quite logical explanation for why the documentation does not seem to correctly describe the behaviour you encounter. ;-)
You may as well just scan the directory in a loop and look at the LastAccessed property of the Files. What are you trying to do when a user opens a certain file?
You should set
watcher.Path = @"C:\junk";
and delete watcher.Filter
line if event should fire for all files
Using Filter property you can set wildcards for matching files, for example *.txt
To get On-Access file path there is one solution of minifilter driver. You have to implement minifilter driver to get the requirements implemented.
Digvijay Rathore gave already an answer, in my opinion the only good answer, even if a bit too short.
I want just to add a few words and a link where interested users could start.
The FileSystemWatcher is useful just to monitor what is happening inside the monitored folder, but it's not able to monitor and intercept what the user (or the OS) is doing.
For example, with a FSW (FileSystemWatcher) you can monitor when a file/folder is created, deleted, renamed or changed in some way, and those events are unleashed AFTER the action is completed, not before nor while.
A simple FSW is not able to know if the user is launching an executable from the monitored folder, in this case it will simply generate no events at all.
To catch when an executable is launched (and tons of other "events") before it is launched and make some action before the code of the executable is loaded in memory, you need to write something at lower (kernel) level, that is, you need to build a driver, in this specific case a (minifilter) File System driver.
This is a good starting point to start to understand the basic of Minifilter Windows Drivers:
https://docs.microsoft.com/en-us/windows-hardware/drivers/ifs/file-system-minifilter-drivers
what you really need is NtQuerySystemInformation enumeration and a timer, that way you can scan the directory and see if any of the files are open. the filesystemwatcher will not give you this info
public void OnChanged(object sender, FileSystemEventArgs e)
{
string FileName = System.IO.Path.GetFileName(e.FullPath);
if(IsAvailable(System.IO.Path.Combine(RecievedPath,FileName)))
{
ProcessMessage(FileName);
}
}
private void ProcessMessage(string fileName)
{
try
{
File.Copy(System.IO.Path.Combine(RecievedPath,fileName), System.IO.Path.Combine(SentPath,fileName));
MessageBox.Show("File Copied");
}
catch (Exception)
{ }
}
private static bool IsAvailable(String filePath)
{
try
{
using (FileStream inputStream = File.Open(filePath, FileMode.Open, FileAccess.Read, FileShare.None))
{
if (inputStream.Length > 0)
{
return true;
}
else
{
return false;
}
}
}
catch (Exception)
{
return false;
}
}