Problem and .NET Fix

Some customers have observed that a FileSystemWatcher monitoring a network drive fails to fire events after setting InternalBufferSize to certain values. The problem is that the value provided to InternalBufferSize is invalid and FileSystemWatcher attempts to notify your error handler when you enable raising events, but without an error handler you won't know about the problem.

The sample code below demonstrates this problem. If you uncomment the line that adds an error handler, then you'll get notification. Note that this is one of the many reasons it's important to add an error handler.

Unfortunately this particular failure is a bit more complicated than adding an error handler. In current releases, FileSystemWatcher has a bug in which it returns the wrong error if you request an invalid buffer size. Even if you add an error handler, ErrorEventArgs.GetException() will show this exception:

System.ComponentModel.Win32Exception: The operation completed successfully

But this is what you should see:

System.ComponentModel.Win32Exception: The supplied user buffer is not valid for the requested operation

We've already fixed this bug and the fix will appear in the next major runtime release. To clarify, with the fixed version, you will still get the exception in the error handler, but the exception message will be correct.

Workaround

With and without the runtime bug, setting the InternalBufferSize to 25 * 4096 is failing. To find a good buffer size, you can use the fact that, if your buffer size is valid, then it won't result in your error handler being called (i.e. it won't really get called to tell you the operation was successful). So you can experiment with buffer size; for example this succeeds for me:

watcher.InternalBufferSize = 4 * 4096;

You can try this out using the sample code below.

Sample Code

using System;
using System.IO;

class Repro
{

    static void Main()
    {

        // string networkDir = ???;
        FileSystemWatcher watcher = new FileSystemWatcher(networkDir, "*.*");

        watcher.Created += OnCreated;

        // uncomment out line below to add the error handler

        // watcher.Error += OnError;
        watcher.IncludeSubdirectories = true;

        watcher.InternalBufferSize = 25 * 4096;
        // watcher.InternalBufferSize = 4 * 4096;

        watcher.NotifyFilter = NotifyFilters.FileName;

        watcher.EnableRaisingEvents = true;

        while (Console.ReadLine() != "x") { }
        watcher.Dispose();

    }

    private static void OnCreated(object source, FileSystemEventArgs e)
    {
        Console.WriteLine("File: " + e.FullPath + " " + e.ChangeType);
    }

    private static void OnError(object source, ErrorEventArgs e)
    {
        Console.WriteLine("Error!");
        Console.WriteLine(e.GetException());
    }

}