#define useIsolatedStorage
//The XML configuration file may be written to isolated storage or to normal file storage.
//Normal file storage is useful for debugging as it is easy to view or modify the XML source.
using System;
using System.Collections;
using System.Drawing;
using System.IO;
using System.IO.IsolatedStorage;
using System.Security;
using System.Text;
using System.Windows.Forms;
using System.Xml;
namespace FileFind
{
/// <summary>
/// ConfigInfo holds configuration data as well as data that is commonly shared between
/// program modules and forms.
/// Product/version information is maintained in AssemblyInfo.cs
/// Configuration information is stored when the application exits and retrieved at the next start up.
/// If useIsolatedStorage is #defined, application setting are saved in isolated storage specific to
/// the program and user. Otherwise, the information is stored in the program execution directory
/// where it is simple to view or modify the XML source for testing.
///
/// ConfigInfo is also used to pass data from the DiskSelection dialog back to the caller.
/// </summary>
class ConfigInfo
{
#region Local constants and variables
private object syncobj = new object(); //local lock object
/// <summary>
/// Product/version identification constants
/// </summary>
private const string PRODUCTNAME = "File Find";
private const string PRODUCTDATE = "2008";
private static string PRODUCTVERSION =
System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString();
/// <summary>
/// Maintenance
/// Version 1.0.0.0 Initial coding
/// 2.0.0.0 Code restructured and optimized based on hard won knowledge
/// 2.1.0.0 Added ResolvePartitions logic to Form1.cs to eliminate
/// seek contention on partitioned physical drives.
/// 2.1.0.3 Added reparse point processing (do not recurse into it)
/// 2.1.0.4 Added time filters
/// 2.1.0.5 Added hidden folder/file menu option
/// 2.1.0.6 Switched from foreach (FileSystemInfo to FileSystemEnumerator in DiskScan
/// to significantly speed up access to network drives
/// 2.1.0.7 Added Menu->Options->Scanning via enumerator to ease testing and
/// allow for Windows 7 bug. Windows 7 failed when using enumerator.
/// 2.1.0.8 Added NumericScaling class
/// 2.1.0.9 Final clean up before publication to www.codeproject.com
/// 2.1.0.10 Changed .cvs to .csv file extention
/// Added code to correctly handle embedded commas, new line characters and double quotes for save to .CSV files
/// Modified exit from Excludes to refresh selected drive information
/// Modified .CSV save routine to properly handle reservered characters (comma and double quotes) and changed
/// the seperation character to a tab.
/// 2.1.0.11 Modified menu titles and rearranged menu items. Changed opening instructions.
/// Added status area at bottom of form to report disks being searched and thread terminations.
/// Modified SelectAllDisks logic to handle a system with no drives.
/// 2.1.0.12
/// Added "Waiting on logical/physical drive resolution" message to Form1.cs
/// Grid view of "Folders only" no longer has file name or size columns
/// 2.1.0.13
/// Added busy cursor during logical/physical disk resolution, Sort and Grid view swap.
/// Totally revamped BeginUpdate/EndUpdate logic for filesFoundBox displays resulting in
/// better response and faster searches when a large number of hits are found.
/// 2.1.0.14
/// Moved logical to physical disk resolution to LogicalPhysicalDiskResolution class
/// Corrected Form1.excludesButton_Click to resolve with currently selected disk drives.
/// Add disk info display to single/double click of Disk column in grid view.
/// Now launches Drive for double click.
/// 2.1.0.15
/// Improved user identity checking in About.
/// Corrected an error in Directory delete
/// </summary>
private const string CONFIGFILENAME = "FileFind.xml"; //name of the configuration file
private static bool alreadyInitialized = false; //determines if the following static fields are already loaded
private static bool isDirty = false; //determines if ConfigInfo should be saved at exit
private static bool removedSavedOptions = false; //Isolated storage is not to be written at termination
public enum DateTimeRangeSearch
{
DateTimeRangeOff,
DateTimeRangeByCreate,
DateTimeRangeByModified,
DateTimeRangeByLastAccessed
};
private static DateTimeRangeSearch dateTimeRange;
private static DateTime fromDateTime;
private static DateTime toDateTime;
//variables held for Form to Form communications
private static ArrayList selectedDisks; //contains: string of disk letters
//for example: C:\, D:\, etc
//variables to be saved for the next execution of this program
private static ArrayList ignoreFolders = null; //contains files and folders to exclude when searching
//contains: string
private static bool startWithGrid = false; //start in List or Grid view
private static Font font = null; //display panels in this font
private static bool showUnauthorizedFolders; //if True, security exceptions are displayed
private static bool showHiddenFoldersFiles; //if True, search and show hidden folders and files
private static bool scanningViaEnumerator; //if True, search files and folders using enumerators
private static bool autoScrolling; //if true, auto scroll list view
#endregion Local constants and variables
#region Properties
public string ProductName
{ get { return PRODUCTNAME; } }
public string ProductVersion
{ get { return PRODUCTVERSION; } }
public string ProductDate
{ get { return PRODUCTDATE; } }
public bool StartWithGrid
{ //determines if the initial display should begin with a list or grid view
//List view is the inital default
//The current view is saved when the application exits and the
//application will be restarted with the same view.
get { return startWithGrid; }
set
{
if(value != startWithGrid)
{ startWithGrid = value; isDirty = true; }
}
}
public bool ShowUnauthorizedFolders
{ //determines if a display of failed folder accesses should be created or not
get { return showUnauthorizedFolders; }
set { showUnauthorizedFolders = value; }
}
public bool ShowHiddenFoldersFiles
{ //determines if hidden folders or files should be shown and searched
get { return showHiddenFoldersFiles; }
set { showHiddenFoldersFiles = value; isDirty = true; }
}
public bool ScanningViaEnumerator
{
get { return scanningViaEnumerator; }
set { scanningViaEnumerator = value; isDirty = true; }
}
public bool AutoScrolling
{
get { return autoScrolling; }
set { autoScrolling = value; isDirty = true; }
}
public ArrayList IgnoreFolders
{ //a set of folder nodes, drives or specific drive folder combinations to be excluded
//populated by the IgnoreFolders class
get { lock (syncobj) { return ignoreFolders; } }
set { lock (syncobj) { ignoreFolders = value; isDirty = true; } }
}
public ArrayList SelectedDisks
{ //set of drives selected to be searched
//populated by the DiskSelection class
get
{
lock (syncobj)
{
ArrayList selected = new ArrayList(selectedDisks);
return selected;
}
}
set { lock (syncobj) { selectedDisks = value; } }
}
public Font UseFont
{ //font to use for displays
//selected via menu option
get { lock (syncobj) { return font; } }
set { lock (syncobj) { font = value; isDirty = true; } }
}
public ArrayList DefaultFolders
{ //generate a default exclusion list
get
{
ArrayList defaultFolders = new ArrayList();
defaultFolders.Add("System Volume Information");
defaultFolders.Add("$Recycle.Bin");
defaultFolders.Add("RECYCLER"); //NTFS
defaultFolders.Add("RECYCLED"); //FAT
defaultFolders.Add("Program Files"); //found on 32 and 64 bit systems
defaultFolders.Add("Program Files (x86)"); //found on 64 bit systems
return defaultFolders;
}
}
public DateTimeRangeSearch IDateTimeRange
{
get { return dateTimeRange; }
set { dateTimeRange = value; }
}
public DateTime IFromDateTime
{
get { return fromDateTime; }
set { fromDateTime = value; }
}
public DateTime IToDateTime
{
get { return toDateTime; }
set { toDateTime = value; }
}
#endregion Properties
#region Public functions
/// <summary>
/// Class constructor
/// On first use, initializes all the static fields to default values then loads
/// stored values from a prior execution.
/// </summary>
public ConfigInfo()
{
if (!alreadyInitialized)
{ //initialize all configuration data when first called
lock (syncobj)
{
alreadyInitialized = true;
selectedDisks = new ArrayList();
ignoreFolders = new ArrayList();
dateTimeRange = DateTimeRangeSearch.DateTimeRangeOff;
DateTime currentDateTime = DateTime.Now;
//fromDateTime = DateTime.MinValue;
fromDateTime = new DateTime(1980, 1, 1, 0, 0, 0);
toDateTime = DateTime.MaxValue;
/*toDateTime = new DateTime(currentDateTime.Year,
currentDateTime.Month,
currentDateTime.Day,
currentDateTime.Hour, 23, 59); */
scanningViaEnumerator =
showHiddenFoldersFiles =
showUnauthorizedFolders =
startWithGrid = false;
autoScrolling = true;
try
{
#if useIsolatedStorage
using (Stream isolatedStorageStream = new IsolatedStorageFileStream(CONFIGFILENAME,
FileMode.Open, IsolatedStorageFile.GetUserStoreForAssembly()))
#else
using (Stream isolatedStorageStream = new FileStream(CONFIGFILENAME, FileMode.Open))
#endif
{
XmlDocument xmldoc = new XmlDocument();
using (StreamReader ifs = new StreamReader(isolatedStorageStream))
{ xmldoc.Load(ifs); }
XmlNode listOrGrid = xmldoc.SelectSingleNode("FileFind/StartView");
if ((null != listOrGrid) && ("Grid" == listOrGrid.InnerText))
startWithGrid = true;
XmlNode showHidden = xmldoc.SelectSingleNode("FileFind/Hidden");
if ((null != showHidden) && ("True" == showHidden.InnerText))
showHiddenFoldersFiles = true;
XmlNode scanning = xmldoc.SelectSingleNode("FileFind/ScanningViaEnumerator");
if ((null != scanning) && ("True" == scanning.InnerText))
scanningViaEnumerator = true;
XmlNode autoScroll = xmldoc.SelectSingleNode("FileFind/AutoScroll");
if (null != autoScroll)
if ("True" == autoScroll.InnerText)
autoScrolling = true;
else
autoScrolling = false;
XmlNode ignore = xmldoc.SelectSingleNode("FileFind/IgnoreFolders");
if (null != ignore)
foreach (XmlNode x in ignore)
ignoreFolders.Add(x.InnerText);
else
ignoreFolders = DefaultFolders;
try
{
XmlNode useFont = xmldoc.SelectSingleNode("FileFind/UseFont");
if (null != useFont)
{
XmlNode root;
root = xmldoc.SelectSingleNode("FileFind/UseFont/Name");
string fontName = root.InnerText;
root = xmldoc.SelectSingleNode("FileFind/UseFont/Size");
string swFont = root.InnerText;
float currentSize = System.Convert.ToSingle(swFont);
FontStyle swStyle = new FontStyle();
root = xmldoc.SelectSingleNode("FileFind/UseFont/Bold");
if ("True" == root.InnerText)
swStyle |= FontStyle.Bold;
root = xmldoc.SelectSingleNode("FileFind/UseFont/Italic");
if ("True" == root.InnerText)
swStyle |= FontStyle.Italic;
root = xmldoc.SelectSingleNode("FileFind/UseFont/Strikeout");
if ("True" == root.InnerText)
swStyle |= FontStyle.Strikeout;
root = xmldoc.SelectSingleNode("FileFind/UseFont/Underline");
if ("True" == root.InnerText)
swStyle |= FontStyle.Underline;
font = new Font(fontName, currentSize, swStyle);
}
}
catch (Exception xe)
{
MessageBox.Show(xe.InnerException.ToString(), PRODUCTNAME + " UseFont",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
}
}
catch (SecurityException se)
{
MessageBox.Show(se.Message, PRODUCTNAME + " Config loading",
MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
}
catch (Exception)
{ }
} //ends lock (syncobj)
} //ends if (!alreadyInitialized)
} //ends public ConfigInfo()
/// <summary>
/// Saves configuration values for the next execution of the application
/// </summary>
public void SaveConfig()
{ //XML Create (creates an XML file via native calls)
if((isDirty) && (!removedSavedOptions))
lock (syncobj)
{
try
{
#if useIsolatedStorage
using (Stream isolatedStorageStream =
new IsolatedStorageFileStream(CONFIGFILENAME, FileMode.Create, IsolatedStorageFile.GetUserStoreForAssembly()))
#else
using (Stream isolatedStorageStream = new FileStream(CONFIGFILENAME, FileMode.Create))
#endif
using(XmlTextWriter appconfig = new XmlTextWriter(isolatedStorageStream, Encoding.UTF8))
{
appconfig.Formatting = Formatting.Indented;
appconfig.WriteStartDocument();
DateTime newDate = DateTime.Now;
appconfig.WriteComment("Created " + newDate);
appconfig.WriteStartElement("FileFind");
appconfig.WriteCData(@"<>\&");
if (startWithGrid)
appconfig.WriteElementString("StartView", "Grid");
else
appconfig.WriteElementString("StartView", "List");
appconfig.WriteElementString("Hidden", showHiddenFoldersFiles.ToString());
appconfig.WriteElementString("ScanningViaEnumerator",
scanningViaEnumerator.ToString());
appconfig.WriteElementString("AutoScroll",
autoScrolling.ToString());
if (null != ignoreFolders)
{
appconfig.WriteStartElement("IgnoreFolders");
foreach (string str in ignoreFolders)
appconfig.WriteElementString("IgnoreFolder", str);
appconfig.WriteEndElement(); //ends IgnoredFolders
}
if (null != font)
{
appconfig.WriteStartElement("UseFont");
appconfig.WriteElementString("Name", font.Name.ToString());
appconfig.WriteElementString("Style", font.Style.ToString());
appconfig.WriteElementString("Size", font.Size.ToString());
appconfig.WriteElementString("Bold", font.Bold.ToString());
appconfig.WriteElementString("Italic", font.Italic.ToString());
appconfig.WriteElementString("Strikeout", font.Strikeout.ToString());
appconfig.WriteElementString("Underline", font.Underline.ToString());
appconfig.WriteEndElement(); //ends UseFont
}
appconfig.WriteEndDocument();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, PRODUCTNAME,
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
} //ends lock (syncobj)
} //ends public void SaveConfig()
public ArrayList SelectAllDisks(out int diskCount)
{ //show all disks as selected except explicitly excluded disks
//returns an ArrayList of selected disks and a count of selected disks
//if the count is -1 then all disks have been selected
ArrayList selected = new ArrayList();
DriveInfo[] allDrives = null;
try
{ allDrives = DriveInfo.GetDrives(); }
catch (Exception ex)
{
MessageBox.Show(ex.Message, PRODUCTNAME + " SelectAllDisks",
MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
allDrives = null;
}
diskCount = 0;
if (allDrives != null)
{
int readyDrives = 0;
lock (syncobj)
{ //freeze contents of ignoreFolders
foreach (DriveInfo drive in allDrives)
{//show drives available
if (drive.IsReady)
{
++readyDrives;
if (!FoundInIgnoreDirectory(drive.Name))
selected.Add(drive.Name);
}
}
} //ends lock (syncobj)
diskCount = selected.Count;
if (diskCount == readyDrives)
diskCount = -1; //all drives selected
}
return selected;
} //ends public ArrayList SelectAllDisks(...
public ArrayList FilterSelectedDisks(ArrayList currentlySelected)
{ //show all disks as selected except explicitly excluded disks
//returns an ArrayList of selected disks and a count of selected disks
//if the count is -1 then all disks have been selected
ArrayList selected = new ArrayList();
lock (syncobj)
{ //freeze contents of ignoreFolders
foreach (string selectedDrive in currentlySelected)
{//show drives available
DriveInfo drive = new DriveInfo(selectedDrive);
if (drive.IsReady)
{
if (!FoundInIgnoreDirectory(drive.Name))
selected.Add(drive.Name);
}
}
} //ends lock (syncobj)
return selected;
} //ends public ArrayList FilterSelectedDisks(...
public void RemoveIsolatedStorage()
{
removedSavedOptions = true;
try
{
#if useIsolatedStorage
IsolatedStorageFile isoFile = IsolatedStorageFile.GetStore(IsolatedStorageScope.User |
IsolatedStorageScope.Assembly,
typeof(System.Security.Policy.Url),
typeof(System.Security.Policy.Url));
String[] fileNames = isoFile.GetFileNames(CONFIGFILENAME);
foreach (string fileName in fileNames)
{
// Delete the files.
isoFile.DeleteFile(fileName);
}
#else
File.Delete(CONFIGFILENAME);
#endif
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, PRODUCTNAME + " Isolated storage / file delete",
MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
} //ends public RemoveIsolatedStorage()
#endregion Public functions
#region Private functions
private bool FoundInIgnoreDirectory(string driveLetter)
{ //Determines if a disk has been excluded.
//This routine does not have hidden file logic.
if (String.IsNullOrEmpty(driveLetter) || (driveLetter.Length < 3))
return true;
string fwdSlash = driveLetter.Replace('\\', '/');
foreach (string str in ignoreFolders)
{
if (':' == str[1])
{ //fully qualified folder name by drive?
if (Char.IsLetter(str[0]))
{
string folder_str = str.Replace('\\', '/');
if (string.Compare(folder_str, fwdSlash, true) == 0)
return true;
}
}
if (string.Compare(str, fwdSlash, true) == 0)
return true;
}
return false;
} //ends private bool FoundInIgnoreDirectory(...
#endregion Private functions
}
}