• The Old New Thing

    Learning about farm animals from my niece


    I was playing with my niece (three years old at the time of this story), and she taught me a lot about farm animals.

    • You get eggs from cows and pigs.
    • Cow eggs are black and taste like bananas.
    • Pig eggs are blue and pink and taste like ice cream.
    • Blue pig eggs taste like vanilla.
    • Pink pig eggs taste like strawberry.

    According to the International Egg Commission, today is World Egg Day.

  • The Old New Thing

    How does a shell namespace extension provide icons for virtual items that track the standard icons set by the user's file associations?


    A customer asked, "What is the correct way to retrieve the icon associated with a file extension? We are writing a shell namespace extension that holds virtual file content, and we want to show the icon that would have been shown if the file were a physical file on disk rather than a virtual one. We tried using SH­Get­File­Info, expecting it to return the icon location and index, but the szDisplay­Name comes out as a blank string. (See sample program attached.) What's the right way to get the location so we can return it in our own Get­UI­Object­Of(IExtract­Icon) handler?"

    #include <windows.h>
    #include <iostream>
    int main()
     SHFILEINFOW info;
     ::SHGetFileInfoW(L".txt", FILE_ATTRIBUTE_NORMAL,
        &info, sizeof(info),
     std::wcout << info.szDisplayName << std::endl;
     std::wcout << info.iIcon << std::endl;
     return 0;

    The location is coming out blank because the file location returned is GIL_NOT­FILENAME so there is no file name to return.

    But let's look past the question to the problem. The problem is that you want to implement IShell­Folder::Get­UI­Object­Of(IExtract­Icon) for your shell namespace extension. Your plan is to create a custom implementation of IExtract­Icon and tell it to report the information you obtained from SH­Get­File­Info. The catch is that this information is lossy because IExtract­Icon::Get­Icon­Location returns additional information that is not captured by SH­Get­File­Info.

    Avoid the loss of fidelity by removing the middle man. Just ask for the standard icon extractor and return that.

    We start with a helper function that takes its inspiration from Get­UI­Object­Of­File but applies a little seasoning from Create­Simple­Pidl:

    HRESULT GetUIObjectOfVirtualFile(HWND hwnd, LPCWSTR pszPath,
        REFIID riid, void **ppv)
      *ppv = nullptr;
      WIN32_FIND_DATAW fd = {};
      fd.dwFileAttributes = FILE_ATTRIBUTE_NORMAL;
      CComHeapPtr<ITEMIDLIST_ABSOLUTE> spidlSimple;
      HRESULT hr = CreateSimplePidl(&fd, pszPath, &spidlSimple);
      if (FAILED(hr)) return hr;
      CComPtr<IShellFolder> spsf;
      PCUITEMID_CHILD pidlChild;
      hr = SHBindToParent(spidlSimple, IID_PPV_ARGS(&spsf), &pidlChild);
      if (FAILED(hr)) return hr;
      return spsf->GetUIObjectOf(hwnd, 1, &pidlChild, riid, NULL, ppv);

    This helper function is like Get­UI­Object­Of­File except that it uses a simple pidl to get the UI object for a file that doesn't actually exist.

    We can use this function to get the icon extractor for an arbitrary file extension.

    HRESULT GetIconExtractorForExtension(
        HWND hwnd,
        PCWSTR pszExtension,
        REFIID riid,
        void **ppv)
     *ppv = nullptr;
     wchar_t szPath[MAX_PATH];
     HRESULT hr = StringCchPrintfW(szPath, ARRAYSIZE(szPath),
                                  L"C:\\a%ls", pszExtension);
     if (FAILED(hr)) return hr;
     return GetUIObjectOfVirtualFile(hwnd, szPath, riid, ppv);

    and then use this function when handling the request for IExtract­Icon.

    if (interfaceId == IID_IExtractIconW ||
        interfaceId == IID_IExtractIconA)
      return GetIconExtractorForExtension(hwnd, L".txt", riid, ppv);
  • The Old New Thing

    What happens if you call VirtualAlloc to MEM_COMMIT a page you never MEM_RESERVE?


    A customer reported that while trying to solve a problem with their program, they noticed that they had been calling Virtual­Alloc incorrectly for years. They were able to reduce it into a simple program:

    #include <windows.h>
    #include <stdio.h>
    #include <tchar.h>
    int _tmain(int argc, _TCHAR* argv[])
     LPVOID base = VirtualAlloc(NULL, 4096, MEM_COMMIT, PAGE_READWRITE);
     _tprintf(TEXT("Allocated at %p\n"), base);
     return 0;

    First of all, thank you for reducing your program. That really focuses the investigation.

    The customer noted that their code was passing the MEM_COMMIT flag without the MEM_RESERVE flag, a scenario that is specifically called out in the documentation:

    The function fails if you attempt to commit a page that has not been reserved. The resulting error code is ERROR_INVALID_ADDRESS.

    But their call to Virtual­Alloc was succeeding! The customer suspected that this was not actually the source of their problem, but they wanted to double-check that perhaps their incorrect use of Virtual­Alloc was somehow indirectly contributing to it. Specifically, they were wondering if what they're doing is okay, or whether they should always use MEM_RESERVE | MEM_COMMIT.

    What the customer found is a compatibility hack. A lot of application forget to set the MEM_RESERVE flag when they MEM_COMMIT, so the memory manager lets it slide if they also pass lpAddress = NULL, indicating that they are requesting a new allocation rather than modifying an existing one.

    The problem is that MSDN fell into the trap of over-documenting. Instead of documenting the contract, MSDN documented the implementation. The contract is "A page being committed must also be reserved." If you try to commit a page that is not also reserved, then the behavior is unspecified. It is therefore valid for the implementation to treat the violation as "Sorry, you lose," or "Okay, I'll let you do it, but just this time."

    It appears that some time after this issue was identified, the MSDN documentation was revised. But they didn't revise it by documenting the contract. They revised it by documenting the implementation more precisely.

    Attempting to commit a specific address range by specifying MEM_COMMIT without MEM_RESERVE and a non-NULL lpAddress fails unless the entire range has already been reserved. The resulting error code is ERROR_INVALID_ADDRESS.

    My recommendation to the customer was to switch to MEM_RESERVE | MEM_COMMIT, since that is the preferred behavior and therefore the one least likely to trigger compatibility behavior. But the fact that they were accidentally omitting the MEM_RESERVE was not related to their problem, and they should keep looking.

  • The Old New Thing

    How do we change permissions on a share as fast as Explorer does it?


    A customer wanted to know what they could do to speed up changing permissions on a share.

    We have a large share (over 50,000 files in over 5000 folders). If we have four or five users with access to the share, and we add one more user, it takes around two minutes. If we have a hundred users and add one more, it takes around seven minutes. Here's the code we are using to add a user:

    // Get the current ACL on the directory.
    var info = new DirectoryInfo(sharePath);
    var security = info.GetAccessControl(AccessControlSections.Access);
    // Create a new rule that grants the user read access.
    var rule = new FileSystemAccessRule(user,
        FileSystemRights.Read | FileSystemRight.Synchronize,
        InheritanceFlags.ContainerInherit |
    // Add the rule to the existing ACL.
    security.SetAccessRuleProtection(true, false);
    // Set the modified ACL back on the directory.

    What can we do get this code to perform as well as Explorer?

    One suggestion was to create a security group that encompasses the people who have access to the share. The job of controlling who has access to the share is now delegated to the security group. When you need to grant Bob access to the share, you merely add Bob to the security group. When you decide that Bob no longer has access, you remove him from the group.

    The customer liaison replied, "The customer cannot use this workaround. How can they improve their code so it is as fast as Explorer?"

    We were unable to figure out exactly why the customer refused to use security groups. Whenever we asked, the customer merely changed the subject and asked how to get their code to be as fast as Explorer.

    I stepped in and pointed out the obvious:

    The customer's code is not doing what they claim they are doing. They claim to be changing share permissions, but the code is actually changing directory permissions.

    To change share permissions, use Get­Named­Security­Info to read the existing permissions on the share and Set­Named­Security­Info to change the permissions. There doesn't appear to be a BCL class for doing this, so you may need to pinvoke to the underlying Win32 functions, then use Object­Security.Set­Security­Descriptor­Binary­Form to convert it into something you can manipulate more easily.

    That was the last we heard from the customer, so it's not clear whether they gave up and decided that we weren't being helpful, or whether the tap on the shoulder was enough to clue them in to why their comparison was a false one. I don't know whether they took any of our advice to put the security information in a security group, but I suspect they didn't.

  • The Old New Thing

    First, try reading the error message, episode 4: Even programmers see error messages without reading them


    Same story, different details. It's the same internal programmer's tool which I have been calling Program Q. Many people have written scripts that help to manage your q tables.

    I'm trying to fribble my q table, but the fribble script gives me the following error:

    fribble: Error: Could not refresh counterbalances. Please manually run q refresh frib1 frib2 -r library

    What does this mean, and what should I do?

    Apparently, this programmer just froze up and stopped reading at the word "error". The error message is two sentences long. The first sentence answers the first question. The second sentence answers the second question.

    I can't even explain this away as a TL;DR. How can two sentences, each of which answers a question you asked, count as TL?

  • The Old New Thing

    How do I obtain the comment for a share?


    Today's Little Program obtains the comment string for a share. This is what shows up in the net view output like this:

    C:\>>net view \\scratch
    Shared resources at \\scratch
    Share name  Type  Used as  Comment
    temp        Disk           MAY BE DELETED AT ANY TIME WITHOUT WARNING
    The command completed successfully.

    Here goes. Remember: Little Programs do little to no error checking.

    #define UNICODE
    #define _UNICODE
    #include <windows.h>
    #include <lm.h>
    #include <stdio.h>
    int __cdecl wmain(int argc, wchar_t **argv)
     PSHARE_INFO_1 info1;
     NetShareGetInfo(argv[1], argv[2], 1, (LPBYTE*)&info1);
     printf("name = %ls\n", info1->shi1_netname);
     printf("remark = %ls\n", info1->shi1_remark);
     return 0;

    The expected command line arguments are the server name and the share name. We ask for information level 1, which gives us the name, the type, and the remark. I just print the name and the remark.

    Bonus program:

    #define UNICODE
    #define _UNICODE
    #include <windows.h>
    #include <lm.h>
    #include <stdio.h>
    int __cdecl wmain(int argc, wchar_t **argv)
     PSERVER_INFO_101 info101;
     NetServerGetInfo(argv[1], 101, (LPBYTE*)&info101);
     printf("comment = %ls\n", info101->sv101_comment);
     return 0;

    This program prints the server comment.

  • The Old New Thing

    Hacking the law: On the role of the marriage officiant in the State of Washington


    The role of the officiant in marriages in the State of Washington is kind of strange.

    For example, the wedding license is filled out in triplicate. One copy goes to the county clerk. The second copy goes to Olympia, the state capital. The third copy goes to the officiant. But the law doesn't say what the officiant must do with that third copy. There is no law that requires the officiant to keep records of the weddings at which he or she has served as officiant, nor is there any law that requires the officiant to produce the copy of the license in case of a dispute. It's just given to the officiant with no strings attached.

    And then there's the issue of which people are qualified to act as officiants: In addition to the usual list of government officials, the law authorizes "any regularly licensed or ordained minister ... or similar official of any religious organization." Although the term "religious organization" is defined, the definition is broad enough that any organization can be a religious organization by simply claiming to be one, at which point it can nominate anyone it chooses as a minister.

    Okay, so basically anybody can serve as an officiant if they are willing to work at it.

    But suppose you find out years later that your minister was not properly ordained, or that he or she lied about his qualifications? No worries; the State of Washington has you covered there, too:

    RCW 26.04.060: Marriage before unauthorized cleric

    A marriage solemnized before any person professing to be a minister ... or similar official of any religious organization in this state ... is not void, nor shall the validity thereof be in any way affected [on these grounds], if such marriage be consummated with a belief on the part of the persons so married, or either of them, that they have been lawfully joined in marriage.

    So if your officiant turns out to have been unqualified, don't worry. The marriage is still valid. So much for that sitcom plot.

    Indeed, only one partner needs to believe that the marriage is valid in order for it to become so. One of the partners could knowingly hire a fake officiant, but as long as the other partner believes that the officiant is real, the marriage is still valid.

    But wait, it's even more than that. Neither party needs to believe in the officiant's legitimacy. They merely need to believe that the marriage is valid.

    Now things get circular.

    Suppose both partners convince themselves (by delusion, or mistaken understanding, or by reading the law quoted above) that they found a loophole that permits comedian Don Novello in the character Father Guido Sarducci to be an officiant at their wedding. The fact that they believe it to be true makes it true.

    The conclusion I draw from this is that the role of the officiant in weddings solemnized in the State of Washington is entirely perfunctory. The important thing is that the paperwork gets filed with the county and state.

  • The Old New Thing

    Calling ShutdownBlockReasonCreate from my service doesn't stop the user from shutting down


    A customer had a service application that needs to perform a sequence of operations that cannot be interrupted by a system shutdown.

    The service starts performing those operations when it starts up, but we found that group policy or other shenanigans can trigger other actions that ultimately lead to a system reboot. We would like to delay the reboot until our service completes its critical sequence of operations.

    We created a simple test application that calls Shutdown­Block­Reason­Create, and it works. If we try to reboot the computer, the shutdown dialog appears indicating that it is waiting for the test application to complete.

    We ported this code into the service, and even though the call succeeds, there is no message shown to the user at reboot, and the reboot proceeds anyway.

    Is Shutdown­Block­Reason­Create expected to work when called from a service? If so, then what we are doing wrong? If not, what alternative designs are available?

    Shutdown blocks apply only to the session in which they are created. This is sort-of implied by the fact that the Shutdown­Block­Reason­Create function is exported from user32.dll, and it takes a window handle parameter, and window handles are valid only in the desktop from which they were created. Since the interactive session is session 1 and services are in session 0, the block request has no effect. (This is just another application of the principle Does this work in a service? The default answer is NO.)

    Note also that the shutdown block is not a hard block. The user could click "Shut down anyway". Besides, the system assumes "Shut down anyway" if the user takes no action within some number of seconds.

    Note also that if the system is shut down remotely, there is nobody present to answer the question, and it's not clear where to display the message anyway.

    The correct way to delay shutdown indefinitely from a service is to set the SERVICE_ACCEPT_PRE­SHUTDOWN flag in its service status. This registers the service for preshutdown notifications, at which point it can finish up your critical actions before releasing shutdown to continue.

    Note that long shutdown times is one of the major points of end-user frustration, so you should do what you can to wrap things up quickly. Otherwise, you're going to be another data point in the "Windows sucks" database.

  • The Old New Thing

    If you can't remember the exact text of a dialog box (so you can search for it), you can ask the Internet


    Some time ago, I noted that If you're looking for the code that displays a particular dialog box, the most directly way to find it is to look for the dialog box. That works if you have a screen shot of the dialog box. But what if you don't?

    A colleague of mine wanted to find the code that displays the "Your password is going to expire soon" notification, but he didn't know what string to look for. It so happened that he asked me four hours too late, because my password happened to have expired that morning, but by the time he asked me for the text of the message, I had already changed my password.

    Think out of the box: You know who probably has a screen shot of the "your password is going to expire soon" notification? Somebody on the Internet.

    A Web image search quickly turned up the exact text.

  • The Old New Thing

    Why can't I create a file equal to the available disk space?


    A customer was trying to exercise some boundary cases in their application, one of which entailed "out of disk space" scenarios. The way they did this was very simple: Call Get­Disk­Free­Space­Ex to see how much disk space is available, and then create a file of that size. This worked on some volumes, but on other volumes, it failed with "Not enough disk space." Even after making sure no other programs were accessing the drive in question, the error persisted. Why?

    The amount of disk space required to create a file of a particular size is not exactly equal to the number of bytes in the file. After all, the file system also needs to remember the file name, the security attributes, various timestamps, and information to keep track of where on the disk all the bytes of the file are stored. And then there are the less obvious things like the change journal records to record that the file was created and object tracking records for link tracking.

    Just because your volume has exactly X bytes free doesn't mean that you will be able to create a file whose size is exactly X, because additional disk space will be needed to keep track of the metadata. If you want to fill a disk to the brim, you could start by filling it nearly to the brim, then growing the file until you get "Not enough disk space." If you want to get fancy, you could grow the file by large chunks until you can't add large chunks any more, and then switch to smaller and smaller chunks. You may also want to use the Set­File­Valid­Data function to avoid wasting time writing zeroes to all the sectors.

Page 1 of 460 (4,600 items) 12345»