Results 1 to 21 of 21

Thread: VB.Net 2010 - FileSystemWatchers

  1. #1

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Question VB.Net 2010 - FileSystemWatchers

    Hello, I'm having issues trying to get file system watchers working properly, I'm not sure whats not right here, I want to use multiple, but I can't even get one of them to fire on an event...

    simple form with a listbox for folders to watch and a listbox to list changes detected and a command button to launch watchers.

    Code:
     
    
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            lstFolders.Items.Add("C:\temp\1")
            lstFolders.Items.Add("C:\temp\2")
            lstFolders.Items.Add("C:\temp\3")
    
        End Sub
    
        Private Sub cmdWatch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdWatch.Click
    
            For i As Integer = 0 To lstFolders.Items.Count - 1
                'MsgBox(Me.lstFolders.Items(i))
                fnWatchFolder(lstFolders.Items(i), "*.txt")
            Next
    
        End Sub
    
        Public Function fnWatchFolder(ByVal strFolderToWatch As String, ByVal strFileExtension As String) As Boolean
    
            ' Get the path to the directory we will watch.
            ' Make the FileSystemWatcher.
    
            Dim FileWatcher = New FileSystemWatcher(strFolderToWatch, strFileExtension)
            FileWatcher.NotifyFilter = NotifyFilters.FileName ' Or NotifyFilters.FileName
            FileWatcher.EnableRaisingEvents = True
            AddHandler FileWatcher.Changed, AddressOf OnChanged
            fnWatchFolder = True
        End Function
        Public Sub OnChanged(ByVal source As Object, ByVal e As FileSystemEventArgs)
            MsgBox("change occured")
            lstChanges.Items.Add(e.FullPath & " : " & e.ChangeType.ToString("G"))
        End Sub

  2. #2
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    You are creating a new FileSystemWatcher inside the method, once you leave the method, it is gone! .Net got rid of it as you have left no way to get back to it. Move the declaration out, if you need more than one, then create a (list of) them.

  3. #3

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    thanks for the info, I understand what you're saying but I dont quite understand how best to structure what your saying... any chance you can provide me a little more guidance

  4. #4
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    Only if you invite me over to stay in NZ for a month!


    For now, just move the declaration out of the method.
    Code:
    Private WithEvents TheFileWatcher As FileSystemWatcher
    
    Public Function fnWatchFolder(ByVal strFolderToWatch As String, ByVal strFileExtension As String) As Boolean
    
            ' Get the path to the directory we will watch.
            ' Make the FileSystemWatcher.
    
            TheFileWatcher = New FileSystemWatcher(strFolderToWatch, strFileExtension)
            TheFileWatcher.NotifyFilter = NotifyFilters.FileName ' Or NotifyFilters.FileName
            TheFileWatcher.EnableRaisingEvents = True
    '        AddHandler FileWatcher.Changed, AddressOf OnChanged  You can use the WithEvents above to just xxx Handles TheFileWatcher.Changed event
            Return True
        End Function

  5. #5

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    haha yes you'd like NZ, but I tell ya, we spent far less money on living expenses when we were living in London than what we do here, its become incredibly expensive place to live here.

    I understand your changes and they all work well, but how do i instigate this withevents/onchanged method now... previosuly with the addhandler when and event was raised it woudl go to the private sub onchanged and then you could do what ever with the notifican event... how do i get to this same place? your comment xxx the ... has me lost!

  6. #6
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    I have toured around NZ, still fancy moving over!


    Code:
    Public Sub OnChanged(ByVal source As Object, ByVal e As FileSystemEventArgs) Handles TheFileWatcher.Changed
    
    ...
    End Sub

  7. #7

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    You should do it, plenty of work here for coders, we're trying to hire one at the moment. (www.seek.co.nz or www.trademe.co.nz for job listings in NZ)

    Okay thanks for the above that all works well, except after one detection the filewatcher stops and so does the debugger! shouldnt it keep running until the enableraisingevents = false?
    I want to continue monitoring until I choose to stop.

  8. #8
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    I already had visa to live, but could not sell the house or I would already be there!

    Likely you had an exception of some sort, I would guess that the event is not being fired on the main thread, so you adding an entry to the listbox is causing a cross-thread exception. For now, take out that line, just use the messagbox to ensure it is working. If this is working OK, then lookup UI threading in the code bank.

  9. #9

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    Private WithEvents TheFileWatcher As FileSystemWatcher
    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    lstFolders.Items.Add("C:\temp\1")
    lstFolders.Items.Add("C:\temp\2")

    Me.cmdStopWatch.Enabled = False
    End Sub
    Public Sub cmdWatch_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cmdWatch.Click
    fnWatchFolders()
    End Sub

    Public Function fnWatchFolders() As Boolean
    'Only seems to watch the last folder passed to the fnWatchFolder

    For i As Integer = 0 To lstFolders.Items.Count - 1
    TheFileWatcher = New FileSystemWatcher(lstFolders.Items(i), "*.txt")
    TheFileWatcher.NotifyFilter = NotifyFilters.FileName
    TheFileWatcher.EnableRaisingEvents = True
    Next
    cmdWatch.Enabled = False
    cmdStopWatch.Enabled = True
    cmdAddFolder.Enabled = False
    cmdRemoveFolder.Enabled = False
    cmdExit.Enabled = False
    Return True


    End Function

    Public Sub OnChanged(ByVal source As Object, ByVal e As FileSystemEventArgs) Handles TheFileWatcher.Changed, TheFileWatcher.Created, TheFileWatcher.Renamed, TheFileWatcher.Deleted
    MsgBox("Change detected: " & (e.FullPath & " : " & e.ChangeType.ToString("G")))
    Debug.Print("change" & e.FullPath & " : " & e.ChangeType.ToString("G"))
    Dim strChangeItem As String = ("change" & e.FullPath & " : " & e.ChangeType.ToString("G"))
    'addChangedDataToChangedListboxInvoker(strChangeItem) ' doesn't work as expected yet.
    End Sub



    Now as i see it, each time a filesystem watcher is instigated via the loop that holds the folder locations, the filesystemwatcher is getting overidden to only monitor that last folder.

    somehow does there need to be a collection of file system watchers that each are incremented so that there is FSW1, FSW2 etc so that it can handle this? and then are the onchanged events FSW.changed fsw.created need to be fsw(x).created etc or am i over complciating this...
    I dont get how this needs to be structured, yet it seems so simple!!!

  10. #10
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    Yes, a collection of system watchers. I gave you a hint earlier .

    Code:
    Private MyFSWList As New Generic.List(Of FileSystemWatcher)
    Code:
    'Inside a loop
    Dim TheFileWatcher As New FileSystemWatcher(lstFolders.Items(i), "*.txt")
    TheFileWatcher.NotifyFilter = NotifyFilters.FileName
    TheFileWatcher.EnableRaisingEvents = True
    AddHandler TheFileWatcher. xxxxx, AdressOf xxx 'You can not use withevents on items that are not declared individually
    MyFSWList.Add(TheFileWatcher) 'Adding this to the collection keeps a reference to it, thus stopping it going out of scope

  11. #11

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    Okay, so theory was right, but implementation still unsure...

    remembering, that i will have (X) number of folders to watch. and this will only be known at runtime, the code needs to read in these values and create a 'handled' watcher for each instance. so each instance that is identified at runtime let say 5, will need to be declared somehow in here with the xxx's ?


    For i As Integer = 0 To lstFolders.Items.Count - 1
    Dim TheFileWatcher As New FileSystemWatcher(lstFolders.Items(i), "*.txt")
    TheFileWatcher.NotifyFilter = NotifyFilters.FileName
    TheFileWatcher.EnableRaisingEvents = True
    AddHandler TheFileWatcher. xxxxx, AdressOf xxx 'You can not use withevents on items that are not declared individually
    MyFSWList.Add(TheFileWatcher) 'Adding this to the collection keeps a reference to it, thus stopping it going out of scope_
    Next

    It would seem that you are giving me an inch, when I really need a foot.
    setting myself up for beer when you get down here again aren't I!

  12. #12
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    If I gave you a foot, you would not know what to do with it next time .

    Code:
    Dim TheFileWatcher As New FileSystemWatcher(lstFolders.Items(i), "*.txt")
    Notice the NEW keyword, it is creating a new copy. Because it is new, you have no reference to it, you have no handlers, and nothing setup to tell you about changes. So, the next couple of lines setup those parts

    Code:
    TheFileWatcher.NotifyFilter = NotifyFilters.FileName
    TheFileWatcher.EnableRaisingEvents = True
    Then you have to attach up the handles manually, which you know how to do, as you did it in the first post!

    Code:
     AddHandler TheFileWatcher.Changed, AddressOf OnChanged
    I did not give you this directly, as you have actually changed the events you are watching since your first post to include others:

    Code:
    AddHandler TheFileWatcher.Changed, AddressOf OnChanged
    AddHandler TheFileWatcher.Created, AddressOf OnChanged
    Remember, this is inside a loop, and you are calling this on every NEW watcher, so you are adding in your example 5 handlers for .Changed, and another 5 for .Created etc etc.

  13. #13

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    Okay, brilliant, thanks for clarifying that...
    so the below works well and makes sense, I guess the addhandler creates its own magical accessible instance of 'thefilewatcher' which is why it didnt makes sense to me. (surely it would overwrite each time, but it doesnt so good)


    Code:
     Public Function fnWatchFolders() As Boolean
    
            For i As Integer = 0 To lstFolders.Items.Count - 1
                Dim TheFileWatcher As New FileSystemWatcher(lstFolders.Items(i), "*.txt")
                TheFileWatcher.NotifyFilter = NotifyFilters.FileName
                TheFileWatcher.EnableRaisingEvents = True
                AddHandler TheFileWatcher.Changed, AddressOf OnChanged
                AddHandler TheFileWatcher.Created, AddressOf OnChanged
                AddHandler TheFileWatcher.Renamed, AddressOf OnChanged
                AddHandler TheFileWatcher.Deleted, AddressOf OnChanged
    
                MyFSWList.Add(TheFileWatcher) 'Adding this to the collection keeps a reference to it, thus stopping it going out of scope_
            Next
            cmdWatch.Enabled = False
            cmdStopWatch.Enabled = True
            cmdAddFolder.Enabled = False
            cmdRemoveFolder.Enabled = False
            cmdExit.Enabled = False
            Return True
    
        End Function

    Now moving back to an earlier query, which is providing visual notification of the changes, so lstchanges.items.add(strchangeItem) This fails to work and the program just halts as we talked about earlier, so i tried RTFM and invoked the following, but this just doesnt not seem to work, no doubt have got this wrong somewhere! (commented in magenta)

    Code:
        Public Sub OnChanged(ByVal source As Object, ByVal e As FileSystemEventArgs) Handles TheFileWatcher.Changed, TheFileWatcher.Created, TheFileWatcher.Renamed, TheFileWatcher.Deleted
            Dim strChangeItem As String = ("Change Detected: " & e.FullPath & " : was " & e.ChangeType.ToString("G"))
            MsgBox(strChangeItem)
            Debug.Print(strChangeItem)
            'lstChanges.Items.Add(strChangeItem)        'addChangedDataToChangedListboxInvoker(strChangeItem) ' doesn't work as expected yet.    End Sub
    
        Private Delegate Sub addChangedDataToChangedListboxInvoker(ByVal strChangeItem As String)
        Private Sub addChangedDataToChangedListbox(strChangeItem As String)
            If Me.lstChanges.InvokeRequired Then
                Me.lstChanges.Invoke(New addChangedDataToChangedListboxInvoker(AddressOf addChangedDataToChangedListbox))
            Else
                Me.lstChanges.Items.Add(strChangeItem)
            End If
        End Sub


    Also, I'm guessing we need to use that collection created above, when we want to stop the filewatcher from running,

    Obviously here, its not going to be an instance anymore so will fail, as we want to use the collection of TheFileWatcher(s) and set .enableraisingevents to false for each of the items in the collection somehow ?

    Code:
        Private Sub cmdStopWatch_Click(sender As System.Object, e As System.EventArgs) Handles cmdStopWatch.Click
    
            TheFileWatcher.EnableRaisingEvents = False
            cmdWatch.Enabled = True
            cmdStopWatch.Enabled = False
            cmdAddFolder.Enabled = True
            cmdRemoveFolder.Enabled = True
            cmdExit.Enabled = True
        End Sub

  14. #14

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    Hmnn seems the closing the watchers was easier than I expected...

    Code:
        For Each fsw In MyFSWList
                fsw.EnableRaisingEvents = False
            Next
    works a treat...

    the updating of controls is not so easy!

  15. #15
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    Quote Originally Posted by n10ct View Post
    I guess the addhandler creates its own magical accessible instance of 'thefilewatcher' which is why it didnt makes sense to me. (surely it would overwrite each time, but it doesnt so good)
    There is no magic involved, it was as I explained earlier, you create a NEW filewatcher object inside the loop first, it is this NEW object that you add the handler for.

  16. #16
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    In answer to your other question, there is an example here of how to access the control from off the UI thread exactly as you need.

    Code:
    Private Delegate Sub SetTextBoxText(ByVal text As String) 
    
    Private Sub SetTextBoxText(ByVal text As String)
        If Me.TextBox1.InvokeRequired Then
            Me.TextBox1.Invoke(New SetTextBoxTextInvoker(AddressOf SetTextBoxText), _
                               text)   
        Else
            Me.TextBox1.Text = text
        End If
    End Sub
    You seem to have used this, but I notice a crucuial parameter missing from this line?

    Code:
      Me.lstChanges.Invoke(New addChangedDataToChangedListboxInvoker(AddressOf addChangedDataToChangedListbox))

  17. #17

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Re: VB.Net 2010 - FileSystemWatchers

    doh! works like a charm, must have cut off that damn parameter!!!
    thank you for your direction!! kinda glad I forced myself to do this in vb.net, and not just do it in vb6 (which would have been way faster!) next step is to see if i can manipulate services like i could with vb6 and provide this as a windows service that has some notifyicon and form capacity as well. ( yeah i know this breaks some rules but works faultlessly in vb6 on a few hundred thousand desktops I know of. haha.
    I imagine .net service control/creation maybe harder to manipulate!

  18. #18
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    Actually it is far far easier than in VB6 .

  19. #19

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Talking Re: VB.Net 2010 - FileSystemWatchers

    Hmnn, beg to differ on the far easier in VB6,
    you are so limited in what you can "make happen" with all the new rules etc, (but its easier from the point of view you dont need a whole structure template if you dont already have one) but in anycase I have managed to get a windows service running and all the SQL using LINQ (woooooo!) working and populating a SQL database beautifully, currently it runs at around 1000 event rows per day, which is great.

    I have one issue that doing my head in, and the only way I have been able to successfuly debug the service, to get the exact line of code that the errors is occuring is do eventlog reporting on a per line of code basis!

    The issue with this fault is that it happens every 600 - 800 events ( or every 8 - 12 hours) so debugging manually is not possible.

    So for part of my filesystemwatcher OnChanged event:

    Code:
    Dim intFileSize As Integer
    
                Try
                    LogInfo("debug run 15")
                    Dim info As New FileInfo(strChangeFullFilePath)
                    LogInfo("debug run 16")
                    intFileSize = info.Length
                    LogInfo("debug run 17")
                Catch ex As Exception
                    LogInfo("debug run 18")
                    Throw ex
                    LogInfo("debug run 19")
                End Try
    
                LogInfo("debug run 20")
                If intFileSize = Nothing Then intFileSize = 0
                LogInfo("debug run 21")

    Now all this does obviously is grabs the filesize for the file that the filesystemwatcher has discovered, in my case its a .TMP file that is renamed to .XXX when it has finished the copy routine.

    So every 600 - 800 events (or 8 - 12 hrs), I'm getting a:

    Application: OnlineReportingEngine.exe Framework Version: v4.0.30319 Description: The process was terminated due to an unhandled exception. Exception Info: System.OverflowException Stack: at OnlineReportingEngine.OnlineReportingEngineService.OnChanged(System.Object, System.IO.FileSystemEventArgs) at System.IO.FileSystemWatcher.CompletionStatusChanged(UInt32, UInt32, System.Threading.NativeOverlapped*) at System.Threading._IOCompletionCallback.PerformIOCompletionCallback(UInt32, UInt32, System.Threading.NativeOverlapped*)


    In my event log reporting i am getting "Debug Run 15", "Debug Run 16","Debug Run 18" which means the offending line of code is definately:

    Code:
    intFileSize = info.Length
    now for what ever reason, it might be a 200GB file or a 200MB file, so this could just be a timing thing, but regardless, I want to do this right..

    I could just use a thread sleep for say 5000, but i'd be happy enough for the overflow error to be handled exception out and just present 0 as filesize, rather than crash the service, but id prefer to get the filesize.

    What would be the best way to handle this kind of situation ?

    and why is my try catch not handling it? what have I done wrong here?
    all my others are working as expected, just this one is odd.

  20. #20
    PowerPoster
    Join Date
    Mar 2002
    Location
    UK
    Posts
    4,780

    Re: VB.Net 2010 - FileSystemWatchers

    The answer to your issue is pretty simple, look at the documentation for the .Length property and you will see that it is in fact a Long, not an Integer. You are finding a file that is longer than the size of the integer. You should actually get this as an error if you have Option Strict/Explicit turned On (should do anyway).

    Your Try/Catch is handling the exception, however you are just throwing it again, which will stop the process as nothing else higher up the stack is available to catch it.
    Last edited by Grimfort; Apr 13th, 2012 at 08:00 AM.

  21. #21

    Thread Starter
    Junior Member
    Join Date
    Sep 2004
    Location
    New Zealand
    Posts
    31

    Red face Re: VB.Net 2010 - FileSystemWatchers

    Oh my god!! I can't believe I missed that!
    Thank you yet again! Geez gonna be more like a crate of beers when you get here!

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width