Holy cow, I wrote a book!
Hotkeys involving the Windows logo key are reserved by the system. New ones are added over time. For example, Windows 98 added Win+D to show the desktop. Windows 2000 added Win+U to call up the Utility Manager. Windows XP added Win+B to move keyboard focus to the taskbar notification area. And a whole bunch of new hotkeys were added in Windows Vista, such as Ctrl+Win which is used by speech recognition. (It's also a bit of a pun: "Control Windows", get it?)
The fact that these hotkeys are reserved is hard to find. It's buried in a bullet point a third of the way down the Guidelines for Keyboard User Interface Design document. It's also highlighted in the WHQL keyboard requirements right in the section title: "Windows Logo Key Support (Reserved for Operating System Use)". But even if you didn't find the documentation (and I don't blame you), the history of Windows clearly indicates that new Windows logo hotkeys arrive on a pretty regular basis. If your program uses one of those hotkeys, there's a good chance it'll conflict with a future version of Windows.
Why isn't this mentioned in the RegisterHotKey documentation? Perhaps it should. But historically, function documentation merely told what a function does, not how it should be used. How a function should be used is a value judgement, and it was traditionally not the role of function documentation to make value judgements or specify policy. If you go to a programming language's specification document, you'll find a discussion of what the language keywords do, but no guidance as to how you should use them. Like a language specification, function documentation historically limited itself to how something is done, not whether it ought to be done. Recommendations traditionally belong in overviews, white papers, and other guidance documents. After all, the CreateFile documentation doesn't say "Do not create application data in the My Documents folder." The CreateFile function doesn't care; its job is to create files. Whether a file is created in the correct location is a guideline or policy decision at a higher level.
RegisterHotKey
CreateFile
Note: I don't know whether that is still the position of the function documentation team, that it limit itself to the facts and avoid value judgements and guidance. My goal today is to draw attention to the guidance.
A second installment in a very sporadic series titled The first day at Microsoft, relating stories of funny things that happened on people's first days at Microsoft. Today, we hear from Employee Y:
One of the things you have to do on your first day is get your photo taken for your identification badge, and I waited in line with the droves of other new college interns starting that same day. As a result, the line for photos extended out of the room into the parking garage. (ID badges are distributed from a room in the basement of one of the parking garages.) |----- | CAR -----+----- * * * * * +-----* ID | * room |----- * | CAR * -----|----- * | CAR * |----- * | CAR * |----- * As we waited in line, a car pulled up and wanted to park in that empty space near the door that people were blocking. The entire line of college interns just stood and stared in stunned amazement when they realized that the person driving the car was Bill Gates. This stalemate lasted a good ten seconds before I spoke up and said, "Hey, everybody. I think Bill is trying to park in that empty space." That was enough to snap people out of their frozen state. A hole was made, Bill parked his car, crisis resolved.
One of the things you have to do on your first day is get your photo taken for your identification badge, and I waited in line with the droves of other new college interns starting that same day. As a result, the line for photos extended out of the room into the parking garage. (ID badges are distributed from a room in the basement of one of the parking garages.)
|----- | CAR -----+----- * * * * * +-----* ID | * room |----- * | CAR * -----|----- * | CAR * |----- * | CAR * |----- *
As we waited in line, a car pulled up and wanted to park in that empty space near the door that people were blocking. The entire line of college interns just stood and stared in stunned amazement when they realized that the person driving the car was Bill Gates.
This stalemate lasted a good ten seconds before I spoke up and said, "Hey, everybody. I think Bill is trying to park in that empty space."
That was enough to snap people out of their frozen state. A hole was made, Bill parked his car, crisis resolved.
I like to amuse myself by thinking that each of those interns that blocked Bill from getting to the parking space cost the company more money in wasted time than the intern will make all summer.
You can use the FormatMessage message with the FORMAT_MESSAGE_FROM_SYSTEM flag to indicate that the message number you passed is an error code and that the message should be looked up in the system message table. This is a specific case of the more general case where you are not in control of the message, and when you are not in control of the message, you had better pass the FORMAT_MESSAGE_IGNORE_INSERTS flag.
FormatMessage
FORMAT_MESSAGE_FROM_SYSTEM
FORMAT_MESSAGE_IGNORE_INSERTS
Let's look at what happens when you don't.
#include <windows.h> #include <stdio.h> #include <tchar.h> int __cdecl main(int argc, char **argv) { TCHAR buffer[1024]; DWORD dwError = ERROR_BAD_EXE_FORMAT; DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM; DWORD dwResult = FormatMessage(dwFlags, NULL, dwError, 0, buffer, 1024, NULL); if (dwResult) { _tprintf(_T("Message is \"%s\"\n"), buffer); } else { _tprintf(_T("Failed! Error code %d\n"), GetLastError()); } return 0; }
If you run this program, you'll get
Failed! Error code 87
Error 87 is ERROR_INVALID_PARAMETER. What went wrong? Let's pass the FORMAT_MESSAGE_IGNORE_INSERTS flag to see what the message was. Change the value of dwFlags to
ERROR_INVALID_PARAMETER
dwFlags
DWORD dwFlags = FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS;
and run the program again. This time you get
Message is "%1 is not a valid Win32 application. "
Aha, now we see the problem. The message corresponding to ERROR_BAD_EXE_FORMAT contains an insertion %1. If you don't pass the FORMAT_MESSAGE_IGNORE_INSERTS flag, the FormatMessage function will insert the first parameter in the argument list (or argument array). But we didn't pass an argument list, so the function fails.
ERROR_BAD_EXE_FORMAT
%1
Actually, we got lucky. If we had passed an argument list or argument array, the function would have inserted the corresponding string, even if the argument list we passed didn't have a string in the first position.
If you are not in control of the format string, then you must pass FORMAT_MESSAGE_IGNORE_INSERTS to prevent the %1 from causing trouble. If somebody was being particularly evil, they might decide to give you a format string that contains a %9, which is almost certainly more insertions than you provided. The result is a buffer overflow and probably a crash.
%9
This may have been obvious to some people, in the same way that you shouldn't pass a string outside your control as the format string to the printf function, but I felt it worth mentioning.
printf
One evening, I parked pointing downhill and like the book says, I turned my wheels to the right before parking. But I turned it a bit too far, because when I returned to the car and inserted the key into the ignition, the key wouldn't turn.
The wrong thing to do is to force the key until it breaks.
Here's the right thing to do:
Take the steering wheel and turn it left and right. One direction will have a little more play than the other. Grab the wheel with your left hand and apply pressure turning it in the direction with more play while using your right hand to turn the key in the ignition. (Or, if you're like me and can't figure it out, just wobble the wheel back and forth until the key unsticks.)
Note: I scheduled this item independently of its partner. By an amazing coincidence, both items warn against forcing something until it breaks.
On the drive property sheet for an NTFS volume, there is a checkbox called "Compress drive to save disk space." If you check that box, the shell marks the drive as "compress all newly-created files" and also goes through and compresses all the existing files on the drive.
Well, almost all the file.
Some files are exempted by default.
Examples of exempted files are the files involved in booting the system (NTLDR, NTDETECT.COM, HIBERFIL.SYS) and files for which write requests must succeed (PAGEFILE.SYS). (If a file is compressed, then a write to previously-committed file data may fail if the new data does not compress as well as the old data and there is no more disk space.) These files are exempted on all drives, even if they're not your system drive.
NTLDR
NTDETECT.COM
HIBERFIL.SYS
PAGEFILE.SYS
On the other hand, if you right-click one of these exempted files and explicitly compress it, then the shell will compress it (or at least try to). For boot files, this will typically succeed since boot files are used only at boot; once the system is running, they aren't needed any more and therefore there aren't any open handles to the file with restrictive sharing modes.
Of course, if you do this to your system drive, it won't boot any more. So don't do that.
Like with many things in the physical world, if you force it too hard, it may break.
Welcome, Slashdot readers. Remember, this Web site is for entertainment purposes only.
Why are INI files deprecated in favor of the registry? There were many problems with INI files.
The registry tried to address these concerns. You might argue whether these were valid concerns to begin with, but the Windows NT folks sure thought they were.
Commenter TC notes that the pendulum has swung back to text configuration files, but this time, they're XML. This reopens many of the problems that INI files had, but you have the major advantage that nobody writes to XML configuration files; they only read from them. XML configuration files are not used to store user settings; they just contain information about the program itself. Let's look at those issues again.
XML manages to sidestep many of the problems that INI files have, but only if you promise only to read from them (and only if everybody agrees to use a standard-conforming parser), and if you don't require security granularity beyond the file level. Once you write to them, then a lot of the INI file problems return.
Welcome to Black Friday, the traditional start of the Christmas shopping season. I suspect there will be a bunch of people who are hoping Santa will get them an iPhone. Here's one story of what lies in store.
One of my friends stood in line on the first day of iPhone availability and got one of the highly-anticipated gadgets. We happened to get together two days later, and of course there was a lot of showing off and playing with the phone's features. But for me what was telling was the part of the phone which shows you the phone usage statistics. After two days, the numbers looked something like this:
Sounds about right.
The GetEffectiveClientRect function is another one in the category of functions that everybody tries to pretend doesn't exist. It's not as bad as MenuHelp, but it's still pretty awful.
GetEffectiveClientRect
MenuHelp
The idea behind the GetEffectiveClientRect function is that you have a frame window with a bunch of optional gadgets, such as a status bar or toolbar. The important thing is that these optional gadgets all reside at the borders of the window. In our examples, the toolbar goes at the top and the status bar goes at the bottom. You might also have gadgets on the left and right such as a navigation tree or a preview pane. They can also be stacked up against the border, such as an address bar and a toolbar. The important thing is that all the gadgets go around the border.
The first parameter to the GetEffectiveClientRect function is the window whose effective client rectangle you wish to compute; no surprises there. The second parameter is a pointer to the rectangle that receives the result; again, hardly surprising. It's that third parameter, the array of integers, that is the weird one.
The first two integers in the array are ignored. The remainder of the array consists of pairs of nonzero integers; the array is terminated by a pair consisting of zeroes. Of each pair, only the second integer is used; it is the control identifier of a child window of the window you passed in. If that child window is visible (in a special sense I'll explain later), then its window rectangle is subtracted from the parent window's client rectangle. After all the rectangles of visible children are subtracted away, what remains is the effective client rectangle.
For example, suppose your window's client rectangle is 100×100 and there is a toolbar at (0, 0)–(100, 20) and a status bar at (0, 90)–(100, 100), both visible. The GetEffectiveClientRect starts with the full client rectangle (0, 0)–(100, 100), subtracts the two rectangles corresponding to the toolbar and status bar, resulting in (0, 20)–(100, 90).
If the control IDs for the toolbar and status bar are 100 and 101, respectively, then the array you need to pass would be { *, *, ¤, 100, ¤, 101, 0, 0 } where * can be anything and ¤ can be any nonzero value.
{ *, *, ¤, 100, ¤, 101, 0, 0 }
Continuing from the above example, if the status bar were hidden, then the effective client rectangle would be (0, 20)–(100, 100) because hidden windows are ignored when computing the effective client rectangle.
Okay, first question: What is that special sense of visible I mentioned above? I didn't write simply visible because IsWindowVisible reports a window as visible only if the window and all its parents are visible. But all that GetEffectiveClientRect cares about is whether the window is visible in the sense that the WS_VISIBLE style is set. In other words, that the window would be visible if its parent is.
IsWindowVisible
WS_VISIBLE
Why does the GetEffectiveClientRect use this strange definition of visible? Because it wants to make it possible for you to get the effective client rectangle of a window while it is still hidden, the result being the effective client rectangle you would get once the window becomes visible. This is valuable because it allows you to do your calculations "behind the scenes" while the window is still hidden (for example, in your WM_CREATE handler).
WM_CREATE
Second question: Why is the integer array so crazy? What's with all the ignored values and the "must be nonzero" values? Why can't it just be the array { 100, 101, 0 }?
{ 100, 101, 0 }
The format of the integer array is the same as the one used by the ShowHideMenuCtl function. The intent was that you could use the same array for both functions. The two functions do work well together: The ShowHideMenuCtl function do the work of letting the user toggle the toolbar and status bar on and off, and GetEffectiveClientRect lets you compute the client rectangle that results.
ShowHideMenuCtl
That said, the GetEffectiveClientRect function is largely ignored nowadays. It doesn't do anything you couldn't already do yourself, and when you write your own version, you don't need to deal with that crazy integer array.
On our team's web site, buried among the other debugging documents, was a page titled simply "Magic 8 Ball"®¹. If you visited it, you got a dark blue circle with a lighter-blue triangle, on which appeared white text with a randomly-chosen message. The messages were things like
It was fun to give the 8-ball a shake, but the real purpose of the 8-ball was to be a link sent out in response to failure reports.
You see, there was a secret URL for each of the 8-ball's responses, so you could respond to a failure report with something like
The Magic 8 ball says... http://internalserver/magic8.asp?TWVGS
and when the person clicked on the link, they got an 8-ball that said "Known bug" or "Memory corruption".
Some teams liked the 8-Ball's responses so much, they asked us to add new custom messages to the repertoire.
Anyway, I was reminded of this by the story of Radio8Ball.
¹Magic 8-Ball is a registered trademark of Tyco Toys, Inc. When the Tyco scandal hit the airwaves, I always did a double-take before realizing that it was a different company.
Everybody has their own pet theory on how Vladimir Putin can retain power after the end of his second official term. I earlier wrote of one such theory: Change the constitution to permit a third term. In the intervening months, other theories have been put forth. Each one chips away at a different part of the statement that "the president can be elected to at most two consecutive terms":
There's also another method that merely plays by a different set of rules: Install a crony as president and pull the strings from backstage.
As I noted in my earlier entry, I'm much more fascinated by the machinery being put into motion to arrange for Putin to retain power than in whether he actually does.
On an unrelated note, Mark MacKinnon explains the magic phrase to use as a foreigner when pulled over arbitrarily by the police.