Holy cow, I wrote a book!
A customer noticed that environment variables were being
truncated at 2047 characters and wanted to know what
the maximum length of an environment variable is.
This is one of those cases where you can answer the customer's
question or you can try to answer the question the customer is
If you just answer the question, you're doing the customer a disservice.
The theoretical maximum length of an environment variable
is around 32,760 characters.
However, you are unlikely to attain that theoretical maximum in
All environment variables must live together in a single environment
block, which itself has a limit of 32767 characters.
But that count is the sum over all environment variable names and
so you could, I guess, hit that theoretical maximum length if
you deleted all the environment variables and then set a single
variable called X with that really huge 32,760-character value.
In practice, of course,
you have to share the environment block with all the other
variables in the block,
so your random call to SetEnvironmentVariable with
a 32,760-character string is unlikely to succeed.
But that's not your only practical limit.
It also depends on how you're setting the variable;
i.e., the code that your environment-variable-setting technique
passes through before it gets to the
If you're using a batch file,
then you're constrained by
the maximum command line length
since the environment variable needs to fit into the command line
buffer of the batch processor.
On the other hand, maybe you're setting the Environment registry key,
in which case
you run into a 2048-character limit
in the code that parses that registry key and builds an environment
block out of it.
There's also a limitation in the dialog box for interactively
setting environment variables, the numeric value of which I don't
happen to know off the top of my head.
This is one of those skills you have to develop when answering
questions from customers:
Taking the customer's question and trying to figure out
what their real question is.
There was quite a bit of reaction to what I thought was a simple
"Hey, here's what's going on" article from last year,
specifically on how the Adaptive Display Timeout means that
Windows doesn't always start the screen saver exactly on time.
As you may recall, this feature adjusts the time it takes for
the screen saver to activate if the user keeps dismissing it
immediately after it starts.
One of those small things that makes the computer adapt to you
rather than vice versa,
and an adaptation that you probably don't even notice when it happens.
I think these two responses below summarize the extremes of
the types of reactions this feature generated.
Vista/W7 has some nice touches too.
Such little things is what we love about Macs.
Ich finde das erstaunlich.
In einem Linux-System kann man soetwas relativ leicht selber scripten,
und sich z.B. einen Button erzeugen,
der den Bildschirmschoner kurzzeitig ganz ausschaltet.
Sowas geht unter Windows freilich auch, aber kaum ein User
kennt das System hinreichend gut.
Deshalb stellen sich dort solche Probleme. Erstaunlich.
This is incredible.
On Linux, you can script this yourself relatively easily
and create, for example, a button which
completely disables the screen saver for a short time.
Admittedly, you can also do this on Windows, but
hardly any users know the system that well.
And therefore we have these types of problems.
On the one hand, the feature is something so cool,
it must have been stolen from a Mac.
On the other hand, this feature shows everything that is
wrong with Windows.
I mean, on Linux, you can solve this problem by simply
writing a script!
Surely by now
you've seen the video
where NetGenHacker101 shows you how
to use the "Tracer T" program to view "how many IP's are
looking at Google", their name, and connection speed (to then to then to then).
(And commenter squizz
explains why it "worked" in spite of the http prefix.)
But more awesome is the fact
that somebody ported the video to linux!
Bonus video craziness:
It's in Korean but somehow that just adds to the insanity.
(Warning: Five minutes of your life you will never get back.)
The comments on the YouTube video identify the song as
"Bo Peep Bo Peep <- possibly
the most addictive/annoying song ever."
I was in the grocery store,
and there was a sign advertising a new product.
Delight in a cup
Your favorite XYZ Ice Cream
Now in convenient single-serve cups.
Delight in a cup
Your favorite XYZ Ice Cream
Now in convenient single-serve cups.
I took a look at the cup.
Seemed kind of big for a single serving.
I picked one up to read the nutritional information.
Servings per container: 2
It has been
that South Carolina now
requires "subversive groups" to register
with the Secretary of State
(and pay a $5 filing fee).
Curiously, the list of organizations which must register include
"an organization subject to foreign control."
I wonder if this means that all consulates have to register,
and that when any foreign dignitary visits
South Carolina, they have to pay a $5 filing fee.
(Not to mention all foreign-owned companies like Shell Oil.)
Actually, it has been pointed out that a "subversive organization"
includes one which advocates, teaches, or practices the propriety
of controlling the government of the United States.
I guess this means all political parties are subversive organizations.
(Something most of us knew already.)
And apparently, in your registration, you also have to
include the bylaws or minutes of meetings from the last year.
I wonder whether you have to resubmit the minutes each year.
I'm sure somebody could keep a government bureaucrat busy for a long time
by submitting hundreds of pages of "minutes".
Anyway, this is a long and largely superfluous set-up for a different story.
The mother of a colleague of mine came to visit from Canada.
For some reason, the United States requires visitors to fill out a
questionnaire asking them whether they are a drug dealer,
whether they are a Nazi war criminal, and this question:
Do you advocate the overthrow of the United States government
by force or subversion?
The sweet old lady
studied the question for a while,
then circled force.
On the form, it also says
"Answering Yes will not necessarily
exclude you from admission to the United States."
FindFirstFile, when asked to provide information about
a symbolic link,
returns information about the link itself and not the link destination.
If you use the FindFirstFile function,
you can tell that you have a symbolic link because the
file attributes will have the FILE_ATTRIBUTES_REPARSE_POINT
and the dwReserved0 member will contain the special value
Okay, great, so now I know I have a symbolic link,
but what if I want information about the link target?
For example, I want to know the size of the link target,
its last-modified time, and its name.
To do this, you open the symbolic link.
The I/O manager dereferences the symbolic link and gives
you a handle to the link destination.
You can then call functions like
to obtain information about the symbolic link target.
If the field is called dwReserved0,
shouldn't it be off limits?
Why isn't the field called dwReparsePointType?
Oscar Night is a few weeks away, but
when you settle in to watch the show with your bowl of popcorn,
please be aware that inhaling deeply from the
fumes of a freshly-opened bag of microwave popcorn is
not the greatest decision you can make from a health standpoint.
(Then again, you probably ought to reconsider
eating microwave popcorn in the first place,
but let's leave that aside.)
A disease informally known as popcorn lung afflicts
people who work in popcorn factories and has been known since 2002.
But in 2007,
doctor diagnosed the first case of popcorn lung in an end-user.
The risk is not from eating the popcorn but from breathing it.
"This patient described enjoying the smell so much he was
actually inhaling the steam."
The best part of the article was when the patient was asked,
"Are you around a lot of popcorn?"
"I am popcorn."
Update: Oscar Night is
not actually this weekend.
That's what happens when you schedule your blog entries over a year
in advance and have to guess when Oscar Night is coming.
why programs run more slowly when the system is running with
Well, for one thing, of course, when you have more than one monitor,
there's more stuff on the screen for the system to keep track of.
It's the same reason that programs run more slowly on a large monitor
than on a small monitor.
And if there's only one monitor,
then functions like MonitorFromPoint become
trivial if the flag is something like MONITOR_DEFAULTTONEAREST,
because when there's only one monitor,
answering questions like "What monitor is closest to this point"?
becomes very easy.
If your two monitors are not the same dimensions,
then the union of the two monitors will not be rectangular,
which makes clipping against the union of all monitors
But I suspect the big penalty for multiple monitors
kicks in if you make the mistake of setting your monitors
to different color formats,
for example, if you set one monitor to 565 format
and set another to 24bpp.
If the two monitors do not use the same color format,
then programs will be forced to use DIBs instead of DDBs
for screen bitmaps,
in case a window is moved to a window with a different
color format (or worse, is positioned so it straddles
two monitors with different color formats).
In principle, programs need only use the "worst-case" DIB;
for example, if one monitor is 555 and the other is 565,
then a 565 DIB will suffice.
In practice, however, most programs just fall back to a
24bpp or 32bpp DIB when faced with monitors with different
(You query whether all monitors have the same color format
by calling GetSystemMetrics(SM_SAMEDISPLAYFORMAT).)
Since a format conversion takes place when a DIB is blitted
to a device with a different color format,
forcing a program to retain its bitmaps as DIBs means that
for at least one of the monitors (and probably both),
you're going to undergo a format conversion when that DIB
is drawn to the screen.
There are also
a few miscellaneous optimizations which are disabled
when not all your monitors use the same color format
because the cost of using DIBs outweighs the savings
from the optimization.
So if you haven't already,
go into your display settings and check that you set all
your monitors to the same color depth.
If you don't do this,
then a large class of graphics optimizations is lost.
Not sure it helps, though.
We saw fibers a long time ago when I looked at how you can
use fibers as a form of coroutines to simplify the writing of
A fiber is a handy tool,
but it's a tool with very sharp edges.
fibers are promiscuous with threads,
you have to be careful when running code that cares
about what thread it is running on,
because that code may discover that its thread
changed out from under it.
For example, critical sections and mutexes remember which thread
If you enter a critical section on a fiber,
and then you unschedule the fiber,
then reschedule it onto a different thread,
and then you leave the critical section,
your critical section will end up corrupted because
you broke the rule that says that a critical section
must be exited on the same thread that entered it.
Actually, you were already in bad shape once you unscheduled
the fiber while it owned a resource:
An unscheduled fiber cannot release the resource.
Unscheduling a fiber is like
suspending a thread:
Anybody who later waits for that fiber to do anything will be
waiting for an awful long time,
because the fiber isn't running at all.
The difference, though, is that the fiber is unscheduled at controlled
points in its execution, so you at least have a chance at suspending
it at a safe time if you understand what the fiber is doing.
For example, suppose you enter a critical section on a fiber,
and then unschedule the fiber.
Some time later, a thread (either running as a plain thread
or a thread which is hosting a fiber)
tries to enter the critical section.
One of two things can happen:
if you use an object which has thread affinity on a fiber,
you are pretty much committed to keeping that fiber on that
thread until the affinity is broken.
This affinity can be subtle,
because most code was not written with fibers in mind.
Any code which calls TlsGetValue has thread
because thread local storage is a per-thread value,
not a per-fiber value.
(This also applies to moral equivalents to TlsGetValue,
like code which calls GetCurrentThreadId and uses it as
a lookup key in a table.)
You need to use FlsGetValue to get values
which follow fibers around.
But on the other hand, if the code is not running on a fiber,
then you can't call FlsGetValue since there is no
fiber to retrieve the value from.
This dichotomy means that it's very hard if not impossible
to write code that is both thread-safe and fiber-aware
if it needs to store data externally on a per-thread/fiber basis.
Even if you manage to detect whether you are running on a thread or
a fiber and call the appropriate function,
if somebody calls ConvertThreadToFiber or
then the correct location for storing your data changed
behind your back.
If you are calling into code that you do not yourself control,
then in the absence of documentation to the contrary,
you don't really have enough information to know whether
the function is safe to call on a fiber.
For example, C runtime functions like
have thread affinity (even though there's nothing obviously
threadlike about comparing strings)
because they rely on the current thread's locale.
(similar to the bottom line from
You have to understand the code that runs on your fiber,
or you may end up accidentally stabbing yourself in the eyeball.
Structured exception handling is fiber-safe since it
is stack-based rather than thread-based.
Note, however, that when you call ConvertThreadToFiber,
any active structured exception handling frames on the thread
become part of the fiber.