QText 3.60

It has been a long hiatus but time has come to have new QText out.

Most notable change will be for double-click. While it behaves a bit different than notepad does, it is more in sync with what you would expect a bit more modern program to do. Of course shortcuts follow the same behavior and whole thing should be a bit more natural for heavy keyboard user.

And that is pretty much single big change for it. Everything is same as it was with quite some bug-fixing compared to previous version. Program is a bit more friendly to new users (some balloon hints and similar nice touches); there are some high-DPI changes (no longer toolbar hunting on very high resolution screens, e.g. > 200 dpi); and lot of similar changes that you probably won’t even notice.

As always, upgrade is available directly through application, or you can download it from these pages.

Enjoy.

Scaling Toolstrip Images With DPI

Cheapest way to make high-DPI application is just to specify it as such in manifest and let font auto-sizing do the magic. Final result is more than acceptable and it definitely beats blurred fonts you would have without it.

However, this method doesn’t scale toolstrip icons (usually 16x16 pixels). They remain at same pixel size as before. If your monitor is 192 DPI, icons will look half their size. As monitors get higher and higher DPI situation just gets worse. Only proper solution would be to check system DPI and load higher resolution icons.

However, cheating a bit is ok too. Instead of having multiple sets of icons with different resolution each, we can resize ones that we already have. Yes, result will be a bit ugly, but not worse than Windows built-in scaling would do. All that can be achieved by having simple code in form constructor:

internal partial class MyForm : Form {
    public FilesEditForm(TabFiles tabFiles) {
        InitializeComponent();
        this.Font = SystemFonts.MessageBoxFont;

        using (var g = this.CreateGraphics()) {
            var scale = Math.Max(g.DpiX, g.DpiY) / 96.0;
            var newScale = ((int)Math.Floor(scale * 100) / 50 * 50) / 100.0;
            if (newScale > 1) {
                var newWidth = (int)(mnu.ImageScalingSize.Width * newScale);
                var newHeight = (int)(mnu.ImageScalingSize.Height * newScale);
                mnu.ImageScalingSize = new Size(newWidth, newHeight);
                mnu.AutoSize = false; //because sometime it is needed
            }
        }
    }
}

First variable simply contains scaling factor current monitor has compared to standard 96 DPI one. For example, 120 DPI monitor would cause variable’s value to be 1.25.

Next we try to determine how much we should magnify icons. In order to avoid unnecessary small adjustments, new scale is then calculated and rounded to .5 increments. If scale factor is 1.25, it will round-down to 1; scale of 1.6 will round-down to 1.5; scale of 2.2 will round-down to 2 and so on.

Check is made whether there is scaling to be done and, if needed, we simply calculate new image width and height using current size as a template. Assuming that icons were 16x16, scale factor of 1.5 would cause them to be 24x24.

Latest order of business is to turn off auto size. On most forms this step might be skipped without any issue. However, some stubborn forms will have their menu stay the same size as long as AutoSize is turned on (at least on .NET Framework 2.0). If you are on latest framework and/or your forms don’t misbehave, you can skip it safely.

PS: To have .25 increments, just swap 50 for 25; to have only whole number increments, swap 50 for 100.

Why I Don't Loop Through Dispose

Quite often graphical classes have a lot of disposing to do, e.g.:

public void Dispose() {
    foreBrush.Dispose();
    backBrush.Dispose();
    someBrush.Dispose();}

One might be tempted to optimize that a bit:

public void Dispose() {
    foreach(IDisposable element in new IDisposable[] { foreBrush, backBrush, someBrush,}) {
        element.Dispose();
    }
}

I personally find this code a bit easier to maintain and it serves same purpose. But I never really use it due to one serious drawback - it is not recognized by code analysis.

Code analysis that is part of Visual Studio Professional (and higher) does not recognize operation of this loop and thus it reports CA2213: Disposable fields should be disposed violation. While it is clear that violation is invalid, it still means that our loop goes completely unchecked.

If we add one more disposable field to class at some future time, first scenario would give us notice and we would be aware of forgotten dispose. After quick check we add dispose of that field and all is nice.

In second case we have taken responsibility of disposal ourselves and Visual Studio is not capable of checking the loop. There is nobody to check that all fields are disposed and if we forget to dispose it, it will be up to garbage collection to do it.

This will usually not be a major issue because resources will be released at some time. If we take some OS resource (e.g. file handle) it might be a bit annoying for rest of system but again nothing critical.

However, under rare circumstances, it might become important. Call me lazy, but I would rather have a bit uglier code that is automatically validated than have beautiful code that I need to check myself.

In the Year 2013

As always, first post of a year is reserved for a bit of statistics.

This year I have slowed-down posting a bit with only 74 posts since January. As usual 40% of posts is programming related, followed by 25% of Windows posts. Rest is such a mishmash of everything that I wont even go into analyzing it.

Traffic-wise it was a fantastic year - another 25% increase is greatly appreciated. Unfortunately huge 66% of traffic comes from places unknown so it is really doubtful whether it is even worth tracking this. Assuming same distribution of unknown locations as ones that were recognized, USA leads with 60% of visits. After that there is 20% visits from Germany and 15% from India. Other 216 countries cover the rest.

Google Chrome leads the pack with 40% visitors. Next one is Internet Explorer with 25% followed closely by Firefox. All other browsers are in traces. Mostly users came with desktop browsers (more than 95%).

Vast majority of search traffic to blog came in search for Windows 8.1 product key, probably because of my Installing Windows 8.1 (or 8) without a product key post. Another huge chunk were ones searching for VHD Attach and MagiWOL.

Pingdom claims 99.93% uptime (6h down) which is definitely helped by CloudFlare. While free CloudFlare account is not a perfect solution, it is definitely helping with site’s speed. For next year I will need to think of some other improvements.

And that’s all folks!

Variable Parsing Au Bash

Every command-line processor has a way to allow for embedded variables. Those familiar with DOS will recognize percent encoded variables, e.g. “echo I am %USERNAME%”. Those more familiar with Unixoids will be more relaxed around dollar variables, e.g.: “echo I am $USERNAME”. Either way gives possibility to combine fixed text with some external value. I personally prefer bash-style so I will continue with it.

If we try to parse “User $USERNAME is working on $OS using $NUMBER_OF_PROCESSORS processors.”, this is really easy for human to tackle. Even on first glance, we know that result should be “Joe is working on Windows NT using 1024 processors.”. Making computer recognize that is a bit more involved.

Well, generic solution is really simple. Just make an function that will extract all variables from string and ask us what values might those be:

string ParseVariables(string text) {
    var res = ParseVariablesStateMachine(text, **delegate(string variable)** {
        **return Environment.GetEnvironmentVariable(variable);**
    });
    return res;
}

As you can see from above code, we call into ParseVariablesStateMachine method giving it whole input text alongside with a callback delegate. Function will take care of parsing variables out and ask us what each value should be via delegate function. In our example we do simple environment variable lookup but this can be modified to return almost anything.

This delegate will return value back into calling method and that method will continue string processing until next variable comes along. At that time it will repeat call to our delegate; rinse and repeat. At the end it will return value composed of all these variables in one nice string.

One way to tackle this problem is by using a simple state machine (yes, name was kinda giving it away). We definitely have starting state, we have state where we found inner variable, and state where variable is being processed. Code may look something like this (heavily redacted):

string ParseVariablesStateMachine(string text, Func<string, string> variableCallback) {
    var state = ParsingState.Default;
    for (int i = 0; i < text.Length; i++) {
        switch (state) {
            case ParsingState.Default:
                if (text[i] == '$') { state = ParsingState.VariableStart; }
                break;

            case ParsingState.VariableStart:
                state = ParsingState.NormalVariable;
                break;

            case ParsingState.NormalVariable:
                if (!char.isLetterOrDigit(text[i])) {
                    variableCallback.Invoke(text.substring(variableStart, variableLength));
                    state = ParsingState.Default; //search for next variable
                }
                break;
        }
    }
    return parsedString;
}

Full example source is available for download.

Modifying ParseVariablesStateMachine mathod to parse DOS-style variables is exercise left to a reader. It is actually simpler than bash-style parsing because we know when variable ends based on closing percent sign.

PS: Full example also covers extended variable style (e.g. ${USERNAME}.).