Sunday, March 20, 2011

How A Simple Bug Creates A Larger Problem: The Logoff Bug in Software Updater (Or: The Perils of Using e.Cancel in a FormClosing)

If you’re using Windows XP and have installed Project Nelson 1.0 Build 020 (which includes Software Updater), you may have noticed an inability to shutdown or log off your computer. Before you ask, an updated version of Software Updater without the bug is on the way has been released, along with a bunch of optimising and code cleanup (but that’s mainly under the hood.) You should get a notification through Software Updater when that’s ready, but in the meantime you can launch Task Manager and, under the Processes tab, select SoftwareUpdater.exe and hit “End Process”. You should be able to log off then.
So, how did I screw up a program so massively for it to prevent shutdown? Actually, it was really simple. For developers, this is a warning message about the problems of cancelling the closing of your window without taking all things in account.

The Problem

Software Updater consists of a few forms, but the important one is the main window. On the main window is a NotifyIcon object, the object which I can use to give my program a constant presence in the notification area.
(This is a bad idea for reasons Raymond Chen lists, but really, that’s beside the point, and the same problem would exist anyway, since that form also contains the code to check updates. I will be removing the superfluous icon in a later version anyway, so, yuh.)
Now, I wanted to keep the form open when someone clicked the close button, so it could do its business. I’d hide it from the user, but it would still be there, running the stuff it needed to run.
After a poke around the form’s FormClosing event, I decided to use the following code:
Private Sub Main_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    e.Cancel = True
    Me.Visible = False
End Sub
See the problem yet?
The problem is that every time anything tries to close the form, whether it’s hidden or not, this code will execute. The window will say “De-nied!” and hide the window. Including when the computer tries to, say, shut down.
I’d like to note this isn’t a problem in Windows Vista or above, which ignores the app saying “De-nied!” and punches its lights out closes it anyway. But really, you shouldn’t be lazy and rely on the operating system to do your job. (I have an excuse – my main computer is Windows Vista, so I had to borrow another person’s computer to test it out on, and even then I thought I’d messed something up in the installer script, not the program itself.)

The Solution

Through persistent Googling of the problem (as, once I’d figured out the problem went away after you killed Software Updater, on a hunch I tried searching for variations of e.Cancel shutdown problems) I found what I was looking for.
It turns out that during my poking around, somehow I’d missed that FormClosing had an e.CloseReason variable. There are quite a few options to choose from, but the one we’re looking for is CloseReason.WindowsShutDown. To wit:
Private Sub Main_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
    If Not e.CloseReason = CloseReason.WindowsShutDown Then
        e.Cancel = True
        Me.Visible = False
    End If
End Sub

And that, my friends, is that. Later days, and may you not make the same mistake I did!

Monday, August 10, 2009

App Paths? What App Paths?

This article is part of Bad Things Programmers Do, a laundry list of common mistakes that catch even the best developers.

One of the most annoying things I’ve come across while developing Project Nelson is the dreadful support for App Paths in other applications. Now, for most devs it would probably be only slightly annoying, but it’s especially aggravating for me seeing as Project Nelson is dependant on them being there to work (efficiently).

What are app paths anyway?

Short answer: The term “App Paths” refers to the registry key located at HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\App Paths.

Long answer: Since Windows lets people install software where-ever they please (and good-neighbour apps should never assume they know where an app lives), App Paths provides a central lookup for the locations of any given app. Think of it as an application address book.

What’s the big deal?

While most of the big/popular/old programs register their paths, some of the newer/smaller/unpopular apps don’t. I find this happens most among independent developers (for example, IRC clients and RSS readers are dominated by these people) and open source apps or Linux-ports.

But even big, powerful, closed source companies can do this – for example, Safari (yes, the web browser) doesn’t do it, despite the fact that iTunes does. Whisky Tango Foxtrot.

Why should I use App Paths?

Say I wanted to launch Firefox. I could assume that I’d find it at C:\Program Files\Mozilla Firefox\firefox.exe, and for 90% of the English-speaking world that’d be alright. However, then my program would break for:

  • People who installed Windows on a drive other than C:.
  • People who moved their Program Files directory to a drive other than C:.
  • People who installed Firefox in a directory other than the default.
  • People who don’t speak English.

Nice going, you just angered an 30-year-old Brazilian who installs his software to a network drive and has his Windows directory on D:\. Pray he’s not a mobster with contacts in your town.

Long story short, if you expect other developers to run your program, you’ve got to tell them where it is first. :D

How do I use App Paths?

Look up the default value in the key HKLM\Software\Microsoft\Windows\App Paths\%filename%, where %filename% represents the filename of the executable (e.g.firefox.exe).

  • You should also look up the “Path” value (in the same key) so you know what CurrentDirectory you should run it under; if none exits, simply use the parent directory.
  • Some apps (for some odd reason) use HKEY_CURRENT_USER instead of HKLM. It’s best to check both places, just to be sure, but you won’t be missing much by only using HKLM.
    • If you're developing an app, never store your app path under HKCU unless you know your app will only be used by one user on each computer or you install in the users’ AppData directory (*cough*Google Chrome*cough*). The reason for this is because you then have to set it for each user (e.g. at first start), and when you uninstall the app, the old references will still linger.

Setting up shop

You should register yourself in App Paths as part of your installation script.

Register the following values under the key HKLM\Software\Microsoft\Windows\App Paths\%filename%:

Value name Type Value
(Default) String value (REG_SZ) The path to the executable (e.g. “C:\Program Files\Mozilla Firefox\firefox.exe” for firefox.exe
Path String value (REG_SZ) The CurrentDirectory you want to open the executable under (optional)

What about Linux/Mac OS X?

  • Mac OS X uses fat binaries, so all you need to do is look in /Applications.
  • Linux will store the program in either /bin, /sbin, /usr/bin or /usr/sbin (most likely in /usr/bin), so search those directories and you should find it.

Either way, these locations should be in your $PATH, so you shouldn’t have much trouble finding programs, and programs shouldn’t have any trouble finding you.

Saturday, July 11, 2009

Operating Conventions Part II (How To Fix What Shouldn’t Be Broken)

This is part two of Operating Conventions, which is itself part of Bad Things Programmers Do. You can read Part 1, but you don’t really have to.

Method 1: Just Fix It

Seriously. Redirect your file open dialogs to the proper My Documents (or better yet, remember the last location.) Use Windows Contacts. Use the favourites folder. Do it the right way, and it won’t be a problem anymore.

Method 2: But compatibility!

If you really must, because some program written years ago by a developer you don’t even know is still alive depends on it, then keep a compatibility struct synced to the OS’s APIs. Make it plain that other developers are not to use the old way anymore, as it may disappear off the face of the earth at any time (this is called deprecation.)

Method 3: But my way is better!

If you truly believe your way is better, then its’ still up to you to keep the OS up-to-date. Use proprietary extensions that other programs will ignore. At the very least, do it your way completely, but keep the OS version synced to any changes.

Remember, above all, if you do it right the first time, you don’t have to worry about compatibility later down the road. Your users will be happy, you’ll be happy, and other developers will be happy too.

Next time on Bad Things Programmers Do, we’ll talk about HKLM\Software\Microsoft\Windows\CurrentVersion\App Paths, otherwise known as the bane of my existence (because programs don’t register themselves there.)

Ciao!

--MarkKB

Wednesday, January 14, 2009

Operating System Conventions

Operating systems have a way of doing things. They provide APIs for developers to hook into and use, and default locations for users to put stuff into.

For example, most operating systems now provide a Documents folder as a default location to put their stuff in, a Bookmarks or Favourites folder to store website links, and music, picture and video folders for various media types. Vista also provides a common Feeds API, and a common contacts framework.

However, many programs are not updated to support, or worse, completely ignore these conventions. While this is not always a big deal to the developers and power users, it is a big deal when Ma switches from one app to another and can’t find her stuff. (They may not be using your software, but you’ve just completely alienated them from trying it out again, or recommending it to others.)

Non-Deliberate Examples

Operating systems often replace functionality that has traditionally been handled by programs. For example, before Microsoft introduced the My Documents folder in Windows 98, most word processors saved their documents to C:\Documents, C:\My Documents, C:\Docs, or variations thereof. At least by 2002, one (admittedly minor) word processor was still doing this, saving to C:\Documents\<insert program name here> Docs.

The same thing happened with the Downloads folder in Windows Vista – even today, many popular download managers and *ahem* file sharing apps don’t download their files to the Vista Downloads folder.

And, of course, we must not forget how every single game seems intent on putting <Program Name> Saved Games in my Documents folder, rather than App Data where it belongs, or the user’s Saved Games folder in Vista.

(I myself am not immune – File Manager “Nemo”’s fav folders idea was formed before I knew Vista would have a similar feature, and developed before I had a working build of Vista to play with, for example.)

And Then There’s…

Some programs deliberately ignore conventions altogether – whether it’s to create a “walled garden” to keep users in, because it’s out of spite or contempt, or simply because it’s the way they’ve always done it.

Browsers are a rather egregious example – apart from Internet Explorer, the default browser in Windows, none of the major browsers use Windows’ Favourites folder for their favourites/bookmarks, and none of them use each other’s bookmark database (although many use the same system.) This one stands out particularly well, seeing as Windows has had a bookmark folder since Microsoft started shipping an internet browser with Windows - Windows 98 with IE4 in 1998, just over a decade ago. They aren’t even stored in some proprietary format – they use plain text, and Windows even provides an API, just in case you don’t want to do the heavy lifting yourself.

The common Feeds API is another example – Apart from Microsoft’s own Internet Explorer and Windows Live Mail, no other program that has anything remotely to do with RSS/Atom feeds uses it.

A particularly annoying one is how email programs’ contact/address books – heck, anything with some kind of contact system – seems to use their own system of doing things. Although Outlook Express/Windows Live Mail have generally been good with this, even Microsoft Outlook doesn’t use the default OS contacts database of their own operating system. (Windows Live Messenger doesn’t do it either. Hmm…)

Next time, I’ll discuss how to fix these problems without breaking your apps. ‘Till then!

--MarkKB

Monday, September 22, 2008

Bad Things Programmers Do

[Updated 14 Jan 2009 with new article titles.]

I’ve decided to start a series about the bad things many programmers do. Suggestions at markkeyb@gmail.com would be appreciated!

Many things on this list are about things that programmers shouldn’t really do, but do anyway. Many of them make small little programs, but some are really high profile or really popular, and often are looked up to by less prominent programmers as how to do things, which only propagates the problem.

Articles in this series:

Operating System Conventions (Part 2)
App Paths? What App Paths?
Uncommon Controls and Dialogs
Hardcoded Paths
Inappropriate Tray Usage

This list will be updated with links when I’ve published the articles. Yay!

--MarkKB