Why is FileSystemWatcher closing the program? - c#

I have:
using System.IO;
using System.Windows.Forms;
namespace myNamespace1
{
public partial class Form1 : Form
{
FileSystemWatcher watcher = new FileSystemWatcher();
public Form1()
{
InitializeComponent();
watcher.Path = #"c:\users\Me\desktop\z";
watcher.Created += new FileSystemEventHandler(watcher_Created);
watcher.EnableRaisingEvents = true;
}
void watcher_Created(object sender, FileSystemEventArgs e)
{
Text = e.Name + " " + e.ChangeType.ToString();
}
}
}
When I add a folder or file to the folder (-z) – the program closes. Why?
I'm running in Debug mode. And I don't get any exception from VS.
EDIT:
The answer:
jon-skeet's answer
+(in a comment)
In Visual Studio, can you go to the Debug Menu -> Exceptions. On this dialog, make sure that next to Common Language Runtime Exceptions, make sure both 'Thrown' and 'User Unhandled' are ticked, click OK and try debugging again. – dash

Assuming Text is trying to change a UI property, you're changing the UI from the wrong thread. FileSystemWatcher raises events on thread-pool threads, but you're only meant to access the UI from the UI thread. That's probably throwing an exception in the thread-pool thread, which is bringing down the process.
Try this instead:
void watcher_Created(object sender, FileSystemEventArgs e)
{
Action action = () => Text = e.Name + " " + e.ChangeType;
// Or Dispatcher.Invoke - it depends on your application type
Invoke(action);
}

Without knowing the details of what kind of program you created, I'm guessing you have an unhandled exception occurring somewhere in your code that is causing your application to close.
Update
After looking at your edit, it looks like Jon is correct (as usual). Your application is trying to update the Text property on the wrong thread. Your handler should really be:
Action a = () => e.Name + " " + e.ChangeType.ToString();
Invoke(a);

In addition to Justin's answer, you can only specifiy a directory for the Path property.
To monitor changes on a specific file, use the Filter property.
Also try adding some exception handling or stepping through the code in debug mode to see what is happening. Pay close attention to how you are setting the label, although I'd expect to see a cross thread exception.
Are you seeing any exceptions at all?

What's Text, and what's done with it when the event fires?
Bear in mind the FileSystemWatcher creates its own thread from the threadpool to handle events. Also, there is a good deal of unmanaged code under the hood of this class, which can result in unhandled exceptions being silently swallowed if you have "Just My Code" turned on in the debugger options.
You may want to create a producer/consumer model to handle this -- see After FileSystemWatcher fires - Thread Pool or Dedicated thread? for more details.

Is it a windows service?
Generally, if the file watcher couldnt find the folder or has no access to a folder, it dies.
Did u check ur EventLog?

Related

Preventing FileSystemWatcher throwing TaskCanceledException when calling Shutdown()

I am building a WPF application that checks whether a file has been modified within a certain period of time and if so, the application exits.
I am having an issue that the method that ultimately triggers the call of App.Current.Shutdown() is an event handler attached to a FileSystemWatcher event and causes a TaskCanceledException to be thrown.
A minimal working example is as follows:
Create a new WPF application. In App.xaml.cs
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
FileSystemWatcher w = new FileSystemWatcher();
w.Path = /*path to suitable test folder*/
w.Filter = "Test.txt";
w.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
w.Changed += (s, a) =>
{
//Shutdown(); --Throws InvalidOperationException (Calling thread cannot access this object)
Application.Current.Dispatcher.Invoke(() => Shutdown());
};
w.EnableRaisingEvents = true;
}
}
Edit the file Test.txt and the application should close.
In order to prevent the exception showing, I can surround the shutdown call with a empty try-catch block
try
{
Application.Current.Dispatcher.Invoke(() => Shutdown())
}
catch(TaskCanceledException)
{
}
but this seems to be a hack and doesn't solve the underlying issue.
It seems to me that C# is trying to tell me I am going about this the wrong way. Is there a better way?
There is a special method in the dispatcher to invoke a shutdown: InvokeShutdown
Calling Application.Current.Dispatcher.InvokeShutdown(); from the Changed event handler avoids the exception.
This shuts down the dispatcher, which in turn leads to the shutdown of the application. There's some discussion on the difference between this and Application.Shutdown here.

Invoking with textbox c#

Part of my program uses an event handler for the receive data of my serial port. The idea is when data is received that the text received is then added to the textbox (rx). I did not used to have this problem but something has changed and I can't figure out what. So now I am re-examining the way this is handled.
During the form load of my winform the last thing I do is
if (!serialPort1.IsOpen)
{
serialPort1.Open();
serialPort1.DataReceived += new SerialDataReceivedEventHandler(DataReceivedHandler);
}
Then I have the event handler
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e)
{
string indata1 = serialPort1.ReadExisting();
// rx.Text = " "; accidentally posted this. it was from trial and error.
rx.AppendText(Environment.NewLine + indata1);
}
When I run the program it stops at the rx.AppendText(Environment.NewLine + indata1); and gives the error
invalidoperationexception was unhandled: Control "accessed from a
thread other than the thread it was created on.
From what I have been able to read suggests that I need to use invoke or BeginInvoke.
I have never had problems appending the text before so now I can't understand why it's a problem. Also from what I have been reading on invoking i just don't understand it.
Can someone help me understand how to use the invoke instance for my situation? or perhaps show me another way of appending the text box?
Usually the exception you're seeing occurs when you run in debug mode, and if you run your application in release mode, you're unlikely to see the exception.
However, it is best to use invoke, as you have read. Something like this:
private delegate void RefreshTextBox();
private void DataReceivedHandler(object sender, SerialDataReceivedEventArgs e) {
//this event is raised in an event separate from UI thread,
//so InvokeRequired must be checked and Invoke called to update UI controls.
if (this.InvokeRequired) {
RefreshTextBox d = new RefreshTextBox(RefreshTextBoxResults);
Invoke(d);
} else {
RefreshTextBoxResults();
}
}
private void RefreshTextBoxResults() {
string indata1 = serialPort1.ReadExisting();
rx.Text = " ";
rx.AppendText(Environment.NewLine + indata1);
}
The first time you see this invoke stuff, it's nearly impossible to follow, but take a close look and give it some time and it will make sense. Promise. :)
Updates in GUI applications should only be done on the GUI thread. Another thread attempting to update GUI components directly will result in either the error you described or in seemingly random behavior.
The role of Invoke & friends is to enable a secondary thread to safely forward GUI updates to the GUI thread, which will then process them from a queue.
In your case (assuming WinForms here):
rx.BeginInvoke(
(Action)(() =>
{
rx.AppendText(Environment.NewLine + indata1);
}));
BeginInvoke is asynchronous, so the thread calling it will not wait for the actual updates to be processed before moving on, while Invoke is synchronous.

C# move file as soon as it becomes available

I need to accomplish the following task:
Attempt to move a file. If file is locked schedule for moving as soon as it becomes available.
I am using File.Move which is sufficient for my program. Now the problems are that:
1) I can't find a good way to check if the file I need to move is locked. I am catching System.IO.IOException but reading other posts around I discovered that the same exception may be thrown for different reasons as well.
2) Determining when the file gets unlocked. One way of doing this is probably using a timer/thread and checking the scheduled files lets say every 30 seconds and attempting to move them. But I hope there is a better way using FileSystemWatcher.
This is a .net 3.5 winforms application. Any comments/suggestions are appreciated. Thanks for attention.
You should really just try and catch an IOException. Use Marshal.GetHRForException to check for the cause of the exception.
A notification would not be reliable. Another process might lock the file again before File.Move is executed.
One possible alternative is by using MoveFileEx with a MOVEFILE_DELAY_UNTIL_REBOOT flag. If you don't have access to move the file right now, you can schedule it to be moved on the next reboot when it's guaranteed to be accessible (the moving happens very early in the boot sequence).
Depending on your specific application, you could inform the user a reboot is necessary and initiate the reboot yourself in addition to the moving scheduling.
It's simple:
static void Main(string[] args)
{
//* Create Watcher object.
FileSystemWatcher watcher = new FileSystemWatcher(#"C:\MyFolder\");
//* Assign event handler.
watcher.Created += new FileSystemEventHandler(watcher_Created);
//* Start watching.
watcher.EnableRaisingEvents = true;
Console.ReadLine();
}
static void watcher_Created(object sender, FileSystemEventArgs e)
{
try
{
File.Move(e.FullPath, #"C:\MyMovedFolder\" + e.Name);
}
catch (Exception)
{
//* Something went wrong. You can do additional proceesing here, like fire-up new thread for retry move procedure.
}
}
This is not specific to your problem, but generally you will always need to retain the 'try it and gracefully deal with a failure' mode of operation for this sort of action.
That's because however clever your 'detect that the file is available' mechanism is, there will always be some amount of time between you detecting that the file is available and moving it, and in that time someone else might mess with the file.
The scheduled retry on exception (probably increasing delays - up to a point) is probably the simplest way to achieve this (your (2) ).
To do it properly you're going to have to drop to system level (with Kernel code) hooks to trap the file close event - which has its own idiosynchrases. It's a big job - several orders of magnitude more complex than the scheduled retry method. It's up to you and your application case to make that call, but I don't know of anything effective in between.
Very old question, but google led me here, so when I found a better answer I decided to post it:
There's a nice code I found in the dotnet CLI repo:
/// <summary>
/// Run Directory.Move and File.Move in Windows has a chance to get IOException with
/// HResult 0x80070005 due to Indexer. But this error is transient.
/// </summary>
internal static void RetryOnMoveAccessFailure(Action action)
{
const int ERROR_HRESULT_ACCESS_DENIED = unchecked((int)0x80070005);
int nextWaitTime = 10;
int remainRetry = 10;
while (true)
{
try
{
action();
break;
}
catch (IOException e) when (e.HResult == ERROR_HRESULT_ACCESS_DENIED)
{
Thread.Sleep(nextWaitTime);
nextWaitTime *= 2;
remainRetry--;
if (remainRetry == 0)
{
throw;
}
}
}
}
There is also a method for just IOException. Here's the usage example:
FileAccessRetrier.RetryOnMoveAccessFailure(() => Directory.Move(packageDirectory.Value, tempPath));
Overall, this repo contains a lot of interesting ideas for file manipulations and installation/removal logic, like TransactionalAction, so I recommend it for reviewing. Unfortunately, these functions are not available as NuGet package.
Have a look at the FileSystemWatcher.
http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher(VS.90).aspx
Listens to the file system change
notifications and raises events when a
directory, or file in a directory,
changes

Silverlight 4 Clipboard Security Exception "access is not allowed"?

I'm new in Silverlight and i am doing some tests. With my current test I try to display in real time the current Clipboard content. But there is a weird behaviors with this code :
namespace SilverlightTest
{
public partial class MainPage : UserControl
{
private Timer _timer;
public MainPage()
{
InitializeComponent();
var dispatcher_timer = new DispatcherTimer {Interval = new TimeSpan(0, 0, 0, 5)};
dispatcher_timer.Tick += new EventHandler(timer_Callback);
dispatcher_timer.Start();
}
private void timer_Callback(object state, EventArgs eventArgs)
{
current_clip_board.Content = Clipboard.GetText();
}
private void button1_Click(object sender, RoutedEventArgs e)
{
current_clip_board.Content = Clipboard.GetText();
}
}
}
The button Event and the timer Event are suppose to do exactly the same action.
But it doesn't ! The Button works fine and set the clipboard text into the label but the timer throw an exception :
Clipboard access is not allowed
The question is : why ? :)
Thanks.
PS : I would bet on a thread problem :p
Clipboard access, in a partial trust (in-browser) Silverlight application (the scenario you're likely referring to above), is restricted. The GetText property is accessible only in scenarios that the Silverlight runtime determines were initiated by the user. Your example is perfect -- by a button click for example. A dispatch timer however is not user initiated, so the property throws an exception (this is especially important within the context of a in-browser application, which could be a big security hole if you could create a Silverlight application that just ran silently in the browser, watching the user's clipboard updates without their knowledge).
See this clipboard documentation for more details.
Just trigger Clipboard.ContainsText() instead of Text. The method ContainsText is allowed!
Have you tried this:
private void timer_Callback(object state, EventArgs eventArgs)
{
Dispatcher.Invoke(new System.Threading.ThreadStart(delegate()
{
current_clip_board.Content = Clipboard.GetText();
}
}
edit
After a quick search, it appears that Clipboard is only available in response to a user action see here and here.
In partial trust (the default mode for
browser-hosted Silverlight-based
applications), Silverlight also
restricts clipboard access to its two
key APIs GetText and SetText. These
APIs can only be invoked from within a
context that is determined by the
Silverlight runtime to be in response
to a user-initiated action. For
example, clipboard access is valid
from within a handler for a Click or
KeyDown event. In contrast, clipboard
access is not valid from a handler for
Loaded or from a constructor, and
access attempts throw exceptions.
If your only option is to use a timer, then don't do it at all. The clipboad is a shared resource, and you're going to raise "cannot open clipboard" errors in other programs as they try to access the clipboard. i.e. user copies something from WinWord, WinWord tries to open the clipboard, but can't, because you've got it locked while you're examining it.
Hello this works for me but only in IE Microsoft.LightSwitch.Threading.Dispatchers.Main.BeginInvoke(() => HtmlPage.Window.Eval("window.clipboardData.setData('Text','testtestest')"));
just use getData method

FileSystemWatcher - only the change event once firing once?

I'm using the below code to listen for change events of a file i download off a server and open. however the change event only gets fired the first time the file is saved, then on subsequent saves the file watcher does not fire the change events?
Can anyone see whats going on?
private FileSystemWatcher StartWatchingFile()
{
fw = new FileSystemWatcher();
fw.Path = this.directoryLocation;
fw.Filter = this.Filename;
fw.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite;
// Add event handler
fw.Changed += new FileSystemEventHandler(fw_Changed);
// Open file
System.Diagnostics.Process.Start(this.CreateAbsoluteFilePath(this.Filename));
// Begin watching.
fw.EnableRaisingEvents = true;
return fw;
}
//************************
void fw_Changed(object sender, FileSystemEventArgs e)
{
MessageBox.Show("File: " + e.FullPath + " " + e.ChangeType);
}
EDIT: The StartWatchingFile() now returns the filewatcher which is kept in a class that will not be garbage collected, just to make sure i'm holding the whole class as thought the fw_changed() function might not be able to be called. So the whole class is now not getting garbage collectioned. The class is held in a ArrayList which is a public member of a class
Regards,
Jon
I'm sorry I can't answer your question specifically. In general, I'll contribute that, if you use it enough, you'll learn that FileSystemWatcher is not reliable. Microsoft Connect shows multiple problems with it. I agree with Jason Jackson's take on FileSystemWatcher.
Is it reproduceable that it always works for the first time?
If not, the FileSystemWatcher might have been collected by the garbage collector in the meantime after StartWatchingFile has finished because it's declared locally.
If so, does the process you're starting probably lock the file so the file actually isn't modified?

Categories