initial checkin of yaulw (locally)

This commit is contained in:
Donald Duck
2016-02-15 12:32:26 -05:00
commit 857eda29e3
115 changed files with 27392 additions and 0 deletions

287
File/CHMFile.cs Normal file
View File

@@ -0,0 +1,287 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Resources;
using IO = System.IO;
using System.Windows.Forms;
using System.Windows;
using System.Windows.Interop;
using Yaulw.Process;
using Diag = System.Diagnostics;
namespace Yaulw.File
{
/// <summary>
/// CHM Help File Wrapper
/// </summary>
public class CHMFile
{
#region Private Members
/// <summary>
/// The Full File Name and Path to the CHM File
/// </summary>
private string _FileNameNPath = "";
/// <summary>
/// The File Stream that created the CHM File (if used)
/// </summary>
private IO.Stream _FileStream = null;
/// <summary>
/// Internally we keep track of each Form to Help Context ID
/// </summary>
private Dictionary<Form, int> s_FormContextMap = new Dictionary<Form, int>();
#endregion
#region Construction
/// <summary>
/// Construct a CHMFile object with the specified chm file
/// </summary>
/// <param name="FileNameNPath">a full path to a valid chm file</param>
public CHMFile(string FileNameNPath)
{
if (!String.IsNullOrEmpty(FileNameNPath) && IO.File.Exists(FileNameNPath) && (IO.Path.GetExtension(FileNameNPath).ToLower() == "chm"))
_FileNameNPath = FileNameNPath;
else
throw new ArgumentException("Invalid chm File or File does not exist");
}
/// <summary>
/// Construct a CHMFile object from the specified stream (will construct a chm file in
/// a temporary location from the specified stream)
/// </summary>
/// <param name="stream">stream to construct the chm file from</param>
/// <param name="ApplicationName">The name of the application (will be used when creating the .chm file)</param>
/// <param name="ForceNewFile">if true, will force a new file to be written out, false will only write file if not exists</param>
public CHMFile(IO.Stream stream, string ApplicationName, bool ForceNewFile)
{
if (stream != null && !String.IsNullOrEmpty(ApplicationName))
{
_FileStream = stream;
_FileNameNPath = IO.Path.GetTempPath() + ApplicationName + ".chm";
EnsureCHMFileExistance(ForceNewFile);
}
else
throw new ArgumentNullException("Resource can not be null. ApplicationName can not be empty");
}
#endregion
#region Public Consts
/// <summary>
/// Legacy MFC View Context offset
/// </summary>
public const int MNU = 0x10000;
/// <summary>
/// Legacy MFC Dialog Context offset
/// </summary>
public const int DLG = 0x20000;
#endregion
#region Public Methods
/// <summary>
/// Attaches the HelpRequest Handler as well as shows the HelpButton on the CaptionBar
/// </summary>
/// <param name="form">WinForm to Attach Help Button to</param>
/// <param name="dwContextId">the Help Topic Context Id to attach to the specified WinForm</param>
public void AttachHelpCaptionButtonToWinForm(Form form, int dwContextId)
{
// Set the HelpButton to be displayed
form.MinimizeBox = false;
form.MaximizeBox = false;
form.HelpButton = true;
// add the form / contextID to the map
s_FormContextMap[form] = (int)dwContextId;
// Subscribe to the Help Requested Handler
form.HelpRequested += new HelpEventHandler(form_HelpRequested);
// Subscribe to the Destroyed Event Handler *to remove the form from the list*
form.HandleDestroyed += new EventHandler(form_HandleDestroyed);
}
/// <summary>
/// Launch CHM Help
/// </summary>
public void LaunchHelp()
{
int bHelpIsAlreadyRunning_Pid = 0;
Diag.Process[] ps = ProcessW.AllRunningProcessesOf("hh", false, true);
if (ps != null && ps.Length >= 1)
{
foreach (Diag.Process p in ps)
{
string ProcessName = "";
string CommandLine = "";
ProcessW.GetCommandLineArgumentsForProcessPID(p.Id, out ProcessName, out CommandLine);
if (CommandLine.Contains(_FileNameNPath))
{
bHelpIsAlreadyRunning_Pid = p.Id;
break;
}
}
}
// No need to launch a second time
if (bHelpIsAlreadyRunning_Pid != 0)
{
// Set Focus
IntPtr hWnd = Yaulw.Win32.Functions.GetFirstTopLevelWindowForProcess(bHelpIsAlreadyRunning_Pid);
if (hWnd != IntPtr.Zero)
Yaulw.Win32.User32.SetActiveWindow(hWnd);
}
else
{
// Launch
EnsureCHMFileExistance(false);
PStarter.StartProcess(PStartInfo.CreateProcess(_FileNameNPath, "", "", false, System.Diagnostics.ProcessWindowStyle.Normal, true), false, false);
}
}
/// <summary>
/// Launch CHM Help
/// </summary>
/// <param name="form">form which will be the parent of the CHM File</param>
public void LaunchHelp(Form form)
{
if (form != null)
{
Control control = Control.FromHandle(form.Handle);
if (control != null)
{
EnsureCHMFileExistance(false);
Help.ShowHelp(control, _FileNameNPath);
}
}
}
/// <summary>
/// aunch CHM Help
/// </summary>
/// <param name="window">Window which will be the parent for the CHM file</param>
public void LaunchHelp(Window window)
{
if (window != null)
{
Control control = Control.FromHandle(GetHandleForWPFWindow(window));
if (control != null)
{
EnsureCHMFileExistance(false);
Help.ShowHelp(control, _FileNameNPath);
}
}
}
/// <summary>
/// Launch CHM Help for the specified Context
/// </summary>
/// <param name="form">form which will be the parent of the CHM File</param>
/// <param name="dwContextId">Context Id to launch chm file with</param>
public void LaunchHelp(Form form, int dwContextId)
{
if (form != null)
{
Control control = Control.FromHandle(form.Handle);
if (control != null)
{
EnsureCHMFileExistance(false);
Help.ShowHelp(control, _FileNameNPath, HelpNavigator.TopicId, dwContextId.ToString());
}
}
}
/// <summary>
/// aunch CHM Help for the specified Context
/// </summary>
/// <param name="window">Window which will be the parent for the CHM file</param>
/// <param name="dwContextId">Context Id to launch chm file with</param>
public void LaunchHelp(Window window, int dwContextId)
{
if (window != null)
{
EnsureCHMFileExistance(false);
Help.ShowHelp(null, _FileNameNPath, HelpNavigator.TopicId, dwContextId.ToString());
}
}
#endregion
#region Private WinForm Help Event Handlers
/// <summary>
/// Handle HelpRequests
/// </summary>
private void form_HelpRequested(object sender, HelpEventArgs hlpevent)
{
Form form = sender as Form;
if (form != null)
{
int dwContextId = s_FormContextMap[form];
Help.ShowHelp(form, _FileNameNPath, HelpNavigator.TopicId, dwContextId.ToString());
}
}
/// <summary>
/// Handle Form Destroys
/// </summary>
private void form_HandleDestroyed(object sender, EventArgs e)
{
Form form = sender as Form;
if (form != null)
s_FormContextMap.Remove(form);
}
#endregion
#region Private Helpers
/// <summary>
/// Creates the CHMFile from the stream (if a stream was used)
/// </summary>
/// <param name="ForceCreationOfFile">true to force re-creation of the file, false otherwise</param>
private void EnsureCHMFileExistance(bool ForceCreationOfFile)
{
if (_FileStream != null)
{
if (ForceCreationOfFile || !IO.File.Exists(_FileNameNPath))
{
using (IO.FileStream fs = new IO.FileStream(_FileNameNPath, IO.FileMode.Create))
{
using (IO.BinaryWriter writer = new IO.BinaryWriter(fs))
{
// Read from the Resource
Byte[] streamData = new Byte[_FileStream.Length];
_FileStream.Read(streamData, 0, streamData.Length);
// Write to File
writer.Write(streamData);
writer.Close();
}
}
}
}
}
/// <summary>
/// Uses the InteropHelper to get the Handle of a WPF Window
/// </summary>
/// <param name="window">a WPF Window</param>
/// <returns>an hWnd for the specified WPF Window</returns>
private IntPtr GetHandleForWPFWindow(Window window)
{
WindowInteropHelper InteropHelper = new WindowInteropHelper(window);
return InteropHelper.Handle;
}
#endregion
}
}

193
File/FileWriter.cs Normal file
View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Yaulw.File
{
/// <remarks>
/// Simple Line-By-Line UTF/Ascii File Writer Object
/// </remarks>
public class FileWriter
{
#region Private Members
private string _FileName = "";
private string _FileType = "";
private string _dirPath = "";
private bool _OverideExisting = false;
private bool _FileIsCreated = false;
#endregion
#region Construction
/// <summary>
/// Create a Simple UTF/Ascii Line FileWriter Object
/// </summary>
/// <param name="FileName">The Name of the File (If blank will generate a random file name)</param>
/// <param name="FileType">The Type of File to write to (Default = "log")</param>
/// <param name="dirPath">The path where to write the file (If Blank will use Temp Path)</param>
/// <param name="OverideExisting">true to overide an existing file, false will try to append by default</param>
public FileWriter(string FileName = "", string FileType = "log", string dirPath = "", bool OverideExisting = true)
{
_FileName = FileName;
_FileType = FileType;
_dirPath = dirPath;
_OverideExisting = OverideExisting;
// Generate File Name and Path, if not exist
if(String.IsNullOrEmpty(_FileName))
_FileName = System.IO.Path.GetFileNameWithoutExtension(System.IO.Path.GetRandomFileName());
if(String.IsNullOrEmpty(_dirPath))
_dirPath = System.IO.Path.GetTempPath();
// Make Sure Path Exists
if (!Directory.Exists(_dirPath))
Directory.CreateDirectory(_dirPath);
}
#endregion
#region Write Ascii
/// <summary>
/// Write a Line in Ascii to File
/// </summary>
/// <param name="line">ascii line to write</param>
public void WriteLineA(string line)
{
using (FileStream fs = CreateFileStream())
using(StreamWriter sw = new StreamWriter(fs, Encoding.ASCII))
{
sw.WriteLine(line);
sw.Flush();
}
}
/// <summary>
/// Write Lines in Ascii to file
/// </summary>
/// <param name="lines">ascii lines to write</param>
public void WriteLineA(string[] lines)
{
using (FileStream fs = CreateFileStream())
using (StreamWriter sw = new StreamWriter(fs, Encoding.ASCII))
{
foreach (string line in lines)
sw.WriteLine(line);
sw.Flush();
}
}
#endregion
#region Write UTF
/// <summary>
/// Write a Line in UTF to File
/// </summary>
/// <param name="line">utf line to write</param>
public void WriteLineUTF8(string line)
{
using (FileStream fs = CreateFileStream())
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
sw.WriteLine(line);
sw.Flush();
}
}
/// <summary>
/// Write Lines in UTF to File
/// </summary>
/// <param name="lines">utf lines to write</param>
public void WriteLineUTF8(string[] lines)
{
using (FileStream fs = CreateFileStream())
using (StreamWriter sw = new StreamWriter(fs, Encoding.UTF8))
{
foreach (string line in lines)
sw.WriteLine(line);
sw.Flush();
}
}
#endregion
#region Public Properties
/// <summary>
/// Returns the File Name
/// </summary>
public string FileName { get { return (this._FileName + "." + this._FileType); } }
/// <summary>
/// Returns the Path where the File is located
/// </summary>
public string Path { get { return (this._dirPath); } }
/// <summary>
/// Returns both Path and FileName
/// </summary>
public string FileNameNPath { get { return (this.Path + "\\" + this.FileName); } }
#endregion
#region Public Methods
/// <summary>
/// Deletes the File, if it exists
/// </summary>
/// <returns>true if successful, false otherwise</returns>
public bool DeleteFile()
{
try
{
if (System.IO.File.Exists(this.FileNameNPath))
{
System.IO.File.Delete(this.FileNameNPath);
_FileIsCreated = false;
return true;
}
}
catch (Exception) { /* ignore */ }
return false;
}
#endregion
#region Private Methods
/// <summary>
/// Creates the File Stream, either in Create or Append Mode
/// </summary>
/// <returns>a File Stream to Write to * Must be Closed by Caller *</returns>
private FileStream CreateFileStream()
{
try
{
bool bFileExists = System.IO.File.Exists(this.FileNameNPath);
if (!_FileIsCreated && _OverideExisting && bFileExists)
{
_FileIsCreated = true;
return (new FileStream(this.FileNameNPath, FileMode.Create));
}
else if (bFileExists)
{
return (new FileStream(this.FileNameNPath, FileMode.Append));
}
else
{
_FileIsCreated = true;
return (new FileStream(this.FileNameNPath, FileMode.Create));
}
}
catch (Exception) { /* ignore */ }
return null;
}
#endregion
}
}

213
File/INIFile.cs Normal file
View File

@@ -0,0 +1,213 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Yaulw.Tools;
using Yaulw.Win32;
using System.Diagnostics;
namespace Yaulw.File
{
/// <remarks>
/// Responsible for Reading and Writing an INI File.
/// Simply construct an INIFile Object passing in a File name and Path,
/// as well as an enum that lists all the Categories and Keys.
///
/// An example *You can mix and match Categories and Keys as needed *:
/// public enum INICatsNKeys
/// {
/// App_Settings__Load_XML_At_StartUp,
/// App_Settings__Allow_Command_Line_to_override_INI,
/// App_Settings__Default_User,
/// App_Settings__Default_Server,
/// Runtime_Debug__Error_Debug_Level,
/// Data_Access__Read_Only,
/// Settings__Program_Folder,
/// Settings__User1_Default,
/// Recent_File_List__File1,
/// Recent_File_List__File2,
/// Recent_File_List__File3,
/// Recent_File_List__File4,
/// }
///
/// The '__' Character signifies a category to Key change
/// the '_' will be replaced by ' ', when actually writing to the Ini File.
/// </remarks>
public class INIFile
{
#region Private Members
private string _IniPathNFileName = String.Empty;
private Type _IniKeysNCategories = null;
#endregion
#region Construction
/// <summary>
/// Initialize an INIFile object with a valid path and FileName to write/read from.
/// Also pass in an Enum Type that contains Category and Key Information. This Enum will be used
/// to read and write to the INIFile (to determine which Section/Key to read/write from/to)
/// </summary>
/// <param name="IniPathNFileName">Pass in the full file name and path to use * Creates Directory, if it does not exits *</param>
/// <param name="IniKeysNCategories">Pass in an Enum that specifies the Categories and Keys</param>
/// <exception cref="ArgumentException">Thrown if an invalid Enum is passed in via IniKeysNCategories</exception>
public INIFile(string IniPathNFileName, Type IniKeysNCategories)
{
// Check and ensure Enum Accuracy
if (IniKeysNCategories.IsEnum && EnumTool.EnumType_HasCategoryNKey(IniKeysNCategories))
{
_IniKeysNCategories = IniKeysNCategories;
}
else
throw new ArgumentException("IniKeysNCategories is not an Enum or not all Enums contain Key and Category Information");
// Ensure Directory Existence
if (!Directory.Exists(Path.GetDirectoryName(IniPathNFileName)))
Directory.CreateDirectory(Path.GetDirectoryName(IniPathNFileName));
_IniPathNFileName = IniPathNFileName;
}
#endregion
#region Public Properties
/// <summary>
/// Ini File Used by IniFile
/// </summary>
public string IniFile { get { return _IniPathNFileName; } }
#endregion
#region Public Ini Key Reader / Writer Functions
/// <summary>
/// Use this to directly set a key to any string value
/// </summary>
/// <param name="cKey">Specify Key and category set Directly</param>
/// <param name="Value">value to set</param>
/// <exception cref="ArgumentException">If cKey is not a valid Category/Key Pair Enum</exception>
public void SetKeyValue<T>(Enum cKey, T Value)
{
if (EnumTool.Enum_HasCategoryNKey(cKey))
{
string Category;
string Key;
EnumTool.Enum_ToCategoryNKey(cKey, out Category, out Key);
string ValueStr = ObjTool.ConvertObjToString<T>(Value);
SetKeyValueString(Category, Key, ValueStr);
}
else
{
throw new ArgumentException("cKey must have both Category and Key Information");
}
}
/// <summary>
/// Use this to directly retrieve a key
/// </summary>
/// <param name="cKey">Specify Key and category set Directly</param>
/// <param name="defaultValue">default value to return, if not found</param>
/// <returns>value retrieved or default value</returns>
/// <exception cref="ArgumentException">If cKey is not a valid Category/Key Pair Enum</exception>
public T GetKeyValue<T>(Enum cKey, T defaultValue)
{
try
{
if (EnumTool.Enum_HasCategoryNKey(cKey))
{
string Category;
string Key;
EnumTool.Enum_ToCategoryNKey(cKey, out Category, out Key);
// Get Key and verify that something was found
string defaultValueStr = ObjTool.ConvertObjToString<T>(defaultValue);
string KeyValue = GetKeyValueString(Category, Key, defaultValueStr);
bool bHasAValue = (KeyValue.Trim().Length != 0);
// always write the value back out to ini
SetKeyValue(cKey, bHasAValue ? KeyValue : defaultValueStr);
// Return value
if (bHasAValue)
{
return ObjTool.ConvertStringToObj<T>(KeyValue);
}
else
{
return defaultValue;
}
}
else
{
throw new ArgumentException("cKey must have both Category and Key Information");
}
}
catch (Exception) { /* ignore */ }
return defaultValue;
}
#endregion
#region Private Generic Ini Key Reader / Writer Functions
/// <summary>
/// Set a value for the specified Key and for the specified category
/// </summary>
/// <param name="category">specify category</param>
/// <param name="key">specify key</param>
/// <param name="value">specify a value to set</param>
private void SetKeyValueString(string category, string key, string value)
{
bool bSuccess = Kernel32.WritePrivateProfileString(category, key, value, IniFile);
Debug.Assert(bSuccess);
}
/// <summary>
/// Retrieve the value for a specified Key and for a specified category
/// </summary>
/// <param name="category">specify category</param>
/// <param name="key">specify key</param>
/// <param name="defaultValue">specify default value, returned when no value found</param>
/// <returns>the value for the Key, or default value if no value found</returns>
private string GetKeyValueString(string category, string key, string defaultValue)
{
StringBuilder returnString = new StringBuilder(1024);
Kernel32.GetPrivateProfileString(category, key, defaultValue, returnString, 1024, IniFile);
return returnString.ToString().Split('\0')[0];
}
#endregion
#region Private Generic Ini File Readers (Not Used)
/// <summary>
/// Use this to return all the categories in an INI File
/// </summary>
/// <returns>a list with Gategory Items, or 0 length list is none found</returns>
private List<string> GetAllCategories()
{
StringBuilder returnString = new StringBuilder(65536);
uint returnValue = Kernel32.GetPrivateProfileString(null, null, null, returnString, 65536, IniFile);
List<string> result = new List<string>(returnString.ToString().Split('\0'));
result.RemoveRange(result.Count - 2, 2);
return result;
}
/// <summary>
/// Use this to return the Keys from a category from an INI File
/// </summary>
/// <returns>a list with Key Items, or 0 length list is none found</returns>
private List<string> GetAllKeysInCategory(string category)
{
StringBuilder returnString = new StringBuilder(32768);
Kernel32.GetPrivateProfileString(category, null, null, returnString, 32768, IniFile);
List<string> result = new List<string>(returnString.ToString().Split('\0'));
result.RemoveRange(result.Count - 2, 2);
return result;
}
#endregion
}
}

185
File/ISReadWrite.cs Normal file
View File

@@ -0,0 +1,185 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO.IsolatedStorage;
using System.IO;
using System.Reflection;
namespace Yaulw.File
{
/// <summary>
///
/// </summary>
public enum ISScope
{
User,
Machine,
}
/// <summary>
/// Class allows reading and writing to isolated Storage
/// </summary>
public class ISReadWrite
{
#region Private Members
private string _ISOLATED_STORAGE_FILENAME = "";
private bool _bFileInIsoStoreExists = false;
private Xml.XSerializer _XSerializer = null;
private IsolatedStorageScope _scope = IsolatedStorageScope.None;
private IsolatedStorageFile _isoStore = null;
#endregion
#region Construction
/// <summary>
///
/// </summary>
/// <param name="ISFileName"></param>
public ISReadWrite(string ISFileName) : this(ISFileName, ISScope.Machine) { }
/// <summary>
///
/// </summary>
/// <param name="ISFileName"></param>
/// <param name="scope"></param>
public ISReadWrite(string ISFileName, ISScope scope)
{
_ISOLATED_STORAGE_FILENAME = ISFileName;
if (String.IsNullOrEmpty(_ISOLATED_STORAGE_FILENAME))
throw new ArgumentNullException("ISFileName can not be empty.");
#if NET4
if (!IsolatedStorageFile.IsEnabled)
throw new Exception("Isolated Storage not enabled");
#endif
_scope = ConvertISScopeToIsolatedStorageScope(scope);
_isoStore = IsolatedStorageFile.GetStore(_scope, typeof(System.Security.Policy.Url), typeof(System.Security.Policy.Url));
_bFileInIsoStoreExists = (_isoStore.GetFileNames(ISFileName).Length > 0);
_XSerializer = new Xml.XSerializer();
}
#endregion
#region Public Read / Write Methods
public string ReadFromIS()
{
using (IsolatedStorageFileStream fs = new IsolatedStorageFileStream(_ISOLATED_STORAGE_FILENAME, FileMode.OpenOrCreate, _isoStore))
using (StreamReader reader = new StreamReader(fs))
{
_bFileInIsoStoreExists = true;
string strFileContents = reader.ReadToEnd();
if (!String.IsNullOrEmpty(strFileContents))
return strFileContents;
}
return String.Empty;
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <returns></returns>
public T ReadFromIS<T>()
{
using (IsolatedStorageFileStream fs = new IsolatedStorageFileStream(_ISOLATED_STORAGE_FILENAME, FileMode.OpenOrCreate, _isoStore))
using (StreamReader reader = new StreamReader(fs))
{
_bFileInIsoStoreExists = true;
string strFileContents = reader.ReadToEnd();
if (!String.IsNullOrEmpty(strFileContents))
{
T t = _XSerializer.ReadFromString<T>(strFileContents);
return t;
}
}
return default(T);
}
/// <summary>
///
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="SerializableObject"></param>
public void WriteToIS<T>(T XMLSerializableObject) where T : new()
{
using (IsolatedStorageFileStream fs = new IsolatedStorageFileStream(_ISOLATED_STORAGE_FILENAME, FileMode.Create, _isoStore))
using (StreamWriter writer = new StreamWriter(fs))
{
_bFileInIsoStoreExists = true;
string strFileContentsToWrite = _XSerializer.WriteToString<T>(XMLSerializableObject);
if(!String.IsNullOrEmpty(strFileContentsToWrite))
writer.Write(strFileContentsToWrite);
}
}
/// <summary>
///
/// </summary>
public void WriteToIS(string Content)
{
using (IsolatedStorageFileStream fs = new IsolatedStorageFileStream(_ISOLATED_STORAGE_FILENAME, FileMode.Create, _isoStore))
using (StreamWriter writer = new StreamWriter(fs))
{
_bFileInIsoStoreExists = true;
string strFileContentsToWrite = Content;
if (!String.IsNullOrEmpty(strFileContentsToWrite))
writer.Write(strFileContentsToWrite);
}
}
#endregion
#region Public Methods
/// <summary>
///
/// </summary>
public void Delete()
{
if (_bFileInIsoStoreExists)
{
_isoStore.DeleteFile(_ISOLATED_STORAGE_FILENAME);
_bFileInIsoStoreExists = false;
}
}
#endregion
#region Public Properties
public bool Exists
{
get { return _bFileInIsoStoreExists; }
}
#endregion
#region Private Helpers
/// <summary>
///
/// </summary>
/// <param name="scope"></param>
/// <returns></returns>
private IsolatedStorageScope ConvertISScopeToIsolatedStorageScope(ISScope scope)
{
switch (scope)
{
case ISScope.User:
return IsolatedStorageScope.User | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
case ISScope.Machine:
return IsolatedStorageScope.Machine | IsolatedStorageScope.Domain | IsolatedStorageScope.Assembly;
}
return IsolatedStorageScope.Application;
}
#endregion
}
}

172
File/LineReplacer.cs Normal file
View File

@@ -0,0 +1,172 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using IO = System.IO;
namespace Yaulw.File
{
#region Rule Definitions
/// <summary>
/// Comparer Modifier used when looking at the line
/// </summary>
public enum LineReplace_ComparerModifier
{
None,
toLower,
toUpper,
}
/// <summary>
/// Rule Used to determine which line to replace
/// ~Replace Line with contains the new line to put instead
/// </summary>
public struct LineReplace_Rule
{
public string Contains;
public string StartsWith;
public string EndsWith;
public LineReplace_ComparerModifier Comparer;
public string ReplaceLineWith;
}
#endregion
/// <summary>
/// Useful for replacing lines in a text file.
/// It reads in a text file line by line and compares the lines.
/// Using the rules you can replace a line or multiple lines and write out to the text file.
/// </summary>
public class LineReplacer
{
#region Private Members
private Dictionary<String, LineReplace_Rule> _RulesDictionary = new Dictionary<string, LineReplace_Rule>();
private string _fileNameNPath = "";
private Encoding _encoding = Encoding.UTF8;
#endregion
#region Construction
/// <summary>
/// Allows for easy line replacing of a text file
/// </summary>
/// <param name="FileNameNPath">Full File Name and Path to a file that exists</param>
/// <exception cref="ArgumentException">Thrown when File does not exist</exception>
public LineReplacer(string FileNameNPath, Encoding encoding)
{
if (String.IsNullOrEmpty(FileNameNPath) || !IO.File.Exists(FileNameNPath))
throw new ArgumentException("Line Replace makes only sense on Files that exist already");
_fileNameNPath = FileNameNPath;
_encoding = encoding;
}
#endregion
#region Public Methods
/// <summary>
/// Add/Update Line Replacing Rules into here BEFORE calling ReplaceLines()
/// </summary>
/// <param name="RuleName">unique name of the rule</param>
/// <param name="rule">Rule Definition</param>
/// <returns>true if successfully added, false otherwise</returns>
public bool AddUpdateRule(string RuleName, LineReplace_Rule rule)
{
if (!String.IsNullOrEmpty(RuleName))
{
// We must be able to match on something
if (String.IsNullOrEmpty(rule.StartsWith) && String.IsNullOrEmpty(rule.EndsWith) &&
String.IsNullOrEmpty(rule.Contains))
return false;
// We must be able to replace with something
if (String.IsNullOrEmpty(rule.ReplaceLineWith))
return false;
// Rule is good, add it
_RulesDictionary[RuleName] = rule;
}
return false;
}
/// <summary>
/// Call this Function to Replace all the Lines of the Text Files that
/// match a specific Rule
/// </summary>
public void ReplaceLines()
{
if (_RulesDictionary.Count <= 0)
return;
// # Readin and Process all Lines
List<string> ReadInLines = new List<string>();
using (IO.FileStream fs = new IO.FileStream(_fileNameNPath, IO.FileMode.Open))
using (IO.StreamReader reader = new IO.StreamReader(fs, _encoding))
{
// # Iterate thru all the lines in the File
for (string Line = reader.ReadLine(); Line != null; Line = reader.ReadLine())
{
FoundRuleMathAndPerformedAction(ref Line);
ReadInLines.Add(Line);
}
}
// # Write out all the Lines
using (IO.FileStream fs = new IO.FileStream(_fileNameNPath, IO.FileMode.Create))
using (IO.StreamWriter writer = new IO.StreamWriter(fs, _encoding))
{
foreach (string Line in ReadInLines)
writer.WriteLine(Line);
}
}
#endregion
#region Private Helpers
/// <summary>
/// Responsible for finding a match between a line and a rule and
/// performing the action
/// </summary>
/// <param name="Line">Line to find a match for</param>
/// <returns>true, if match was found/action was done, false otherwise</returns>
private bool FoundRuleMathAndPerformedAction(ref string Line)
{
if (String.IsNullOrEmpty(Line))
return false;
bool bFoundMatch = false;
// Iterate foreach rule for a line
foreach (LineReplace_Rule rule in _RulesDictionary.Values)
{
// Make sure to use the proper comparer Modifier for the rule
string line = Line;
if (rule.Comparer == LineReplace_ComparerModifier.toLower)
line = Line.ToLower();
else if (rule.Comparer == LineReplace_ComparerModifier.toUpper)
line = Line.ToUpper();
// Now let's match on the actual Rule
if (!bFoundMatch && !String.IsNullOrEmpty(rule.StartsWith))
bFoundMatch = line.StartsWith(rule.StartsWith);
if (!bFoundMatch && !String.IsNullOrEmpty(rule.EndsWith))
bFoundMatch = line.StartsWith(rule.EndsWith);
if (!bFoundMatch && !String.IsNullOrEmpty(rule.Contains))
bFoundMatch = line.StartsWith(rule.Contains);
if (bFoundMatch)
{
Line = rule.ReplaceLineWith;
break;
}
}
return bFoundMatch;
}
#endregion
}
}

176
File/LoggerQuick.cs Normal file
View File

@@ -0,0 +1,176 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Yaulw.Assembly;
namespace Yaulw.File
{
/// <summary>
/// Easy Class for quick and dirty logging *that can automatically on a daily basis*
/// </summary>
public class LoggerQuick
{
#region Private Members
/// <summary>
/// FileWriter Object
/// </summary>
private Yaulw.File.FileWriter _fileWriter = null;
/// <summary>
/// Current Directory
/// </summary>
private string _curPath = "";
/// <summary>
/// Log Debug Messages
/// </summary>
private bool _LogDebug = false;
/// <summary>
/// Name of the Log (also serves as RegKey)
/// </summary>
private string LogName = "";
#endregion
#region Construction
/// <summary>
/// Quick Logger (which can clear itself daily and has no dependencies)
/// quick n' dirty logs in the current directory from which it is called
/// </summary>
/// <param name="LogName">Name of the Log file</param>
/// <param name="bLogDebugMessages">true to spit out DebugMessages, false otherwise</param>
public LoggerQuick(string LogName, bool bLogDebugMessages)
{
if(String.IsNullOrEmpty(LogName))
throw new ArgumentException("LogName can't be empty");
// Log Name, which will also server as the registry key name
this.LogName = Path.GetFileName(LogName);
// Log Debug Messages?
_LogDebug = bLogDebugMessages;
// Get the current running directory
if (String.IsNullOrEmpty(_curPath))
_curPath = Path.GetDirectoryName(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileNameNPath(AssemblyW.AssemblyST.Executing));
// Set up FileWriter
if (_fileWriter == null)
_fileWriter = new Yaulw.File.FileWriter(LogName, "log", _curPath, false);
}
/// <summary>
/// Quick Logger (which can clear itself daily and has no dependencies)
/// quick n' dirty logs in the current directory from which it is called
/// </summary>
/// <param name="LogName">Name of the Log file</param>
/// <param name="bLogDebugMessages">true to spit out DebugMessages, false otherwise</param>
/// <param name="path">path to log to</param>
public LoggerQuick(string LogName, bool bLogDebugMessages, string path)
{
if (String.IsNullOrEmpty(LogName))
throw new ArgumentException("LogName can't be empty");
// Log Name, which will also server as the registry key name
this.LogName = Path.GetFileName(LogName);
// Log Debug Messages?
_LogDebug = bLogDebugMessages;
// make sure path is valid
try
{
if (!String.IsNullOrEmpty(path))
{
path = Path.GetDirectoryName(path);
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
}
}
catch (Exception) { /* ignore */ }
// Get the current running directory
if (String.IsNullOrEmpty(_curPath) && String.IsNullOrEmpty(path))
_curPath = Path.GetDirectoryName(AssemblyW.SpecializedAssemblyInfo.GetAssemblyFileNameNPath(AssemblyW.AssemblyST.Executing));
else
_curPath = path;
// Set up FileWriter
if (_fileWriter == null)
_fileWriter = new Yaulw.File.FileWriter(LogName, "log", _curPath, false);
}
#endregion
#region Public Log Methods
/// <summary>
/// Debug Logging only logs when _LogDebug is set
/// </summary>
/// <param name="line"></param>
/// <param name="args"></param>
public void Debug(string line, params object[] args)
{
if (_LogDebug)
Log("Debug: ", line, args);
}
/// <summary>
/// Info Logging
/// </summary>
/// <param name="line"></param>
/// <param name="args"></param>
public void Info(string line, params object[] args)
{
Log("Info: ", line, args);
}
/// <summary>
/// Error Logging
/// </summary>
/// <param name="line"></param>
/// <param name="args"></param>
public void Error(string line, params object[] args)
{
Log("Error: ", line, args);
}
#endregion
#region Private Log Methods
/// <summary>
/// Used for logging * Medisoft people * crack me up
/// </summary>
/// <param name="line"></param>
/// <param name="ars"></param>
private void Log(string prePrend, string line, params object[] args)
{
if (_fileWriter != null)
{
// Clear the log once a day automatically - yeah!
DateTime LastLogged = Yaulw.Registry.RegKey.GetKey<DateTime>("LoggerQuick", LogName, DateTime.MinValue);
if (LastLogged != DateTime.MinValue && LastLogged.Day != DateTime.Now.Day)
_fileWriter.DeleteFile();
// Always set the DT Stamp, for every log
Yaulw.Registry.RegKey.SetKey<DateTime>("LoggerQuick", LogName, DateTime.Now);
// Now let's start Logging
line = prePrend + line;
if (args != null)
_fileWriter.WriteLineA(String.Format(line, args));
else
_fileWriter.WriteLineA(line);
}
}
#endregion
}
}

391
File/Logging.cs Normal file
View File

@@ -0,0 +1,391 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using Diag = System.Diagnostics;
// Log4Net Declarations
using log4net.Appender;
using log4net.Core;
using log4net.Layout;
using log4net.Config;
using log4net;
using Yaulw.Other;
namespace Yaulw.File
{
/// <summary>
/// Logging Detail
/// </summary>
public enum Logging_Detail
{
NONE,
ERROR,
INFO,
DEBUG
}
/// <summary>
/// Used to Configure a Logger Instance in the Logging Class via AddGlobalLoggerConfiguration()
/// <example>
/// <code>
/// Logging_Configuration config;
/// config.LogFileNameNPath = "c:\\LogFile.log";
/// config.Detail = Logging_Detail.Error;
/// config.UseExclusiveFileLock = false;
/// config.maxFileSizeInMB = 4;
/// config.numOfBackupLogFiles = 3;
/// config.Log4NetDetailPatternLayout = "%date{dd MMM HH:mm:ss,fff} [%thread] %level - %message%newline"; (Default)
/// "%date{dd MMM yyyy HH:mm:ss,fff} [%thread] %level %logger - %message%newline";
/// config.LogCallingTypeAndCallingFunction = true;
/// </code>
/// </example>
/// </summary>
public struct Logging_Configuration
{
public string LogFileNameNPath;
public Logging_Detail Detail;
public bool UseExclusiveFileLock;
public int maxFileSizeInMB;
public int numOfBackupLogFiles;
public string Log4NetDetailPatternLayout;
public bool LogCallingType;
public bool LogCallingFunction;
}
/// <remarks>
/// Is a Wrapper Object around Log4Net's Rolling File Appender.
/// Use it by calling AddGlobalLoggerConfiguration() with a valid Logging Configuration.
/// You can configure multipe Logger Instances distinguished by Name.
/// subsequent calls can call GetLogger() with the named Logger instance to receive a valid logger object
/// </remarks>
public class Logging
{
#region Private Static Members
private static Dictionary<string, Logging_Configuration> _loggerConfigurationMap = new Dictionary<string, Logging_Configuration>();
private static Dictionary<string, ILog> _loggerObjects = new Dictionary<string, ILog>();
// If this process is hosted in VS then it changes the stack frame
private static bool s_IsVSHosted = false;
#endregion
#region Private Construction
/// <summary>
/// Private Constructor should only be called by static GetLogger() Function
/// </summary>
/// <param name="bLogCallingTypeAndCallingFunction">if true, will log calling type and Calling Function</param>
private Logging(bool bLogCallingType, bool bLogCallingFunction)
{
s_IsVSHosted = Diag.Process.GetCurrentProcess().ProcessName.Contains("vshost");
_LogCallingType = bLogCallingType;
_LogCallingFunction = bLogCallingFunction;
}
#endregion
#region Internal Members
// Initialized by GetLogger()
internal ILog _Log4NetLog = null;
// Initialized by GetLogger()
internal bool _LogCallingType = false;
// Initialized by GetLogger()
internal bool _LogCallingFunction = false;
#endregion
#region Public Log Methods
/// <summary>
/// Log Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Info(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader() + String.Format(message, args)); } }
/// <summary>
/// Log Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Info(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
/// <summary>
/// Log Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Info(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader() + String.Format(message, args), exception); } }
/// <summary>
/// Log Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Info(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Info(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
/// <summary>
/// Log Debug Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Debug(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader() + String.Format(message, args)); } }
/// <summary>
/// Log Debug Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Debug(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
/// <summary>
/// Log Debug Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Debug(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader() + String.Format(message, args), exception); } }
/// <summary>
/// Log Debug Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Debug(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Debug(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
/// <summary>
/// Log Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Error(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader() + String.Format(message, args)); } }
/// <summary>
/// Log Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Error(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
/// <summary>
/// Log Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Error(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader() + String.Format(message, args), exception); } }
/// <summary>
/// Log Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Error(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Error(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
/// <summary>
/// Log Fatal Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Fatal(string message, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader() + String.Format(message, args)); } }
/// <summary>
/// Log Fatal Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Fatal(string message, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + String.Format(message, args)); } }
/// <summary>
/// Log Fatal Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Fatal(string message, Exception exception, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader() + String.Format(message, args), exception); } }
/// <summary>
/// Log Fatal Error Information
/// </summary>
/// <param name="message">Message to write</param>
/// <param name="exception">Exception to Log</param>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
/// <param name="args">arguments to pass to String.Format</param>
public void Fatal(string message, Exception exception, int nPlusMinus, params object[] args) { if (_Log4NetLog != null) { _Log4NetLog.Fatal(MessageHeader(nPlusMinus) + String.Format(message, args), exception); } }
/// <returns>
/// Message Header to be shown on every log message
/// </returns>
/// <param name="nPlusMinus">Use this to add/substract from the base stack level you want to retrieve</param>
private string MessageHeader(int nPlusMinus = 0)
{
// When Running this from via VS it behaves differently then when
// running it outside of it, when running it regularly, each foreach loop
if (s_IsVSHosted)
{
if (_LogCallingType && _LogCallingFunction)
return StackWalker.GetTypeFromStack(nPlusMinus + 1) + " - " + StackWalker.GetMethodNameFromStack(nPlusMinus + 1) + "()- ";
else if (_LogCallingFunction)
return StackWalker.GetMethodNameFromStack(nPlusMinus + 1) + "()- ";
else
return "";
}
else
{
if (_LogCallingType && _LogCallingFunction)
return StackWalker.GetTypeFromStack(nPlusMinus) + " - " + StackWalker.GetMethodNameFromStack(nPlusMinus) + "()- ";
else if (_LogCallingFunction)
return StackWalker.GetMethodNameFromStack(nPlusMinus) + "()- ";
else
return "";
}
}
#endregion
#region Public Static Configuration and Logger Creation Methods
/// <summary>
/// Used to add a new Configuration and Logger Instance onto a Static Map.
/// Will create one logger instance per unique name.
/// </summary>
/// <param name="Name">a name for the logger instance</param>
/// <param name="Configuration">a valid configuration to use on the instance</param>
/// <returns>a logging object that can be used to log</returns>
public static Logging AddGlobalLoggerConfiguration(string Name, Logging_Configuration Configuration)
{
// Must have a Valid Input
if (string.IsNullOrEmpty(Name))
throw new ArgumentException("Name Is Invalid");
if (!_loggerObjects.Keys.Contains(Name.ToLower()))
{
// Create the Repository
log4net.Repository.ILoggerRepository repository = LogManager.CreateRepository(Name.ToLower());
// Create FileAppender Configuration
RollingFileAppender appender = RollingFileAppenderCreator(Configuration);
// Run the Configuration against the Repository
BasicConfigurator.Configure(repository, appender);
// Add Configuration to our Static Map
_loggerConfigurationMap[Name.ToLower()] = Configuration;
// Last, but not least, Create the new Logging Instance Object and Store it
_loggerObjects[Name.ToLower()] = LogManager.GetLogger(Name.ToLower(), Name.ToLower());
}
// Let the Caller get the Logging Object
return GetLogger(Name);
}
/// <summary>
/// Used to retrieve a named logging instance that has already been created via a previous call
/// to AddGlobalLoggerConfiguration().
/// </summary>
/// <param name="Name">a name for a previously created Logging instance</param>
/// <returns>a Logging object that can be used to log</returns>
public static Logging GetLogger(string Name)
{
if (_loggerObjects.Keys.Contains(Name.ToLower()) && _loggerConfigurationMap.Keys.Contains(Name.ToLower()))
{
bool bLogCallingType = _loggerConfigurationMap[Name.ToLower()].LogCallingType;
bool bLogCallingFunction = _loggerConfigurationMap[Name.ToLower()].LogCallingFunction;
Logging logger = new Logging(bLogCallingType, bLogCallingFunction);
logger._Log4NetLog = _loggerObjects[Name.ToLower()];
return logger;
}
else
throw new ArgumentException("Must call AddGlobalLoggerConfiguration() with a Configuration Before calling this Function");
}
#endregion
#region Private Static Helper Methods
/// <summary>
/// Creates a Log4Net RollingFileAppender with the specified configuration
/// </summary>
/// <param name="config">a valid configuration</param>
/// <returns>a Log4Net RollingFileAppender Object</returns>
private static RollingFileAppender RollingFileAppenderCreator(Logging_Configuration config)
{
#region Input Validation
if (config.maxFileSizeInMB <= 0)
throw new ArgumentException("Logging_Configuration - Invalid maxFileSizeInMB");
if (config.numOfBackupLogFiles < 0)
throw new ArgumentException("Logging_Configuration - Invalid numOfBackupLogFiles");
if (String.IsNullOrEmpty(config.LogFileNameNPath))
throw new Exception("Logging_Configuration - Invalid LogFileNameNPath");
if (!Directory.Exists(Path.GetDirectoryName(config.LogFileNameNPath)))
Directory.CreateDirectory(Path.GetDirectoryName(config.LogFileNameNPath));
#endregion
// Create and Set Layout for FileAppender
RollingFileAppender rfAppender = new RollingFileAppender();
// Set Layout
if (!String.IsNullOrEmpty(config.Log4NetDetailPatternLayout))
rfAppender.Layout = new PatternLayout(config.Log4NetDetailPatternLayout);
else
rfAppender.Layout = new PatternLayout("%date{dd MMM HH:mm:ss,fff} [%thread] %level - %message%newline");
// Locking Minimal allows us to run Log4Net from multiple processes
if (config.UseExclusiveFileLock)
rfAppender.LockingModel = new FileAppender.ExclusiveLock();
else
rfAppender.LockingModel = new FileAppender.MinimalLock();
// Configure FileName and always set Appent to true
rfAppender.File = config.LogFileNameNPath;
rfAppender.AppendToFile = true;
// According to the listings on the blog site
// http://blog.aggregatedintelligence.com/2009/08/log4net-logging-levels-available.html
// Error, will log Error, Fatal
// Info, will log Info, Error, and Fatal
// Debug, will log Info, Error, Fatal and Debug
if (config.Detail == Logging_Detail.NONE)
rfAppender.Threshold = Level.Off;
else if (config.Detail == Logging_Detail.ERROR)
rfAppender.Threshold = Level.Error;
else if (config.Detail == Logging_Detail.INFO)
rfAppender.Threshold = Level.Info;
else if (config.Detail == Logging_Detail.DEBUG)
rfAppender.Threshold = Level.Debug;
rfAppender.MaximumFileSize = String.Format("{0}MB", config.maxFileSizeInMB);
rfAppender.MaxSizeRollBackups = config.numOfBackupLogFiles;
// Setting to RollingMode.Size will make MaxSizeRollBackups work
rfAppender.RollingStyle = RollingFileAppender.RollingMode.Size;
rfAppender.ActivateOptions();
return rfAppender;
}
#endregion
}
}

190
File/Tail.cs Normal file
View File

@@ -0,0 +1,190 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace Yaulw.File
{
/// <remarks>
/// A File SystemWatcher utility that functions like the infamous unix tail utility,
/// with a callback when the file get's created or updated.
/// </remarks>
public class Tail
{
#region Public Events
/// <summary>
/// Event Delegate for the Incoming Data Event
/// </summary>
/// <param name="sender">object reference to the sending Tail Object</param>
/// <param name="newData">change data / or full data if bIsNewFile is true</param>
/// <param name="bIsNewFile">true if a new file was created</param>
public delegate void IncomingDataHandler(object sender, string newData, bool bIsNewFile);
/// <summary>
/// Caller must subscribe to the Incoming Data Event
/// </summary>
public event IncomingDataHandler IncomingData = null;
#endregion
#region Private Members
private string _FileNameNPath = "";
private FileSystemWatcher _fileSystemWatcher = null;
private long _previousSeekPosition = 0;
private object _lockingObj = new Object();
private const int MAX_BYTE_TO_READ_IN_ONE_TIME = 1024 * 16;
#endregion
#region Construction
/// <summary>
/// Construct a new Tail Object to monitor the specified file
/// </summary>
/// <param name="FileNameNPath">File to Monitor with Tail</param>
public Tail(string FileNameNPath)
{
_previousSeekPosition = 0;
_FileNameNPath = FileNameNPath;
}
#endregion
#region Public Methods
/// <summary>
/// Start Monitoring the File
/// </summary>
public void StartMonitoring()
{
// Get File Information * Setup System Watcher *
FileInfo targetFile = new FileInfo(_FileNameNPath);
_fileSystemWatcher = new FileSystemWatcher();
_fileSystemWatcher.IncludeSubdirectories = false;
_fileSystemWatcher.Path = targetFile.DirectoryName;
_fileSystemWatcher.Filter = targetFile.Name;
_fileSystemWatcher.Created += new FileSystemEventHandler(TargetFile_Created);
_fileSystemWatcher.Changed += new FileSystemEventHandler(TargetFile_Changed);
// Perform an Initial read, if the file exists
if (targetFile.Exists)
TargetFile_Created(null, null);
// Start up File System Watcher
_fileSystemWatcher.EnableRaisingEvents = true;
}
/// <summary>
/// Stop Monitoring the File
/// </summary>
/// <param name="bDispose">set to false, if you are running into trouble during a shutdown</param>
public void StopMonitoring(bool bDispose = true)
{
_fileSystemWatcher.EnableRaisingEvents = false;
if(bDispose)
_fileSystemWatcher.Dispose();
_fileSystemWatcher = null;
}
/// <summary>
/// To read a file from Beginning to End. Call this function,
/// if you want to reset the position counter and start reading again from the beginning.
/// </summary>
/// <returns>the Contents of the File</returns>
public StringBuilder ReadFromBeginningToEndOfFile()
{
_previousSeekPosition = 0;
return ReadFileContentsTillEndStartingFromPreviousSeekPosition();
}
#endregion
#region Private Helper Methods
/// <summary>
/// Handled File System Watcher's Created Callback
/// </summary>
/// <param name="source">SystemWatcher object</param>
/// <param name="e">SystemWatcher event args</param>
private void TargetFile_Created(object source, FileSystemEventArgs e)
{
// Read the File Contents
StringBuilder sb = ReadFromBeginningToEndOfFile();
//call delegate with the string
if (IncomingData != null && sb.Length > 0)
IncomingData(this, sb.ToString(), true);
}
/// <summary>
/// Handled File System Watcher's Changed Callback
/// </summary>
/// <param name="source">SystemWatcher object</param>
/// <param name="e">SystemWatcher event args</param>
private void TargetFile_Changed(object source, FileSystemEventArgs e)
{
// File size size changed to less! ~someone must have
// changed content inside of it
FileInfo targetFile = new FileInfo(_FileNameNPath);
bool bIsNew = false;
if (targetFile.Length < _previousSeekPosition)
{
_previousSeekPosition = 0;
bIsNew = true;
}
// Read the File Contents
StringBuilder sb = ReadFileContentsTillEndStartingFromPreviousSeekPosition();
//call delegate with the string
if(IncomingData != null && sb.Length > 0)
IncomingData(this, sb.ToString(), bIsNew);
}
/// <summary>
/// Helper Function to read a file from _previousSeekPosition to End.
/// </summary>
/// <returns>contents of file starting from _previousSeekPosition</returns>
private StringBuilder ReadFileContentsTillEndStartingFromPreviousSeekPosition()
{
lock (_lockingObj)
{
// Open the file
FileStream fs = new FileStream(_FileNameNPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
// Read File Contents into a StringBuilder
StringBuilder sb = new StringBuilder();
bool bReadOrContinueReadingFile = true;
while (bReadOrContinueReadingFile)
{
// Position the file
_previousSeekPosition = (int)fs.Seek(_previousSeekPosition, SeekOrigin.Begin);
//read from current seek position to end of file
byte[] bytesRead = new byte[MAX_BYTE_TO_READ_IN_ONE_TIME];
int numBytes = fs.Read(bytesRead, 0, MAX_BYTE_TO_READ_IN_ONE_TIME);
_previousSeekPosition += numBytes;
// Append Data to the String Builder
for (int i = 0; i < numBytes; i++)
sb.Append((char)bytesRead[i]);
// If we have read up to MAX_BYTE_TO_READ_IN_ONE_TIME, then there could be more data...
bReadOrContinueReadingFile = (numBytes == MAX_BYTE_TO_READ_IN_ONE_TIME);
}
// Close File
fs.Dispose();
fs = null;
// Return SB object
return sb;
}
}
#endregion
}
}