1

編集: コードを変更しようとしました。代わりに別のサブを使用してください。しかし今、何かが変わると、プログラムはクラッシュするだけです。ログを無効にしたり、ブレークポイントを設定したりしましたが、プログラムは長くは続きません。これは、Visual Basic ログのエラー メッセージです (これは、プログラムがクラッシュするたびに表示されます)。

System.Windows.Forms.dll で、タイプ 'System.InvalidOperationException' の初回例外が発生しました

コードは次のとおりです (ExecProtectCompareModule と ExecProtect が何であるか疑問に思われる方のために、いくつかのプロセス モニター テストを作成しました)。

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

クラス終了

編集終了

以前、「ファイル内の md5 コードのみを監視するフォルダー モニターがクラッシュする」という名前の質問をしたことがあります。しかし、うまくいきません。PictureBoxes などを含む Form2 を表示しようとすると、プログラム全体が終了したため、フォームだけを含む TestForm という名前のフォームを作成しました。変更したファイルのコードは、コードで指定した md5 コードと同じですが、表示されるフォームがフリーズするだけで、ファイル ストリームが閉じないため、f.Close() を使用してファイル ストリームを閉じようとしました。しかし、変更されたファイルの md5 コードがコードで指定した md5 コードと等しい場合に MsgBox を表示するコードを作成すると、正常に動作します。コードは次のとおりです。

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
4

1 に答える 1

0
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)

編集

何かおかしいことに気が付きましたか?ファイルでファイルストリームを開き、最初のものを閉じずに、同じ変数を使用して同じファイルで別のファイルストリームをすぐに開きます。これが、VS で開いているファイルを報告する理由の 1 つです。行を削除します。f = New FileStream...

ファイルの削除が原因でイベントが発生すると、ここで別の問題が発生します。

それで:

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

これらの最後の 2 つは何もしていないようです。オブジェクトは作成されますが、使用されません。しかし、objFileは問題のファイルから構築されているため、ファイルの削除や操作を妨げている可能性があります。

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()

これで MD5 コードができたので、ファイルストリーム ( ) を閉じて、f他の作業を行うことができます。開いているファイルを削除または移動することはできません。

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

前のコードと同様に、TestForm がフォーム クラスの場合、そのインスタンスを作成する必要があります。

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

フォームは単なるクラスです。それらを使用する前にインスタンス化する必要があります。

編集の続き

最後に、フリーズはログ イベントでやりすぎた結果です (ログの変更と MD5 の計算と新しいフォームの表示)。多くのフォルダー内の多くのファイルを監視している間、アプリの速度が低下しないことに気付いたでしょう。これは、filewatcher が別のスレッドで実行されるためです。新しいフォームのインスタンスを作成するか、そのイベントから表示すると、フォームは明らかにそのスレッドで実行されます。

実際のロギングに関係のないものを削除するには、コードを作り直す必要があります。その場合、すべてのものの代わりに、変更されたファイルを todo リストを表す List(of String) に追加することができます。MD5 を実行し、そのリストの他の場所で何かを作成して、アプリのスレッドで実行されるようにします。

最終編集

フォームがフリーズすることだけが心配な場合は、これを追加します。

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

それはより大きな問題を遅らせるだけですが、あなたはそれが重要だと考えているようです. 次に、これを 3 回お伝えしましたが、ファイル操作が削除の場合は、削除されたファイルを開くことができないため、ログ ルーチンを終了する必要があります。

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

次に発生する問題は、2 つ以上のファイルが変更された場合です。ファイル/タスクをキューに入れる方法が必要です。いくつかのもののために他のサブを呼び出すアプローチは、物事を個別のタスクに分解しますが、サブと呼ばれるものはFWスレッドから呼び出されるため、問題を移動しました。キューの場合、List(of String) を考えていましたが、独自の BackgroundWorker を持つ新しいクラス (最後の投稿で提案されているように) の方が良いかもしれません。

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 は、新しい宣言を含む (修正された) MD5 サブルーチンです。

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

     Dim sFile As String = e.Argument

もう一度、ハッシュを取得したらファイルを閉じます。

    md5.ComputeHash(f)
    f.Close()

フォームを開かないでください。ハッシュを取得するだけです。

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

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

BackgroundWorker が完了すると、イベントが発生します。

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

これを使用するには、ログ イベントで 1 行のコードを使用します。

  Dim fMgr As New FileMgr(e.FullPath)

各ファイル操作 Windows レポートは、独自の BackgroundWorker を実行する新しいファイル ヘルパーを作成します。あまり多くのことをしていないので、0 バイトより大きいファイルを処理するまで、一度に多くのファイルが生きていることはありません。ファイルが開いていて使用中の場合は、MD5Sub/ProcessFile に Try/Catch も必要です。

監視フォルダーに 6 つのファイルをドロップし、Form2 の 6 つのコピーを取得しました。エラーもフリーズもありませんでした (そして、これらすべてに対する賛成票さえありませんでした)。

于 2013-10-22T13:58:37.050 に答える