Programming in C#, Java, and god knows what not

OpenFolderDialog

Illustration

I hate FolderBrowserDialog. It is limited, ugly and stuck in Windows 2000 GUI. Whenever I had to select folder, I would resort to using SaveFileDialog instead. User would select any file name and I would just use directory part. It was non-optimal but still better than FolderBrowserDialog.

Vista brought new common file dialogs but I pretty much ignored them - most of my programs need to run under XP so there was not much benefit in using Windows Vista specific controls. However, those controls had special mode that finally brings folder selection in normal FileOpenDialog.

Code (after you define all needed COM interfaces) is actually quite straightforward. Once FOS_PICKFOLDERS is set, half of work is done. All other code is just plumbing to show the form and get user’s selection in form of path.

var frm = (IFileDialog)(new FileOpenDialogRCW());
uint options;
frm.GetOptions(out options);
options |= FOS_PICKFOLDERS;
frm.SetOptions(options);

if (frm.Show(owner.Handle) == S_OK) {
    IShellItem shellItem;
    frm.GetResult(out shellItem);
    IntPtr pszString;
    shellItem.GetDisplayName(SIGDN_FILESYSPATH, out pszString);
    this.Folder = Marshal.PtrToStringAuto(pszString);
}

Full code with Windows XP compatibility and little bit more error checking is available for download. However do notice that all unneeded COM fat has been trimmed in order to have it concise. Short and sweet I say.

[2012-02-12: Fixed bug in source code.]

Downloading File With Progress

As I was creating upgrade procedure for few programs of mine I had a need to download file. With progress bar. Most of you can already see a solution: HttpWebRequest in BackgroundWorker.

Base idea is creation of HttpWebRequest, getting it’s response as stream and iterating through all bytes until we read them all. Heart of (DoWork) code is:

var request = (HttpWebRequest)HttpWebRequest.Create(url);
using (var response = (HttpWebResponse)request.GetResponse()) {
    using (var stream = response.GetResponseStream()) {
        using (var bytes = new MemoryStream()) {
            var buffer = new byte[256];
            while (bytes.Length < response.ContentLength) {
                var read = stream.Read(buffer, 0, buffer.Length);
                if (read > 0) {
                    bytes.Write(buffer, 0, read);
                    bcwDownload.ReportProgress((int)(bytes.Length * 100 / len));
                } else {
                    break;
                }
            }
        }
    }
}

Before we send result back to RunWorkerCompleted event we need to get file name that was actually delivered. While this step is optional, I find it especially useful if there are some redirections on web site (e.g. pointing you to newer version of file):

[csharp highlight=“1”] string fileName = response.ResponseUri.Segments[response.ResponseUri.Segments.Length - 1]; e.Result = new DownloadResult(fileName, bytes.ToArray()); [/csharp]

P.S. Do notice that DownloadResult is our own class - there is no such class in .NET Framework.

In RunWorkerCompleted we only must save file as such:

var res = (DownloadResult)e.Result;
var file = new FileInfo(res.FileName);
using (var frm = new SaveFileDialog() { FileName = file.Name }) {
    if (frm.ShowDialog(this) == DialogResult.OK) {
        File.WriteAllBytes(frm.FileName, res.Bytes);
        MessageBox.Show(this, "Done.", "Something", MessageBoxButtons.OK, MessageBoxIcon.Information);
    }
}

And with that you have your file downloaded.

Full source code (with all missing parts of code) is available for download.

Mercurial Keyring

There is one non-intuitive thing with securing Mercurial. You should remove all authentication data from URL and TortoiseHg will actively enforce it (assuming that you are Yes guy). However even with mercurial_keyring extension enabled it will ask for a user name and password. And it will ask every time you push.

Don’t worry. It isn’t that mercurial_keyring extension is broken, we are just missing some data in %USERPROFILE%\mercurial.ini configuration file:

[extensions]
mercurial_keyring = 

[auth]
bb.schemes = http https
bb.prefix = bitbucket.org
bb.username = jmedved

Example above is something I use for BitBucket but it is applicable for any other server. Only thing that needs to change is prefix (bb in this case) that needs to be unique within configuration file and prefix of your server.

Drag & Drop

It is sad how often I see applications that could have use of drag&drop mechanism but are blissfully unaware of it. Sad part is that half of those annoying applications are mine. :)

And it is annoyingly easy to implement. In addition to setting AllowDrop=true on your favorite control or form you need to implement two events:

private void list_DragEnter(object sender, DragEventArgs e) {
    e.Effect = e.Data.GetDataPresent(DataFormats.FileDrop) ? DragDropEffects.Move : DragDropEffects.None;
}

private void list_DragDrop(object sender, DragEventArgs e) {
    if (e.Data.GetDataPresent(DataFormats.FileDrop)) {
        var files = (string[])e.Data.GetData(DataFormats.FileDrop);
        DoSomething(files);
    }
}

And this is all there is to it.

Ping

Few days ago I needed to check whether certain server was dead or alive. Any network guy will tell you that ping is your mate. While he also might tell you that ping might not work at all times (damn you firewall) I will ignore this unfortunate part for a moment. Suffice to say that ping works for my scenario.

While I used to solve this issues with good old P/Interop, I decided to check whether .NET Framework 3.5 (one that I used) is smarter that old grandpa 2.0. And what do you know, there is Ping class available inside System.Net.NetworkInformation namespace.

Class was made by someone who clearly hadn’t read Framework Design Guidelines but it does provide complete solution. At least code is easy enough:

var ping = new Ping();
var reply = ping.Send("www.example.com");
if (reply.Status == IPStatus.Success) {
    Debug.WriteLine(reply.RoundtripTime + " ms.");
}

Rollback in Mercurial

Illustration

Lets start with assumption that you are both user of Mercurial and that you made an error in merging. Or it might be directory restructuring gone bad. In any case, you need to go few revisions back.

Let’s assume that we have small project well into development. Situation is simple enough and there are no branches involved. Only important thing to notice is that version that works was 137 and all changes after that are something that we would rather forget:

140: Some editing.
139: Fixing renames.
138: Directory reorganization.
137: Everything is working!
...

There are two solutions that can bring us toward situation as it was in 137.

Easiest, and (in my opinion) cleanest solution, is just to clone your repository. Making new clone that goes to revision 137 will solve problems with a clean cut. Unfortunately there are couple of problems with this clean solution. If your repository is shared one, be prepared to call every person that uses it and to tell them they need to delete their local repository and make a new clone. If you forget to do that changes that you just removed might magically appear when someone else pushes (since Mercurial will think that they have newer version). Some sort of synchronization is definitely needed.

Another issue with this method would be loss of history. If you had any changes done between 137 and 140, they are forever gone. That might not be a problem if there wasn’t many changes or if they were trivial but you should be careful about this.

Illustration

Fortunately Mercurial has way of solving this and it is called backout. Just remember to give it revision where you messed up. In this case that revision would be 138 (directory reorganization).

This method is not as nice since all that “bad” code is there. However, all history is preserved and all changes that happened after revision that was backed out are merged again. While it still might be a good move to notify team of changes, nobody will kill you if you forget to. :)

Mercurial on FreeNAS

Illustration

In search for smallest possible Mercurial installation I remembered my old friend FreeNAS. This is small NAS server (at least in 0.7 version) based on FreeBSD 7.3. System requirements are low: 256 MB of RAM and 512 MB system disk is all that is needed. And, of course, you need to have full installation of FreeNAS. Embedded will not suffice.

I will not explain how to setup FreeNAS here since it works out of box with pure defaults. Only thing to configure is where you want your data to be and this should be easy enough to do by yourself (hint: check “Disks” menu). My final goal is to have equivalent for Mercurial under Ubuntu.

First step is to install needed packets. This can be done from web interface (System->Packages) and following packets are needed (given in order of installation):

Now we need to copy some basic files: [bash highlight=“1,2”] $ cp /usr/local/share/doc/mercurial/www/hgweb.cgi /mnt/data/hg/hgweb.cgi $ cp /var/etc/lighttpd.conf /var/etc/lighttpd2.conf [/bash]

We also need a new config file that should be situated at “/mnt/data/hg/hgweb.config” and it should have following lines:

[collections]
/mnt/data/hg/ = /mnt/data/hg/

[web]
baseurl=/hg/
allow_push=*
push_ssl=false

We need to edit “/mnt/data/hg/hgweb.cgi” in order to fix config parameter. Just change example config line with:

config = "/mnt/data/hgweb.config"

At the BOTTOM of existing “/var/etc/lighttpd2.conf” (notice that we created this file via cp few steps ago) we need to add:

server.modules += ( "mod_rewrite" )
url.rewrite-once = (
    "^/hg([/?].*)?$" => "/hgweb.cgi/$1"
)
$HTTP["url"] =~ "^/hgweb.cgi([/?].*)?$" {
    server.document-root = "/mnt/data/hg/"
    cgi.assign = ( ".cgi" => "/usr/local/bin/python" )
}
$HTTP["querystring"] =~ "cmd=unbundle" {
    auth.require = (
        "" => (
            "method"  => "basic",
            "realm"   => "Mercurial",
            "require" => "valid-user"
        )
    )
    auth.backend = "htpasswd"
    auth.backend.htpasswd.userfile = "/mnt/data/hg/.htpasswd"
}

This config will ensure that everybody can pull repositories while only users in .htpasswd file can push. If you want authorization for pull also, just delete two highlighted files. Notice that users are defined in .htpasswd file that needs to be created with htpasswd command-line tool. Since that tool is not available in FreeNAS easiest way to get user lines is to use online tool.

In order to test how everything works, just go to shell and restart lighttpd with new config:

kill -9 `ps auxw | grep lighttpd | grep -v grep | awk '{print $2}'`
/usr/local/sbin/lighttpd -f /var/etc/lighttpd2.conf start

If everything goes fine, you should be able to access repositories at “http://192.168.1.250/hg/” (or whatever you machine ip/host name is).

As last step we need to add those two commands above (kill and lighttpd) to System->Advanced->Command scripts. Both lines get into their own PostInit command. This ensures that, after every reboot, we start lighttpd with our “enhanced” config file.

P.S. Do not even try to edit “/var/etc/lighttpd.conf”. It gets overwritten after every restart.

P.P.S. This post is just about enabling Mercurial under FreeNAS and because of this it is simplified. It is mere starting point. For further reading check official Publishing Repositories with hgwebdir.cgi guide and my guide on setting-up Mercurial under Ubuntu.

Getting String Value for All Object's Properties

In last post I wen’t through task of restoring properties from their textual representation. But how did we end up with text?

It is as simple as loop through all public properties and then using TypeConverter in order to properly convert a value to it’s string representation. Do notice that ConvertToInvariantString is preferred over ConvertToString in order for code to properly work on non-USA Windows.

public static IDictionary<string, string> GetPairs(object objectInstance) {
    var result = new Dictionary<string, string>();
    foreach (var propertyInfo in objectInstance.GetType().GetProperties()) {  //loops through all public properties
        var propertyConverter = TypeDescriptor.GetConverter(propertyInfo.PropertyType);  //gets converter for property
        var stringValue = propertyConverter.ConvertToInvariantString(propertyInfo.GetValue(objectInstance, null));  //converts value to string
        result.Add(propertyInfo.Name, stringValue);
    }
    return result;
}

P.S. Saving key/value pairs to file is not shown here… guess how it is done… :)

Setting a Value From String

It all started with list of key value pairs from file. Each key was some property on object that needed to be set and value was obviously value for that property. Since there was no type information in file, I had to use reflection in order to set value. And then problem hit me. Reflection would not sort out my problem with converting string value to proper type.

To solve it, I just loop through all key/value pairs and find property with that name in my object’s instance. Once property is found, I get a magic thing called TypeConverter. TypeConverter enables conversion from string to proper type that can be used in standard reflection SetValue call. And thus problem is solved. Code follows:

foreach (var item in pairs) {                                                                         //go through all key/value pairs
    var propertyInfo = instance.GetType().GetProperty(item.Key);                                      //find property with same name
    Trace.Assert(propertyInfo != null);                                                               //we must have this property
    var propertyConverter = TypeDescriptor.GetConverter(propertyInfo.PropertyType);                   //lets find proper converter.
    Trace.Assert(propertyConverter != null);                                                          //we must have converter
    propertyInfo.SetValue(instance, propertyConverter.ConvertFromInvariantString(item.Value), null);  //set value
}