views:

37

answers:

3

I have a windows service using a FileSystemWatcher to monitor a folder, print added images, then delete the image after printing.

 private void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            FileSystemWatcher Watcher = new FileSystemWatcher();
            Watcher.Path = @"C:\Images";
            Watcher.Created += new FileSystemEventHandler(Watcher_Changed);
            Watcher.EnableRaisingEvents = true;
        }

        private void Watcher_Changed(object sender, FileSystemEventArgs e)
        {
            try
            {
                PrintDocument myDoc = new PrintDocument();
                myDoc.PrintPage += new PrintPageEventHandler(print);
                FilePath = e.FullPath;
                myDoc.PrinterSettings.PrinterName = @"\\Network Printer";
                myDoc.Print();
                using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
                {
                    sw.WriteLine("Printed File: " + FilePath);
                }
                File.Delete(e.FullPath);
            }
            catch(Exception excep)
            {
                using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
                {
                    sw.WriteLine("Error: " + excep.ToString());
                }
            }
        }

The problem is that I get the exception thrown Error: System.IO.IOException: The process cannot access the file because it is being used by another process. that the file is being used by another process when I try to delete it. I'm guessing this is because the FileSystemWatcher is keeping some sort of reference to it. Any idea on what to do here, to delete the file after it gets printed?

Edit: Did not include this function from my code before:

private void print(object sender, PrintPageEventArgs e)
        {
            try
            {
                using (Image i = Image.FromFile(FilePath))
                {
                    Point p = new Point(0, 0);
                    e.Graphics.DrawImage(i, p);
                }
            }
            catch(Exception exep)
            {
                throw exep;
            }
        }

I applied the using block suggestion to this function too, but also moved the delete to this function which is event handler for mydoc.EndPrint, to ensure all ties to the file were cut, and this seems to do the trick.

void myDoc_EndPrint(object sender, PrintEventArgs e)
{
    File.Delete(FilePath);
}
A: 

Kill mydoc, I think this is what keeping the file in use

Chen Kinnrot
+1  A: 

PrintDocument implements IDisposable, you need to make sure it releases it's file handle by wrapping it in a using block.

private void bw_DoWork(object sender, DoWorkEventArgs e)
    {
        FileSystemWatcher Watcher = new FileSystemWatcher();
        Watcher.Path = @"C:\Images";
        Watcher.Created += new FileSystemEventHandler(Watcher_Changed);
        Watcher.EnableRaisingEvents = true;
    }
private void Watcher_Changed(object sender, FileSystemEventArgs e)
{
    try
    {
        using (PrintDocument myDoc = new PrintDocument())
        {
            myDoc.PrintPage += new PrintPageEventHandler(print);
            FilePath = e.FullPath;
            myDoc.PrinterSettings.PrinterName = @"\\Network Printer";
            myDoc.Print();
            using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
            {
                 sw.WriteLine("Printed File: " + FilePath);
            }
        }
        File.Delete(e.FullPath);
    }
    catch(Exception excep)
    {
        using (StreamWriter sw = new StreamWriter("C:\\error.txt"))
        {
            sw.WriteLine("Error: " + excep.ToString());
        }
    }
}
Christopher Edwards
No luck with this. Same error. `Error: System.IO.IOException: The process cannot access the file 'C:\ProcessBookImages\013Figure.GIF' because it is being used by another process.`
roviuser
I guess then it must be the watcher itself. I think the FileSystem watcher is holding a reference to the file because the Changed event is firing before the Created event. Try moving the code to the Created event.
Christopher Edwards
No, according to this - http://msdn.microsoft.com/en-us/library/system.io.filesystemwatcher.created.aspx - my last comment wasn't correct.
Christopher Edwards
Ahh, got it (I think). Change this Watcher.Created += new FileSystemEventHandler(Watcher_Changed); to this Watcher.Changed += new FileSystemEventHandler(Watcher_Changed);
Christopher Edwards
If that doesn't work, take out the File.Delete(e.FullPath); line and make sure the event isn't firing multiple times.
Christopher Edwards
see my edits above. its not about the watcher.changed, it was about the file still be used. The files are very small, so only a single event gets called when they are added to the directory, and thats fsw.created.
roviuser
A: 

By default the FSW fires multiple events while the file is being created, not just for when the file is inserted into the filesystem. To minimize this effect I set:

FSW.NotifyFilter  =  NotifyFilters.FileName;

Also the FSW fires this event when the file is first created and not when it has completely loaded into the filesystem. If you have a large file then there will be a distinct time delay between this event firing and the file actually being available for use. There is no FSW even that tells you when the file has been completely written. To get around this I use a retry loop to open the file for exclusive reading and trap errors with a try/catch. And keep trying to load the file until I succeed (or I hit a retry limit) and sleeping for a bit when I fail.

If you google around a bit you will find lots of solutions for getting around FSW limitations

Peter M