Win2000pro
VB6.0sp6
です。よろしくお願いします。
特定のテキストファイルを監視して、
そのテキストファイルが更新されれば即座にそれを感知し、
その内容を表示する、
というようなプログラムを作成したいです。
TimerコントロールとFileLen関数を組み合わせて、
一定間隔ごとにファイルのサイズを比較して、
変化を監視する、というのを思いつきましたが、
即座に更新を感知するためにはIntervalを短く設定する必要があり、
パフォーマンス的にどうかな、と思いました。
もっとスマートなやり方を教えてください。
FindFirstChangeNotificationというAPIで、
特定のディレクトリを監視して、ファイルのサイズ変更等も監視
できるみたいなんですが、
以下のコードがうまくいきません。
これは標準モジュールです------------------------
Public Declare Function FindFirstChangeNotification Lib "kernel32.dll" _
Alias "FindFirstChangeNotificationA" _
(ByVal lpPathName As String, ByVal bWatchSubtree As Long, _
ByVal dwNotifyFilter As Long) As Long
Public Declare Function FindCloseChangeNotification Lib "kernel32.dll" _
(ByVal hChangeHandle As Long) As Long
Public Declare Function GetLastError Lib "kernel32.dll" () As Long
Public Const FILE_NOTIFY_CHANGE_FILE_NAME = &H1
Public Const FILE_NOTIFY_CHANGE_DIR_NAME = &H2
Public Const FILE_NOTIFY_CHANGE_ATTRIBUTES = &H4
Public Const FILE_NOTIFY_CHANGE_SIZE = &H8
Public Const FILE_NOTIFY_CHANGE_LAST_WRITE = &H10
Public Const FILE_NOTIFY_CHANGE_SECURITY = &H100
Public Const INVALID_HANDLE_VALUE = -1
----------------------ここまで
ここからがメインモジュールです----------------
Private Sub Command1_Click()
Dim obj_a As Long
obj_a = FindFirstChangeNotification( _
"c:\test.txt", _
0, _
FILE_NOTIFY_CAHNGE_LAST_WRITE _
)
If obj_a = INVALID_HANDLE_VALUE Then
print "エラーです"
print GetLastError
End If
Print FindCloseChangeNotification(obj_a)
End Sub
---------------------------------ここまで
これを実行するとフォームに、
「エラーです
0
0
」
と表示されます。どうやらうまくいっていないようですが、
原因がわかりません。
すみません。上記のコード一箇所訂正です。
FindFirstChangeNotificationの第一引数は、
"c:\test"
です。
これでは?
×FILE_NOTIFY_CAHNGE_LAST_WRITE
○FILE_NOTIFY_CHANGE_LAST_WRITE
このあとでWaitForSingleObject()に続いていきます。
#Option Explicitは入れるようにしたほうが。。。
何度もすみません。
以下のコードで一応それらしいことはできました。
標準モジュールにAPIや定数を宣言しています。
Private Sub Command1_Click()
Dim obj_a As Long
obj_a = FindFirstChangeNotification("c:\test", 0, FILE_NOTIFY_CHANGE_SIZE)
If obj_a = INVALID_HANDLE_VALUE Then
Print "エラー"
Print GetLastError
End If
WaitForSingleObject obj_a, INFINITE
MsgBox "変更された"
FindCloseChangeNotification (obj_a)
End Sub
しかし、このやり方ではディレクトリ全体に対する監視は出来ても、
ファイル単独に関して更新されたかどうかというのは判別できません。
上記のコードに各々のファイルに対してサイズの変化をチェックする
コードを加えなければなりません。
ということは、一番最初の投稿のように、
TimerコントロールとFileLen関数を使用して、1秒ごとのファイルの
サイズの変化をチェックするというやり方がベストなのでしょうか?
もっとよいやり方はないでしょうか?
へむりんさん、ありがとうございます。
おっしゃるとおり単純なスペルミスでした。
すみません。
変数の宣言を強制するオプションをチェックしていた
つもりだったのですが、はずれていました。
お手数かけました。
一応それっぽいことはできたのですが、
まだいろいろと改善しなければならないようです。
たとえば、
WaitForSingleObjectの第二引数にINFINITEを指定してしまうと、
コードを実行後、プログラムが無反応になります。
監視しているディレクトリに変化を起こせば解除されますが、
ちょっと不便です。
obj_a = 0
do
if obj_a = 0 then
obj_a = FindFirstChangeNotification
else
FindNextChangeNotification(obj_a)
end if
If obj_a = INVALID_HANDLE_VALUE Then
end if
ret = WaitForSingleObject obj_a, 100
if ret = WAIT_OBJECT_0 then exit do
DoEvents
loop
手打ち & コピペでエラーチェックもしていませんが
こんな感じでは?
変更されたファイル名はRaiseEventで取得できるようですが
未確認です。
Googleで検索してみてください。
キーワード
「RaiseEvent FindFirstChangeNotification」等
うーん…
リアルタイムにしようとすれば、
VB側でウィンドウプロシージャを扱える状態にして、
その上でCか何かでDLLを作ってその中で
FindFirstChangeNotification()とWaitForSingleObject()を使って監視する無限ループを持つスレッドを作ってやって、
変化があったらVB側のウィンドウにウィンドウメッセージを投げて、
VB側で受け取って…
という具合になるかな。
そこまでするのが面倒なら…他に手がありそうだけど、思いつかない(orz
何かぁゃιぃのを見つけてきましたよ…:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/APISP/html/sp_shlobj_pcjr.asp
何か問題があるようです@SHChangeNotifyRegister:
http://tinyurl.com/8jlf8
やっぱり別スレッドで監視し続けるのが一番いいのかな…?
OSがNT系ならReadDirectoryChangesWの方が楽でしょう。
SHChangeNotifyRegisterはメッセージベースで扱いが楽ですが、
結局のところSHChangeNotifyに対する反応+α程度でしかありません。
また、95系とNT系では使う手順が異なりますし。
これは、そもそもはIShellChangeNotify::OnChangeを呼び出すため
の補助、として作られた、という経緯もあります。
# ですから、既存のシェル機能と連携して使う分にはむしろ有効。
ツイート | ![]() |