December 17, 2009

WPF Timer (DispatcherTimer )

Comparison of different timers in .NET is found here. Unfortuneately this does not mention the DispatchTimer which is more appropriate for WPF usage (but not only)
using System.Windows.Threading;
...
private DispatcherTimer timer;    
...
const int MILLISECOND = 10000L;
timer = new DispatcherTimer();  
// Disable (stop) it 
timer.IsEnabled = false;
// Set timer event interval
timer.Interval = new TimeSpan(3000L * MILLISECOND);
// Timer events
timer.Tick += new EventHandler(timer_Tick);
...
timer.Start(); // at some point start the timer
...
void timer_Tick(object sender, EventArgs e)
{
  if (...)
  {
    timer.Stop();
  }
}

December 16, 2009

Sample Custom Method Attribute.

An example of a custom attribute on a method:
[AttributeUsage(AttributeTargets.Method)] 
public class ProjectReloadRequiredAfterTestAttribute
 : System.Attribute
{
}

public void Discover(MethodBase mb)
{
  if (mb.GetCustomAttributes(typeof(
      ProjectReloadRequiredAfterTestAttribute), 
      false).Length > 0)
  {
    reloadProjectRequired = true;
  }
}  
 
[Test]
[ProjectReloadRequiredAfterTestAttribute]
public void TestCreateAndDeletePart()
{
  Discover(System.Reflection.MethodBase.GetCurrentMethod());
  ...
}

Adjusting Privileges

This code is untested but may be required to shut down a PC using the exit windows API (see here
#region Adjust Priveleges

//This snippet is tested on WinXP and Vista
[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool AdjustTokenPrivileges(IntPtr htok, bool disall,
               ref TokPriv1Luid newst, int len, IntPtr prev, IntPtr relen);

[DllImport("kernel32.dll", ExactSpelling = true)]
internal static extern IntPtr GetCurrentProcess();

[DllImport("advapi32.dll", ExactSpelling = true, SetLastError = true)]
internal static extern bool OpenProcessToken(IntPtr h, int acc, 
                                             ref IntPtr phtok);

[DllImport("advapi32.dll", SetLastError = true)]
internal static extern bool LookupPrivilegeValue(string host, string name,
                                                 ref long pluid);

[StructLayout(LayoutKind.Sequential, Pack = 1)]
internal struct TokPriv1Luid
{
    public int Count;
    public long Luid;
    public int Attr;
}

internal const int SE_PRIVILEGE_ENABLED = 0x00000002;
internal const int TOKEN_QUERY = 0x00000008;
internal const int TOKEN_ADJUST_PRIVILEGES = 0x00000020;
//http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspx
internal const string SE_TIME_ZONE_NAMETEXT = "SeTimeZonePrivilege"; 
internal const string SE_SHUTDOWN_NAME = "SeShutdownPrivilege";

private bool AddShutDownPrivilegeToApp()
{
    try
    {
        bool retVal;
        TokPriv1Luid tp;
        IntPtr hproc = GetCurrentProcess();
        IntPtr htok = IntPtr.Zero;
        retVal = OpenProcessToken(hproc, TOKEN_ADJUST_PRIVILEGES |
                                   TOKEN_QUERY, ref htok);
        tp.Count = 1;
        tp.Luid = 0;
        tp.Attr = SE_PRIVILEGE_ENABLED;
        retVal = LookupPrivilegeValue(null, SE_SHUTDOWN_NAME, ref tp.Luid);
        retVal = AdjustTokenPrivileges(htok, false, ref tp, 0, 
                                      IntPtr.Zero, IntPtr.Zero);
        return retVal;
    }
    catch (Exception ex)
    {
        //throw;
        return false;
    }

}

#endregion


Visual Studio Plug-In Build Properties

Lets say your writing a plug-in for an application "SomeApp.exe" at the following directory:
"D:\Projects\Smed\win32_vs90\Debug\SomeApp.exe"

Under "Build" tab set
"Output path:" by using the "Browse" button browse to "D:\Projects\Smed\win32_vs90\Debug\"

Under "Debug" tab set
"Start external program:" to "D:\Projects\Smed\win32_vs90\Debug\SomeApp.exe"
"Working directory" to "D:\Projects\Smed\win32_vs90\Debug\"

Under "Reference Paths" tab
Add "D:\Projects\Smed\win32_vs90\Debug\" to the reference paths

December 15, 2009

GetRelativePath Helper

public static class FileSystemInfoExtender
{
    public static string GetPathRelativeTo(this FileSystemInfo file, string path)
    {
        string fullPath = Path.GetFullPath(path);
        string res = string.Empty;
        if (file.FullName.StartsWith(fullPath))
        {
            res = file.FullName.Substring(fullPath.Length);
        }
        res = res.Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar);
        string sep = Path.DirectorySeparatorChar.ToString();
        if (res.StartsWith(sep))
        {
            res = res.Substring(1);
        }
        return res;
    }
}
and some tests
FileInfo file = new FileInfo(@"D:\Projects\smeg\src\blah\xxxx\whistle\stop\Carbuncle.cs");
string relPath = file.GetPathRelativeTo(@"D:\Projects\smeg\src");
Debug.Assert(relPath.Equals(@"blah\xxxx\whistle\stop\Carbuncle.cs", 
StringComparison.OrdinalIgnoreCase));
relPath = file.GetPathRelativeTo(@"D:/Projects/smeg/src");
Debug.Assert(relPath.Equals(@"blah\xxxx\whistle\stop\Carbuncle.cs", 
StringComparison.OrdinalIgnoreCase));
relPath = file.GetPathRelativeTo(@"D:\Projects\smeg\src\");
Debug.Assert(relPath.Equals(@"blah\xxxx\whistle\stop\Carbuncle.cs", 
StringComparison.OrdinalIgnoreCase));

November 26, 2009

Accessing Command Line Arguments In WPF

public partial class App : Application
{
    protected override void OnStartup(StartupEventArgs sea)
    {
        CommandLine.Instance.SetArguments(sea.Args);
        base.OnStartup(sea);
    }
}

public class CommandLine
{
    private CommandLine()
    {}

    private static readonly CommandLine instance = new CommandLine();

    public static CommandLine Instance
    {
        get { return instance; }
    }

    public IEnumerable Arguments
    {
        get { return args; }
    }

    public void SetArguments(string[] args)
    {
        this.args = args ?? new string[0];
    }

    private string[] args = new string[0];
}
then to use
private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            foreach (string arg in CommandLine.Instance.Arguments)
            {
                if (arg.ToUpper() == "/C")
                {
                    if (System.Windows.Forms.Clipboard.ContainsText())
                    {
                        tbCode.Text = System.Windows.Forms.Clipboard.GetText();
                    }
                }
            }

        }
Doh!
Even easier:
string[] arguments = Environment.GetCommandLineArgs();
When processing command line args using Environment.CommandLineArgs(), found that the system automatically matches " in an argument. So if you have a path that contains a spaces, as long as that path is wrapped with " marks, the path will not be parsed into multiple arguments but rather appear as a single argument. eg.:
-myArg:C:\Program Files\MyProgram\Something.exe
will get parsed as multiple arguments:
  • -myArg:C:\Program
  • Files\MyProgram\Something.exe
whereas
-myArg:"C:\Program Files\MyProgram\Something.exe"
will get parsed as a single argument:
  • -myArg:C:\Program Files\MyProgram\Something.exe

Have also noticed that carriage return line feeds can get sucked into a command line argument. Perhaps a "Trim()" should be applied to each argument string before it is processed to be sure this whitespace is removed. Here is a sample command line parser:
internal class CommandLineParser
{
    public string Drive { get; set; }
    public string TrueCryptFile { get; set; }
    public string KeyFile { get; set; }

    const string DrivePrefix = "-D";
    const string TrueCryptFilePrefix = "-T";
    const string KeyFilePrefix = "-K";

    public void CommandLineArgs(string[] args)
    {
        //string[] args = Environment.GetCommandLineArgs();
        Debug.WriteLine("Args:" + string.Join(",", args));
        int ix = 0;
        foreach (string arg in args)
        {
            Debug.WriteLine("arg[" + ix++.ToString() + "]=\'" + arg + "\'");
        }
        foreach (string rawArg in args)
        {
            // Get rid of whitespace chars at the beginning and end
            string arg = rawArg.Trim(); 
            if (arg.Length < 2)
              continue;
            string argument = (arg[0] == '/') ? "-" + arg.Substring(1) : arg;
            int end = argument.IndexOf(':');
            if ((end == -1) && ((end + 1) >= argument.Length))
                continue;
            if (argument.ToUpper().StartsWith(DrivePrefix))
            {
                Drive = argument.Substring(end + 1).Substring(0, 1) + ":";
            }
            else if (argument.ToUpper().StartsWith(TrueCryptFilePrefix))
            {
                TrueCryptFile = argument.Substring(end + 1);
            }
            else if (argument.ToUpper().StartsWith(KeyFilePrefix))
            {
                KeyFile = argument.Substring(end + 1);
            }
        }
        Debug.WriteLine("Processed command line args:");
        Debug.WriteLine("Drive=\"" + Drive + "\"");
        Debug.WriteLine("TrueCryptFile=\"" + TrueCryptFile + "\"");
        Debug.WriteLine("KeyFile=\"" + KeyFile + "\"");
    }
}

// and tester (not really finished)
class CommandLineParserTester
{
    public void TestCommandLineParser()
    {
        CommandLineParser clp = new CommandLineParser();
        clp.CommandLineArgs(new string[] { 
            @"-D:M",
            @"-T:F:/Temp/truecrypt.tc",
            @"-K:F:/Temp/truecrypt.keyfile" });
        Assert(clp.Drive == "M:");
        Assert(clp.TrueCryptFile == @"F:/Temp/truecrypt.tc");
        Assert(clp.KeyFile == @"F:/Temp/truecrypt.keyfile");
    }
}

November 19, 2009

Debugger/Editor Attributes

DebuggerDisplay - Use it to specify how a class or struct should be displayed in the debugger when the cursor hover over the item
[DebuggerDisplay("Count = {count}")]
class blahblahblah ...
DebuggerStepThrough - Instructs the debugger to step through that marked property or attribute, and not into it:
[DebuggerStepThrough]
public int Key
{
  [System.Diagnostics.DebuggerStepThrough]
  get { return key; }
  [System.Diagnostics.DebuggerStepThrough]
  set { key = value; }
}
DebuggerBrowsable - Determines if and how a field or property is displayed in the debugger variable windows.
[DebuggerBrowsable(DebuggerBrowsableState.Never)]
private int key;
see also DebuggerDisplay and DebuggerBrowsable – Two Debugger Attributes you should know

EditorBrowsable - Use this 'EditorBrowsable' property to restrict intellisense/visual studio visibility of a property
[EditorBrowsable(EditorBrowsableState.Never)]
int MyProperty
...

DefaultValue - Then there is the 'DefaultValue' property that sets the default value of a C# class property. Used by visual designers, etc
[DefaultValue(42)] 
public int MyProperty { get; set; }