Wilson WindowWare Tech Support

WinBatch WinBatch+Compiler WebBatch
Home | Tech Database | Tech BBS | White Papers | Purchase


How to Watch for Files and Then Do Something

Keywords:   watch for files

;********************************************************************
;  This routine watches three different folders to see when a file
;  is created.  It processes the files, then continues watching.
;  It can easily be modified to watch a different number of folders.
;
;  Assumption:   The folders are usually empty.  When a file is dropped 
;  into them, we process the file and then either delete it or move it 
;  somewhere else.  This simplifies processing since we can look in the 
;  directories and grab anything we find there.  If this is not the case 
;  you'll need to add code that decides which files you want to operate on.
;
;  The process displays a window with a STOP button.
;  Push the button to stop processing.
;********************************************************************


;**********************************************************************
;  Create an array to hold the names of the folders you want to watch,
;  then put the folder names into the array.
;********************************************************************
WatchDir = ArrDimension(3)  

WatchDir[0] = "C:\Windows\Desktop\WatchOne"  
WatchDir[1] = "C:\Windows\Desktop\WatchTwo"  
WatchDir[2] = "C:\Windows\Desktop\WatchThree" 

;********************************************************************
;  The remainder of the routine will process as many directories
;  as you have defined above.  (The array size tells it how many.)
;********************************************************************
NumberOfFolders = ArrInfo(WatchDir,1)
FolderArrayTop  = NumberOfFolders - 1

;********************************************************************
;  Function to get an error message after an API error.
;  Pass it the code returned by DllLastError()
;********************************************************************
#DefineFunction SystemMessage(Err)
  Buffer = BinaryAlloc(256)
  BinaryEodSet(Buffer,255)
  if  0 == DllCall(StrCat(DirWindows(1),"Kernel32.dll"),long:"FormatMessageA",long:4096,long:0,long:Err,long:0,lpbinary:Buffer,long:256,long:0)
     Text = StrCat("Error #",Err)
  else
     Text = BinaryPeekStr(Buffer,0,256)
  endif
  BinaryFree(Buffer)
  Return Text
#EndFunction

;********************************************************************
;  Initialize the API.
;  Note.. The "MsgWaitForMultipleObjects" API, which we call below
;         requires a pointer to an array of handles.  We manage this
;         by poking the handles into a binary buffer, and passing
;         the buffer as "lpbinary".
;********************************************************************
User32   = DLLLoad(StrCat(DirWindows(1),"User32.DLL"))
Kernel32 = DllLoad(strcat(DirWindows(1),"KERNEL32.DLL"))
Handles  = ArrDimension(NumberOfFolders)
HandleBinary = BinaryAlloc(NumberOfFolders*4)
For X = 0 to FolderArrayTop
   Handles[X] = DLLCALL(Kernel32,long:"FindFirstChangeNotificationA",lpstr:WatchDir[X],long:1,long:1)
   if Handles[X] == -1          ; -1 is an error status.  Cancel processing
       Err = DllLastError()
       Message(StrCat("Error ",Err),StrCat("Error... Directory = ",WatchDir[X],@CRLF,SystemMessage(Err)))
       for Y = 0 to (X-1)
           DLLCALL(Kernel32,long:"FindCloseChangeNotification",long:Handles[Y])
       next
       DllFree(Kernel32)
       DllFree(User32)
       BinaryFree(HandleBinary)
       Exit
   endif
   BinaryPoke4(HandleBinary,X*4,Handles[X])
Next

;********************************************************************
;  A box with a STOP button
;********************************************************************
BoxesUp("25,25,400,150",@NORMAL)
BoxCaption(1,"Waiting")
BoxDrawText(1,"50,300,700,800","Watching Directories.",@TRUE,0)
BoxButtonDraw(1,1,"STOP","600,200,900,800")

;********************************************************************
;  The Wait Loop
;********************************************************************
Err = 0;
while (1)
    ; -----------------------------------------------------------------------------
    ; Note:  In the following call, "-1" means "No Timeout".  
    ; If you want a timeout you can substitute a time in ms.  (1000 = 1 second.)   
    ; WaitStatus == 258 indicates a timeout.
    ;------------------------------------------------------------------------------
    WaitStatus = DLLCall(User32,long:"MsgWaitForMultipleObjects",long:NumberOfFolders,lpbinary:HandleBinary,long:0,long:-1,long:255)
    Yield()   ; Process any queued system events.
    ; -----------------------------------------------------------------------------
    ;  Test the button.  If the user pressed it, we exit.
    ;------------------------------------------------------------------------------
    if BoxButtonStat(1,1) then break
    ; -----------------------------------------------------------------------------
    ;  A return status of -1 indicates an error.
    ;------------------------------------------------------------------------------
    if WaitStatus < 0 then
        Err = DllLastError()
        Message(StrCat("Error ",Err),StrCat("Error while waiting for new files.",@CRLF,SystemMessage(Err)))
        break
    endif
    ; -----------------------------------------------------------------------------
    ;  If a directory changed the return status is its index in the Handle Array.
    ;  Process the directories that changed.
    ;------------------------------------------------------------------------------
    if WaitStatus < NumberOfFolders
         FileList = FileItemize(StrCat(WatchDir[WaitStatus],"\*.*"))
         FileCount = ItemCount(FileList,@TAB)
         For X = 1 to FileCount
             NewFile = ItemExtract(X,FileList,@TAB)
             ;--------------------------------------------------------------------
             ; Here we can do whatever we want with the new file.
             ; Then (given the assumptions made for this routine)
             ; we delete or move it, so it won't be processed again.
             ;--------------------------------------------------------------------
             Message(StrCat("New File in ",WatchDir[WaitStatus]),StrCat("New File: ",NewFile))
             FileDelete(StrCat(WatchDir[WaitStatus],"\",NewFile))
         Next
         ;--------------------------------------------------------------------
         ; After the API sees a change in a folder, we must tell it to
         ; keep watching for another change.  (Zero status = an error.)
         ;--------------------------------------------------------------------
         if 0 == DLLCALL(Kernel32,long:"FindNextChangeNotification",long:Handles[WaitStatus])
            Err = DllLastError()
            Message(StrCat("Error ",Err),StrCat("Error... Directory = ",WatchDir[WaitStatus],@CRLF,SystemMessage(Err)))
            break
         endif  
    endif
endwhile

;********************************************************************
;   Clean up on exit
;********************************************************************
BinaryFree(HandleBinary)
For X = 1 to FolderArrayTop
    DLLCALL(Kernel32,long:"FindCloseChangeNotification",long:Handles[X])
next
DllFree(Kernel32)
DllFree(User32)
return


Article ID:   W15288