August 16, 2008

Regular Expressions

For matching purposes:
? = 0 or 1 match
* = 0..n matches
+ = 1..n matches
{m,n} = from 'm' to 'n' matches where 'm' and 'n' are digits
{n} = exactly 'n' matches where 'n' is a digit
\d = numeric digit
\D = anything but a numeric digit
\s = any whitespace character
\S = any non-whitespace character
\w = Any alphabetical character and '_'
\W = Any non-alphabetical character or '_'

This example matches a United Kingdom postcode:
using System.Text.RegularExpressions;
...
const string PostCodeRegEx = @"(GIR0AA|[A-PR-UWYZ]([0-9]{1,2}|" + 
  "([A-HK-Y][0-9]|[A-HK-Y][0-9]([0-9]|[ABEHMNPRV-Y]))|" +
  "[0-9][A-HJKS-UW])[0-9][ABD-HJLNP-UW-Z]{2})";
public bool IsPostCode(string postCode)
{
    postCode = postCode.Trim().Replace(" ", string.Empty);
    bool res = Regex.IsMatch(postCode, PostCodeRegEx);
    return res;
}
This example Matches a SID:
using System.Text.RegularExpressions;
...
result = string.Empty;
const string SID_PATTERN = @"(\w-\d-\d-\d{2}-\d+-\d+-\d+)";
Regex reg = new Regex(SID_PATTERN);
MatchCollection mc = reg.Matches(sid);
if (mc.Count > 0)
{
    result = mc[0].Value;
}

Enums

See this blog entry for information and example on the use of DescriptionAttribute with Enums

This example uses an ComboBox to store the enumeration values as strings Preparing the Combobox
foreach (XXXEnum entry in Enum.GetValues(typeof(XXXEnum)))
    comboBox.Items.Add(entry);
OR
cbLoggingLevel.Items.AddRange(Enum.GetValues(typeof(XXXEnum)));

// Making an initial selection
comboBox.SelectedIndex = comboBox.Items.Count - 1; // Select the last one
OR
comboBox.SelectedIndex = 0; // Select the first
Converting to and from a string
//To convert an enum to a string use:
MyComboBox.SelectedItem = m_Object.XXXEnum .ToString();

//The reverse process is a little more complicated
XXXEnum gc = (XXXEnum ) Enum.Parse(typeof(XXXEnum ),
                        MyComboBox.SelectedItem.ToString(), true);
There is a better way to parse the enum from a string that I found here.:
public static class StringExtender
{
  public static TEnum ParseToEnum<TEnum>(this string name)
    where TEnum : struct
  {
    if (false == typeof(TEnum).IsEnum)
      throw new NotSupportedException(typeof(TEnum).Name + " must be an Enum");

    string trimmed = name.Trim();
    
    if (false == Enum.IsDefined(typeof(TEnum), trimmed))
      throw new ArgumentException(string.Format(
         "\'{0}\' is not defined in type of enum {1}", trimmed, typeof(TEnum).Name));

    return (TEnum)Enum.Parse(typeof(TEnum), trimmed);
  }
}
alternatively use the TryParse method.
public class EnumTester
{
  public enum DescriptionsEnum
  {
    None,
    AddOn,
    SnapOn,
    Adjacent,
    Fixed,
  };

  public void ParseEnumFromStringTest()
  {
    DescriptionsEnum test = DescriptionsEnum.None;
    test = StringExtender.ParseToEnum<DescriptionsEnum>("Adjacent");
    Debug.Assert(test == DescriptionsEnum.Adjacent);
    test = "Fixed".ParseToEnum<DescriptionsEnum>();
    Debug.Assert(test == DescriptionsEnum.Fixed);
    test = "   SnapOn  ".ParseToEnum<DescriptionsEnum>();
    Debug.Assert(test == DescriptionsEnum.SnapOn);
    //test = "      snapon    ".ParseToEnum<DescriptionsEnum>(); // FAILS!
    //Debug.Assert(test == DescriptionsEnum.SnapOn);

    bool success = Enum.TryParse<DescriptionsEnum>("Adjacent", out test);
    Debug.Assert(test == DescriptionsEnum.Adjacent);
    success = Enum.TryParse<DescriptionsEnum>("fixed", true, out test);
    Debug.Assert(test == DescriptionsEnum.Fixed);
    success = Enum.TryParse<DescriptionsEnum>("  fixed     ", true, out test);
    // Line below succeeds. - TryParse is more robust so use it instead!
    Debug.Assert(test == DescriptionsEnum.Fixed); 
  }
}

Iterating through enumerated types:
foreach (XXXEnum entry in Enum.GetValues(typeof(XXXEnum)))
{
    Debug.WriteLine(entry.ToString() + "=" + ((int)entry).ToString());                
}
See Flags Based Enumerated Types

Color

To create a color with a given RGB value use
Color color = Color.FromRGB(0xf1, 0xee, 0x45);
//otherwise
Color.Red, ...

Random Number Generator

Random class in .Net is part of System namespace
//Declare an object
Random randomNumberGenerator = new Random();
random.NextDouble() //to get the next random number between 0.0 and 1.0;
random.Next() // to get the next random positive integer number
// to get the next random integer, x where  'upper' <= x  < 'lower'
random.Next(lower, upper) 
Byte[] b = new Byte[10];
random.NextBytes(b); to set an array of bytes

//To set a seed for the random number generator
int seed = 137;
System.Random randomNumberGenerator = new System.Random(seed);

August 10, 2008

Ownerdraw ListView

Msdn: On Msdn Find this article with Google TODO: Add our code here

Standard Delegates And Events

Standard event handler, no delegate definition necessary.
public event EventHandler xxxChanged;
Standard delegate handler, no delegate definition necessary.
using System;
//public delegate void Action()
Action xxxDelegate = new Action(xxxMethod);

public delegate TResult Func()
//Use it with anonymous methods:
Func methodCall = delegate() { return xxx.MethodReturningABool(); };
//There are other Func overloads, eg:
//public delegate TResult Func()
Func convert = delegate(int s)
         { return i.ToString() }; 

OR
// definition: public delegate void MethodInvoker()
using  System.Windows.Forms;
...
MethodInvoker xxxDelegate = new MethodInvoker(xxxMethod);

Loading Objects Using Reflection

This helper class loads a bunch of objects from assemblies found in the specified search path. The objects must support an interface of the given type eg usage. List<ISomeInterface> plugIns = PluginHelper.LoadPlugins <ISomeInterface>(@".\");
class PluginHelper
{

  // Loading a bunch of objects dynamically using reflection
  // In this case the type parameter specifies an interface for
  // an object with a public default constructor
  public static IList<INTERFACE> LoadPlugins<INTERFACE>(
         string searchPath)
  //where INTERFACE :  // (only reference types)
  {
    List<INTERFACE> objList = new List<INTERFACE>();

    string[] files = Directory.GetFiles(searchPath, "*.dll");
    foreach (string file in files)
    {
      try
      {
        Assembly assembly = Assembly.LoadFrom(file);
        foreach (Type type in assembly.GetTypes())
        {
          if (!type.IsClass || type.IsNotPublic) continue;
          Type[] interfaces = type.GetInterfaces();
          if (((IList<Type>)interfaces).Contains(typeof(INTERFACE)))
          {
            try
            {

              // Find the default constructor
              ConstructorInfo conInfo = type.GetConstructor(new Type[0]);
              bool hasPublicDefaultConstructor = ((conInfo != null) &&
                  ((conInfo.Attributes | MethodAttributes.Public) > 0));
              if (hasPublicDefaultConstructor)
              {
                object obj = Activator.CreateInstance(type);
                INTERFACE instance = (INTERFACE)obj;
                Debug.Assert(instance != null);
                objList.Add(instance);
              }
              else
              {
                Trace.WriteLine("LoadPlugins<INTERFACE>() - Can not create the type \'" +
                    type.ToString() + "\' in assembly \'" + file +
                    "\' as it does not have a public default constructor");
              }
            }
            catch (Exception ex)
            {
              Trace.WriteLine("Exception occurred creating an instance of \'" +
                  type.ToString() + "\' from assembly \'" + file + "\'");
            }

          }

        }
      }
      catch (Exception ex)
      {
        Trace.WriteLine("Exception occurred trying to load from assembly \'" +
            file + "\'");
      }
    }
    return objList;
  }

}

Xml Serialisation/Deserialisation

A simple helper class
using System.Xml.Serialization;

...
public static class XmlSerializationHelper
{

    // Serialize the given type (only reference types) to an Xml string
    // Catches any exceptions
    // Eg:
    // string xmlString = SerializationHelper.SerializeToXml<MyClass>(myClass);      
    public static string TrySerializeToXml<T>(this T targetObj, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        string res = string.Empty;
        try
        {
            StringBuilder builder = new StringBuilder();
            XmlSerializer xmlSerializer = new XmlSerializer(typeof (T), extraTypes);
            xmlSerializer.Serialize(new StringWriter(builder), targetObj);
            res = builder.ToString();
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.SerializeToXml<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during serialization " +
                                ex.ToString());
        }
        return res;
    }


    // Deserialize the given type (only reference types) from an Xml string
    // Eg:
    // MyClass myObj = SerializationHelper.DeserializeFromXml<MyClass>
    //(xmlString);
    public static T TryDeserializeFromXml<T>(this string xml, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        T obj = null;
        try
        {
            XmlSerializer xmlSerializer = new XmlSerializer(typeof (T), extraTypes);
            obj = (T) xmlSerializer.Deserialize(new StringReader(xml));
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.DeserializeFromXml<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during deserialization " +
                                ex.ToString());
        }
        return obj;
    }


    // Serialize the given type (only reference types) to an Xml filePath
    public static void TrySerializeToXmlFile<T>(this T targetObj, 
        string filePath, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        try
        {
            using (TextWriter tw = new StreamWriter(filePath))
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof (T), extraTypes);
                xmlSerializer.Serialize(tw, targetObj);
                tw.Close();
            }
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.SerializeToXml<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during serialization " +
                                ex.ToString());
        }
    }


    // Deserialize the given type (only reference types) from an Xml filePath
    public static T TryDeserializeFromXmlFile<T>(FileInfo file, params Type[] extraTypes)
        where T : class // (only reference types)
    {
        T obj = null;
        try
        {
            using (Stream fs = new FileStream(file.FullName, FileMode.Open))
            {
              // Use an XmlReader as according to the MSDN documentation it
              // "automatically detects and uses the encoding specified by 
              // the XML document."
              using (XmlReader xmlReader = new XmlTextReader(fs))
              {
                 XmlSerializer serializer = new XmlSerializer(typeof (T), extraTypes);
                 obj = (T) serializer.Deserialize(xmlReader);
              }
            }  
            //using (TextReader tr = new StreamReader(file.FullName))
            //{
            //    XmlSerializer serializer = new XmlSerializer(typeof (T), extraTypes);
            //    obj = (T) serializer.Deserialize(tr);
            //    tr.Close();
            //}
        }
        catch (Exception ex)
        {
            Trace.WriteLine("SerializationHelper.TryDeserializeFromXmlFile<T>: " +
                            "Exception occurred during deserialization " + ex.ToString());
            Debug.Assert(false, "Exception occurred during deserialization " +
                                ex.ToString());
        }
        return obj;
    }


}

Using this XmlSerialiser/Deserialiser sample
class XmlSerialiserDeserialiserTester
{
  public void TestTaskSerialisation()
  {
    string testPath = Path.Combine(Path.GetTempPath(), "TestSerializer.xml");

    TaskManager tm = new TaskManager();
    tm.Add(new Task { When = Task.WhenEnum.Fortnight, Displayable = true, 
        Description = "Buy water proofing spray" });
    string serialised = tm.TrySerializeToXml<taskmanager>(); // Serialize
    Debug.WriteLine(serialised);

    TaskManager dtm = serialised.TryDeserializeFromXml<taskmanager>(); // Deserialize
    Debug.Assert(tm.Count == dtm.Count);
    Debug.Assert(tm[0].Description.Equals(dtm[0].Description, 
                                          StringComparison.InvariantCultureIgnoreCase));
  }
}

public class TaskManager : List<Task>
{
}

public class Task
{
 public enum WhenEnum
 {
  Fortnight = 1,
  Month = 2,
  Year = 3,
 }
 public WhenEnum When { get; set; }
 public bool Displayable { get; set; }
 public string Description { get; set; }
}

Symmetric Encryption in C#

The following code is based on that found in this article: Cryptography Simplified in Microsoft .NET The Key and the IV are needed to decrypt the encrypted text
using System;
using System.Text;
using System.Security.Cryptography;
using System.IO;
using System.Diagnostics;

...

// Simple Symmetric Encryption helper class
// Encrypts/Decrypts strings
public class SymmetricEncryptor
{
    // Private Variables for this Form
    private SymmetricAlgorithm m_EncryptionAlgorithmn;

    //Default constructor. Default Encryption algorithmn 
    // to TripleDESCryptoServiceProvider
    public SymmetricEncryptor()
    {
        m_EncryptionAlgorithmn = Rijndael.Create();
    }

    public SymmetricEncryptor(SymmetricAlgorithm symmetricAlgorithm)
    {
        m_EncryptionAlgorithmn = symmetricAlgorithm;
    }

    // Generate a Key for use with the Encryptor
    public string GenerateKeyString()
    {
        m_EncryptionAlgorithmn.GenerateKey();
        return Convert.ToBase64String(m_EncryptionAlgorithmn.Key);
    }

    // Generate an Initialisation Vector (as a string) for use with the Encryptor
    public string GenerateIVString()
    {
        m_EncryptionAlgorithmn.GenerateIV();
        return Convert.ToBase64String(m_EncryptionAlgorithmn.IV);
    }

    // Generate an Initialisation Vector for use with the Encryptor
    public byte[] GenerateIV()
    {
        m_EncryptionAlgorithmn.GenerateIV();
        return m_EncryptionAlgorithmn.IV;
    }


    // Get/Set the a Key for use with the Encryptor. 
    // Note the Key is provided as a Base 64 encoded string
    public string KeyString
    {
        get
        { return Convert.ToBase64String(m_EncryptionAlgorithmn.Key); }
        set
        { m_EncryptionAlgorithmn.Key = Convert.FromBase64String(value); }
    }

    // Get/Set the a Initialisation Vector for use
    // with the Encryptor. Note the Initialisation 
    // Vector is provided as a Base 64 encoded string
    public string IVString
    {
        get
        {
            return Convert.ToBase64String(m_EncryptionAlgorithmn.IV);
        }
        set
        { m_EncryptionAlgorithmn.IV = Convert.FromBase64String(value); }
    }


    // Get/Set the a Key for use with the Encryptor. 
    // Note the Key is provided as a Base 64 encoded string
    public byte[] Key
    {
        get
        { return m_EncryptionAlgorithmn.Key; }
        set
        { m_EncryptionAlgorithmn.Key = value; }
    }

    // Get/Set the a Initialisation Vector for use with the Encryptor.
    public byte[] IV
    {
        get
        { return m_EncryptionAlgorithmn.IV; }
        set
        { m_EncryptionAlgorithmn.IV = value; }
    }

    // Encrypt a string
    public string EncryptToString(string Value)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateEncryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = Encoding.UTF8.GetBytes(Value);
        bytes = ApplyCryptoTransform(bytes, ct);
        return Convert.ToBase64String(bytes);
    }

    // Decrypt a string
    public string DecryptFromString(string Value)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateDecryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = Convert.FromBase64String(Value);
        bytes = ApplyCryptoTransform(bytes, ct);
        return Encoding.UTF8.GetString(bytes);
    }

    // Encrypt a string
    public byte[] EncryptToBytes(string Value)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateEncryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = Encoding.UTF8.GetBytes(Value);
        bytes = ApplyCryptoTransform(bytes, ct);
        return bytes;
    }

    // Decrypt a string
    public string DecryptFromBytes(byte[] encrBytes)
    {
        ICryptoTransform ct = m_EncryptionAlgorithmn.CreateDecryptor(
            m_EncryptionAlgorithmn.Key,
            m_EncryptionAlgorithmn.IV);
        byte[] bytes = ApplyCryptoTransform(encrBytes, ct);
        return Encoding.UTF8.GetString(bytes);
    }


    private static byte[] ApplyCryptoTransform(byte[] bytes,
        ICryptoTransform ct)
    {
        MemoryStream ms = new MemoryStream();
        CryptoStream cs = new CryptoStream(ms, ct, CryptoStreamMode.Write);
        cs.Write(bytes, 0, bytes.Length);
        cs.FlushFinalBlock();
        cs.Close();

        return ms.ToArray();
    }

    public byte[] GenerateKey()
    {
        m_EncryptionAlgorithmn.GenerateKey();
        return m_EncryptionAlgorithmn.Key;
    }
}
Here is a tester that demonstrates usage of the class.
public class SymmetricEncryptorTester
{
    public void Test()
    {
        string test = "98The0quick1brown2fox3jumps4over5the6lazy7cow";
        byte[] key;
        byte[] iv;
        string encrypted;
        string res;
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            key = se.GenerateKey();
            iv = se.GenerateIV();
            Debug.WriteLine(ByteToArray("key", key));
            Debug.WriteLine(ByteToArray("iv", iv));
            encrypted = se.EncryptToString(test);
            Debug.WriteLine("encrypted=" + encrypted);
        }
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            se.IV = iv;
            se.Key = key;
            res = se.DecryptFromString(encrypted);
            Debug.Assert(res.Equals(test, StringComparison.InvariantCulture));
            Debug.WriteLine("res=" + res);
        }
    }

    public void Test2()
    {
        string test = "98The0quick1brown2fox3jumps4over5the6lazy7cow";
        byte[] key;
        byte[] iv;
        byte[] encrypted;
        string res = "";
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            key = se.GenerateKey();
            iv = se.GenerateIV();
            Debug.WriteLine(ByteToArray("key", key));
            Debug.WriteLine(ByteToArray("iv", iv));
            encrypted = se.EncryptToBytes(test);
            Debug.WriteLine(ByteToArray("encrypted", encrypted));
        }
        {
            SymmetricEncryptor se = new SymmetricEncryptor();
            se.IV = iv;
            se.Key = key;
            res = se.DecryptFromBytes(encrypted);
            Debug.Assert(res.Equals(test, StringComparison.InvariantCulture));
            Debug.WriteLine("res=" + res);
        }

    }


    private string ByteToArray(string name, byte[] bytes)
    {
        string res = "byte[] " + name + " = new byte[" 
            + bytes.Length.ToString() + "] { ";
        for (int ix = 0; ix < bytes.Length; ix++)
        {
            res += "0x" + bytes[ix].ToString("X");
            if (ix < (bytes.Length - 1))
                res += ", ";
        }
        res += " }";
        return res;
    }
}

August 5, 2008

Base 64 Encoding

byte[] key = new byte[32] { 0xEC, 0x16, 0x50, 0x73, 0xB8,
0x91, 0xCE, 0x40, 0x68, 0x58, 0xEC, 0x31, 0x4E, 0xF1, 0xD3,
0x87, 0x49, 0x27, 0x25, 0xA2, 0x3B, 0xCD, 0xA8, 0x4C, 0x39,
0x41, 0xE2, 0x37, 0x62, 0xEF, 0xE9, 0x43 }; // Encode to Base 64 string string base64Encoded = Convert.ToBase64String(key); // Convert Base 64 string back to a byte array byte[] bytes = Convert.FromBase64String(base64Encoded);

Cmd Shell

To exectue a command with the cmd.exe shell use the /k or /c argument /k => Execute the command and keep the shell window open /c => Execute and then close the Cmd window eg:
cmd.exe /k ipconfig /all

File and Directory Classes

Generally it is best to use the FileSystemInfo (abstract base), FileInfo (for files), and DirectoryInfo (for directories) classes. Here is a class diagram to show how the 3 are related:
These classes are found in the "System.IO" namespace.

The "File" and "Directory" classes are used directly on strings:
Using System.IO;
...
// Determining If A File Is A Directory
private bool IsDirectory(string path)
{
    bool res = ((File.GetAttributes(path) & FileAttributes.Directory) ==
                FileAttributes.Directory);
    return res;
}

File.Exists(filname); // To check if a file exists
Directory.Exists(path) // To check if a directory exists

//To get the last time for the last change to a file use:
File.GetLastWriteTime(fileUri).ToString();
Some Iterators for iterating over Files and/or Directories recursively
public static class FileSystemInfoExtender
{
    // Iterate all files in a path, with 
    // an option to recurse through subdirectories
    public static IEnumerable<FileSystemInfo> 
      IterateFiles(this FileSystemInfo targ, bool recurse)
    {
        if (targ == null)
            throw new ArgumentNullException("targ");

        // return initial target
        yield return targ;

        if (recurse)
        {
            DirectoryInfo diTarg = targ as DirectoryInfo;
            // If targ is a directory
            if (diTarg != null)
            {                   
                // Get its contents as FileSystemInfo objects
                FileSystemInfo[] fsis = TryGetFileSystemInfos(diTarg);
                foreach (FileSystemInfo fsi in fsis)
                {
                    foreach (FileSystemInfo fsiInner in 
                        fsi.IterateFiles(recurse))
                        yield return fsiInner;
                }
            }
        }
    }

    // Iterate all files in a path, with 
    // recurse through subdirectories first
    public static IEnumerable<FileSystemInfo> 
        IterateFilesChildrenFirst(
          this FileSystemInfo targ, 
          bool recurse)
    {
        if (targ == null)
            throw new ArgumentNullException("targ");

        if (recurse)
        {
            DirectoryInfo diTarg = targ as DirectoryInfo;
            // If targ is a directory
            if (diTarg != null)
            {
                // Get its contents as FileSystemInfo objects
                FileSystemInfo[] fsis = TryGetFileSystemInfos(diTarg);
                foreach (FileSystemInfo fsi in fsis)
                {
                    foreach (FileSystemInfo fsiInner in
                        fsi.IterateFilesChildrenFirst(recurse))
                        yield return fsiInner;
                }
            }
        }

        // return initial target
        yield return targ;
    }


    private static FileSystemInfo[] TryGetFileSystemInfos(
      DirectoryInfo diTarg)
    {
        FileSystemInfo[] fsis = new FileSystemInfo[0];
        try
        {
            fsis = diTarg.GetFileSystemInfos();
        }
        catch (Exception ex)
        { 
            LogError("Calling GetFileSystemInfos() on \'" + diTarg.FullName + "\' threw " + 
                "an exception: " + ex.ToString());
        }
        return fsis;
    }

    // Iterate all directories in a path, with
    // an option to recurse through subdirectories
    public static IEnumerable<DirectoryInfo> IterateDirectories(
        this DirectoryInfo diTarg, bool recurse)
    {
        if (diTarg == null)
            throw new ArgumentNullException("diTarg");

        if (recurse) // return its children
        {
            DirectoryInfo[] dirs = TryGetDirectories(diTarg);
            foreach (DirectoryInfo dir in dirs)
            {
                foreach (DirectoryInfo dirInner in 
                    dir.IterateDirectories(recurse))
                {
                    yield return dirInner;
                }
            }
        }
        yield return diTarg; // return the current dir
    }

    private static DirectoryInfo[] TryGetDirectories(
        DirectoryInfo diTarg)
    {
        DirectoryInfo[] dirs = new DirectoryInfo[0];
        try
        {
            dirs = diTarg.GetDirectories();
        }
        catch (Exception ex)
        {
            LogError("Calling GetDirectories() on \'" +
                diTarg.FullName + 
                "\' threw " + 
                "an exception: " + 
                ex.ToString());
        }
        return dirs;
    }
 
    private static void LogError(string exStr)
    {
        Debug.WriteLine(exStr);
    }

    public static bool TryDeleteFileSystemInfo(this FileSystemInfo fsi)
    {
        bool success = true;
        try
        {
            fsi.Delete();
        }
        catch (Exception ex)
        {
            success = false;
            LogError("Delete \'" + 
                fsi.FullName + 
                "\' threw an exception: " +
                ex.ToString());
        }
        return success;
    }
}
for something similar check out the Directory.GetFiles(string path, string searchPattern, SearchOption searchOption); method

#region FileAttributesExtender

public static class FileAttributesExtender
{
    // Return lhs flags plus rhs flags
    public static FileAttributes Union(
        this FileAttributes lhs, FileAttributes rhs)
    {
        return lhs | rhs;
    }

    // Return flags common to lhs and rhs
    public static FileAttributes Intersection(
         this FileAttributes lhs, FileAttributes rhs)
    {
        return lhs & rhs;
    }

    // Return lhs flags minus rhs flags
    public static FileAttributes Difference(
         this FileAttributes lhs, FileAttributes rhs)
    {
        FileAttributes common = lhs & rhs;
        int res = (int)lhs - (int)common;
        return (FileAttributes)(res);
    }

    // Return true if lhs contains all the flags within rhs
    public static bool Contains(
         this FileAttributes lhs, FileAttributes rhs)
    {
        FileAttributes common = lhs & rhs;
        return (common == rhs);
    }

    // Return true if lhs contains one of the flags within rhs
    public static bool ContainsAnyOf(
        this FileAttributes lhs, FileAttributes rhs)
    {
        FileAttributes common = lhs & rhs;
        return ((int)common > 0);
    }

    // NON-extension methods here
    public static FileAttributes FromString(string source)
    {
        FileAttributes res = (FileAttributes)Enum.Parse(
             typeof(FileAttributes), source, true);
        return res;
    }

}

#endregion FileAttributesExtender
Sample usage to delete user files in their 'Temp' directory
private void DeleteTemporaryFiles(string tempPath)
{
  System.IO.DirectoryInfo targ = new 
         System.IO.DirectoryInfo(tempPath);
  bool success = false;
  foreach (System.IO.FileSystemInfo fsi in 
                     targ.IterateFiles(false))
  {
    Debug.Write(fsi.FullName);
    Debug.Write(" Attributes:" + fsi.Attributes.ToString("f"));
    if (!fsi.Attributes.ContainsAnyOf(
           System.IO.FileAttributes.System | 
           System.IO.FileAttributes.Temporary))
    {
      success = true;
      try
      {
        fsi.Delete();
      }
      catch (Exception ex)
      {
        success = false;
        Debug.Write(ex.ToString());
      }
      Debug.Write(success ? " Deleted" : " Could not Delete!");
    }
    Debug.WriteLine("");
  }
}

Useful string methods

//To check a string contains a substring:
bool ContainsString(string container, string contained)
{
  return (container.IndexOf(contained) > -1);
}
// To replace all space characters
mystring.Trim().Replace(" ", string.Empty);
string.Join Opposite To string.Split
private static void TestJoinSplit()
{
    string[] test = new string[] { "x", "y", "z" };
    string joined = string.Join(",", test);
    Debug.WriteLine(joined);
    string[] splitUp = joined.Split(',');
    for (int ix = 0; ix < test.Length; ix++)
    {
        Debug.Assert(splitUp[ix] == test[ix]);
    }
}
Outputs: x,y,z

Using Shell To Start A Process

Starting another OS process. Eg to open an image in the defult editor/viewer
Process shellRunProcess = new Process();
shellRunProcess.StartInfo.FileName = fileName;
shellRunProcess.Start();

Post Build Events

Post Build Event to copy Your Plug-in DLL to the XXX Output directory Add to PostBuild for the project:
copy "$(TargetPath)" "$(ProjectDir)..\XXX\$(OutDir)"
Post Build Event for XmlSerialiser Projects Add to PostBuild for the project:
"$(DevEnvDir)..\..\SDK\v2.0\Bin\sgen.exe"  "$(TargetPath)"
copy "$(TargetDir)$(TargetName).XmlSerializers.dll" "$(ProjectDir)..\XXX\bin\Debug\"