Skip to content

Instantly share code, notes, and snippets.

@hisui
Created May 10, 2012 13:23
Show Gist options
  • Save hisui/2652956 to your computer and use it in GitHub Desktop.
Save hisui/2652956 to your computer and use it in GitHub Desktop.
更新ファイル監視に…
require "Win32API"
class FilesystemWatcher
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
WAIT_OBJECT_0 = 0x00000000
WAIT_ABANDONED_0 = 0x00000080
WAIT_TIMEOUT = 0x00000102
WAIT_FAILED = -1
INFINITE = 0xFFFFFFFF
INVALID_HANDLE_VALUE = -1
# p : *void (ポインタ)
# i : int, DWORD, BOOL など
# l, n : long, HANDLE など
# v : void
FindFirstChangeNotification = Win32API.new "kernel32", "FindFirstChangeNotification", %w(p i i), "n"
FindNextChangeNotification = Win32API.new "kernel32", "FindNextChangeNotification", %w(n), "i"
FindCloseChangeNotification = Win32API.new "kernel32", "FindCloseChangeNotification", %w(n), "i"
WaitForSingleObjectEx = Win32API.new "kernel32", "WaitForSingleObjectEx", %w(n i i), "i"
WaitForMultipleObjectsEx = Win32API.new "kernel32", "WaitForMultipleObjectsEx", %w(n p i l i), "i"
def initialize
@handle_map = {}
end
def watch(filename, subtree=true, attachment=nil, flags=
FILE_NOTIFY_CHANGE_FILE_NAME |
FILE_NOTIFY_CHANGE_DIR_NAME |
FILE_NOTIFY_CHANGE_ATTRIBUTES |
FILE_NOTIFY_CHANGE_SIZE |
FILE_NOTIFY_CHANGE_LAST_WRITE |
FILE_NOTIFY_CHANGE_CREATION )
handle = FindFirstChangeNotification.call(filename, (subtree ? 1: 0), flags)
if handle == INVALID_HANDLE_VALUE
raise RuntimeError.new "Failed to call WINAPI:FindFirstChangeNotification(...)."
end
@handle_map[handle] = attachment
handle
end
def unwatch(handle)
unless @handle_map.key? handle
raise ArgumentError.new "Unregistered handle object:#{handle}"
end
FindCloseChangeNotification.call handle
@handle_map.delete handle
end
def close
@handle_map.each_key {|handle|
FindCloseChangeNotification.call handle
}
end
def wait(timeout=INFINITE)
result = WaitForMultipleObjectsEx.call(
@handle_map.size, @handle_map.keys.pack("V*"), 0, timeout, 0)
if result == WAIT_FAILED
raise RuntimeError.new "Failed to call WINAPI:WaitForMultipleObjectsEx(...)."
end
@handle_map.each {|handle, attachment|
next unless WAIT_OBJECT_0 == WaitForSingleObjectEx.call(handle, 0, 0)
if FindNextChangeNotification.call(handle) == 0
raise RuntimeError.new "Failed to call WINAPI:FindNextChangeNotification(...)."
end
yield [handle, attachment]
}
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment