Holy cow, I wrote a book!
This quick puzzle floated past one of our internal discussion groups.
// in process A
hEventA = CreateEvent(NULL, FALSE, TRUE, TEXT("MyNamedEvent"));
// in process B
hEventB = OpenEvent(EVENT_MODIFY_STATE, FALSE, TEXT("MyNamedEvent"));
In Process B, the OpenEvent succeeds, but the
WaitForSingleObject returns immediately instead of
[Correction: I confused the matter by passing TRUE as
the third parameter, thereby creating an event that is initially
signalled. Change it to FALSE so that the event
is created non-signalled, in which case the
WaitForSingleObject would be expected to wait.]
It didn't forget them; it's just double-checking with you.
The developer responsible for CD autoplay
in Windows XP SP2 explained it to me.
There were two problems with the way Windows XP handled CD autoplay.
when you installed a new program that included CD autoplay capability,
many users didn't know where in the UI to go to select that new program
as their default CD autoplay program.
If they had previously selected a program and ticked
"Always perform this action",
there was no easily-discoverable way
to undo the "always" flag to make the dialog reappeared
and allow the user to select the new program instead.
many programs, upon installation,
secretly hacked the undocumented CD autoplay settings
in order to set themselves as the default CD autoplay handler,
gleefully overriding the user's previously-stated preference.
Because these programs egotistically believed themselves to be
the coolest most amazing program ever written in the history of mankind.
In other words, the two problems were,
"I just installed this program
and I want it to be the CD autoplay program"
and its converse
"I just installed this program
and I don't want it to be the CD autoplay program".
Windows XP SP2 introduced new behavior related to CD autoplay
in an attempt to address these problems:
When it sees that a new CD autoplay handler is available,
it shows you the CD autoplay dialog one more time.
This gives you a chance to (a) pick that new program you just
installed, or (b) un-pick that program you just installed
(if it was presumptuously rude enough to set itself as your default).
The first time you insert a CD into your computer after upgrading to
Windows XP SP2, you will also get the CD autoplay dialog.
This is a "better late than never" dialog to cover for any handlers
that were installed before you upgraded to Windows XP SP2.
What's the moral of the story?
Whereas in the old days, you only had to worry about helping other programmers
interface with your feature,
in the new software landscape,
you also have to worry about stopping programmers who
are trying to abuse your interface.
Mark your calendars for
the 2005 Seattle Chicken Tour,
scheduled this year for July 16th.
Seattle Tilths Annual City Chickens and Coop Tour
July 16, 2005 10 am — 4 pm
$10 per family or group of four
Seattles city chickens owners invite you
into their backyards for a first-hand look at raising chickens.
Discover the variety of breeds that might be nesting in your neighborhood,
learn about raising chickens,
see how families integrate chickens into their organic gardening practices,
as well as the ingenious coops that shelter these chickens.
You will need a car to travel on this self-guided tour
of over a dozen backyard chicken broods.
Bring the whole family, and your out-of-town visitors,
for this unique view of Seattles backyards.
I am not certain whether advance registration is required,
so if you're interested, you should contact
Seattle Tilth sooner rather than later.
In response to the news that
strncpy is so dangerous,
at least one person has called for Visual Studio to
revoke support for such a dangerous function,
considering the continued support for the function
grounds for holding the compiler manufacturer liable for any defects
in programs compiled with that compiler.
Well, for one thing, while it's true that strncpy
is dangerous if used improperly, it is still a valid function,
and my original discussion explained the history behind
strncpy and the very specific scenario
in which it is still useful.
It just so happens that most people don't use the function in the
manner it was intended, but instead treat it as a sort of
"copy string with a character limit" function, which it isn't really.
For another thing, just because something is dangerous doesn't
mean it shouldn't be supported. Pointers and casts are dangerous, but
I don't see them disappearing from C or C++ any time soon.
Third, support for strncpy is mandated by the C standard.
If you removed it, you couldn't call yourself a C compiler any more.
(Not to mention breaking compatibility with existing source code that
uses the strncpy function. How would you like it if you
bought a so-called C compiler and found that it
couldn't compile a large class of valid C programs?)
Okay, maybe you never wondered why you never saw a vomiting rat,
the intrepid researchers at
the Annals of Improbable Research
have discovered that
there's a good reason,
Anne's rat page
explain in more detail than you probably wanted.
Probably the biggest advantage of 64-bit Windows is not the larger registers
but rather the expansive 64-bit address space.
Recall that even when the /3GB switch is set,
32-bit programs receive only 2GB of address space unless they
indicate their willingness to cope with addresses above 2GB by
passing the /LARGEADDRESSAWARE flag.
This flag means the same thing on 64-bit Windows.
But since 64-bit Windows has a much larger address space available
it can afford to give the 32-bit Windows program the entire
4GB of address space to use.
This is mentioned almost incidentally in
Knowledge Base article Q889654
in the table "Comparison of memory and CPU limits
in the 32-bit and 64-bit versions of Windows".
In other words, certain categories of 32-bit programs
(namely, those tight on address space)
benefit from running on 64-bit Windows machine,
even though they aren't explicitly taking advantage of any 64-bit features.
In an earlier article,
I presented a simple way of avoiding timing overflows
which seemed to create a bit of confusion.
The short version: Given a starting time start,
an ending time end and an interval interval,
the way to check whether the interval has elapsed is to use the
expression end - start >= interval.
The naive expression end >= start + interval
suffers from integer overflow problems.
end - start >= interval
end >= start + interval
To simplify the discussion, let's operate in base-100 instead of
base-232. The same logic works, but I think operating
in base-100 will be easier to follow.
Base-100 means that we remember only the last two digits of any number.
Consider a starting time of start = 90 and an
interval of interval = 10. Using the wrong expression
yields end >= start + interval = 90+10 = 100 = 0.
In other words, end >= 0 which is always true since
end has the range 0...99. As a result,
the wrong expression will think that the interval has expired prematurely.
start = 90
interval = 10
end >= start + interval = 90+10 = 100 = 0
end >= 0
Using the correct expression, we have end - 90 >= 10.
Of the numbers 0..99, the ones that give a difference
less than 10 are 90 through 99.
Once end = 0, the result is 0 - 90 = 10,
which correctly indicates that 10 ticks have elapsed since 90
once the timer reaches 0.
end - 90 >= 10
end = 0
0 - 90 = 10
You can work through a similar mistake using start = 89
instead of start = 90; in this case, the wrong expression
end >= start + interval = 89 + 10 = 99,
or in other words, end >= 99. This has the opposite
problem from the previous case, namely that the expression will fail
to detect that the interval has expired once the timer rolls over.
start = 89
end >= start + interval = 89 + 10 = 99
end >= 99
But why does the end - start expression work?
It's very simple: You just have to remember your rules of arithmetic
from elementary school.
end - start
(x - c) - (y - c) = x - c - y + c = x - y
This rule is useful because it lets you delay the overflow as long
as possible by subtracting the starting point from all your time
markers; it has no effect upon time intervals.
Wouldn't it be great if start = 0? Then the overflow
won't happen for 100 ticks. Well, you can act "as if" the starting
point were start = 0 by simply subtracting
start from all your time markers.
start = 0
Those who prefer a graphical view can think of time passing as
the hands around a clock (which wraps around at 60 minutes, say).
When you decide to record your start point, rotate the clock
so that the "12" precisely lines up with wherever the hand happens
to be. You can now read off the elapsed time directly from your
rotated clock. Rotating your clock is the same as subtracting
(or adding) a constant to all time markers.
Of course, this trick falls apart once you have to measure time
intervals that come close to the wraparound time of your timer.
In our 100-tick timer, for example, trying to measure the passage
of 90 ticks is very difficult because there is only a 10-tick window
where the inequality is satisfied. If we fail to catch the timer
during that window, we miss it and have to wait another 90 ticks.
So don't do that. In practical terms, this means that you shouldn't
use GetTickCount to measure time intervals longer
than 15 days.
reported on a startling discovery in Chicago:
That government jobs go not to those best qualified to
perform them, but rather to those with the best connections.
Who'd-a thunk it?
Shocked by this discovery, the Daley administration
vowed to end it.
The City of Chicago's top lawyer Mara Georges told
incredulous City Hall reporters yesterday
the hiring system will now be completely fair, objective,
and free of political influence.
"City hiring will be on the square, yes."
The Associated Press notes that
"City officials have long denied
that political favoritism or patronage
had anything to do with who got jobs."
The Chicago Sun-Times
captures the sentiment quite succinctly:
Who knew politics as usual in Chicago is against the law?
Some people attempt to simulate keyboard input to an application
by posting keyboard input messages, but this is not reliable for
First of all, keyboard input is a more complicated matter than
those who imprinted on the English keyboard realize.
Languages with accent marks have dead keys,
Far East languages have a variety of Input Method Editors,
and I have no idea how complex script languages handle input.
There's more to typing a character than just pressing a key.
Second, even if you manage to post the input messages into
the target window's queue, that doesn't update the keyboard
shift states. When the code behind the window calls
the GetKeyState function
the GetAsyncKeyState function,
it's going to see the "real" shift state and not the fake
state that your posted messages have generated.
The SendInput function
was designed for injecting input into Windows.
If you use that function, then at least the shift states will be
reported correctly. (I can't help you with the complex input problem,
Everyone "knows" that the following pairs of expressions are equivalent:
x*2 ≡ x<<1
x/2 ≡ x>>1
Too bad they aren't.
In the C language standard, there is no requirement that
the internal representation of signed integers be two's complement.
All the permissible representations agree for positive numbers,
but negative numbers can have different representations.
If x is negative, then x*2 and
x<<1 are quite different on a sign/magnitude system.
However, Win32 requires a two's complement machine, in which case
the first equivalence
x*2 ≡ x<<1 is indeed always true.
Of course, the compiler is free to recognize this and rewrite your
multiplication or shift operation. In fact, it is very likely to
do this, because x+x is more easily
pairable than a multiplication or shift.
Your shift or multiply-by-two is probably going to be rewritten as
something closer to an add eax, eax instruction.
add eax, eax
As for the second so-called equivalence, the C language specification
originally did not specify whether division of a negative number by
a positive number rounds towards or away from zero, but in 1999,
the specification was revised to require rounding towards zero.
Furthermore, the result of a right-shift of a negative value is
unspecified, so the expression x>>1 has an unspecified
result if x is negative.
Even if you assume that the shift fills with the sign bit,
The result of the shift and the divide are different
if x is negative.
(-1) / 2 ≡ 0
(-1) >> 1 ≡ -1
The moral of the story is to write what you mean.
If you want to divide by two, then write "/2",