#region License // Copyright (c) 2010, Jasper Yeh. // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // * Neither the name of ClearCanvas Inc. nor the names of its contributors // may be used to endorse or promote products derived from this software without // specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, // OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE // GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY // OF SUCH DAMAGE. #endregion using System; using System.IO; using System.Security.Permissions; using ClearCanvas.Common.Utilities; using Timer = System.Threading.Timer; namespace Nullstack.ClearCanvasEx.DevTools.Common { public abstract class FileMonitor : IDisposable { public static FileMonitor CreateFileMonitor(string filename) { if (Environment.OSVersion.Platform == PlatformID.Win32NT && Environment.OSVersion.Version.Major < 6) return new SystemFileMonitor(filename); return new TimerFileMonitor(filename, 1000); } private event EventHandler _changed; private event EventHandler _existsChanged; private readonly string _filename; protected FileMonitor(string filename) { if (string.IsNullOrEmpty(filename)) throw new ArgumentNullException("filename"); _filename = filename; } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } public string Filename { get { return _filename; } } public abstract bool Exists { get; } public event EventHandler Changed { add { _changed += value; } remove { _changed -= value; } } public event EventHandler ExistsChanged { add { _existsChanged += value; } remove { _existsChanged -= value; } } protected virtual void Dispose(bool disposing) {} protected void InvokeChanged(EventArgs e) { EventsHelper.Fire(_changed, this, e); } protected void InvokeExistsChanged(EventArgs e) { EventsHelper.Fire(_existsChanged, this, e); } private class SystemFileMonitor : FileMonitor { private FileSystemWatcher _fileWatcher; private bool _exists; [PermissionSet(SecurityAction.Demand, Name = "FullTrust")] public SystemFileMonitor(string filename) : base(filename) { var pathDirectory = Path.GetDirectoryName(filename); var pathFile = Path.GetFileName(filename); if (string.IsNullOrEmpty(pathDirectory) || string.IsNullOrEmpty(pathFile)) throw new ArgumentException("filename"); _fileWatcher = new FileSystemWatcher(pathDirectory, pathFile) {EnableRaisingEvents = true}; _fileWatcher.NotifyFilter |= NotifyFilters.LastWrite | NotifyFilters.Size; _fileWatcher.Created += FileExistenceChanged; _fileWatcher.Deleted += FileExistenceChanged; _fileWatcher.Renamed += FileExistenceChanged; _fileWatcher.Changed += FileLiveChanged; } protected override void Dispose(bool disposing) { if (_fileWatcher != null) { _fileWatcher.EnableRaisingEvents = false; _fileWatcher.Created -= FileExistenceChanged; _fileWatcher.Deleted -= FileExistenceChanged; _fileWatcher.Renamed -= FileExistenceChanged; _fileWatcher.Changed -= FileLiveChanged; _fileWatcher.Dispose(); _fileWatcher = null; } } public override bool Exists { get { return _exists; } } private void FileLiveChanged(object sender, FileSystemEventArgs e) { InvokeChanged(new EventArgs()); } private void FileExistenceChanged(object sender, FileSystemEventArgs e) { _exists = File.Exists(_filename); InvokeExistsChanged(new EventArgs()); } } private class TimerFileMonitor : FileMonitor { private readonly FileInfo _file; private Timer _timer; private DateTime _lastModifiedDate; private long _lastSize; private bool _lastExists; public TimerFileMonitor(string filename, int intervalMilliseconds) : base(filename) { _file = new FileInfo(filename); _lastExists = _file.Exists; _lastSize = _lastExists ? _file.Length : -1; _lastModifiedDate = _lastExists ? _file.LastWriteTimeUtc : DateTime.MinValue; _timer = new Timer(Callback, null, intervalMilliseconds, intervalMilliseconds); } protected override void Dispose(bool disposing) { if (_timer != null) { _timer.Dispose(); _timer = null; } } public override bool Exists { get { return _file.Exists; } } private void Callback(object s) { _file.Refresh(); if (_lastExists != _file.Exists) InvokeExistsChanged(new EventArgs()); if (_file.Exists) { if (_lastModifiedDate != _file.LastWriteTimeUtc || _lastSize != _file.Length) InvokeChanged(new EventArgs()); } _lastExists = _file.Exists; _lastSize = _lastExists ? _file.Length : -1; _lastModifiedDate = _lastExists ? _file.LastWriteTimeUtc : DateTime.MinValue; } } } }