Question

EDIT: I've tried to change the code, and eg. instead use different subs. But now, when something changes, the program only crash. I've disabled logging, setting breakpoints and so, but the program doesn't come long. This is the error message(s) in the Visual Basic logs (this coming every time the program crash):

A first chance exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll

And here's the code (I've made some process monitor tests if you wonder what ExecProtectCompareModule and ExecProtect is):

Imports System.IO
Imports System.Diagnostics
Imports System.Text
Imports System.Security.Cryptography
Public Class Form1
Dim processList As String
Dim processList2 As String
Public watchfolder As FileSystemWatcher
Dim log As String

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.IncludeSubdirectories = True

    watchfolder.Path = TextBox1.Text



    watchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.FileName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.Attributes


    AddHandler watchfolder.Changed, AddressOf logchange
    AddHandler watchfolder.Created, AddressOf logchange
    AddHandler watchfolder.Deleted, AddressOf logchange


    AddHandler watchfolder.Renamed, AddressOf logrename


    watchfolder.EnableRaisingEvents = True

    Button1.Enabled = False
    Button2.Enabled = True


End Sub
Private Sub logchange(ByVal source As Object, ByVal e As  _
                    System.IO.FileSystemEventArgs)
    '  Dim msg As String = Environment.NewLine & "File " & e.FullPath & " "

    ' Select Case e.ChangeType
    '  Case IO.WatcherChangeTypes.Created
    '  msg &= "has been created" + "  " + "Time:" + " " + Format(TimeOfDay)

    '  Case IO.WatcherChangeTypes.Deleted
    ' msg &= "has been deleted" + "  " + "Time:" + " " + Format(TimeOfDay)

    '   Case IO.WatcherChangeTypes.Changed
    ' msg &= "has been modified" + "  " + "Time:" + " " + Format(TimeOfDay)

    '  End Select






    'log &= msg
    'log &= Chr(13)






    'Dim writer As New IO.StreamWriter("log.txt", True)
    'writer.WriteLine(msg)
    'writer.Close()


    Label6.Text = e.FullPath
    md5checkdelay.Start()
End Sub

Public Sub logrename(ByVal source As Object, ByVal e As  _
                        System.IO.RenamedEventArgs)
    Select Case e.ChangeType
        Case IO.WatcherChangeTypes.Created
            Exit Sub
        Case IO.WatcherChangeTypes.Changed
            Exit Sub
        Case IO.WatcherChangeTypes.Deleted
            Exit Sub
        Case Else



            ' Dim msgrn As String = Environment.NewLine & "File " + e.OldName + " "
            ' msgrn &= "has been renamed to" + " " + e.Name + "  " + "Time:" + " " + Format(TimeOfDay)

            ' log &= msgrn
            ' log &= Chr(13)







            'Dim writer As New IO.StreamWriter("log.txt", True)
            'writer.WriteLine(msgrn)
            'writer.Close()

            Label5.Text = e.FullPath
            md5checkdelay.Start()
    End Select
End Sub
Sub md5check()

    Dim md5code As String

    Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
    Dim f As FileStream = New FileStream(Label5.Text, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    'f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    md5.ComputeHash(f)
    'Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
    'Dim objFile = ObjFSO.GetFile(e.FullPath)

    Dim hash As Byte() = md5.Hash
    Dim buff As StringBuilder = New StringBuilder
    Dim hashByte As Byte
    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next
    md5code = buff.ToString()

    If md5code = "D41D8CD98F0B24E980998ECF8427E" Then
        Dim frm2 As New Form2
        frm2.Show()
        f.Close()
    Else
        f.Close()
    End If
End Sub
Sub md5check2()

    Dim md5code As String

    Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
    Dim f As FileStream = New FileStream(Label5.Text, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    'f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    md5.ComputeHash(f)
    'Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
    'Dim objFile = ObjFSO.GetFile(e.FullPath)

    Dim hash As Byte() = md5.Hash
    Dim buff As StringBuilder = New StringBuilder
    Dim hashByte As Byte
    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next
    md5code = buff.ToString()

    If md5code = "D41D8CD98F0B24E980998ECF8427E" Then
        Dim frm2 As New Form2
        frm2.Show()
        f.Close()
    Else
        f.Close()
    End If
End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

    watchfolder.EnableRaisingEvents = False
    Button1.Enabled = True
    Button2.Enabled = False
End Sub

Private Sub Button3_Click(sender As System.Object, e As System.EventArgs) Handles Button3.Click
    Dim frm2 As New Form2
    frm2.ShowDialog()
End Sub

Private Sub ExecProtect_Tick(sender As System.Object, e As System.EventArgs) Handles ExecProtectMonitorModule.Tick
    For Each p As Process In Process.GetProcesses()
        processList = processList & " " & p.ProcessName & vbNewLine
    Next
    Label3.Text = processList
End Sub

Private Sub ExecProtectCompareModule_Tick(sender As System.Object, e As System.EventArgs) Handles ExecProtectCompareModule.Tick
    If Not Label2.Text = Label3.Text Then
        MsgBox("New process started!", 0 + 64)
        processList2refresh()
    End If
End Sub
Sub processList2refresh()
    For Each p As Process In Process.GetProcesses()
        processList2 = processList2 & " " & p.ProcessName & vbNewLine
        Exit Sub
    Next
End Sub

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    For Each p As Process In Process.GetProcesses()
        processList2 = processList2 & " " & p.ProcessName & vbNewLine
    Next
    Label2.Text = processList2
End Sub

Private Sub md5checkdelay_Tick(sender As System.Object, e As System.EventArgs) Handles md5checkdelay.Tick
    'The timer that adds 1 second delay before it checks the md5code after the file(s) is changed
    Label4.Text = Label4.Text + 1
    If Label4.Text = 1 Then
        md5check()
    End If
End Sub

Private Sub md5checkdelay2_Tick(sender As System.Object, e As System.EventArgs) Handles md5checkdelay2.Tick
    'The timer that adds 1 second delay before it checks the md5code after the file(s) is changed but for the rename function instead
    Label7.Text = Label7.Text + 1
    If Label7.Text = 1 Then
        md5check2()
    End If
End Sub

End Class

EDIT END

I've made a question before, named "Folder monitor that monitors md5 code in the files only crashes", that someone told me to close the filestream and use another code to show the form. But it doesn't work. I've made a form named TestForm, that, doesn't contain anything, just the form, because the whole program closed when I tried to show Form2 that contains PictureBoxes and more, and I have writed the code to show TestForm when the md5 code of the modified file is equal to the md5 code I've specified in the code, but the form that shows only freeze up, and the filestream won't close, I tried f.Close() to close the filestream. But if I write the code to show a MsgBox when the md5 code of the modified file is equal to the md5 code I specified in the code, it works fine. Here is the code:

Imports System.IO
Imports System.Diagnostics
Imports System.Text
Imports System.Security.Cryptography
Public Class Form1
Public watchfolder As FileSystemWatcher

Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click

    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.IncludeSubdirectories = True

    watchfolder.Path = TextBox1.Text



    watchfolder.NotifyFilter = IO.NotifyFilters.DirectoryName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.FileName
    watchfolder.NotifyFilter = watchfolder.NotifyFilter Or _
                               IO.NotifyFilters.Attributes


    AddHandler watchfolder.Changed, AddressOf logchange
    AddHandler watchfolder.Created, AddressOf logchange
    AddHandler watchfolder.Deleted, AddressOf logchange


    AddHandler watchfolder.Renamed, AddressOf logrename


    watchfolder.EnableRaisingEvents = True

    Button1.Enabled = False
    Button2.Enabled = True


End Sub
Private Sub logchange(ByVal source As Object, ByVal e As  _
                    System.IO.FileSystemEventArgs)
    If System.IO.Path.GetFileName(e.FullPath).ToLower = "log.txt" Then Exit Sub
    Dim msg As String = Environment.NewLine & "File " & e.FullPath & " "

    Select Case e.ChangeType
        Case IO.WatcherChangeTypes.Created
            msg &= "has been created" + "  " + "Time:" + " " + Format(TimeOfDay)

        Case IO.WatcherChangeTypes.Deleted
            msg &= "has been deleted" + "  " + "Time:" + " " + Format(TimeOfDay)

        Case IO.WatcherChangeTypes.Changed
            msg &= "has been modified" + "  " + "Time:" + " " + Format(TimeOfDay)

    End Select

    Dim writer As New IO.StreamWriter("log.txt", True)
    writer.WriteLine(msg)
    writer.Close()
    Dim md5code As String



    Dim md5 As MD5CryptoServiceProvider = New MD5CryptoServiceProvider
    Dim f As FileStream = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, FileShare.Read, 8192)
    md5.ComputeHash(f)
    Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
    Dim objFile = ObjFSO.GetFile(e.FullPath)

    Dim hash As Byte() = md5.Hash
    Dim buff As StringBuilder = New StringBuilder
    Dim hashByte As Byte
    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next
    md5code = buff.ToString()
    If md5code = "D41D8CD98F0B24E980998ECF8427E" Then 'D41D8CD98F0B24E980998ECF8427E is the md5code of a blank txt file
        ' Dim frm2 As New Form2
        ' frm2.Show()
        TestForm.Show()
        f.Close()
    Else
        f.Close()
    End If
End Sub

Public Sub logrename(ByVal source As Object, ByVal e As  _
                        System.IO.RenamedEventArgs)
    Select Case e.ChangeType
        Case IO.WatcherChangeTypes.Created
            Exit Sub
        Case IO.WatcherChangeTypes.Changed
            Exit Sub
        Case IO.WatcherChangeTypes.Deleted
            Exit Sub
        Case Else
            Dim msgrn As String = Environment.NewLine & "File " + e.OldName + " "
            msgrn &= "has been renamed to" + " " + e.Name + "  " + "Time:" + " " + Format(TimeOfDay)
            Dim writer As New IO.StreamWriter("log.txt", True)
            writer.WriteLine(msgrn)
            writer.Close()
    End Select

End Sub

Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click

    watchfolder.EnableRaisingEvents = False
    Button1.Enabled = True
    Button2.Enabled = False
End Sub
End Class
Was it helpful?

Solution

Dim f As FileStream = New FileStream(e.FullPath, FileMode.Open, _
         FileAccess.Read, FileShare.Read, 8192)
f = New FileStream(e.FullPath, FileMode.Open, FileAccess.Read, _
     FileShare.Read, 8192)
md5.ComputeHash(f)

Edit

Notice anything odd? You are opening a filestream on the file, then immediately opening another filestream on the same file using the same variable without closing the first. Thats one reason it reports the file open in VS. Delete the f = New FileStream... line.

You will have ANOTHER problem here when the event fires due to a File Delete.

Then:

Dim ObjFSO As Object = CreateObject("Scripting.FileSystemObject")
Dim objFile = ObjFSO.GetFile(e.FullPath)

These last 2 dont appear to do anything. The objects are created but not used. But since objFile is built from the file in question, it could be preventing you from deleting or working with the file.

Dim hash As Byte() = md5.Hash
Dim buff As StringBuilder = New StringBuilder
Dim hashByte As Byte
For Each hashByte In hash
    buff.Append(String.Format("{0:X1}", hashByte))
Next
md5code = buff.ToString()

Since you now have the MD5 code, you should close the filestream (f) so you can do other things. You cannot delete or move the file while it is open.

If md5code = "D41D8CD98F0B24E980998ECF8427E" Then 
    ' Dim frm2 As New Form2
    ' frm2.Show()
    TestForm.Show()
    f.Close()
Else
    f.Close()
End If

As with your previous code, if TestForm is form class, you must create an instance of it:

Dim frm As New TestForm
frm.Show                       ' or frm.ShowDialog

Forms are just classes. You must instance them before using them.

Edit continued

Finally, the freeze is a result of doing too much in a log event (log change AND compute MD5 AND show a new form). You have probably noticed that your app does not slow down while monitoring many files in many folders. Thats because the filewatcher runs on a different thread. When you create an instance of a new form or show it from that event, the form apparently runs on that thread.

You need to rework your code to remove the stuff that does not relate to actual logging. In that event, instead of all that stuff you might add the changed file to a List(of String) which represents a todo list. Do the MD5 and form stuff elsewhere on that list so it takes place on your app's thread.

FINAL edit

If all you are worried about is the form freezing, add this:

    watchfolder = New System.IO.FileSystemWatcher()
    watchfolder.SynchronizingObject = Me

It will only delay more major issues, but you seem to think it is important. Next, I have told you this 3 times now, but you MUST exit the log routines if the file operation was a delete because you cannot open a deleted file:

Case IO.WatcherChangeTypes.Deleted
    Exit Sub                         ' after the log

The next problem you will get is when 2+ files have changed. You need a way to queue files/tasks. Your approach to calling other subs for some stuff DOES break things down to discrete tasks, but those called sub are called from the FW thread so you just moved the problem around. For a queue I was thinking a List(of String) but a new class (as suggested in your last post) with its own BackgroundWorker might be better.

Public Class FileMgr
  Friend thisFile As String
  Friend thisHash As String = ""

  Dim frm2 As Form2
  Private WithEvents bw As BackgroundWorker


  Public Sub New(ByVal f As String)
      thisFile = f

      bw = New BackgroundWorker
      AddHandler bw.DoWork, AddressOf ProcessFile
      ' Explorer might not be done creating it yet, 
      ' especially if you drop 3-4 files, so wait
      Threading.Thread.Sleep(250)
      ' start the BW with the name of the file
      bw.RunWorkerAsync(thisFile)
  End Sub

ProcessFile is just your (fixed) MD5 sub with a new declaration:

  Private Sub ProcessFile(ByVal sender As Object, _
       ByVal e As System.ComponentModel.DoWorkEventArgs) Handles bw.DoWork

     Dim sFile As String = e.Argument

AGAIN, CLOSE THE FILE ONCE YOU HAVE THE HASH:

    md5.ComputeHash(f)
    f.Close()

DONT OPEN ANY FORMS. JUST GET THE HASH.

    For Each hashByte In hash
        buff.Append(String.Format("{0:X1}", hashByte))
    Next

    thisHash = buff.ToString()       ' last line!!!

When the BackgroundWorker is done, it raises an event:

Private Sub bw_RunWorkerCompleted(ByVal sender As Object, _
    ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
      Handles bw.RunWorkerCompleted

   ' I dont know why each file has to have its own form rather
   ' that a report item in a listbox but I also dont know why you
   ' are computing a hash for a 0 byte new file
    If thisHash = "D41D8CD98F0B24E980998ECF8427E" Then
        frm2 = New Form2
        frm2.Label1.Text = thisFile
        frm2.Show()
    End If

End Sub
End Class

To use it, takes one line of code in the log events:

  Dim fMgr As New FileMgr(e.FullPath)

EACH file operation Windows reports will create a new file helper which will run its own BackgroundWorker. Since you arent doing too much there wont be too many alive at one time until you are processing files larger than 0 bytes. You also need a Try/Catch in MD5Sub/ProcessFile for times when the file is open and in use.

I dropped 6 files in the watch folder, got 6 copies of Form2, no errors and no freezes (and not even an upvote for all this).

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top