• The Old New Thing

    Raymond's Windows Universal Samples API concordance


    If you want to find an SDK sample that uses a particular feature of the Universal Windows Platform, you can try my Windows Universal Samples API concordance on http://oldnewthing.github.io/Windows-universal-samples/. Expand the tree view to find the thing you're interested in, and it will provide links to every line of C# code that uses it.

    The following deep links are also supported:

    I will try to keep this site in sync with the latest release of the Windows Universal Samples repo. The site is kind of ugly right now, but it works just barely well enough to do what I needed.

    Note that the concordance is not complete. There are holes in the analysis which I hope to fill in over time. But at least it's a decent start.

    Eventually, I'll blog about the program I used to generate this information. The short answer is Roslyn. That's why it searches only in C# samples.

  • The Old New Thing

    Cynical interpretations of various project milestones

    Official name Cynical interpretation
    Coding milestone Writing new bugs
    Integration milestone Merging bugs from other teams
    Stabilization milestone Fixing bugs
  • The Old New Thing

    I guess this explains why Warren Buffett hasn't retired


    Microsoft provides to its employees a retirement calculator that is more detailed than the kinds you can find on the Internet. After gathering all sorts of information, including your savings and spending patterns, it draws some nice bar charts and tells you how many years you should continue working before you can retire.

    Even if I tell the calculator that I have a billion dollars in savings, it still tells me, "You should work one more year."

    Clarifying note: I don't actually have a billion dollars in savings.

  • The Old New Thing

    Using an intermediate library to make the main library retargetable


    A customer was developing a static library targetting both Windows XP Win32 applications and universal Windows apps. (This was before Windows XP reached end-of-life.)

    Our library uses critical sections, but unfortunately there is no version Initialize­Critical­Section that is available to both Windows XP Win32 applications and universal Windows apps. Universal Windows apps must use Initialize­Critical­Section­Ex, but that function is not available to Windows XP Win32 applications. Is there a way to dynamically target both Windows XP Win32 applications and universal Windows apps, pass WACK validation, and still have one library?

    We thought we could use Get­Module­Handle and Get­Proc­Address to detect which platform we are one, but Get­Module­Handle is not allowed in universal Windows apps, so we're back where we started.

    Are we stuck having two versions of our library, one for Windows XP Win32 applications and one for universal Windows apps?

    Runtime dynamic linking (Load­Library, Get­Proc­Address) is not permitted in universal Windows apps, which means that for universal Windows apps, you must have an entry for Initialize­Critical­Section­Ex in your import table. But if that function is in your input table, then it won't load on Windows XP.

    (You might think that you could have a second library to be used by Windows XP clients that implements the Initialize­Critical­Section­Ex function. Unfortunately, you will run afoul of dllimport.)

    You are going to have to have separate libraries at some point, but you don't have to have two versions of your library. You could build your library to call, say, Contoso­Initialize­Critical­Section, and have two helper libraries, one for Windows XP Win32 applications and one for universal Windows apps, each of which implement the Contoso­Initialize­Critical­Section function in a manner appropriate to the target.

    In other words, people targeting Windows XP would link to ContosoCore.dll and ContosoXPSupport.dll. People writing universal Windows apps would link to ContosoCore.dll and ContosoStoreSupport.dll.

    This approach has a few advantages:

    • It's simple, works (because it's so simple), and everybody understands it.
    • All the files in your core library need to be compiled only once.

    The second clause pays off if your library is large, or if you need to add new operating system targets.

    Update: I guess I didn't make it clear. My suggestion is that Contoso­Core.dll link to the nonexistent Contoso­Support.dll. If your program targets Windows XP, then rename Contoso­XP­Support.dll to Contoso­Support.dll. If your program is a universal Windows app, then rename Contoso­Store­Support.dll to Contoso­Support.dll.

    This technique also works with static libraries. You have a single Contoso­Core.lib which calls a Contoso­Initialize­Critical­Section function. There are two implementations of Contoso­Initialize­Critical­Section, one in Contoso­XP­Support.lib and another in Contoso­Store­Support.lib. Each application chooses which support library to link in.

  • The Old New Thing

    When I change the icon in my shortcut, why doesn't it update on the screen?


    A customer was having trouble updating the icon in one of their shortcuts. Here's what they shared with us:

        i_shell_link->SetIconLocation(icon_file.value().c_str(), 0);

    "Changing the icon from the shortcut property sheet works, but it's not working from our code. Is the shortcut property sheet using a different API from IShell­Link::Set­Icon­Location? In desperation, we added


    but that didn't help. Did we get the flags to SHChange­Notification wrong?"

    The property sheet does use the IShell­Link::Set­Icon­Location method to change the shortcut icon. What the customer forgot was to save their changes!

        i_persist_file->Save(NULL, TRUE);

    where i_persist_file is the IPersist­File that they used to load the shortcut, or they can use Query­Interface to get a new pointer.

    The SHCNE_ASSOC­CHANGED notification is unnecessary, and in fact it's overkill. That's like saying, "I want to change the color of my sofa, so I'm going to demolish my house, rebuild it, and then refurnish it with a new sofa."

    If you want to send a notification to say, "Hey, I updated this file, please go refresh any data you have cached about it," you can do a

        SHChangeNotify(SHCNE_UPDATEITEM, SHCNF_PATH, fullpath, NULL);
  • The Old New Thing

    I saved some files into the Program Files directory, and now they're gone!


    A customer reported that they saved some files in the Program Files directory, but when they went back to check, the files were gone! What happened?

    What most likely happened is UAC Virtualization.

    UAC Virtualization kicks in for applications which were designed for versions of Windows prior to Windows Vista. These applications often assume that they are running with administrative privileges, and when they try to write to file or registry locations that are normally restricted to administrators, they expect them to succeed. So UAC Virtualization lets those writes succeed by secretly redirecting them to another location inside the user profile. The reverse happens when the application later tries to read the file or registry key: If the file or key exists in the redirected location, it is used instead of the one in the administrative location.

    You can read the above-linked TechNet article for details. The short version is that you can find the files in the %LOCAL­APP­DATA%\Virtual­Store directory and the keys under the HKEY_CURRENT_USER\Software\Classes\Virtual­Store key.

    Bonus chatter: There used to be a button in Explorer called Compatibility Files that appears if you are looking at a directory that has a corresponding Virtual Store, and clicking it takes you to that Virtual Store. The button was removed in Windows 8 based on telemetry feedback that showed that very nearly nobody ever clicked on it or even cared about it. Furthermore, in the years since UAC was originally introduced, the number of applications which require UAC Virtualization has dropped significantly, so the need to access items in the Virtual Store dropped correspondingly.

  • The Old New Thing

    Microspeak: move the needle


    The phrase move the needle is part of general business jargon, but it is very popular here at Microsoft. You need to know what it means, and more importantly, you need to be willing to throw it around yourself in order to sound more hip and with-it.

    In general business speak, move the needle means generates a reaction, but at Microsoft, it has the more general sense of provide a perceptible improvement.

    The metaphor here is that there is some sort of meter, like a speedometer or VU meter. Back in the old days, these meters were analog rather than digital, and they consisted of a calibrated arc with a needle that pointed at the current value.

    To move the needle is to have a noticeable effect, presumably positive.

    Here are some citations.

    It's clear that we will need to make some additional improvements if we are to move the needle on performance for customers with high traffic.
    By investing in this solution we move the needle forward on reducing friction and increasing speed to measurable value.

    That second one wins the buzzword award for today.

  • The Old New Thing

    How do I enumerate remembered connections that are not currently connected?


    Harry Johnston wanted to know how to get a list of remembered (but not currently connected) drive mappings.

    The idea here is to make a tweak to the Little Program. Start with what we had and make these changes:

    int __cdecl main(int, char **)
     HANDLE hEnum;

    This changes the program from enumerating connected resources to enumerating remembered resources.

    The last step is to skip the remembered resources that are also connected. But this part is not Win32 programming; it's just programming, For each remembered resource, check if the lpLocal­Name is non-null and matches an lpLocal­Name that came out of an enumeration of connected resources.

    So let's do it. We start with the header files:

    #define UNICODE
    #define _UNICODE
    #define STRICT
    #include <windows.h>
    #include <stdio.h> // horrors! Mixing C and C++ I/O!
    #include <string>
    #include <set>
    #include <memory>
    #include <winnetwk.h>

    Since we are using classes like std::set which throw exceptions, we need to wrap our resources inside RAII classes. Here's one for network resource enumeration:

    class CNetEnumerator
     CNetEnumerator() = default;
     ~CNetEnumerator() { if (m_hEnum) WNetCloseEnum(m_hEnum); }
     operator HANDLE() { return m_hEnum; }
     HANDLE* operator&() { return &m_hEnum; }
     HANDLE m_hEnum = nullptr;

    Here is our function to enumerate all network resources. It uses a callback because arghhhhhhhhhhh wishes it were so.

    template<typename Callback>
    void for_each_network_resource(
        DWORD dwScope,
        DWORD dwType,
        DWORD dwUsage,
        LPNETRESOURCE pnrIn,
        Callback callback)
     CNetEnumerator hEnum;
     WNetOpenEnum(dwScope, dwType, dwUsage, pnrIn, &hEnum);
     const DWORD elements = 65536 / sizeof(NETRESOURCE);
     static_assert(elements > 1, "Must have room for data");
     std::unique_ptr<NETRESOURCE> buffer(new NETRESOURCE[elements]);
     DWORD err;
     do {
      DWORD cEntries = INFINITE;
      DWORD cb = elements * sizeof(NETRESOURCE);
      err = WNetEnumResource(hEnum, &cEntries, buffer.get(), &cb);
      if (err == NO_ERROR || err == ERROR_MORE_DATA) {
       for (DWORD i = 0; i < cEntries; i++) {
     } while (err == ERROR_MORE_DATA);

    There is a bit of trickery to get the enumeration buffer into a form that C++ likes. We had previously used Local­Alloc, which is guaranteed to return memory suitably aligned for NETRESOURCE. However, we can't do it for new BYTE[], since that returns only byte-aligned data. We solve this problem by explicitly allocating NETRESOURCE objects, but choosing a number so that the result is close to our desired buffer size.¹

    We need another helper class so we can create a case-insensitive set.

    struct CaseInsensitiveWstring
     bool operator()(const std::wstring& a, const std::wstring& b) const {
      return CompareStringOrdinal(a.c_str(), a.length(),
                                  b.c_str(), b.length(), TRUE) == CSTR_LESS_THAN;

    Okay, now we can start doing actual work:

    void report(PCWSTR pszLabel, PCWSTR pszValue)
     printf("%ls = %ls\n", pszLabel, pszValue ? pszValue : L"(null)");
    int __cdecl wmain(int, wchar_t **)
     std::set<std::wstring, CaseInsensitiveWstring> connected;
     // Collect the local resources which are already connected.
      RESOURCETYPE_DISK, 0, nullptr, [&](LPNETRESOURCE pnr) {
       if (pnr->lpLocalName != nullptr) {
     // Now look for remembered resources that are not connected.
      RESOURCETYPE_DISK, 0, nullptr, [&](LPNETRESOURCE pnr) {
       if (pnr->lpLocalName == nullptr ||
           connected.find(pnr->lpLocalName) == connected.end()) {
        report(L"localName", pnr->lpLocalName);
        report(L"remoteName", pnr->lpRemoteName);
        report(L"provider", pnr->lpProvider);
     return 0;

    Not exciting. Mostly consists of boring typing. But hey, that's what programming is like most of the time.

    ¹ If we were being super-weenies about the buffer size, we could have written

     union EnumBuffer {
      BYTE bytes[65536];
     std::unique_ptr<EnumBuffer> buffer(new EnumBuffer());
     LPNETRESOURCE pnr = &buffer->nr;
      DWORD cb = sizeof(EnumBuffer);
  • The Old New Thing

    Debugging walkthrough: Access violation on nonsense instruction, episode 3


    A colleague of mine asked for help debugging a strange failure. Execution halted on what appeared to be a nonsense instruction.

    eax=022b13a0 ebx=00000000 ecx=02570df4 edx=769f4544 esi=02570dec edi=05579748
    eip=76c49131 esp=05cce038 ebp=05cce07c iopl=0         nv up ei pl nz na po nc
    cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
    76c49131 ec              in      al,dx

    This is clearly an invalid instruction. But observe that the offset is +2, which is normally the start of the function, because the first two bytes of Windows operating system functions are a mov edi, edi instruction. Therefore, the function is corrupted. Lets look back two bytes to see if it gives any clues.

    0:006> u 76c49131-2
    76c4912f e95aecebf3      jmp     IoLog!Mine_GetFileAttributesExW (6ab07d8e)

    Oh look, somebody is doing API patching (already unsupported) and they did a bad job. They tried to patch code while a thread was in the middle of executing it, resulting in a garbage instruction.

    This is a bug in IoLog. The great thing about API patching is that when you screw up, it looks like an OS bug. That way, nobody ever files bugs against you!

    (In this case, IoLog is a diagnostic tool which is logging file I/O performed by an application which is being instrumented.)

    My colleague replied, "Thanks. Looks like a missing lock in IoLog. It doesn't surprise me that API patching isn't supported..."

  • The Old New Thing

    The Windows 95 I/O system assumed that if it wrote a byte, then it could read it back


    In Windows 95, compressed data was read off the disk in three steps.

    1. The raw compressed data was read into a temporary buffer.
    2. The compressed data was uncompressed into a second temporary buffer.
    3. The uncompressed data was copied to the application-provided I/O buffer.

    But you could save a step if the I/O buffer was a full cluster:

    1. The raw compressed data was read into a temporary buffer.
    2. The compressed data was uncompressed directly into the application-provided I/O buffer.

    A common characteristic of dictionary-based compression is that a compressed stream can contain a code that says "Generate a copy of bytes X through Y from the existing uncompressed data."

    As a simplified example, suppose the cluster consisted of two copies of the same 512-byte block. The compressed data might say "Take these 512 bytes and copy them to the output. Then take bytes 0 through 511 of the uncompressed output and copy them to the output."

    So far, so good.

    Well, except that if the application wrote to the I/O buffer while the read was in progress, then the read would get corrupted because it would copy the wrong bytes to the second half of the cluster.

    Fortunately, writing to the I/O buffer is forbidden during the read, so any application that pulled this sort of trick was breaking the rules, and if it got corrupted data, well, that's its own fault. (You can construct a similar scenario where writing to the buffer during a write can result in corrupted data being written to disk.)

    Things got even weirder if you passed a memory-mapped device as your I/O buffer. There was a bug that said, "The splash screen for this MS-DOS game is all corrupted if you run it from a compressed volume."

    The reason was that the game issued an I/O directly into the video frame buffer. The EGA and VGA video frame buffers used planar memory and latching. When you read or write a byte in video memory, the resulting behavior is a complicated combination of the byte you wrote, the values in the latches, other configuration settings, and the values already in memory. The details aren't important; the important thing is that video memory does not act like system RAM. Write a byte to video memory, then read it back, and not only will you not get the same value back, but you probably modified video memory in a strange way.

    The game in question loaded its splash screen by issuing I/O directly into video memory, knowing that MS-DOS copies the result into the output buffer byte by byte. It set up the control registers and the latches in such a way that then bytes written into memory go exactly where they should. (It issued four reads into the same buffer, with different control registers each time, so that each read ended up being issued to a different plane.)

    This worked great, unless the disk was compressed.

    The optimization above relied on the property that writing a byte followed by reading the byte produces the byte originally written. But this doesn't work for video memory because of the weird way video memory works. The result was that when the decompression engine tried to read what it thought was the uncompressed data, it was actually asking the video controller to do some strange operations. The result was corrupted decompressed data, and corrupted video data.

    The fix was to force double-buffering in non-device RAM if the I/O buffer was into device-mapped memory.

Page 3 of 460 (4,596 items) 12345»