.NET 3.5 ClickOnce アプリケーションがあります。サーバーに保存されている Word ドキュメントのリストを含む単純なグリッドがあります。ボタンをクリックすると、アプリケーションは選択したドキュメントをサーバーから (WCF 経由で) ダウンロードし、定義された一時フォルダーに配置します。その直後に、次の関数を使用してドキュメントのハッシュが計算されます。
Public Shared Function HashFile(ByVal file As String) As String
Using reader As New System.IO.FileStream(file, IO.FileMode.Open, IO.FileAccess.Read)
Using provider As New System.Security.Cryptography.MD5CryptoServiceProvider
Dim hash() As Byte = provider.ComputeHash(reader)
Dim sb As New System.Text.StringBuilder(hash.Length * 2)
For i As Integer = 0 To hash.Length - 1
sb.Append(hash(i).ToString("X2"))
Next
Return sb.ToString().ToLower
End Using
End Using
End Function
Word 文書が開かれます。
Private Shared Function OpenDocument(ByVal path As String) As Boolean
Try
Dim process As New Process
process.StartInfo.FileName = path
process.StartInfo.UseShellExecute = True
process.StartInfo.ErrorDialog = True
process.Start()
Return True
Catch ex As Exception
Return False
End Try
End Function
アプリケーションで開いているすべてのドキュメントのリストがあります。ドキュメントを開いた直後に、そのドキュメントに関する情報がこのリストに追加されます。これまでのところ、かなり単純です。アプリケーションには、1000 ミリ秒ごとにチェックするタイマーがあり、開いているドキュメントのいずれかが既に閉じられているかどうかを確認します。Word からそのような情報を取得する簡単な方法がないため、次のトリックが使用されます。
Public Shared Function IsLockedFile(ByVal path As String) As Boolean
Dim isLocked As Boolean = True
Try
Using fs As FileStream = File.Open(path, FileMode.Open, FileAccess.Write)
isLocked = False
End Using
Catch ex As Exception
End Try
Return isLocked
End Function
アプリケーションが書き込みアクセスでファイルを正常に開いた場合は、ドキュメントが閉じられたことを意味します (Word によってロックされなくなりました)。その直後に、上記と同じ関数を使用して、ファイルの MD5 ハッシュが再度計算されます。古いハッシュが新しいハッシュと等しい場合、ユーザーがドキュメントに変更を加えていないことを意味します。ハッシュが異なる場合、ドキュメントはサーバーにアップロードされます。これは、プロセス全体の簡略化された説明です。
それはかなりうまくいっています。ただし、顧客は、ドキュメントへの変更が時々失われると報告しました。長い間、私たちはその理由を発見しました。アプリケーションが (閉じた) ドキュメントのハッシュを計算するとき、古いハッシュを返すことがあります。ファイルの古いバージョンをまだ読んでいるようです。バグの発生は非常に不確定です。たいていはうまくいっています。たとえば、50回は正しい(異なる)ハッシュを取得しますが、3回続けて間違った(古い)ハッシュを取得します。
開発者環境 (VMware で仮想化された Windows Server 2008) ではバグをシミュレートできず、ホスト (Windows 7 64 ビット、ウイルス対策はオフ) でのみシミュレートできました。
すべてのディスク操作が確実にフラッシュされるように、ハッシュが再計算される前に遅延を入れようとさえしました。しかし、2秒経ってもまだ間違っていました。古いハッシュです。足りないかもしれませんが、どれくらい待てばいいですか?
私がグーグルで調べたところ、.NETアプリケーションで作成されたIO操作をフラッシュする可能性はあります.NETアプリケーションの外部ではありません。ハッシュを読み取るときに読み取り/書き込み用に排他的に開くことも役に立ちませんでした。これを解決する方法、または他に何が原因である可能性がありますか?
ありがとう。