Holy cow, I wrote a book!
For example, many functions in the shell accept a window handle
parameter to be used in case UI is needed.
IShellFolder::EnumObjects, for example.
What happens if you pass GetDesktopWindow()?
If UI does indeed need to be displayed, you hang the system.
Put this together: If the owner of a modal dialog is the desktop,
then the desktop becomes disabled, which disables all of its
descendants. In other words, it disables every window in the
system. Even the one you're trying to display!
You also don't want to pass GetDesktopWindow() as your
hwndParent. If you create a child window whose parent is
GetDesktopWindow(), your window is now glued to the desktop
window. If your window then calls something like
MessageBox(), well that's a modal dialog, and then the rules
above kick in and the desktop gets disabled and the machine
So what window do you pass if you don't have a window?
Pass NULL. To the window manager, a parent of NULL means
"Create this window without an owner." To the shell, a UI window
of NULL typically means "Do not display UI," which is likely
what you wanted anyway.
Be careful, though: If your thread does have a top-level unowned
window, then creating a second such window modally will create much
havoc if the user switches to and interacts with the first window.
If you have a window, then use it.
Nothing is explicitly written about this topic, but you can
put on your logic cap and figure it out.
If you need an invalid thread ID, you can use zero.
How do you know that zero is an invalid thread ID?
It's implied by
Notice that if you pass zero, then the hook is installed into
all threads on the current desktop.
This implies that zero is not itself a valid thread ID.
This sentinel value is confirmed by
GetThreadID, which uses zero as its error return value.
Similarly, if you need an invalid process ID, you can use (DWORD)-1.
This comes from
The value ASFW_ANY has special meaning,
which implies that it is never a valid process ID.
Or, you can use zero as your invalid process ID,
since that is the error value returned by
Who knew that
Dr. Evil designed CPUs, too!
Okay, I was hoping it wasn't going to be needed but it takes only one bad apple...
Here are the ground rules.
Things that increase the likelihood that your comment will be edited or deleted:
If a wave of comment spam is under way,
I may choose to moderate or even close comments until the problem subsides.
More rules may be added later, but I hope it won't be necessary.
All postings are provided "AS IS" with no warranties and confer no rights.
Opinions expressed are those of the respective authors.
More legal stuff here.
[31 May 2004:
Add exceptions for broken link repair.
2 Dec 2004:
Add disclaimer and exception for fixing typos.
13 Dec 2004:
Add remark on temporary closure of comments during spam attacks.
15 Mar 2005: Add remark for off-topic comments.
20 Mar 2007: No "outing".
25 Dec 2008: No disrespectful behavior.
12 March 2009: Examples of insults.
8 July 2010: Self-starring.]
This is a sure sign that you didn't register your CLSID properly;
most likely you forgot to set your threading model properly.
(And if you fail to specify a threading model at all, then
you get the dreaded "main" threading model.)
If somebody tries to create a COM object from a thread whose
model is incompatible with the threading model of the
COM object, then a whole bunch of marshalling stuff kicks in.
And if the marshalling stuff isn't there, then COM can't use your
a long and very technical article in MSDN on COM threading models
which has lots of scary-looking diagrams and tables.
In particular, the second scary table in the
"In-process servers: (almost) totally dependent on their clients"
chapter lists all the combinations of thread models with object
threading models, and what COM tries to do in each case.
In particular, notice that if you have a (mistakenly marked) "main"-threaded
object and somebody on any thread other than the main thread
tries to create it, marshalling will try to kick in.
This is one of those "Oh, that's an easy change" bugs.
The discussion probably went like this:
Some guy whose idea this was:
"For stability reasons, we want to lower the default video acceleration
for Server a notch. Dear Video Setup team, can you do that for us?"
Video Setup team: "Sure thing, that's no problem.
The default setting is all done by us; it should not have any impact
on anybody else. We'll just do it and be done with it."
Guy: "Sweet. Thanks."
And bingo, the default video acceleration dropped to one notch below full
on Server, and everyone was happy.
Except that there's this text tucked away in the Display control panel
that has the word "(recommended)" next to "full acceleration".
That didn't get updated. Oops.
(I wouldn't be surprised if there is also some
help text that didn't get updated for this change.)
No code is an island.
Endpoint-exclusive RECTs and lines are much easier to work with.
For example, the width of a rectangle is right - left,
and its height is bottom - top.
If rectangles were endpoint-inclusive, then there would be annoying
right - left
bottom - top
End-point exclusive rectangles also scale properly.
For example, suppose you have two rectangles (0,0)-(100,100) and
(100,100)-(200,200). These two rectangles barely touch at the
corner. Now suppose you magnify these rectangles by 2, so they
are now (0,0)-(200,200) and (200,200)-(400,400). Notice that
they still barely touch at the corner. Also the length of each
edge doubled from 100 to 200.
Now suppose endpoints were inclusive, so the two rectangles would
be (0,0)-(99,99) and (100,100)-(199,199). Now when you double
them, you get (0,0)-(198,198) and (200,200)-(398,398). Notice
that they no longer touch any more because (199,199) is missing.
Note also that the length of the side of the square is now 199
pixels instead of 200.
Similar problems occur if you need to do subpixel computations.
Well, magnification is used more than you think. In addition to
the obvious things like zooming in/out, it's also used in
printing (since printers are 300dpi but the screen is usually
much lower resolution) and in GDI mapping (ScaleWindowExtEx,
StretchBlt). And subpixel computations are used in
With apologies to Alvy Ray,
I think the best way to interpret this is to view pixels
as living between coordinates, not at them.
here's a picture of the pixel that lives between (10,10) and (11,11).
(In other words, this pixel is the rectangle (10,10)-(11,11).)
Observe that this rectangle starts at (10,10) and ends at (13,12),
just like its coordinates say.
What's the difference?
As you can guess from the title of this entry,
GetDialogBaseUnits is a crock.
Since there is no HWND parameter to GetDialogBaseUnits,
it doesn't know which dialog box's DLUs you want to retrieve.
So it guesses.
And it always guesses wrong.
GetDialogBaseUnits returns the dialog base units
for dialog boxes that use the default system font.
But nobody uses the default system font any more.
It screams "old and dorky".
But it remains the default for compatibility
reasons. (And therefore so too does GetDialogBaseUnits.)
Everybody selects a custom font for their dialog box,
usually "MS Sans Serif 8" or possibly "Tahoma" if they
are one of those hip Windows 2000 folks.
That is why you must use MapDialogRect.
function accepts a dialog box handle so it can use the
Somebody@somewhere.else described me as having the social skills
of a thermonuclear device.
I don't remember the incident in question, but I'll have to accept
that it happened.
I have a very low tolerance for laziness.
If you come to me for help,
I expect you to have done your homework.
(Though I try to scale my expectations to your position.
If you're in a coding position then you had better know
how to use a debugger.
If you're in a testing position, then you had better know
at least how to install the debugger.
This is considered part of the standard skill set for a tester.)
But the absolute worst thing you can do is start a conversation by
saying, "Hey, Raymond, since you know everything,
can you do this for me...?"