I’m now convinced that .NET’s support for localization is very poorly designed indeed. While on the surface, the concept of localization (also referred to as internationalization) is a noble effort to enhance or make possible the use of computers by speakers of foreign languages, if it gets in the way of development it can be a very disruptive and problematic tool.
Take the following error an early beta tester of OrangeNote supplied me with:
System.Windows.Markup.XamlParseException: Verdien System.Windows.Data.BindingExpression kan ikke tilordnes egenskapen Opacity for objektet System.Windows.Controls.Border. Invalid real literal ‘1.0’ Feil på objektet System.Windows.Data.Binding i kodefilen OrangeNote;component/viewers/debugterminal.xaml, linje 122, posisjon 5.
Now the first and most obvious problem is that the error is not in English! While it’s true that error messages presented to the user should most certainly be translated to their native language whenever possible, exception messages are not oriented towards end users. The purpose of an exception is to convey information back to the programmer that a particular problem has arisen in the code of a program, with the intention of providing useful information to addressing and correcting the problem.
For example, when translated, the above reads roughly like this:
System.Windows.Markup.XamlParseException: Value of System.Windows.Data.BindingExpression can not be assigned to attribute Opacity for object System.Windows.Controls.Border. Invalid real literal ‘1.0’ Error in object System.Windows.Data.Binding in file OrangeNote;component/viewers/debugterminal.xaml, line 122, position 5.
Is this really something the end user needs to know? If not, why go through the trouble of translating it in the first place? Perhaps Microsoft expects my users to fix my bugs for me. Furthermore, the platform doesn’t even appear to provide any way to explicitly obtain an English version of an exception, further increasing the absurdity of the matter.
But this is only the beginning.
If you take a closer look at the problem the exception is describing you might notice something strange: .NET is complaining that “1.0” is not a valid value for the Opacity property of a System.Windows.Controls.Border (which is a Double). Come again? 1.0 is a perfectly valid value for Opacity, unless you’re running your program on a locale that represents decimal values differently. That’s right, we can’t even program our app in English anymore! When simply changing the locale of your system affects what applications you can run on it, this is a clear indicator of a serious design problem.
Granted, this issue arises in some atypical scenarios involving dynamic parsing of lambda expressions, but the fact that it arises at all is the problem. What started out as a means to make applications more user friendly to foreign language speakers turned into a roadblock that can actually interfere with applications running at all.
In closing, my recommendations to Microsoft are as follows: First and foremost, eliminate the ridiculous and useless translating of exceptions into local dialects, and second, provide a more intuitive programming environment that takes into account programmer locale when running an application, not just user locale. These two things combined will make for a much more pleasant experience both for programmers and end users in multilingual scenarios.
See you next time.
Just a quick post to show-off OrangeNote’s brand new crash recovery and reporting dialog. Ironically, this is something that you hopefully won’t be seeing when you run OrangeNote, but I’ve always found a friendly and elegant crash dialog to convey a sense of professionalism and polish on an application. If it’s going to crash, we may as well make it as pleasant an experience as possible.
OrangeNote™ includes the same error reporting system employed by FeedBeast™, which anonymously logs and records all unhandled exceptions that occur in the program so they can be quickly addressed in future updates. As always, submitting crash reports is completely optional.
OrangeNote™ is available for beta testing at Wakoopa, and anyone that gets involved in the project during testing will receive a complimentary license for their help.
Since the beginning of the FeedBeast project, I’ve been on something of a quest to find the perfect self-extracting executable maker, and I’m delighted to say I’ve finally found it! You may have already heard of it; it’s called WinRAR.
Windows software deployment is a complex process. Coming from the Mac and getting dumped into the deep end of Windows deployment, so to speak, it was quite a shock. There are a great many things you need to worry about just to get your software onto your end-user’s PC, and the headaches are multiplied if you’re deploying a .NET-based app like FeedBeast or OrangeNote.
One of the key concerns in such a deployment is making sure that the user’s computer has the .NET framework installed, before even beginning the installation of your product. This is done with the aid of what’s called a “bootstrapper”. [I'm not entirely sure where that term came from, but I reckon it has something to do with the idea of "strapping" something onto your program, which is exactly what a bootstrapper does.] It’s basically a second executable that sits alongside your installer (usually called “setup.exe”) that performs several checks to make sure your system has the necessary “prerequisites” for your program to run and/or install, optionally downloading and installing them if they are lacking.
The problem that arises from this configuration is we now have a whole directory of junk to distribute, not a nice clean singular installer file like we started with. In today’s web-deployed world, this is a real problem: users don’t want to have to download and extract a zip file just to gain access to the installer. This is where a self-extracting executable comes in.
A self-extracting executable bundles all of these pieces together into a zip file, but packages that zip file as an actual executable program, with enough logic built-in that it can extract its contents and launch the bootstrapper silently, so that it appears as though the self-extractor is the installer. This is the perception we want to give the user, because it makes things all that much simpler if they can just download a single executable file, run it, and install the program they’re trying to get.
However, it’s not always so easily achieved.
The thing is, while the idea of the self-extractor is simple, there are actually a lot of subtle points that need to be addressed when building the perfect one. First of all, we need to keep in mind that the self-extractor is what the user is going to see, not the (now embedded) installer. Therefore, the ability to customize its icon is quite handy and professional. But there’s more.
Here’s my checklist for capabilities in a self-extracting executable maker, all of which WinRAR excels at:
- Silent mode – this is the ability for the self-extractor to be completely invisible to the user while decompressing an archive. If the archive is small, you don’t need to bother the user with yet another welcome dialog, where to extract to, and/or a progress dialog.
- Extract to temporary directory – hand-in-hand with silent extraction is extracting somewhere that won’t get in the way. WinRAR has the ability to extract to the system TEMP directory, and even cleans up after itself when the installation is complete.
- Ability to execute a file in the extracted archive – this is absolutely essential for building an installer wrapper. Some self-extracting archives are intended just for distributing files and such, not actually installing a program; but for our purposes, we need to have a way to launch the bootstrapper.
- Custom icon – give your installer a professional look by providing your own file icon that can be seen in the web browser downloads and on the desktop.
- Choose whether the executable requests elevation – installation generally requires admin privileges, but you don’t need to authenticate yourself right away. I prefer to defer elevation until the user actually clicks the Install button, which means the extractor doesn’t need to request elevation. If you’re installing from a bootstrapper though, requesting elevation from the get-go could mean only one UAC prompt rather than several.
There are also a ton more options such as the ability to customize the dialogs and logo and display a license agreement–there are seven tabs worth of customizations for self-extracting executables alone!
To put it plainly, WinRAR is well worth the $29 single-user fee. The self-extraction options alone are worth the price. However if even that is too steep for your tastes, there are some free options available, like 7-Zip and IExpress, but if you want the whole package, and my advice, go with WinRAR.
Next: How to write a simple but flexible bootstrapper using the awesome AutoIt scripting language!
Update: I just discovered that WinRAR self-extracting executables even support command-line argument passing! This means I can pass arguments to my WinRAR self-extractor and it will pass them along to the bootstrapper, which (depending on the bootstrapper) can even forward them onto the actual msi, allowing you to define variables that can then be interpreted by the installation engine! Awesome!
While working on OrangeNote, I decided that I wanted a nice modern spinner animation to indicate when a task (like a note search) was being performed asynchronously in the background. You see these things everywhere, and I personally find them pretty slick, but I couldn’t find anything out there already cooked up in WPF, and figured it would be a good learning experience (especially with regards to animation), so I decided to whip up my own.
It didn’t take long before I ran into a pretty solid limitation (or oversight perhaps) concerning animations in WPF: they are all specified with respect to a single property to be animated. In other words, there’s no global, top-down view of the state of objects involved in an animation–everything is fragmented and split up into parallel timelines. Time is innately global. It’s perhaps the most global of all things.
Suffice it to say I found this frustrating and confusing, so my quest to develop a spinning wheel animation quickly escalated into something much more: a new way to do animation in WPF.
I pulled up a copy of WordPad (OrangeNote wasn’t quite usable at this point) and jotted down some rough theoretical ideas for how I might achieve what I wanted. I wanted to keep it simple, and reuse as much of the existing infrastructure as possible, while focusing on enabling multiple properties to be animated together within the confines of a single sequential timeline. I decided the best approach was to think of transforming an ideal representation into an equivalent native representation that WPF could understand. It all has to do with factoring (yes, the same kind of factoring from high-school algebra). The idea is this: take a time-dominant form of representing an animation (where time is on the outside, and property states–represented by Setters–are on the inside) and turn it into the native property-dominant form that WPF is based on.
Turns out it worked. You can read all about it in my latest Code Project article. So if you’re stuck on a particularly complicated animation in WPF and are frustrated that you can’t think globally, check it out. And for that matter, tell your friends too. It’s completely free and open source, of course, and it even includes a spinning wheel demo project. ;)
I know it’s not exactly the most popular blog (yet!), but it’s my baby and I’m glad to see it has a home on the web again. Mind you I haven’t yet figured out how to import all my old data that I think I backed up from its last life, but I can always start fresh if I have to.
Anyhow, I’m working on a cool new WPF-based Windows app called OrangeNote (based on the Mac app of the same name developed by a friend of mine), and I must say it’s looking good.
Get a load of this… it’s beautiful even when it’s not showing anything. :)
So stay tuned for that. It’s gonna be great.
What? You want to know what it does? Well I don’t want to give it all away, but it’s basically a system-wide repository for all your textual information, complete with a lightning-quick, full-text search engine that can be brought up with a global hotkey. You’ll basically never have to use a text file to jot something down again.
On that note, it’s good to be back, and with any luck piHole will be around for a lot longer this time around!
See you next post.