3

I have a Windows Service that monitors a folder for new files and runs a process. However, the service crashes every time I drop files into the monitored folder. Here is the Exception I am receiving:

Application: Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.IO.IOException Stack: at System.IO._Error.WinIOError(Int32, System.String) at System.IO._Error.WinIOError() at System.IO.File.Move(System.String, System.String) at Service.Service.Process(System.String, System.String) at Service.Service.OnChanged(System.Object, System.IO.FileSystemEventArgs) at System.IO.FileSystemWatcher.OnCreated(System.IO.FileSystemEventArgs)
at System.IO.FileSystemWatcher.NotifyFileSystemEventArgs(Int32, System.String) at System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32, UInt32, System.Threading.NativeOverlapped*) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)

Everything was working fine and then all of the sudden, it crashes every time I use it. I don't remember changing anything that would cause this. Here is my code:

public Service()
{
    InitializeComponent();
}

protected override void OnStart(string[] args)
{
    FileSystemWatcher watcher = new FileSystemWatcher(ConfigurationManager.AppSettings["UploadPath"]);

    watcher.Created += new FileSystemEventHandler(OnChanged);
    watcher.EnableRaisingEvents = true;
}

public static void OnChanged(object source, FileSystemEventArgs e)
{
    Process(e.Name, e.FullPath);
}

public static void Process(string fileName, string path)
{
    string newPath = Path.Combine(ConfigurationManager.AppSettings["NewPath"], fileName);

    Process process = new Process();

    process.StartInfo.UseShellExecute = false;
    process.StartInfo.RedirectStandardOutput = true;
    process.StartInfo.FileName = @"C:\Program Files\Microsoft Security Client\Antimalware\mpcmdrun";
    process.StartInfo.Arguments = " -scan -scantype 3 -file L:\\Test\\";

    process.Start();

    string output = process.StandardOutput.ReadToEnd();
    process.WaitForExit();

    if (process.ExitCode == 0)
    {
        File.Move(path, cleanPath);
    }

    else
    {
        TextWriter tw = new StreamWriter(ConfigurationManager.AppSettings["FailedPath"] + fileName + ".txt");
        tw.WriteLine(output);
        tw.Close();

        File.Delete(path);
    }
}
protected override void OnStop()
{

}
Glen Little
  • 6,951
  • 4
  • 46
  • 68
Matt
  • 1,220
  • 3
  • 21
  • 36
  • 1
    Does the account the service runs under still have rights to create documents in the target directory of the Move operation? – stuartd Aug 31 '11 at 17:16
  • 1
    catch the exception in the Process method. It's throwing in the File.Move. See what the exception is, in order to figure out what to do about it. – Cheeso Aug 31 '11 at 17:19
  • 1
    surround the line throwing the exception with a try/catch-block and output information about the context. Maybe the file is still locked by your drag&drop operation. You should use the `using` keyword with TextWriter. – yas4891 Aug 31 '11 at 17:25
  • You should also dispose your Process object. – Hans Aug 31 '11 at 17:35
  • @Stuart. Yes the account does have rights to the folder. – Matt Aug 31 '11 at 18:45
  • @Cheeso. I added a try catch and it looks like it is failing before the file is completely moved to the server. I think yas4891 is right that the file is still locked. What can I do to get around this? – Matt Aug 31 '11 at 18:46
  • Here is the catch: System.InvalidOperationException: No process is associated with this object. at System.Diagnostics.Process.EnsureState(State state) at System.Diagnostics.Process.get_HasExited() at System.Diagnostics.Process.EnsureState(State state) at System.Diagnostics.Process.get_ExitCode() at Service.Service.OnChanged(Object source, FileSystemEventArgs e) – Matt Aug 31 '11 at 19:06
  • It looks like adding a sleep worked. I don't like it but it works. – Matt Aug 31 '11 at 20:47

5 Answers5

1

I suspect the process still has a lock on the file in some cases. Just wondering, why aren't you calling:

process.Close(); // Frees all the resources that are associated with this component

after WaitForExit().

Ta01
  • 31,040
  • 13
  • 70
  • 99
1

Could it be that another process, say another instance of the scanner you're manually starting, still holds a lock to the file at the moment you try to move it?

You should use Process Monitor to see which processes are accessing the file.

Anyway, you don't scan the new file, you always scan the whole folder L:\Test. Is that your intention?

CodeCaster
  • 147,647
  • 23
  • 218
  • 272
0

Two tricks that seem to be needed when working with MpCmdRun:

  1. Include -DisableRemediation to your list of parameters when you call MpCmdRun. This causes the process to run very quickly and report the results back via StandardOutput.

  2. Ignore the returned exit code. Instead, look in the returned StandardOutput string for "found no threats" to know if the file is clean. If that is not there, look for a line that starts with "Threat" and read it to see what virus was found.

Glen Little
  • 6,951
  • 4
  • 46
  • 68
0

Why dont you do following checks just after making sure the process existed with 0, like this,

if (process.ExitCode == 0)
{
    process.Close();
    process.Dispose();
    if (File.Exists(path+filename) && !IsFileLocked(fileInfo) && Directory.Exists(cleanPath))
        File.Move(path, cleanPath);
}

I doubt if the scan process is still quarantining the file while you are trying to move.

reference: know how to check a file is locked?

And ofcourse, you should handle the else conditions appropriately...

Community
  • 1
  • 1
humblelistener
  • 1,456
  • 12
  • 22
0

I added Thread.Sleep(5000) before the creation of the process. This works well but it does at 5 seconds to the scanning of each file. And, as people have stated people, it feels kind of hackish.

Matt
  • 1,220
  • 3
  • 21
  • 36