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.]

QText 2.50

Illustration

QText is improved once more. There are no bigger changes (I am holding them for 3.00 :)) but many will enjoy fixed text manipulation. It is shame to admit that multiline tabs were fundamentally broken for few versions now.

Finally there is upgrade procedure in place. It is not automatic but requires user interaction. I like it better that way but I am open for other suggestions.

Other notable changes include quite a few interface tweaks and bug-fixes.

Try it.

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.

VHD Attach 3.00 Beta 2

Illustration

It is time for second 3.00 beta. You might have noticed that there was no post about first beta at all - I forgot to write it. :)

Most notable update for 3.00 is addition of virtual disk creation. It currently allows creating only dynamic disks but fixed disks will also be supported in future.

Setup is changed a little in order to offer selection of context-menu items before application is even started. That way you can use your favorite combination from first run.

Due to popular demand there is in-application check for upgrade. It will not check automatically but only upon user’s request. In next few weeks I will push few test upgrades so keep on checking.

There is lot of small cosmetic adjustments. Like switching focus to Explorer upon attaching Bit Locker drive or drag&drop support in main window. And lets not forget that those who love analyzing virtual disks just got few more details about VHD.

Download is available on VHD Attach beta page.