Directory.Move Is Case Insensitive

In order to rename file one would use code that looks something like this:

File.Move("file1.txt", "file2.txt");
File.Move("file.txt", "FILE.txt");

Both lines work without any issue, just as you would expect it.

What happens when we do rename with directories (aka folders):

Directory.Move("dir1", "dir2");
Directory.Move("dir", "DIR");

First line works but second one raises IOException (Source and destination path must be different). For some reason Directory.Move does case insensitive checks. For this to work we need slightly different code:

Directory.Move("dir", "DIR.somereallyunexpectedtext");
Directory.Move("DIR.somereallyunexpectedtext", "DIR");

This code first renames directory to temporary name and then renames it to desired one. Tricky code not shown here is exception handling. Either Directory.Move can fail and thus we would need code like this:

Directory.Move("dir", "DIR.somereallyunexpectedtext");
try {
    Directory.Move("DIR.somereallyunexpectedtext", "DIR");
} catch (IOException) {
    Directory.Move("DIR.somereallyunexpectedtext", "dir");
} catch (UnauthorizedAccessException) {
    Directory.Move("DIR.somereallyunexpectedtext", "dir");
}

For any failure cause we need to do rollback (renaming it back to original name from intermediate one). And worst thing is that, if second rename fails, there is probably no chance in rollback working anyhow. Most common solution? Just forget about handling exceptions and rollback between those two renames. Probability is on your side that, if first operation passes, other will pass too.

Canceling Dialog

As I made review of one application I got reminded of one common error. Theory of cancel button is easy enough. It is enough to set button’s DialogResult to Cancel and form’s CancelButton property to that button and form will close automatically. However, what to do if we need to cancel some background operation?

More than once I saw cancel code inside of cancel button’s Click event. This is WRONG. If you are wondering why, just take a look at your application state when somebody decides to close dialog via small red button in upper right corner instead of pressing cancel button. All that carefully crafted cancel code never gets chance to execute.

Solution is trivial. All your code should go inside of either FormClosing or FormClosed event. These events get triggered whatever way you do form cancelling:

    private void Form_FormClosed(object sender, FormClosedEventArgs e) {
        if (backgroundWorker.IsBusy) { backgroundWorker.CancelAsync(); } //just an example of cancellation code
    }

Cancel button should NEVER have any code in it.

P.S. Whether to use FormClosing or FormClosed is mostly matter of philosophical discussion that I intend to leave for other post.

Select or Focus, Which One to Use?

Quite a few Windows Forms controls have both Focus() and Select() methods available. This presents unique challenge - which method to use?

While they both offer same result (ok, almost same) there is subtle difference. Focus is intended only for control authoring, e.g. when you have some composite UserControl. For all other scenarios, Select should be used. Probably nothing bad will happen (or maybe some kittens will die) if you use Focus on controls that behave. However, small differences might force you to use Select on some other controls and that leads to code with uses Focus half of time and Select another half. Kinda hard to read.

It might improve actual readability if Select is used all the time.

Nullable Fields in Database

Duty of every decent Data Access Layer is to convert data types that we have in database to data types of our favorite programming language (C# in this case). And this is easy in case of “normal” data types. Great example here is humble integer. Database and C# have 1 to 1 mapping here. It is as easy as “var x = (int)dr["field"];”.

However, database can have one more trick up it’s sleeve. Every data type can be “nullable”. That is, it can be integer but it can also have special state which signifies lack of data. C# also has same possibility with his nullable types. Intuitive code “var x = (int?)dr["field"];” will not work properly.

While we can make wrapper function for any nullable data type that we need, there is simpler way. All that we need is:

private static Nullable<T> ToNullable<T>(object value) where T : struct {
    if (value == null) { return null; }
    if (System.Convert.IsDBNull(value)) { return null; }
    return (T)value;
}

Now conversion can proceed with “var x = ToNullable(dr["field"]);”. That doesn’t look that ugly, does it?

Update Kills VHD Boot (Temporarily)

Some windows update that got installed on my VHD-based Windows in week from 2011-06-12 to 2011-06-19 killed possibility to boot from them. Instead of normal startup procedure I was greeted with Repair Windows.

Fortunately I had another Windows installation on same machine so I was able to check boot parameters:

bcdedit

 Windows Boot Manager
 --------------------
 identifier              {bootmgr}
 device                  partition=D:
 description             Windows Boot Manager
 locale                  en-US
 inherit                 {globalsettings}
 default                 {current}
 resumeobject            {fa179570-87b4-11e0-b0a7-da74dade416b}
 displayorder            {current}
                         {fa179565-87b4-11e0-b0a7-da74dade416b}
 toolsdisplayorder       {memdiag}
 timeout                 1

 Windows Boot Loader
 -------------------
 identifier              {current}
 device                  partition=C:
 path                    \Windows\system32\winload.exe
 description             Windows 7 (x64)
 locale                  en-US
 inherit                 {bootloadersettings}
 recoverysequence        {fa179566-87b4-11e0-b0a7-da74dade416b}
 recoveryenabled         Yes
 osdevice                partition=C:
 systemroot              \Windows
 resumeobject            {fa179564-87b4-11e0-b0a7-da74dade416b}
 nx                      OptIn

 Windows Boot Loader
 -------------------
 identifier              {aa179565-87b4-11e0-b0a7-da74dade416b}
 device                  partition=E:
 path                    \Windows\system32\winload.exe
 description             My VHD installation
 locale                  en-US
 inherit                 {bootloadersettings}
 recoverysequence        {fa179572-87b4-11e0-b0a7-da74dade416b}
 recoveryenabled         Yes
 osdevice                partition=E:
 systemroot              \Windows
 resumeobject            {fa179570-87b4-11e0-b0a7-da74dade416b}
 nx                      OptIn

There was my problem - somehow update has changed VHD boot device to nonexistent partition E:.

Solution lies in two commands:

bcdedit /set "{aa179565-87b4-11e0-b0a7-da74dade416b}" device "vhd=[C:]\VHDs\Windows7.vhd"
 The operation completed successfully.

bcdedit /set "{aa179565-87b4-11e0-b0a7-da74dade416b}" osdevice "vhd=[C:]\VHDs\Windows7.vhd"
 The operation completed successfully.

P.S. My best is that one of following updates is the killer: