file_watch.hsp

sample\win32_gen2\file_watch.hsp » Plain Format

;
; file_watch.hsp - ReadDirectoryChangesW によるディレクトリ監視
; Win32 API gen2 サンプル (hsp3net 必須)
;
; 使い方:
;   hsp3net から実行する。カレントディレクトリ (curdir) を監視し、
;   ファイルの作成/更新/削除/リネームを検出したらログに表示する。
;   Ctrl+C もしくはウィンドウを閉じて終了。
;
; 動作確認:
;   実行後、別のエクスプローラからカレントフォルダにファイルを
;   作ったり削除したりすると、mes で
;     [ADDED]    hoge.txt
;     [MODIFIED] fuga.txt
;   のように表示される。
;

#include "win32_types_gen2.as"
#include "kernel32_gen2.as"

; --- 未定義の定数を手動で補う ---
#define FILE_LIST_DIRECTORY         0x00000001
#define FILE_FLAG_OVERLAPPED        0x40000000

; FILE_ACTION_* (ReadDirectoryChangesW の通知種別)
#define FILE_ACTION_ADDED            0x00000001
#define FILE_ACTION_REMOVED          0x00000002
#define FILE_ACTION_MODIFIED         0x00000003
#define FILE_ACTION_RENAMED_OLD_NAME 0x00000004
#define FILE_ACTION_RENAMED_NEW_NAME 0x00000005

; --- 監視対象ディレクトリ (curdir) を開く ---
    dir_target = dir_cur
    mes "監視対象: " + dir_target

    ; CreateFileW(dir, FILE_LIST_DIRECTORY, SHARE_READ|WRITE|DELETE,
    ;             NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL)
    sd_null = 0
    share_mode = FILE_SHARE_READ | FILE_SHARE_WRITE | 0x4  ; +FILE_SHARE_DELETE
    hDir = CreateFileW(dir_target, FILE_LIST_DIRECTORY, share_mode, sd_null, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0)
    if hDir = -1 {
        mes "CreateFileW 失敗 (INVALID_HANDLE_VALUE)"
        end
    }

    ; 通知バッファ (FILE_NOTIFY_INFORMATION 列)
    sdim buf, 4096
    dwBytes = 0
    dim ovl_dummy, 1 : ovl_dummy = 0   ; OVERLAPPED* = null

    ; 監視フラグ
    notify = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_SIZE

    mes "変更を待機中... (終了するにはウィンドウを閉じる)"
    objsel 0

*loop
    ; ブロッキング呼び出し: 何か変化があるまで戻らない
    ; ReadDirectoryChangesW の buf は intptr (ポインタ) なので varptr(buf) を渡す
    ret = ReadDirectoryChangesW(hDir, varptr(buf), 4096, 1, notify, dwBytes, ovl_dummy, 0)
    if ret = 0 {
        mes "ReadDirectoryChangesW 失敗"
        CloseHandle hDir
        stop
    }

    ; buf を FILE_NOTIFY_INFORMATION として走査
    ;   offset  0: NextEntryOffset (DWORD)
    ;   offset  4: Action          (DWORD)
    ;   offset  8: FileNameLength  (DWORD, バイト数)
    ;   offset 12: FileName[]      (WCHAR 列, null 終端ではない)
    off = 0
    repeat
        next_off = lpeek(buf, off + 0)
        action   = lpeek(buf, off + 4)
        name_len = lpeek(buf, off + 8)   ; バイト数

        ; WCHAR → cp932 文字列: 一旦別バッファに wchar を吸い出し lstrlenW/変換
        ; 簡易的に wpoke で null 終端を付けた wstr バッファを作って str() する
        sdim wname, name_len + 2
        memcpy wname, buf, name_len, 0, off + 12
        wpoke wname, name_len, 0  ; null 終端

        ; wstr → cp932 変換は hsp3net の cnvwtos() を使う (関数形式)
        fname = cnvwtos(wname)

        switch action
        case FILE_ACTION_ADDED
            mes "[ADDED]    " + fname
            swbreak
        case FILE_ACTION_REMOVED
            mes "[REMOVED]  " + fname
            swbreak
        case FILE_ACTION_MODIFIED
            mes "[MODIFIED] " + fname
            swbreak
        case FILE_ACTION_RENAMED_OLD_NAME
            mes "[RENAMED<] " + fname
            swbreak
        case FILE_ACTION_RENAMED_NEW_NAME
            mes "[RENAMED>] " + fname
            swbreak
        default
            mes "[ACTION=" + action + "] " + fname
        swend

        if next_off = 0 : break
        off += next_off
    loop

    goto *loop