Holy cow, I wrote a book!
And if you do it wrong, focus will get all messed up.
If you are finished with a modal dialog, your temptation
would be to clean up in the following order:
But if you do that, you'll find that foreground activation doesn't go back
to your owner. Instead, it goes to some random other window.
Explicitly setting activation to the intended owner "fixes"
the problem, but you still have all the flicker,
and the Z-order of the interloper window gets all messed up.
What's going on?
When you destroy the modal dialog, you are destroying
the window with foreground activation.
The window manager now needs to find somebody else to give
It tries to give it to the dialog's owner, but the owner is
so the window manager skips it and looks for some other
window, somebody who is not disabled.
That's why you get the weird interloper window.
The correct order for destroying a modal dialog is
This time, when the modal dialog is destroyed, the
window manager looks to the owner and hey this time
it's enabled, so it inherits activation.
The NTFS and FAT filesystems store times and dates differently.
Note, for example, that FAT records last-write time only to two-second
accuracy. So if you copy a file from NTFS to FAT, the last-write
time can change by as much as two seconds.
Why is FAT so much lamer than NTFS? Because FAT was invented in 1977,
back before people were worried about such piddling things like
time zones, much less Unicode. And it was still a major improvement
over CP/M, which didn't have timestamps at all.
It is also valuable to read and understand the consequences of
FAT storing filetimes in local time, compared to NTFS storing
filetimes in UTC.
In addition to the
Daylight Savings time problems,
you also will notice that the timestamp will appear to change if
you take a floppy across timezones.
Create a file at, say, 9am Pacific time, on a floppy disk.
Now move the floppy disk to Mountain time.
The file was created at 10am Mountain time, but if you look
at the disk it will still say 9am, which corresponds to 8am Pacific time.
The file travelled backwards in time one hour.
(In other words, the timestamp
failed to change when it should.)
The long answer:
When balloon tips were first developed, there was no ability
to embed links.
Consequently, programs were free to put insecure text in balloon tips,
since there was no risk that they would become "live".
So, for example, a virus scanner might say
"The document 'XYZ' has been scanned and found to be
free of viruses."
Now suppose hotlinks were supported in balloon tips.
Look at how this can be exploited:
I can write a web page that goes
You download the message and since you are a cautious person,
you ask your virus scanner to check it out.
The balloon appears:
"Oh, how convenient," you say to yourself.
"The virus scanner even included a hotlink to the document
so I can read it."
And then you click on it and your hard drive gets reformatted.
"So why don't you add a NIF_PARSELINKS flag, so people
who want to enable hotlinks in their balloon tips can do so,
and still remain compatible with people who wrote to the old API?"
(I've heard of one person trying to pass a TTF_PARSELINKS flag
member and wondering why it wasn't
working. I hope it's obvious to everybody why this had no chance
Because that would just be passing the buck.
Anybody who used this proposed flag would then have to
be extra-careful not to put untrusted links in their balloon
tips. Most people would just say, "Wow! A new flag!
That's awesome!" and start using it without considering
the serious security implications.
Then somebody can trick the program into putting untrusted
text into a balloon tip and thereby exploit the security hole.
"Aw, come on, who would be so stupid as to write code without
considering all the security implications?"
The best way to make sure things are secure is to make it
impossible to be insecure.
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.