ファイル更新監視
ひとりWikiで外部エディタを使えるようにするための前準備として、表示中のファイルが更新されたら表示も更新する処理を入れる必要があります。そのためにファイル更新を検知する仕組みが必要になります。タイマーで一定時間毎にファイルのタイムスタンプをチェックするというのでも目的は果たせますが、あんまり頻繁にタイムスタンプを調べるのも今ひとつだと思い FindFirstChangeNotification を使う方法にしました。
そうするとスレッドだなということで作ったのが以下のクラス。コンストラクタで、ファイルが更新されたことを検知した時に呼ばれるメソッドを指定し、SetNotifyFile で監視するファイルを指定したら Resume します。
unit UFileChangeNotification; interface uses Classes, Windows; type TFileChangeNotificationProc = procedure(FileName: string) of object; TFileChangeNotification = class(TThread) private FChangeHandle: THandle; FFileChangeNotificationProc: TFileChangeNotificationProc; FLastErrorCode: integer; FNotifyFile: string; FUpdateTime: integer; procedure CallBack; function GetFileUpdateTime(FileName: string): integer; protected procedure Execute; override; public constructor Create( FileChangeNotificationProc: TFileChangeNotificationProc); function SetNotifyFile(FileName: string): boolean; property LastErrorCode: integer read FLastErrorCode; property NotifyFile: string read FNotifyFile; end; implementation uses SysUtils; { TFileChangeNotification } procedure TFileChangeNotification.CallBack; begin FFileChangeNotificationProc(FNotifyFile); end; constructor TFileChangeNotification.Create( FileChangeNotificationProc: TFileChangeNotificationProc); begin inherited Create(True); FChangeHandle := INVALID_HANDLE_VALUE; FFileChangeNotificationProc := FileChangeNotificationProc; end; procedure TFileChangeNotification.Execute; var Ret: integer; UpdateTime: integer; begin while not Terminated do begin Ret := WaitForSingleObject(FChangeHandle, 100); if Ret = WAIT_OBJECT_0 then begin UpdateTime := GetFileUpdateTime(FNotifyFile); if UpdateTime > FUpdateTime then begin FUpdateTime := UpdateTime; Synchronize(CallBack); FindNextChangeNotification(FChangeHandle); end; end; end; if FChangeHandle <> INVALID_HANDLE_VALUE then begin FindCloseChangeNotification(FChangeHandle); end; end; function TFileChangeNotification.GetFileUpdateTime(FileName: string): integer; var Ret: integer; SearchRec: TSearchRec; begin Ret := FindFirst(FileName, faAnyFile, SearchRec); if Ret <> 0 then begin result := 0; exit; end; result := SearchRec.Time; FindClose(SearchRec); end; function TFileChangeNotification.SetNotifyFile( FileName: string): boolean; begin if FChangeHandle <> INVALID_HANDLE_VALUE then begin FindCloseChangeNotification(FChangeHandle); end; FChangeHandle := FindFirstChangeNotification( PChar(ExtractFilePath(FileName)), False, FILE_NOTIFY_CHANGE_LAST_WRITE); if FChangeHandle = INVALID_HANDLE_VALUE then begin FLastErrorCode := GetLastError; result := False; exit; end; FUpdateTime := GetFileUpdateTime(FileName); FNotifyFile := FileName; result := True; end; end.
改めてみるとコメントが全くないですね。