# May, 2004

• #### Thinking through a feature

The commentary after my entry on taskbar grouping drifted into people asking for still more features in taskbar grouping.

Writing the code is the easy part.

Designing a feature is hard.

You have several audiences to consider. It's not just about the alpha geeks; you have to worry about the grandmothers, the office workers, the IT departments. They all have different needs. Sometimes a feature that pleases one group offends another.

So let's look at some of the issues surrounding the proposed feature of allowing users to selectively ungroup items in the taskbar.

One issue with selective grouping is deciding the scope of the feature. Suppose the user ungroups Internet Explorer, then closes all the IE windows, then opens two new IE windows: Do the new ones group?

If so, then you now have an invisible setting. How do you configure grouping for programs that aren't running? (How do you configure something that you can't see?)

Suppose you've figured that out. That's fine for the alpha geeks, but what about grandma?

"The Internet is all disorganized."

"What do you mean?"

"All my Internet windows are all disorganized."

"Can you explain a little more?"

"My taskbar used to be nice and organized, but now the Internet parts are disorganized and spread out all over the place. It used to be nice and neat. I don't know how it happened. I hate the Internet, it's always messing up my computer."

What is the UI for selective ungrouping? Anything that is on a context menu will be executed accidentally by tens of thousands of people due to mouse twitching. Putting the regroup onto the context menu isn't necessarily good enough because those people don't even realize it was a context menu that did it. It was just a mouse twitch.

Mouse twitches cause all sorts of problems. Some people accidentally dock their taskbar vertically; others accidentally resize their taskbar to half the size of the screen. Do not underestimate the havoc that can be caused by mouse twitching.

Soon people will want to do arbitrary grouping. "I want to group this command prompt, that notepad window, and this calc window together."

What about selective ungrouping? "I have this group of 10 windows, but I want to ungroup just 2 of them, leaving the other 8 grouped together."

Once you have selective/arbitrary grouping, how do you handle new windows? What group do they go into?

Remember: Once you decide, "No, that's too much," there will be thousands of people cursing you for not doing enough. Where do you draw the line? And also remember that each feature you add will cost you another feature somewhere else. Manpower isn't free.

But wait, the job has just begin. Next, you get to sit down and do the usability testing.

Soon you'll discover that everything you assumed to be true is completely wrong, and you have to go back to the drawing board. Eventually, you might conclude that you over-designed the feature and you should go back to the simple on/off switch.

Wait, you're still not done. Now you have to bounce this feature off corporate IT managers. They will probably tear it to shreds too. In particular, they're going to demand things like remote administration and the ability to force the setting on or off across their entire company from a central location. (And woe unto you if you chose something more complicated than an on/off switch: Now you have to be able to deploy that complex setting across tens of thousands of computers - some of which may be connected to the corporate network via slow modems!)

Those are just some of the issues involved in designing a feature. Sometimes I think it's a miracle that features happen at all!

(Disclaimer: I'm not saying this is how the grouping feature actually came to be. I just used it as a starting point for a rant.)

For another perspective, you can check out KC Lemson's discussion of the feature-design process a few days ago under the topic There's no such thing as a simple feature.

• #### When you change the insides, nobody notices

I find it ironic when people complain that Calc and Notepad haven't changed. In fact, both programs have changed. (Notepad gained some additional menu and status bar options. Calc got a severe workover.)

I wouldn't be surprised if these are the same people who complain, "Why does Microsoft spend all its effort on making Windows 'look cool'? They should spend all their efforts on making technical improvements and just stop making visual improvements."

And with Calc, that's exactly what happened: Massive technical improvements. No visual improvement. And nobody noticed. In fact, the complaints just keep coming. "Look at Calc, same as it always was."

The innards of Calc - the arithmetic engine - was completely thrown away and rewritten from scratch. The standard IEEE floating point library was replaced with an arbitrary-precision arithmetic library. This was done after people kept writing ha-ha articles about how Calc couldn't do decimal arithmetic correctly, that for example computing 10.21 - 10.2 resulted in 0.0100000000000016.

(These all came from people who didn't understand how computers handle floating point. I have a future entry planned to go into floating point representations in more detail.)

Today, Calc's internal computations are done with infinite precision for basic operations (addition, subtraction, multiplication, division) and 32 digits of precision for advanced operations (square root, transcendental operators).

Try it: 1 / 3 * 10000000000 - 3333333333 =. The result is one third exactly. Type 1/x - 3 = and you get zero back. (Of course, if you don't believe that, then repeat the sequence "* 10000000000 - 3333333333 =" until you're bored and notice that the answer always comes back as 0.33333333333333333333333333333333. If it were fixed-precision, then the 3's would eventually stop coming.)

Thirty-two positions of precision for inexact results not good enough? The Power Calculator PowerToy uses the same arithmetic engine as Calc and lets you crank the precision to an unimaginable 512 digits.

Anyway, my point is that - whether you like it or not - if you don't change the UI, nobody notices. That's so much effort is spent on new UI.

• #### Is open source the new monoculture?

Okay I know I'm going to get into a lot of trouble for even bringing up this topic...

This past weekend, Ulf Harnhammar discovered two buffer overflow and two directory traversal vulnerabilities in LHA, a library of data compression functions.

Since the code for this is public, it has been copied all over the place. At least one commercial archive management program and at least one commercial mail antivirus program are vulnerable. A denial of service attack is already under way against the mail antivirus program; all you have to do is attach a malformed LHA file to a message, causing the scanner to crash when it attempts to scan the attachment. When the administrator restarts the mail server, the scanner will resume where it left off... and crash again. (Somebody with more time on their hands could craft a more clever LHA file attack that takes over the mail server itself.)

The fact that the code itself was public meant that everybody didn't have to write their own LHA functions. This is a good thing. However, it also means that everybody has the same security vulnerabilities. This is a bad thing.

So we have one bug that can take down large numbers of machines, even though they're all running different software.

How do you track all the versions? Is there a solution to this? Is it even a problem?

• #### Extending the Internet Explorer context menu

In a comment, Darrell Norton asked for a "View in Mozilla" option for Internet Explorer.

Internet Explorer's context menu extension mechanism has been in MSDN for years. Let me show you how you can create this extension yourself.

First, create the following registry key:

[HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\MenuExt\View in Mozilla]
@=REG_SZ:"C:\some\path\to\ViewInMozilla.htm"
Contexts=REG_DWORD:1


Of course, you need to change C:\some\path\to to an actual path.

How did I know to do this? Because steps 1, 2 and 3 in the "Implementation Steps" section tell me (1) what key to create, (2) what to set the default value to, and (3) what to set Contexts to. I chose a Context value of 1, which means "Default".

Okay, now to write the script ViewInMozilla.htm. Well, the documentation says that I can access context from the menuArguments property of the external object. So let's start with that.

<SCRIPT>
</SCRIPT>


Okay, let's run this puppy. Launch IE, right-click on a blank space in the web page, select "View in Mozilla", and you get...

    [object]


Woo-hoo! This is a major accomplishment: Something happened at all. Doing things in small steps makes it easy to identify where a problem is. If we had run full steam ahead to completion and then it didn't work, we wouldn't have known whether it was due to a bug in the script, a bad registration, a bad filename...

Now that I have the menu arguments, I can use that to suck out information about the item that the context menu applies to. Let's try this:

<SCRIPT>
</SCRIPT>


Woo-hoo, now it gives me the URL. Almost there. All that's left to do is to run a program with that URL as the command line parameter.

<SCRIPT>
var shell = new ActiveXObject("WScript.Shell");
shell.run("mozilla \"" + external.menuArguments.document.URL + "\"");
</SCRIPT>


Mission accomplished.

Now you too can create Internet Explorer context menu extensions.

In fact, go ahead and do it, since Darrell asked for it: Create an Internet Explorer context menu extension that operates on anchors and opens the linked-to page in Mozilla.

(Bonus: Tony Schreiner cooked up something similar for zooming.)

• #### What is the difference between Minimize All and Show Desktop?

The keyboard shortcut for "Minimize All" is ÿ+M and The keyboard shortcut for "Show Desktop" is ÿ+D. How are they different?

"Minimize All" is easier to describe. It minimizes all the windows that support the "Minimize" command. You can minimize a window by selecting "Minimize" from its System menu, or by clicking the 0 button in the title bar. So "Minimize All" is effectively the same as going to each window that is open and clicking the Minimize button. If there is a window that doesn't have a Minimize button, then it is left alone.

"Show Desktop" takes "Minimize All" one step further. After minimizing all the windows that can be minimized, it then takes the desktop and "raises" it to the top of the window stack so that no other windows cover it. (Well, okay, topmost windows continue to cover it.)

So "Show Desktop" manages to get a few more windows out of your way than "Minimize All".

Note, however, that when you return the desktop to its normal state (either by selecting "Show Open Windows" or just by switching to another window), all the un-minimizeable windows come back because the desktop has "lowered" itself back to the bottom of the window stack.

• #### When do you put ... after a button or menu?

When do you put "..." after a button or menu? For example, some menus say "Save as..." and some buttons say "Customize...". What is the rule for dots?

Many people believe that the rule for dots is "If it's going to display a dialog, then you need dots." This is a misapprehension.

The rules are spelled out in the Windows User Interface Design Specifications and Guidelines (what a mouthful). Scroll down to "Ellipses".

I could repeat what's written there, or I could just tell you to read it.

I'm going to tell you to read it.

Okay, maybe I'm going to repeat what's written there, but briefly:

Use an ellipsis if the command requires additional information before it can be performed. Sometimes the dialog box is the command itself, such as "About" or "Properties". Even though they display a dialog, the dialog is the result, as opposed to commands like "Print" where the dialog is collecting additional information prior to the result.

• #### Do you know when your destructors run? Part 2.

Continuing from yesterday, here's another case where you have to watch your destructors. Yesterday's theme was destructors that run at the wrong time. Today, we're going to see destructors that don't run at all!

Assume there's an ObjectLock class which takes a lock in its constructor and releases it in its destructor.

DWORD ThreadProc(LPVOID p)
{
... do stuff ...
ObjectLock lock(p);
... do stuff ...
return 0;
}


Pretty standard stuff. The first batch of stuff is done without the lock, and the second batch is done inside the lock. When the function returns, the lock is automatically released.

But suppose somebody adds a little code to this function like this:

DWORD ThreadProc(LPVOID p)
{
... do stuff ...
ObjectLock lock(p);
...
...
return 0;
}


The code change was just to add an early exit if the object was cancelled.

But when does that ObjectLock destructor run?

It runs at the return statement, since that's when the lock goes out of scope. In particular, it is not run before you call ExitThread.

Result: You left an object locked permanently.

You can imagine how variations on this code could lead to resource leaks or other problems.

• #### String sorting is not done by ASCII code any more.

Just because you have the ASCII table memorized doesn't mean you know how sorting works.

I remember a bug filed where somebody said that the "sort" command was sorting underscores incorrectly:

AAA__
AAAAA


this was claimed to be wrong "because underscore character follow uppercase letters and precedes lowercase letters".

Well perhaps it does if you think ASCII sorting is the way sorting should be.

ASCII sorting is so last century.

The CompareString function describes two types of sorting, "word sort" and "string sort". And both of them sort punctuation before letters.

• #### There are two types of scrollbars

Remember that there are two types of scrollbars.

One is the standalone scrollbar control. This one has its own window handle, and consequently can be given focus and all those other fun things you can do with window handles. To manipulate them, pass the handle to the scrollbar control to the appropriate scrollbar function (SetScrollInfo, for example) and pass SB_CTL as the nBar parameter to indicate that you have a scrollbar control.

The other type is the horizontal or vertical scrollbar (or both) attached to a window by virtue of having the WS_HSCROLL and/or WS_VSCROLL style. These are nonclient scrollbars and are not controls. They are just decorations added to some other window. You can't give them focus since they aren't windows in their own right. To manipulate them, pass the handle to the containing window to the appropriate scrollbar function and pass SB_HORZ or SB_VERT as the nBar parameter to indicate that you want to manipulate the nonclient horizontal or vertical scrollbar.

I'm writing this down since some people seem to miss the distinction between these two cases.