December, 2008

  • The Old New Thing

    On 64-bit Windows, 32-bit programs run in an emulation layer, and if you don't like that, then don't use the emulator


    On 64-bit Windows, 32-bit programs run in an emulation layer. This emulation layer simulates the x86 architecture, virtualizing the CPU, the file system, the registry, the environment variables, the system information functions, all that stuff. If a 32-bit program tries to look at the system, it will see a 32-bit system. For example, if the program calls the GetSystemInfo function to see what processor is running, it will be told that it's running on a 32-bit processor, with a 32-bit address space, in a world with a 32-bit sky and 32-bit birds in the 32-bit trees.

    And that's the point of the emulation: To keep the 32-bit program happy by simulating a 32-bit execution environment.

    Commenter Koro is writing an installer in the form of a 32-bit program that detects that it's running on a 64-bit system and wants to copy files (and presumably set registry entries and do other installery things) into the 64-bit directories, but the emulation layer redirects the operations into the 32-bit locations. The question is "What is the way of finding the x64 Program Files directory from a 32-bit application?"

    The answer is "It is better to work with the system than against it." If you're a 32-bit program, then you're going to be fighting against the emulator each time you try to interact with the outside world. Instead, just recompile your installer as a 64-bit program. Have the 32-bit installer detect that it's running on a 64-bit system and launch the 64-bit installer instead. The 64-bit installer will not run in the 32-bit emulation layer, so when it tries to copy a file or update a registry key, it will see the real 64-bit file system and the real 64-bit registry.

  • The Old New Thing

    How do I obtain the computer manufacturer's name?


    One customer wanted a way to determine the name of the computer manufacturer. For example, they wanted to make some function call and get back "IBM" or "Compaq" or "Dell". I don't know why they wanted this information, and for the moment, I don't care.

    And of course, when you're looking for information, you don't search MSDN; that's for crazy people. No, let's just fire up regedit and hit Ctrl+F. (I can't imagine how many application compatibility bugs were created by that "helpful" Ctrl+F dialog in regedit.)

    The customer found the registry keys that are used to customize the System control panel, as well as the OEMINFO.INI file that also takes part. But then the question of reliability arose. After all, since it's just a registry key and an INI file, the user could just edit it and make it say anything they want. If the customer wiped their hard drive and reinstalled Windows from scratch, then this information would be lost, too. This customer wanted some degree of assurance that if the computer claimed to be a Dell, then it really was a Dell.

    Enter WMI. The Scripting Guys are all over WMI. If you search for the phrase "from Win32_ComputerSystem" you will find hit after hit from the Hey, Scripting Guy! column.

    And it so happens that WMI exposes the computer manufacturer info as well. If you look at the scripts that the Scripting Guys put out, probably two thirds of them fall into this pattern:

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colItems = objWMIService.ExecQuery("Select * from something")
    For Each objItem in colItems
         Wscript.Echo objItem.something

    All we have to do is fill in the "something".

    strComputer = "."
    Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2")
    Set colItems = objWMIService.ExecQuery("Select * from Win32_ComputerSystem")
    For Each objItem in colItems
         Wscript.Echo "System Name: " & objItem.Name
         Wscript.Echo "Manufacturer: " & objItem.Manufacturer
         Wscript.Echo "Model: " & objItem.Model

    Okay, so great, we can use WMI to get this information. But how reliable is it?

    Well, the WMI folks tell me that they get the information by querying the SMBIOS directly, so it's as reliable as your BIOS. Major manufacturers will put their names into the BIOS¹, but if you're running on a home-built machine, the values are whatever came with your motherboard. The BIOS manufacturers typically put placeholder strings into their SMBIOS, setting the manufacturer to a generic string like "Manufacturer", for example. When the motherboard manufacturer installs the BIOS, they're supposed to replace the placeholder strings with something more meaningful, but most of them don't bother. The result is that a machine you put together from parts you bought at the local computer shop will most likely just say "Manufacturer" for the manufacturer.

    In summary, if you query WMI for the computer manufacturer and it comes back "Dell", then you can be pretty sure you have a Dell. (Either that or somebody with way too much time on their hands burned a custom BIOS that says "Dell".) On the other hand, if it comes back as "Manufacturer" then you're still in the dark. All you know is you've got some sort of generic computer.

    ¹Even though major manufacturers will put their name into the BIOS, I'm told that if you send your computer back to the manufacturer and they replace the motherboard, they will sometimes forget to burn their name into the BIOS of the replacement motherboard. As a result, even on a name-brand computer, you might see "Manufacturer".

  • The Old New Thing

    Don't use global state to manage a local problem


    We've seen a few instances where people have used a global setting to solve a local problem. For example, people who use the LockWindowUpdate function to prevent a window from redrawing, toggle a global setting to see what its value is, or who change the system time zone as part of an internal calculation. To this, I'll add as an example a program which figures that if you don't want the program's feature, you don't want that feature in any competing products either.

    The first service pack of Windows XP introduced the Set Program Access and Defaults control panel. Among other things, media players can register here to allow users to choose them as the default media player, to enable access to the media player, or to remove access. The guidelines for the use of this control panel recommend that in response to the Remove access command, media players should remove their user interface entry points (such as shortcuts on the Start menu and notification icons), disable their autoplay feature, and generally act as if they weren't there.

    One media player decided that if the user instructed it to remove its access points and disable its autoplay, it would dutifully remove its user interface entry points, and it would also go into the configuration manager and disable media insertion detection on the CD drive. "If you don't want me to autoplay your CDs, then fine, and I'll make sure nobody else can autoplay your CDs either." They also disabled autorun, a related but separate feature.

    This program addresses a local problem (disable autoplay for Program X) by applying a global solution (disable all media insertion detection). Whether media insertion detection is enabled or disabled, and which programs should be notified when it occurs, is the decision of the computer user. Programs should not be altering hardware configuration unless the user specifically requested it. The correct thing for Program X to do is to remove its autoplay registration, leaving intact the behavior of other programs.

    It turns out that Program X was not disabling media insertion detection out of spite. The people responsible for Program X simply followed the description literally without understanding the big picture. "The documentation says that we should disable our autoplay feature. Well, I guess if we disable media insertion detection, that'll disable our autoplay feature."

    I wonder if their uninstaller reformats the hard drive.

    Moral of the story: Don't use global state to manage a local problem.

  • The Old New Thing

    When you start getting in-page errors on your hard drive, it's time to go shopping for a new hard drive


    The STATUS_IN_PAGE_ERROR describes itself as "The instruction at XXX referenced memory at YYY. The required data was not placed into memory because of an I/O error status of ZZZ." What does this mean?

    It means that the memory manager needed to read some memory from the disk, but the disk returned an error. (Namely, error ZZZ.) Since it has no way to return an error code to your program—I mean, after all, all your program did was read a variable from memory; there's no way to return an error code from int x = y if y cannot be read off the disk—it is reduced to raising an exception.

    When you see this message, and the I/O operation was coming from your hard drive, then you need to go shopping for a new hard drive. (You will also be alerted to a dying drive if your drive supports S.M.A.R.T.)


    You can see this error for sources other than hard drives. For example, if you're running a program over the network and the network connection dies, and the memory manager needs to demand-page some code from the program image, then you'll get this error because the code couldn't be loaded off the network. Similarly, if you yank a CD out of the drive while a program is executing from it (or your CD is damaged), there's a good chance that you'll get this error.

    Naturally, the loss of a network connection or removal of a CD does not mean that your network card or CD-ROM drive is failing; it's a failure of the underlying connection or medium. But if your hard drive starts generating I/O errors, then there's not much that can be blamed aside from the drive itself. (Okay, it might be a failing controller, but it's more likely to be the drive itself.)

  • The Old New Thing

    The Fargo campus responds to Redmond's December 2008 storm conditions


    The main Microsoft campus has been blanketed in snow the past few days. Microsoft Real Estate and Facilities has been sending out emergency alerts regarding the state of the campus, what services are available, what services are reduced, that sort of thing. Our friends over in the Fargo campus are generally unimpressed by all this hubbub and have written up their own adverse weather notification to make fun of us wusses in Redmond. (Reprinted below with some editing.)

    Fargo Campus Open with No Interruptions

    Due to normal cold weather and heavy snowfall the Microsoft Facilities in Fargo, including satellite areas (ABC, DEF, and GHI) will have NO SERVICES INTERUPTED due to Snow/Ice conditions in the local area.


    Current conditions: Light snow and windy
    Temperature: −8°F
    Feels like −40°F
    UV Index: 0 Low
    Wind: From N at 40mph
    gusting to 48 mph
    Humidity: Low
    Pressure: 29.81 in. ↑
    Dew Point: −12°F
    Visibility: 0.8 miles
    Updated: Dec 14 10:25 am CT

    Effective For: Thursday, December 18, 2008 through the end of April

    Please exercise normal caution driving and walking on campus as you are more likely to be attacked by a bunny than slip and fall on the ice.

    Campus Services

    Reception: Building lobbies will be open. If your building reception is closed then they will be fired.

    Shuttle: Campus shuttles will not be operating because there is no such thing as a campus shuttle in Fargo.

    Mailing Services: Mailing Services will be operating under full service.

    Food Service: There will full menu service available in all buildings.

    Facilities Maintenance Response: A full maintenance staff is at work on campus today.

    Building Services: All services such as heat, lighting and network connectivity will be operational.

    Other Advisory Notes:

    Security: Corporate Security advises its services will remain available to the campus. If you need assistance, stop by the office and wake them up.

    Parking: Park as usual, the snow plow drivers will just plow around you. You're all capable of driving on snow/ice so plowing will be limited.

    Connectivity: You shouldn't have any connectivity issues because you're expected to be at work. We only had 10" of snow and 40mph wind.

    Microsoft Company Store: The Company store will not be open today because the Fargo Campus doesn't have a company store.

    Area Roads: In light of the continuing snowfall and icy road conditions, most local roads are snow-covered and slippery and will remain that way until March. For information on current road conditions, please look out the window.

    Weather Updates: For information on how the weather is impacting Microsoft services and accessibility, please visit regularly throughout the day or tune into your local news stations for updates when you are in the office as conditions on campus could quickly change but they probably won't since cold, snow, and ice is the normal conditions this time of year.

    Thank you for your understanding and cooperation.

    Microsoft Real Estate & Facilities

  • The Old New Thing

    How do I change the directory Windows uses for user profiles?


    To change the directory Windows uses for user profiles (by default, the \Users directory), set the ProfilesDirectory setting in your unattend file.

    This setting is available only via the unattend file. There is no GUI interface for this, nor can it be changed after Windows has been installed. Sorry.

  • The Old New Thing

    How to create a Zune podcast from an audiobook or other files you already have


    Here's a trick one of my friends taught me.

    The Zune has two styles of audio playback, one for music, and another for podcasts. For music, clicking right and left move you by song, and when you switch to another album, then come back to the first album, it starts you over at the beginning of the album. On the other hand, for podcasts, clicking right and left seeks through the episode, and when you return to a podcast, it resumes from where you left off. This is nice, because podcast episodes tend to be long, and the sequence is usually important.

    But what if you want the podcast behavior for songs? For example, you might have a book on tape CD or a lecture series that you downloaded to your Zune. When you stop a chapter in the middle, you want to resume where you left off, not from the start of the chapter—and certainly not from the start of the book!

    Here's the secret: Before adding the content to your Zune collection, use Windows Explorer or Windows Media Player or some other metadata-editing tool to do two, possible four, things:

    • Change the Genre to Podcast,
    • Set the album title on all the episodes to the title of the book (or lecture series, or whatever),
    • Confirm that the file creation times are sequential: Episode 1 should have the earliest creation time, and so on.
    • Optionally, set the title of each episode to "Chapter N" or something similarly meaningful.

    Once you have the metadata set correctly, you can import the files into your collection. The Zune will see the Podcast genre and create a new podcast named after the album. It will show up in the Podcast section, not in the Music section. The tracks of the album will be treated as podcast episodes, and the file creation time is used to determine the chronology of the episodes. Set the podcast properties to "Oldest episodes first" and you now have your book on Zune ready for listening.

    What if you already added the files to your collection? Well, you can move them to a temporary directory outside your collection (thereby removing them from the collection), do your metadata editing, then move them back (re-adding them).

    As a shortcut, you can avoid the remove/edit/re-add cycle by editing the metadata while the files are still in your collection, then opening an Explorer window and dragging/dropping the files from Explorer into your Zune music collection (even though they're already there). This sometimes is enough of a nudge to tell the Zune client, "Hey, go look at these files again, I changed something." Remember, even though you dropped the files into your music collection, they will show up in the Podcast section. It will look like they disappeared, but really they just moved.

    I've had mixed success with the drag/drop approach, so I've gotten into the habit of playing it safe and doing the remove/edit/re-add thing.

  • The Old New Thing

    Crazy or cell phone?


    You've seen it, I'm sure. People walking down the street talking to themselves. Crazy or cellphone?

    What really gets me are the people who wear the headsets even when they aren't talking on the telephone, but rather in anticipation of receiving a telephone call. To those people, I have this to say to you:

    You're not that important. Get over yourself.

    I remember a few years ago, I was in Los Angeles attending a little party and got a ride home from somebody who was heading my way. We got in the car, and she put on her headset before putting the car in gear. It was a half-hour drive. No telephone call.

  • The Old New Thing

    2008 year-end link clearance


    Time for the semi-annual link clearance.

    Finally, we have the traditional plug for my column in TechNet Magazine:

  • The Old New Thing

    Why isn't there a SendThreadMessage function?


    Here's an interesting customer question:

    Windows has PostMessage and SendMessage. It also has PostThreadMessage but no SendThreadMessage. Why isn't there a SendThreadMessage function? Am I forced to simulate it with an event?

    What would this imaginary SendThreadMessage function do? Recall that SendMessage delivers the message directly to the window procedure; the message pump never sees it. The imaginary SendThreadMessage function would have to deliver the message directly to.... what? There is no "thread window procedure" to deliver it to.

    Okay, maybe you still intend to process the thread message in your message pump, but you want the caller of the imaginary SendThreadMessage function to wait until you've finished processing the message. But how does it know when you're finished? It can't wait for DispatchMessage to return, since DispatchMessage can't dispatch thread messages. (Where would it dispatch them to?) The processing of the thread message is completely under the control of the message pump. The window manager gives it a thread message, and as far as the window manager is concerned, that's the end of the story.

    You might say that the processing of the thread message is complete when somebody next calls GetMessage or PeekMessage, but there's no guarantee that the next call to a message-retrieval function will come from the message pump. Handling the thread message may result in a call to MessageBox, and as a modal function, it will have its own message loop, which will call GetMessage, resulting in your imaginary SendThreadMessage function deciding that message processing is complete when in fact it's still going on.

    What should you do instead? Just create a window and send it a message. The scenarios where you would want to use the PostThreadMessage function are very limited and specialized. Under normal circumstances, you should just send a regular window message.

Page 1 of 4 (38 items) 1234