From: Dale Martenson Date: 2002-03-27T03:44:36+09:00 Subject: RE: File change notification? >> Is there a straightforward way of getting notified when a file >> changes? In NT I can block a thread on the handle returned by >> FindFirstChangeNotification. Does something like this exist in Ruby? >> I'm currently using the Cygwin version but could be convinced to >> switch. My first example was a Ruby-way of monitoring a specific file based on it modification date. Here is a way of call the Win32 API directly from Ruby to accomplish the task. Is this what you were looking for? # ----------------------------------------------------------------------- # WARNING: Win32 Specific code to follow -- You have been warned!! # ----------------------------------------------------------------------- require 'Win32API' # ----------------------------------------------------------------------- # definitions for Windows constants # ----------------------------------------------------------------------- INVALID_HANDLE_VALUE = -1 INFINITE = 0xFFFFFFFF WAIT_OBJECT_0 = 0x00000000 FILE_NOTIFY_CHANGE_FILE_NAME = 0x00000001 FILE_NOTIFY_CHANGE_DIR_NAME = 0x00000002 FILE_NOTIFY_CHANGE_ATTRIBUTES = 0x00000004 FILE_NOTIFY_CHANGE_SIZE = 0x00000008 FILE_NOTIFY_CHANGE_LAST_WRITE = 0x00000010 FILE_NOTIFY_CHANGE_LAST_ACCESS = 0x00000020 FILE_NOTIFY_CHANGE_CREATION = 0x00000040 FILE_NOTIFY_CHANGE_SECURITY = 0x00000100 # ----------------------------------------------------------------------- # Definitions for Windows function calls # ----------------------------------------------------------------------- # HANDLE FindFirstChangeNotification( # LPCTSTR lpPathName, // directory name # BOOL bWatchSubtree, // monitoring option # DWORD dwNotifyFilter // filter conditions #); k32FindFirstChangeNotification = Win32API.new("kernel32", "FindFirstChangeNotification", ['P', 'I', 'L'], 'L') # BOOL FindNextChangeNotification( # HANDLE hChangeHandle // handle to change notification # ); k32FindNextChangeNotification = Win32API.new("kernel32", "FindNextChangeNotification", ['L'], 'I') # DWORD WaitForMultipleObjects( # DWORD nCount, // number of handles in array # CONST HANDLE *lpHandles, // object-handle array # BOOL bWaitAll, // wait option # DWORD dwMilliseconds // time-out interval # ); k32WaitForMultipleObjects = Win32API.new("kernel32", "WaitForMultipleObjects", ['L', 'P', 'I', 'L'], 'L') # ----------------------------------------------------------------------- # Create notification events # ----------------------------------------------------------------------- dwChangeHandles = [] # Watch the C:\WINDOWS directory for file creation and # deletion. dwChangeHandles[0] = k32FindFirstChangeNotification.Call( "C:\\WINDOWS", # directory to watch 0, # do not watch the subtree FILE_NOTIFY_CHANGE_FILE_NAME) # watch file name changes if dwChangeHandles[0] == INVALID_HANDLE_VALUE then exit end # Watch the C:\ subtree for directory creation and # deletion. dwChangeHandles[1] = k32FindFirstChangeNotification.Call( "C:\\", # directory to watch 1, # watch the subtree FILE_NOTIFY_CHANGE_DIR_NAME); # watch dir. name changes if dwChangeHandles[1] == INVALID_HANDLE_VALUE then exit end # Create storage for two event handles (LONG) lp_dwChangeHandles = " " * 8 # Pack event handles into newly created storage area to be used for Win32 call lp_dwChangeHandles = dwChangeHandles.pack("LL") # Change notification is set. Now wait on both notification # handles and refresh accordingly. while true # Wait for notification. dwWaitStatus = k32WaitForMultipleObjects.Call(2, lp_dwChangeHandles, 0, INFINITE) case dwWaitStatus when WAIT_OBJECT_0 # A file was created or deleted in C:\WINDOWS. # Do what you need to do and restart the # change notification. print "#{Time.now}: A file in C:\\WINDOWS was messed with!\n" if k32FindNextChangeNotification.Call( dwChangeHandles[0] ) == 0 then exit end when WAIT_OBJECT_0+1 # A directory was created or deleted in C:\. # Do what you need to do and restart the # change notification. print "#{Time.now}: The C:\\ directory was messed with!\n" if k32FindNextChangeNotification.Call( dwChangeHandles[1] ) == 0 then exit end else exit end end