Holy cow, I wrote a book!
By default, the Background Intelligent Transfer Service (BITS)
which is used by Automatic Updates
will use idle network bandwidth for downloading updates.
This is normally not a problem.
One case where it can be a problem is
you have a large LAN that shares a single DSL connection.
BITS doesn't see that that DSL connection is shared.
Consequently, each computer on the LAN will be using its
idle network bandwidth to download updates and the total
of all the LAN computers doing this will
oversaturate the DSL connection.
[Typo fixed. 31-Jan-05.]
Another example where this can be a problem is if you have a
network card that connects to a hardware firewall which in turn uses
a dial-up modem to connect to the Internet.
(For example, you might connect through a classic Apple AirPort
which is in turn connected to a modem.)
BITS sees your fast network card and can't see that there is
a bottleneck further downstream.
As a result, it oversaturates the dial-up connection.
To tweak the BITS settings, you can fire up the Group Policy
Editor by typing "gpedit.msc" into the Run dialog. From there,
go to Computer Configuration, Administrative Templates,
Network, then Background Intelligent Transfer Service.
From there you can configure the maximum network bandwidth
that BITS will use.
You can even specify different BITS download rates based on
time of day, so that it downloads more aggressively while you're
sleeping, for example.
In a previous life, I wrote database software.
A customer complained that one of their reports was taking an
unacceptably long amount of time to generate, and I was asked
to take a look at it even though it wasn't my account.
The report was a vacation-days report, listing the number of
vacation days taken and available for each employee. Vacation
days accrued at a fixed rate but were granted only in
quarter-day increments. For example, if you earned 15 vacation
days per year and the year was 32% complete, then you had
accrued 32% × 15 = 4.8 vacation days, of which 4.75 were
available to use.
The existing code to round the number of accrued days down to
the nearest quarter-day went something like this:
* assume that at this point, ACCRUED is the number
* of accrued days.
* STR(ACCRUED,6,2) converts ACCRUED to a 6-character
* string: 3 integer digits, a decimal point, and two
* fractional digits. Excess fractional digits are rounded.
STORE STR(ACCRUED,6,2) TO S
STORE RIGHT(S,2) TO F && extract digits after decimal
IF F < "25"
F = "00" && 00 to 24 becomes 00
IF F < "50"
F = "25" && 25 to 49 becomes 25
IF F < "75"
F = "50" && 50 to 74 becomes 50
F = "75" && 75 to 99 becomes 75
ROUNDED = VAL(LEFT(S,4) + F) && reconstruct value and convert
In other words, the code converted the number to a string,
extracted the digits after the decimal point, did string comparisons
to figure out which quartile the fraction resided in, then
created a new string with the replacement fraction and converted
that string back to a number.
And all this in an interpreted language.
This code fragment was repeated each time rounding-down was
needed because the language supported only 32 subroutines,
and this procedure wasn't important enough to be worth kicking
out one of the other existing subroutines.
I replaced this seventeen-line monstrosity with the one-line
equivalent each time it occurred, and the report ran much faster.
(This is nowhere near the strangest way of implementing rounding.
There are far worse examples.)
Exercise: What is the one-line equivalent?
Exercise: What is the double-rounding bug in the original
If you have a file or directory that does not have a last-modified date, you may find that it causes Explorer to sort very strangely. (How do you get a file or directory with no last-modifiied date? It's hard to do; you need the help of an external file system.) Why is this?
As we learned earlier, a sort comparison function must impose a total order in order to produce consistent results. The problem is that Explorer's comparison function mis-handles files and directories with no last-modified date.
To get some more of the background behind this, you need to know about so-called "simple pidls". A simple pidl is an item ID list that refers to a file or directory that does not actually exist.
The problem is that a valid file or directory with no last-modified date looks just like one of these simple pidls becauses Explorer uses the last-modified date to distinguish whether it is manipulating a real pidl or a simple one.
The problems with sorting occur when it comes time to decide where in the list these "real pidls that are mistaken for simple pidls" go into the sorted list. Explorer tries to keep all folders together, but if it sees a "simple pidl" it can't tell whether that item is a folder or a file (after all, something that doesn't exist is neither a file nor a folder) and it ends up producing inconsistent comparison results.
Moral of the story: Be careful with your sort functions. If you produce inconsistent results in your sort function, you will get inconsistent results in your "sorted" output.
The CMD.EXE batch language
can be awfully cryptic,
but for those who miss the richness of command lines like
kill -1 $(ps -ef | grep inetd | grep -v grep | tr -s " " | cut -f2 -d " ")
Right on schedule, Alton Brown appeared at the Elliot Bay Book Company bookstore in downtown Seattle. One of my friends wondered aloud, "Wait a second, he's promoting his cookbook. How do you do a reading from a cookbook?"
He didn't read from his cookbook.
To an overflow crowd that probably violated a few fire codes, Alton Brown discussed what inspired him to tackle a book on baking, riffed with the audience (he's quite funny when interacting with a crowd), then fielded questions. Alton Brown trivia:
Afterwards, he signed books for ages and managed to be a good sport about it throughout. Then again, this is a book tour, after all. During that time, he's mastered the ability to sign a book and talk at the same time. I, on the other hand, am a rank amateur and couldn't even talk and watch him sign my book at the same time.
Not very well known is that the bottom two bits of kernel HANDLEs
are always zero; in other words, their numeric value is
always a multiple of 4.
Note that this applies only to kernel HANDLEs;
it does not apply to
or to any other type of handle
(USER handles, GDI handles, multimedia handles...)
Kernel handles are things you can pass to
the CloseHandle function.
The availability of the bottom two bits is buried in the
ntdef.h header file:
// Low order two bits of a handle are ignored by the system and available
// for use by application code as tag bits. The remaining bits are opaque
// and used to store a serial number and table index.
#define OBJ_HANDLE_TAGBITS 0x00000003L
That at least the bottom bit of kernel HANDLEs is always zero is implied by
the GetQueuedCompletionStatus function,
which indicates that you can set the bottom bit of the event
handle to suppress completion port notification.
In order for this to work, the bottom bit must normally be zero.
This information is not useful for most application writers,
which should continue to treat HANDLEs as opaque values.
The people who would be interested in tag bits are those who
are implementing low-level class libraries or are wrapping
kernel objects inside a larger framework.
Maybe they don't want people to find them.
The copyright notice for the web site of Hutchison Whampoa Limited states,
Copyright Hutchison Whampoa Limited. 2003. All rights reserved. No person, whether an individual or a body corporate, shall create or establish a hyperlink to the HWL Corporate Website by hypertext reference or imaging without the written permission of Hutchison.
Copyright Hutchison Whampoa Limited. 2003. All rights reserved.
No person, whether an individual or a body corporate, shall create or establish a hyperlink to the HWL Corporate Website by hypertext reference or imaging without the written permission of Hutchison.
I can't create a hyperlink so you'll have to find it yourself.
This isn't an issue of deep linking; they are banning even links to their home page.
Sometimes people try too hard.
You can download a
C# program to look for a file on your PATH,
or you can use a 90-character batch file:
@for %%e in (%PATHEXT%) do @for %%i in (%1%%e) do @if NOT "%%~$PATH:i"=="" echo %%~$PATH:i
The CreateProcess function
creates a new process, but it doesn't wait for the process
to get off the ground before returning.
It just creates the process object and lets it go to do its thing.
The Win32 process model is that each process initializes itself
in context. When a process object is created, it is practically
empty, save for enough information to get the program execution
procedure started. When the thread in the process object is
scheduled, it starts doing the real work of loading DLLs,
initializing them in the correct order, then calling to the
program's entry point.
If, along the way, one of these process startup steps fails,
the process is killed, and the exit code is the reason why
the process couldn't get started. For example, if the problem
was that a function could not be found in a DLL, the exit code
will be STATUS_ENTRYPOINT_NOT_FOUND.
(And don't forget that you can use
the SetErrorMode function
to disable the error dialog.)
I remember a bug report that came on in an old MS-DOS program
(from a company that is still in business so don't ask me to
identify them) that attempted to open the file "". That's the file
with no name.
This returned error 2 (file not found). But the program didn't check the
error code and though that 2 was the file handle. It then
began writing data to handle 2, which ended up going to the screen
because handle 2 is the standard error handle, which by default goes
to the screen.
It so happened that this program wanted to print the
message to the screen anyway.
In other words, this program worked completely by accident.
Due to various changes to the installable file system in Windows 95,
the error code for attempting to open the null file changed from 2
(file not found) to 3 (path not found) as a side-effect.
Watch what happens.
The program tries to open the file "". Now it gets error 3 back.
It mistakenly treats the 3 as a file handle and writes to it.
What is handle 3?
The standard MS-DOS file handles are as follows:
What happens when the program writes to handle 3?
It tries to write to the serial port.
Most computers don't have anything hooked up to the serial port.
The write hangs.
Result: Dead program.
The file system folks had to tweak their parameter validation so
they returned error 2 in this case.