Solved

Change in Dir: Callback for VB5

Posted on 1999-01-11
7
546 Views
Last Modified: 2008-02-01

I need a working example of a VB Callback which executes
upon changes to a directory path which I designate
programmatically beforehand.

In other words, I want to be able to target a directory
path (e.g., "C:\MyApps\MyData\MyDir1"), then have a Callback
component which fires anytime a user:

   o  Copies a file into that directory from another dir,
      or creates a file there through other means.

       > What are the new file's attributes?
          > Name
          > Time stamp
          > Permissions
          > Size
         
   o  Renames a file in that directory

       > What are the renamed file's attributes?
          > Old name (prior to renaming)
          > New name (now)
          > Time stamp
          > Permissions
          > Size

   o  Copies a file in that directory, pastes into same
      directory.

       > What are the new file's attributes?
          > Name
          > Time stamp
          > Permissions
          > Size

   o  Deletes a file within the specified directory.

       > What was the deleted file's name?


This Callback, .BAS, or Class module (I don't care which) MUST FIRE ON THE CHANGE EVENT, not on request from user/developer. The target function (indicating what happened, as outlined above) must fire only when something actually happened in the specified directory. The balance
of the time--while the parent app is loaded--the "listener"
module is doing just that:  listening for changes in that directory.

Not to seem unfriendly, but the answer to this non-trivial
question is NOT simply providing the relevant Win32 API
functions
   FindFirstChangeNotification()
and
   FindNextChangeNotification()

The answer will likely INCLUDE these calls, but the
example providedmust work. I'm giving it 200 points (and perhaps more later) because it requires more than just pointing me to the relevant API calls.

Anyone have ideas on this?  Thanks a lot for your help.

bryker@mpsisys.com
0
Comment
Question by:bryker
  • 3
  • 2
  • 2
7 Comments
 
LVL 2

Expert Comment

by:spenner
Comment Utility
Look at this code on this page I found
http://www.mvps.org/vbnet/code/fileapi/watchedfolder.htm

It "watches" a directory and notifies you whenever something occurs in that directory

It also includes code to grab the properties of the newly created file.  

I don't know if it will work when you delete a file - but it appears to do everything you want.  The reason I don't post it here is because the page also includes a long explanation on the function

While this is kind of "pointing you at the relevant api calls", I think this should answer your question.  If not, then reject this answer.
0
 

Author Comment

by:bryker
Comment Utility

This does indicate the change event, but only the fact--it doesn't inform of what changed, nor how the subject(s) changed.
0
 
LVL 3

Accepted Solution

by:
Michelt earned 200 total points
Comment Utility
Okay Here are the API Calls To Use for this:

Private Declare Function FindFirstChangeNotification Lib_ "kernel32" Alias "FindFirstChangeNotificationA" (ByVal_ lpPathName As String, ByVal bWatchSubtree As Long, _  
ByVal dwNotifyFilter As Byte) As Long

(This One will Find the First Change to Either Directory or File)

Private Declare Function FindNextChangeNotification Lib _ "kernel32" (ByVal hChangeHandle As Long) As Long

(This One will Find the next Change to Either Directory or File)


and Here are the steps to write the correct VB Code to that uses these API calls

1. Create a Bas Module and put the following text inside:

Option Explicit

Public Const INFINITE = &HFFFF
Public Const FILE_NOTIFY_CHANGE_FILE_NAME As Long = &H1
Public Const FILE_NOTIFY_CHANGE_DIR_NAME As Long = &H2
Public Const FILE_NOTIFY_CHANGE_ATTRIBUTES As Long = &H4
Public Const FILE_NOTIFY_CHANGE_SIZE As Long = &H8
Public Const FILE_NOTIFY_CHANGE_LAST_WRITE As Long = &H10
Public Const FILE_NOTIFY_CHANGE_LAST_ACCESS As Long = &H20
Public Const FILE_NOTIFY_CHANGE_CREATION As Long = &H40
Public Const FILE_NOTIFY_CHANGE_SECURITY As Long = &H100
Public Const FILE_NOTIFY_FLAGS = FILE_NOTIFY_CHANGE_ATTRIBUTES_  Or FILE_NOTIFY_CHANGE_FILE_NAME Or _
FILE_NOTIFY_CHANGE_LAST_WRITE

Public Declare Function FindFirstChangeNotification Lib "kernel32" _
    Alias "FindFirstChangeNotificationA" _
   (ByVal lpPathName As String, _
    ByVal bWatchSubtree As Long, _
    ByVal dwNotifyFilter As Long) As Long

Public Declare Function FindCloseChangeNotification Lib_ "kernel32" (ByVal hChangeHandle As Long) As Long

Public Declare Function FindNextChangeNotification Lib_ "kernel32" (ByVal hChangeHandle As Long) As Long

Public Declare Function WaitForSingleObject Lib "kernel32" _
   (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long

Public Const WAIT_OBJECT_0 = &H0
Public Const WAIT_ABANDONED = &H80
Public Const WAIT_IO_COMPLETION = &HC0
Public Const WAIT_TIMEOUT = &H102
Public Const STATUS_PENDING = &H103

end of Bas module

Then on the Form create the following:

1. a Label Called lblMsg
2. a Listbox called List1
3. a Command Button called cmdend
4. a Command Button called cmdstop
5. a Command Button called cmdbegin

Dim changeHandle As Long
Dim hWatched As Long
Dim terminateFlag As Long

Private Sub Form_Load()

   lblmsg = "Press 'Begin Watch'"
   
End Sub


Private Sub cmdEnd_Click()

   If hWatched > 0 Then Call WatchDelete(hWatched)
     
   Unload Me
   Set Form1 = Nothing

End Sub


Private Sub cmdStop_Click()

   Call WatchDelete(hWatched)
   hWatched = 0
     
   cmdBegin.Enabled = True
   lblmsg = "Press 'Begin Watch'"

End Sub


Private Sub cmdBegin_Click()

   Dim r As Long
   Dim watchPath As String
   Dim watchStatus As Long
   
   watchPath = "c:\Test"
   terminateFlag = False
   cmdBegin.Enabled = False
   
   

   WatchChangeAction watchPath
   
   MsgBox "Beginning watching of folder " & watchPath & " .. press OK"
   
   hWatched = WatchCreate(watchPath, FILE_NOTIFY_FLAGS)
   
   watchStatus = WatchDirectory(hWatched, 100)
   
   If watchStatus = 0 Then
   
       WatchChangeAction watchPath
       
       MsgBox "a change has occured, continuing watch..." & vbcr_
        & "This is the trigger to activate other apps/funcs"
       Do
         watchStatus = WatchResume(hWatched, 100)
         
         If watchStatus = -1 Then
             MsgBox "finished Watching " & watchPath
         
         Else: WatchChangeAction watchPath
               MsgBox "a change has occured,continuing
               watch..." & vbcr_
               & "This is the trigger to activate other
               apps/funcs"
       
             
         End If
         
       Loop While watchStatus = 0
   
   
   Else
      MsgBox "Finished Watching" & watchPath
   
   End If
   
End Sub


Private Function WatchCreate(lpPathName As String, flags As Long) As Long

   WatchCreate = FindFirstChangeNotification(lpPathName, False, flags)

End Function


Private Sub WatchDelete(hWatched As Long)
   
   Dim r As Long
   
   terminateFlag = True
   DoEvents

   r = FindCloseChangeNotification(hWatched)
 
End Sub


Private Function WatchDirectory(hWatched As Long, interval As Long) As Long

   Dim r As Long
   Do
      r = WaitForSingleObject(hWatched, interval)
      DoEvents
   
   Loop While r <> 0 And terminateFlag = False
   
   WatchDirectory = r
   
End Function


Private Function WatchResume(hWatched As Long, interval) As Boolean

   Dim r As Long
   
   r = FindNextChangeNotification(hWatched)
   
   Do
     
      r = WaitForSingleObject(hWatched, interval)
      DoEvents
   
   Loop While r <> 0 And terminateFlag = False
   
   WatchResume = r
   
End Function


Private Sub WatchChangeAction(fPath As String)

   Dim fName As String
   
   List1.Clear

   fName = Dir(fPath & "\" & "*.txt")
   
   If fName > "" Then
   
      List1.AddItem "path: " & vbTab & fPath
      List1.AddItem "file: " & vbTab & fName
      List1.AddItem "size: " & vbTab & FileLen(fPath & "\" & fName)
      List1.AddItem "attr: " & vbTab & GetAttr(fPath & "\" & fName)
   
   End If

End Sub


Then Before Running this create a directory called : "c:\test"
This will be the directory that is being watched for changes.
as sson as a Change Occurs the program will notify you with a MSGBOX. If you add a file to The Directory, it will List Path, Name, Attribs and Size  .

Try it it Works, plus the application does hardy use any CPU usage while waiting for the Change Notification. !


0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 
LVL 2

Expert Comment

by:spenner
Comment Utility
To Michelt
In case you haven't noticed, your answer is exactly the same as the one I posted.  You took yours from the vbnet website just like me.  Also, you'll note that the code does NOT get the attributes of the file that has been changed.  Rather, it gets the attributes of the first txt file in the directory.  To get the attributes of the file that has been changed, you would have to compare the time/date of all the files in the dir to the current time/date and take whichever is within 1 minute.

Bryker
I have been unable to find a way to do what you want.  I'm sure there's a way, it's just that I don't know it.
0
 

Author Comment

by:bryker
Comment Utility

Michelt:

Your answer doesn't give me all I want, but I've become convinced that what I want to do is not (feasibly) do-able. I'll give you credit just to close this thing out.
0
 
LVL 3

Expert Comment

by:Michelt
Comment Utility
To Spenner

I don't Quite remember Where I got the Code .. It might have been from VBnet or one of the VB programmer's Journals. But that's Totally Besides the point. As for the the File Attributes I was reffering to  are returned under

      fPath
      fName
      FileLen(fPath & "\" & fName)
      GetAttr(fPath & "\" & fName)

The reason I know this Works is because I use it in one of the Client Server apps. The Only Difference is that The Contents of the Directory Are stored in a Collection To which any and every change is compared.

This way any of the Above Requested Info can be returned. There is also a Count Variable that will know wether or not a File is Added ! This is All Object Oriented in the program and all data is Passes through the properties.

Trust me it works. Itr's the Backend that Drives AS400 to SQL server Updates. Haven't lost a bit of info yet !

   


0
 
LVL 2

Expert Comment

by:spenner
Comment Utility
Fascinating
0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Introduction In a recent article (http://www.experts-exchange.com/A_7811-A-Better-Concatenate-Function.html) for the Excel community, I showed an improved version of the Excel Concatenate() function.  While writing that article I realized that no o…
Background What I'm presenting in this article is the result of 2 conditions in my work area: We have a SQL Server production environment but no development or test environment; andWe have an MS Access front end using tables in SQL Server but we a…
As developers, we are not limited to the functions provided by the VBA language. In addition, we can call the functions that are part of the Windows operating system. These functions are part of the Windows API (Application Programming Interface). U…
Get people started with the utilization of class modules. Class modules can be a powerful tool in Microsoft Access. They allow you to create self-contained objects that encapsulate functionality. They can easily hide the complexity of a process from…

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now