February, 2010

  • The Old New Thing

    What is the maximum length of an environment variable?

    • 25 Comments

    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 really asking. 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 practice.

    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 values, 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 SetEnvironmentVariable call. 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.

  • The Old New Thing

    It appears that car park computers revert to their native language, German, when placed under stress

    • 25 Comments

    A car park in Birmingham switches from English to German in times of stress.

    That reminded me that over a decade ago, a colleague of mine noticed an error message on the screen at the exit to the parking garage at the Seattle-Tacoma International Airport. The way the airport works, you pick up a ticket as you enter, and you pay your parking fee at vending machines stationed around the parking garage, and at the exit, you insert the (paid) ticket into the machine, which verifies that you paid your parking fee and opens the gate.

    When my colleague pulled up to the machine, instead of displaying the expected Please insert ticket message, it had an error message. In German.

    Fortunately, my colleague knows German, and he recognized the error message as a Windows 95 serial port conflict resolution dialog. While he was trying to figure out how to click Abbrechen on a machine with no mouse or keyboard, an attendant walked up, took his ticket, and opened the gate.

    Just another example which demonstrates that parking garage computers are native speakers of German, and they revert to it when placed in stressful situations.

  • The Old New Thing

    Microspeak: Future-proofing

    • 16 Comments

    It has been famously said that England and the United States are two countries separated by a common language. The same holds true for Microspeak.

    In the Redmond dialect of Microspeak, we talk about extensibility: Designing a system with specific points where features can be added in the future, often by outside parties. For example, an example of an extensibility point in the shell would be a context menu handler or a namespace extension.

    In the Reading dialect of Microspeak, the term for this is future-proofing.

    On the other hand, if you use the term future-proofing in Redmond, people will interpret it differently. In Redmond, future-proofing means designing a system so that it continues to function without alteration, even if something happens in the future. (For example, one example of future-proofing—in the Redmond sense of the term—would be using a function like SHGetSpecialFolderPath instead of hard-coding the path to a directory.)

    Update: Some folks have taken issue with this definition, and I will have to defer to their local knowledge. I get my reports on the Reading dialect of Microspeak from my contacts there, so it's possible that they were mistaken, or that the usage was peculiar to their workgroup and incorrectly extrapolated to the entire dialect.

  • The Old New Thing

    It looks a little like CMD except there is white on the background

    • 27 Comments

    Surely by now you've seen the video where NextGenHacker101 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."

  • The Old New Thing

    Why can't I use the linker to delay-load a function from kernel32?

    • 20 Comments

    For some time (I am too lazy to look up when it was introduced), the Visual Studio linker has supported a feature known as delay-loading. But why can't you use this feature to delay-load a function from kernel32? It would be very handy: If you write

    if (CurrentWindowsVersionSupportsKernelFunctionXyz())
    {
      Xyz(...);
    }
    

    the program fails to load on versions of Windows which do not support the function Xyz because the Win32 load rejects loading a module that contains unresolved references. On the other hand, if you could mark kernel32 as delay-loaded, then the code above would work, since the call to Xyz would be redirected to a stub that calls GetProcAddress. Since the GetProcAddress is performed only when the code path is hit, the loader won't complain at load time. But if you try to delay-load kernel32, the linker gets upset at you. Why won't it let me delay-load kernel32?

    The linker delay-load feature operates on the DLL level, not on the function level. When you put a DLL on the /DELAYLOAD list, the linker changes all calls to functions in that DLL into calls to linker-generated stubs. These stubs load the target DLL, call GetProcAddress, then resume execution at the target function.

    Since the delay-load feature operates on the DLL level, if you put kernel32 on the delay-load list, then all calls to functions in kernel32 turn into calls to stubs.

    And then you are trapped in this Catch-22.

    When a function from kernel32 gets called, transfer goes to the stub function, which loads the target DLL (kernel32) to get the target function. Except that loading the target DLL means calling LoadLibrary, and finding the target function means calling GetProcAddress, and these functions themselves reside in kernel32.

    Now you're trapped. To load kernel32, we need to call LoadLibrary, but our call to LoadLibrary was redirected to a stub which... calls LoadLibrary.

    Sure, the linker folks could have added special casing for kernel32, say, having a list of core functions like InitializeCriticalSection which are never delay-loaded and always go directly into kernel32. But that's really out of scope for the /DELAYLOAD feature, whose purpose is not to make it easier to call functions which might not be there, but rather to assist in application startup performance by avoiding the cost of loading the target DLL until a function from it is called. If there were functions that went directly into kernel32, then the stated purpose of delay-loading fails: that import of InitializeCriticalSection forces kernel32 to be loaded when the module is loaded, completely contrary to the aim of delay-loading to avoid loading kernel32 at module load time.

    Now, it's certainly a nice feature to be able to perform delay-loading on a per-function level, in order to make it easier to write code which changes behavior based on the current version of Windows, but that's a different problem from what the /DELAYLOAD switch was created to solve.

Page 4 of 4 (35 items) 1234