# April, 2009

• #### If you can't find the statistics you want, then just make them up

Yesterday, the Wall Street Journal reported on America's Newest Profession: Bloggers for Hire and included this handy little chart:

 Lawyers 555,770 Bloggers 452,000 Computer Programmers 394,710 CEOs 299,160 Firefighters 289,710 Source: Bureau of Labor Statistics

I found this number hard to believe, so I followed the Source link to the information from the Bureau of Labor Statistics. I found that, yup, in a May 2007 survey, the Bureau of Labor Statistics estimated that there were indeed 555,770 lawyers, 394,710 computer programmers, 299,160 chief executives, and 289,710 fire fighters in the United States.

Bloggers? Didn't even make the list. The number 452,000 appears nowhere in the Bureau of Labor Statistics report.

If you can't find the statistics you want, then just make them up (but claim somebody else provided them).

(The comments on the article suggest that the number 452,000 was derived from a Technorati report that there were 20 million blogs, of which only 4.7 million have been active in the past four months. The number 20 million was then combined with a Technorati survey of active bloggers in which 2% of them self-reported blogging as their primary source of income.)

Bonus statistics: The claim that "It takes about 100,000 unique visitors a month to generate an income of \$75,000 a year" is a total misrepresentation of the Technorati report. Technorati said that the average annual income among people with 100,000 or more unique monthly visitors is \$75,000. That's like seeing that the average salary for a professional baseball player is \$3.1 million and concluding that once you reach the big leagues, you'll be pulling down \$3.1 million, when in fact—as the new guy—you'll most likely be making the baseball minimum wage of \$390,000.

• #### What structure packing do the Windows SDK header files expect?

/Zp8

In words, integral types and pointers up to eight bytes in size are stored at their natural alignment. Larger types are stored at eight-byte alignment.

TypeAlignment
BYTE, char, UCHAR 1-byte alignment
WORD, WCHAR, short, USHORT 2-byte alignment
DWORD, int, long, UINT, ULONG, float, 32-bit pointer 4-byte alignment
QWORD, __int64, unsigned __int64, double, 64-bit pointer 8-byte alignment

In other words (saying it a third time), let T be an integral or pointer type. If sizeof(T) ≤ 8, then T is aligned at a sizeof(T)-byte boundary. If sizeof(T) ≥ 8, then T is aligned at an 8-byte boundary.

• #### How to answer the telephone, according to the manual

I have a fancy new office telephone with a bajillion features (most of which I will never even find, much less use). The telephone comes with a helpful manual, explaining how to carry out various tasks. For example:

Using the Handset:
Pick up the handset.

Cool, I was wondering about that.

• #### Principles of economics, translated

Yoram Bauman, the stand-up economist translates Mankiw's ten principles of economics into English.

The proof presented in the footnote to principle 5, as well as an extended version of the translation, can be found in the Annals of Improbable Research.

• #### The dangers of destroying a window while it is processing a sent message

Commenter BryanK wonders why weird things happen if you destroy a window while it is processing the WM_ACTIVATEAPP message. He suspects that it's similar to the problems you encounter when you destroy a window in response to the WM_KILLFOCUS message.

Although I haven't studied the WM_ACTIVATEAPP situation, I wouldn't be surprised if the problem is indeed entirely analogous. It just follows from general programming principles: After all, you are destroying the active window. The WM_ACTIVATEAPP message is sent as part of the activation change, and the documentation says that the message is sent "when a window belonging to a different application than the active window is about to be activated." Notice: "about to be" activated. That other window hasn't been activated yet; you're still the active window.

Destroying the active window means that the window manager has to find a new active window. You're triggering an activation change while another activation change is in progress; no wonder things get all messed up.

I am now going to make a gross generalization. There may be exceptions to this rule, but it's a good place to start: Destroying yourself is (generally speaking) not an acceptable response to a sent message. The code that sent you the message is doing so because it wants to ask you a question (if it cares about the return value) or because it's informing you of something that is happening right now as part of a larger operation. (After all, if the code didn't mind if you received the information after the fact, it would have posted the message instead of sent it.)

And (generally speaking) it's bad form to perform an operation that changes a system's state while it's notifying you that that very state change is in progress. When the state change is in progress, the state is unstable. (If it were stable, then the state change would either not yet have begun or already have finished!)

• #### Why is the animation common control limited to RLE8-compressed animations?

The animation common control is very limited in the type of animations it can play. The animation must be in AVI format, it cannot have any sound, and it must be either uncompressed or use RLE8 compression. Why so many restrictions?

Because if it could handle other file formats, play sound, and support arbitrary codecs, it would just be a reimplementation of the multimedia animation control. (We saw this principle earlier when discussing why you can't do everything with registry values that you can do with registry keys.)

The point of the animation common control is to play very simple animations without the overhead and accompanying complexity of the full generality of the multimedia animation control. Think of it as the 1040EZ of animation. If your animation is comparatively simple and you don't need very much control over its playback at all, then go ahead and use the animation common control, which is designed to be a simple playback control for simple animations. But if your animation is complicated, uses an advanced compression scheme, or contains audio, then you've left the world of simple animations and need to move up to the full-sized 1040 form. There's no point adding support for everything to the simplified control, because once you've added support for everything, you have the complex control that the simplified control was trying to simplify!

Okay, fine, so the animation common control can't be a full-featured animation control or that would have defeated its purpose for existing. But why those specific limitations?

Because those were just barely enough features to play the animations that the shell team needed to play. The animation common control was written by the Windows 95 shell team, and it supports only enough features to be able to play the animations that the Windows 95 Explorer used. After the control was written, the shell team figured, hey, we already wrote it, we may as well do other people a favor and let them call it, too. The downside of this is that even though the shell doesn't use these simple animations any more, it still has to ship the animation control because other applications rely on it. What started out as a courtesy has turned into a support burden.

• #### The frustration of people who are not interested in why something works but only interested in the magic phrase they need to type

It's frustrating when people who are presumably smart (or who are at least pretending to be) have a problem and are satisfied to receive the magic phrase they need to type with no interest at all in understanding why the magic phrase works. For example, here's a question sent to an internal mailing list for users of something I'll call Program Q.

From: X

Why is it that after I use program Q to create a table, nothing else works? Here's a batch file I've written:

q create table newtable
pause
q create table newtable2

The pause command never executes; in fact, nothing in the batch file executes after the first line. How can I create multiple tables from a batch file?

My psychic powers didn't need very much charging up to solve this one. Program Q is a popular one, and some teams like to create a wrapper around it for whatever reason.

My psychic powers tell me that the first "q" on the path is not q.exe.

Another person on the mailing list knew what I was getting at and picked up the ball.

From: Y

Try using call q create table newtable instead.

(Maybe you too can figure out what my psychic powers told me the problem was.)

The response:

From: X

Thanks, that did the trick. I put a call in front of the first line and now the entire batch file runs.

I replied:

Dear X. Please confirm that the first q on the path is in fact a batch file, in order to confirm that you understand the reason why you were encountering the problem, that it has nothing to do with Program Q, and that you understand why the fix works. Don't just copy the answer from your neighbor.

I've already decided that I'm going to blog about people who accept an answer without bothering to understand why it works. Here's your chance to at least look good when that blog entry comes out.

There was no response.

Update: This was a mailing list for a programmer's tool. And if you're a programmer, you'd better understand what you're doing when you do it, not just cargo-cult your way through your job. Especially since this particular problem had nothing to do with Program Q in the first place. (On the other hand, I don't blame non-programmers for being satisfied with magic phrases.)

• #### Taxes redux: You can't open the file until the user tells you to open it

One of the so-called taxes of software development on Windows is being respectful of Hierarchical Storage Management. You can't open a file until the user tells you to open it. This rule has consequences for how Explorer extracts information about a file, because what you definitely don't want is for opening a folder full of archived files in Explorer to result in all the files being recalled from tape. (Actually, file recall is just an extreme case of the cost of opening the file. You run into a similar problem if the file is on a slow medium or over a slow network connection. But just to motivate the discussion, I'll continue with the tape scenario.)

What information does Explorer need in order to display a file in a folder? Well, it needs the file name. Fortunately, that can be determined without opening the file, since the file name is how you identify the file in the first place! When you want to open a file, you pass its name. There, you have the name. If you are showing the contents of a folder, you used a function like FindFirstFile to get a list of all the files, and the list comes in the form of names. Okay, so the name is easy. (There are still subtleties here, but they are not relevant right now.)

Okay, what's next. The icon. Well, in order to get the icon, we need to know the file type, so let's put the icon on hold for now.

The file creation and modification times can be obtained without opening the file; they come out as part of the FindFirstFile, or if you started with a file name, you can recover them with GetFileAttributesEx. Either way, you can get that without opening the file. Same goes for the file size.

The other properties, like Title, Author, Summary... They all require that the file be opened, so Explorer disables the property for files that have been archived to tape. You don't want to recall a file from tape just to show its Author in Explorer.

Okay, that leaves just the file type (and the icon, which depends on the file type). Consider the possibilities for how the file type could be determined.

What do these problems tell us? The first problem, that reading bytes from a file forces a recall, means that file type information cannot be based on the file contents. The second problem, that reading alternate data streams also force a recall, means that you can't put it in an alternate data stream either. All that's left is storing the type in the metadata.

But the third problem tells us that there isn't much metadata to choose from. Whatever mechanism you use needs to be able to survive being sent as an email attachment or being uploaded to an FTP site. Email attachments in particular are extremely limited. Most email programs, when asked to save an attachment, preserve only one piece of metadata: The filename. (They often don't even preserve the last modified time. And good luck getting them to preserve other ad-hoc metadata.)

All of these problem conspire to rule out all the places you can squirrel away type information, leaving just the filename. It's a sucky choice, but it's the only choice left.

And it means that changing a file's extension means the file type information is destroyed (which, from an end user's point of view, may as well be corruption).

• #### Microspeak: The plate

To have a lot on one's plate means to have a lot of tasks and responsibilities.

We shouldn't give this task to Bob. He already has a lot on his plate. (Or: He already has a full plate.)

At Microsoft, this common English language idiom is treated as a normal part of the language. The metaphorical plate has become a synonym for assigned tasks and responsibilities and can be used as a basis for new idioms.

That feature moved off their plate onto ours.

Feature X got postponed to the next release, so there's room on our plate for Feature Y.

Update: Apparently there are some people who believe that Microspeak should restrict itself to jargon used at Microsoft and nowhere else. I employ a broader definition which includes the use of existing jargon which is used in an unusual way or used much more heavily than in the general population. Today's entry is one of the latter: I already pointed out that to have a lot on one's plate is a standard English idiom. What makes it Microspeak is how the word plate has taken on a life of its own at Microsoft, to the point where the original idiom is almost lost.

I apologize to those for whom this explanation was not necessary.

• #### Why is there no support in the window manager for mouse button chording?

Commenter Nekto2 asks why there is no mouse action associated with "click both buttons at the same time".

The window manager doesn't fire a special event for both mouse buttons held down simultaneously like it does for double-clicks. As with higher-order clicks, mouse chording is something that you have to put together yourself from the basic mouse events that the window manager generates. Add these lines to our scratch program:

void OnButtonDown(HWND hwnd, BOOL fDoubleClick,
int x, int y, UINT keyFlags)
{
if ((keyFlags & (MK_LBUTTON | MK_RBUTTON)) ==
(MK_LBUTTON | MK_RBUTTON))
{
MessageBeep(IDOK);
}
}

HANDLE_MSG(hwnd, WM_LBUTTONDOWN, OnButtonDown);
HANDLE_MSG(hwnd, WM_RBUTTONDOWN, OnButtonDown);

When you run this program, it beeps when both the left and right mouse buttons are pressed.

Note that the program does not require the two button presses take place simultaneously. Most people do not have the dexterity to push the two buttons at precisely the same instant in time. (Especially since Einstein taught us that simultaneity is relative anyway.)

Why don't more programs use chording?

Recall that the semantics of double-clicking should be an extension of the single-click so that your program can perform the single-click action immediately (providing positive feedback to the user that the click was recognized), and then continue to the double-click action if a second click comes in. For example, a common pattern is for the single-click to select the clicked-on item and the double-click to launch it. You can stop at the first click and the result still makes sense. For chords, you have to have two stopping points, one if the user left-clicks and stops, and another if the user right-clicks and stops. Coming up with a chord action that is compatible with both stopping points requires more effort.

Another reason why many people choose to avoid chords in their user interface design is that chording requires more dexterity, and many users simply don't have the fine motor control necessary to pull it off without accidentally invoking some other action (such as a drag). Chording is also cumbersome to emulate with MouseKeys, so you run afoul of accessibility issues.

Still, there's nothing technically preventing you from using chording in your program. If you want to code it up, then more power to you.

Page 2 of 3 (28 items) 123