• The Old New Thing

    At least the Danes know how to count


    Even though Danish is impossible for me to pronounce, I do appreciate their stubborn resistance to decimalization. The number 71 is (I hope I get this right) "en og halvfjerdsindstyve", literally, "one and half-four-times-twenty", or more commonly, just "en og halvfjerds". (Those familiar with other Germanic languages recognize "half-four" as meaning "three and a half".)

    (I hope the Danes out there realize that my previous remarks about Danish were all in fun. I'm just fascinated with languages, especially those in the Germanic branch.)

  • The Old New Thing

    What's with those blank taskbar buttons that go away when I click on them?


    Sometimes you'll find a blank taskbar button that goes away when you click on it. What's the deal with that?

    There are some basic rules on which windows go into the taskbar. In short:

    • If the WS_EX_APPWINDOW extended style is set, then it will show (when visible).
    • If the window is a top-level unowned window, then it will show (when visible).
    • Otherwise it doesn't show.

    (Though the ITaskbarList interface muddies this up a bit.)

    When a taskbar-eligible window becomes visible, the taskbar creates a button for it. When a taskbar-eligible window becomes hidden, the taskbar removes the button.

    The blank buttons appear when a window changes between taskbar-eligible and taskbar-ineligible while it is visible. Follow:

    • Window is taskbar-eligible.
    • Window becomes visible ? taskbar button created.
    • Window goes taskbar-ineligible.
    • Window becomes hidden ? since the window is not taskbar-eligible at this point, the taskbar ignores it.

    Result: A taskbar button that hangs around with no window attached to it.

    This is why the documentation also advises, "If you want to dynamically change a window's style to one that doesn't support visible taskbar buttons, you must hide the window first (by calling ShowWindow with SW_HIDE), change the window style, and then show the window."

    Bonus question: Why doesn't the taskbar pay attention to all windows as they come and go?

    Answer: Because that would be expensive. The filtering out of windows that aren't taskbar-eligible happens inside USER32 and it then notifies the taskbar (or anybody else who has installed a WH_SHELL hook) via one of the HSHELL_* notifications only if a taskbar-eligibie window has changed state. That way, the taskbar code doesn't get paged in when there's nothing for it to to.
  • The Old New Thing

    "Beam me up" is not yet recognized


    How soon before this becomes standard equipment at Star Trek conventions?

    Vocera Communications Unveils Wearable, Instant Voice Communications Application

    "Enterprise environments are looking for applications that leverage their investment in wireless communication technologies and increase employee efficiency," ...

    Some of the basic calling features include:

    • Call by name, "Call Bob Thomas."
    • Call by function, "Call a cardiologist."
    • Call by specific location, "Locate a clerk in gardening." ...
    The Vocera Communications System

    Vocera Communications Badge is a wearable device that weighs less than two ounces and can easily be clipped to a shirt pocket or worn on a lanyard. ...

    The Vocera Communications Badge is controlled using natural spoken language. To initiate a conversation with Jim and Mary, for example, the user would simply say, "Conference Jim Anderson and Mary Guscia."

  • The Old New Thing

    Another privacy policy that isn't very private

    Today I read the privacy policy for Nuveen Investment Advisors. I like this part:
    We do not disclose any nonpublic personal information about you to anyone, except as permitted by law.

    "Except as permitted by law". How reassuring. Is it really necessary to have an official policy promising that that you won't break the law? And actually stating that they promise to follow the law on this specific issue raises the question, "So are they willing to break the law with regard to other issues?"

    This sentence basically means, "We reserve the right to disclose nonpublic personal information about you to the fullest extent permitted by law."

    In particular, later in that paragraph, it states that

    ... we may disclose the information we collect, as described above, to companies that perform administrative or marketing services on our behalf...

    In other words, "We may disclose nonpublic information about you to people who will try to sell you stuff."

    All the regulations about privacy disclosure statements hasn't actually secured anybody's privacy, since the regulations only require disclosure; they don't require that they actually do anything to protect your privacy.

  • The Old New Thing

    Danish so-called "pronunciation"


    Of course my real goal in studying German and Swedish is eventually to have all of Denmark surrounded. (After Swedish, the next most likely nearby targets are Norwegian and Dutch.)

    All I know about Denmark I learned from Swedes. Well, if you don't count one Danish co-worker, who moved back to Denmark several years ago. The Swedes tell me, "The Danes would be so much easier to understand if they would only take the hot potato out of their mouth before they started talking." (Two Swedes have told me that Danish sounds "drunk".)

    I thought this was just friendly Scandinavian pick-on-your-neighbor-ism until I actually listened to some Danish closely.

    Believe it or not, the odd collection of sounds that comes out of their mouths (1) counts as a language, and (2) is comprehensible to other Danes. Listen for yourself: Rødgrød med fløde. That "soft d" I will never, ever learn to pronounce properly. It appears to requires the use of throat muscles that most people are content to use only for swallowing.

    This site has a longer sample of Danish speech. You thought swallowing a word was just a figure of speech? Check out the pronunciation of Sverigesfærgen which sounds to me something like "Svesfæn".

    Okay, now that I've publically made fun of Danish, my punishment will probably be that I will be called upon to study it seriously at some point.

  • The Old New Thing

    How to hide privacy violations in a privacy disclosure statement

    I'm looking over my Fidelity privacy disclosure statement, titled "Our commitment to privacy". Google is amazing: It found a copy online: Our Commitment to Privacy. Scroll down to How and Why We Obtain Personal Information, fourth bullet point:
    • Information services and consumer reporting agencies (for example, to verify your identity, to assess your creditworthiness or to better understand your product and service needs)

    (Italics added.) The italicized phrase translates as "We will collect personal information in order to try to sell you stuff".

    Okay, now look at How We Protect Your Information. The second bullet point describes the people they will disclose your personal information to:

    • Unaffiliated service providers (for example, ...)

    Notice that the parenthetical says "for example" and not "restricted to". So their privacy statement that they may disclose your information to any unaffiliated service provider, which basically translates to "everybody".

    So their so-called commitment to privacy actually permits them to collect information from anywhere and give it to anybody. The people who wrote this clearly learned the same lesson I learned from the BBC series Yes, (Prime) Minister: Put the hard part in the title. If the title claims to be demonstrating your commitment to privacy, you can violate it all you want in the body.
  • The Old New Thing

    Famous people doing mundane things = news!


    So an actor learns a foreign language and it's news: Actor Kingsley Masters Farsi Language. Meanwhile, tens of millions of people around the world learn a foreign language without any media coverage whatsoever.

    (And if you read the article: He didn't master Farsi. He mastered basic Farsi. Whatever that means.)
  • The Old New Thing

    You can read a contract from the other side


    An interface is a contract, but remember that a contract applies to both parties. Most of the time, when you read an interface, you look at it from the point of view of the client side of the contract, but often it helps to read it from the server side.

    For example, let's look at the interface for control panel applications.

    Most of the time, when you're reading this documentation, you are wearing your "I am writing a Control Panel application" hat. So, for example, the documentation says

    When the controlling application first loads the Control Panel application, it retrieves the address of the CPlApplet function and subsequently uses the address to call the function and pass it messages.

    With your "I am writing a Control Panel application" hat, this means "Gosh, I had better have a function called CPlApplet and export it so I can receive messages."

    But if you are instead wearing your "I am hosting a Control Panel application" hat, this means, "Gosh, I had better call GetProcAddress() to get the address of the application's CPlApplet function so I can send it messages."

    Similarly, under the "Message Processing" section it lists the messages that are sent from the controlling application to the Control Panel application. If you are wearing your "I am writing a Control Panel application" hat, this means "Gosh, I had better be ready to receive these messages in this order." But if you are wearing your "I am hosting a Control Panel application" hat, this means "Gosh, I had better send these messages in the order listed."

    And finally, when it says "the controlling application release the Control Panel application by calling the FreeLibrary function," your "I am writing a Control Panel application" hat says "I had better be prepared to be unloaded," whereas your "I am hosting a Control Panel application" hat says, "This is where I unload the DLL."

    So let's try it. As always, start with our scratch program and change the WinMain:

    #include <cpl.h>
    int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hinstPrev,
                       LPSTR lpCmdLine, int nShowCmd)
      HWND hwnd;
      g_hinst = hinst;
      if (!InitApp()) return 0;
      if (SUCCEEDED(CoInitialize(NULL))) {/* In case we use COM */
          hwnd = CreateWindow(
              "Scratch",                      /* Class Name */
              "Scratch",                      /* Title */
              WS_OVERLAPPEDWINDOW,            /* Style */
              CW_USEDEFAULT, CW_USEDEFAULT,   /* Position */
              CW_USEDEFAULT, CW_USEDEFAULT,   /* Size */
              NULL,                           /* Parent */
              NULL,                           /* No menu */
              hinst,                          /* Instance */
              0);                             /* No special parameters */
          if (hwnd) {
            TCHAR szPath[MAX_PATH];
            LPTSTR pszLast;
            DWORD cch = SearchPath(NULL, TEXT("access.cpl"),
                         NULL, MAX_PATH, szPath, &pszLast);
            if (cch > 0 && cch < MAX_PATH) {
              RunControlPanel(hwnd, szPath);
      return 0;

    Instead of showing the window and entering the message loop, we start acting like a Control Panel host. Our victim today is access.cpl, the accessibility control panel. After locating the program on the path, we ask RunControlPanel to do the heavy lifting:

    void RunControlPanel(HWND hwnd, LPCTSTR pszPath)
      // Maybe this control panel application has a custom manifest
      ACTCTX act = { 0 };
      act.cbSize = sizeof(act);
      act.dwFlags = 0;
      act.lpSource = pszPath;
      act.lpResourceName = MAKEINTRESOURCE(123);
      HANDLE hctx = CreateActCtx(&act);
      ULONG_PTR ulCookie;
      if (hctx == INVALID_HANDLE_VALUE ||
          ActivateActCtx(hctx, &ulCookie)) {
        HINSTANCE hinstCPL = LoadLibrary(pszPath);
        if (hinstCPL) {
          APPLET_PROC pfnCPlApplet = (APPLET_PROC)
            GetProcAddress(hinstCPL, "CPlApplet");
          if (pfnCPlApplet) {
            if (pfnCPlApplet(hwnd, CPL_INIT, 0, 0)) {
              int cApplets = pfnCPlApplet(hwnd, CPL_GETCOUNT, 0, 0);
              //  We're going to run application zero
              //  (In real life we might show the user a list of them
              //  and let them pick one)
              if (cApplets > 0) {
                CPLINFO cpli;
                pfnCPlApplet(hwnd, CPL_INQUIRE, 0, (LPARAM)&cpli);
                pfnCPlApplet(hwnd, CPL_DBLCLK, 0, cpli.lData);
                pfnCPlApplet(hwnd, CPL_STOP, 0, cpli.lData);
            pfnCPlApplet(hwnd, CPL_EXIT, 0, 0);
        if (hctx != INVALID_HANDLE_VALUE) {
          DeactivateActCtx(0, ulCookie);

    Ignore the red lines for now; we'll discuss them later.

    All we're doing is following the specification but reading it from the host side. So we load the library, locate its entry point, and call it with CPL_INIT, then CPL_GETCOUNT. If there are any control panel applications inside this CPL file, we inquire after the first one, double-click it (this is where all the interesting stuff happens), then stop it. After all that excitement, we clean up according to the rules set out for the host (namely, by sending a CPL_EXIT message.)

    So that's all. Well, except for the red parts. What's that about?

    The red parts are to support Control Panel applications that have a custom manifest. This is something new with Windows XP and is documented in MSDN here.

    If you go down to the "Using ComCtl32 Version 6 in Control Panel or a DLL That Is Run by RunDll32.exe" section, you'll see that the application provides its manifest to the Control Panel host by attaching it as resource number 123. So that's what the red code does: It loads and activates the manifest, then invites the Control Panel application to do its thing (with its manifest active), then cleans up. If there is no manifest, CreateActCtx will return INVALID_HANDLE_VALUE. We do not treat that as an error, since many programs don't yet provide a manifest.

    Exercise: What are the security implications of passing NULL as the first parameter to SearchPath?
  • The Old New Thing

    What order do programs in the startup group execute?


    The programs in the startup group run in an unspecified order. Some people think they execute in the order they were created. Then you upgraded from Windows 98 to Windows 2000 and found that didn't work any more. Other people think they execute in alphabetical order. Then you installed a Windows XP multilingual user interface language pack and found that didn't work any more either.

    If you want to control the order that programs in the startup group are run, write a batch file that runs them in the order you want and put a shortcut to the batch file in your startup group.
  • The Old New Thing

    Why not just block the apps that rely on undocumented behavior?

    Because every app that gets blocked is another reason for people not to upgrade to the next version of Windows. Look at all these programs that would have stopped working when you upgraded from Windows 3.0 to Windows 3.1.
    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Compatibility

    Actually, this list is only partial. Many times, the compatibility fix is made inside the core component for all programs rather than targetting a specific program, as this list does.

    (The Windows 2000-to-Windows XP list is stored in your C:\WINDOWS\AppPatch directory, in a binary format to permit rapid scanning. Sorry, you won't be able to browse it easily. I think the Application Compatibility Toolkit includes a viewer, but I may be mistaken.)

    Would you have bought Windows XP if you knew that all these programs were incompatible?

    It takes only one incompatible program to sour an upgrade.

    Suppose you're the IT manager of some company. Your company uses Program X for its word processor and you find that Program X is incompatible with Windows XP for whatever reason. Would you upgrade?

    Of course not! Your business would grind to a halt.

    "Why not call Company X and ask them for an upgrade?"

    Sure, you could do that, and the answer might be, "Oh, you're using Version 1.0 of Program X. You need to upgrade to Version 2.0 for $150 per copy." Congratulations, the cost of upgrading to Windows XP just tripled.

    And that's if you're lucky and Company X is still in business.

    I recall a survey taken a few years ago by our Setup/Upgrade team of corporations using Windows. Pretty much every single one has at least one "deal-breaker" program, a program which Windows absolutely must support or they won't upgrade. In a high percentage of the cases, the program in question was developed by their in-house programming staff, and it's written in Visual Basic (sometimes even 16-bit Visual Basic), and the person who wrote it doesn't work there any more. In some cases, they don't even have the source code any more.

    And it's not just corporate customers. This affects consumers too.

    For Windows 95, my application compatibility work focused on games. Games are the most important factor behind consumer technology. The video card that comes with a typical computer has gotten better over time because games demand it. (Outlook certainly doesn't care that your card can do 20 bajillion triangles a second.) And if your game doesn't run on the newest version of Windows, you aren't going to upgrade.

    Anyway, game vendors are very much like those major corporations. I made phone call after phone call to the game vendors trying to help them get their game to run under Windows 95. To a one, they didn't care. A game has a shelf life of a few months, and then it's gone. Why would they bother to issue a patch for their program to run under Windows 95? They already got their money. They're not going to make any more off that game; its three months are over. The vendors would slipstream patches and lose track of how many versions of their program were out there and how many of them had a particular problem. Sometimes they wouldn't even have the source code any more.

    They simply didn't care that their program didn't run on Windows 95. (My favorite was the one that tried to walk me through creating a DOS boot disk.)

    Oh, and that Application Compatibility Toolkit I mentioned above. It's a great tool for developers, too. One of the components is the Verifier: If you run your program under the verifier, it will monitor hundreds of API calls and break into the debugger when you do something wrong. (Like close a handle twice or allocate memory with GlobalAlloc but free it with LocalAlloc.)

    The new application compatibility architecture in Windows XP carries with it one major benefit (from an OS development perspective): See all those DLLs in your C:\WINDOWS\AppPatch directory? That's where many of the the compatibility changes live now. The compatibility workarounds no longer sully the core OS files. (Not all classes of compatibility workarounds can be offloaded to a compatibility DLL, but it's a big help.)
Page 409 of 427 (4,265 items) «407408409410411»