<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	
  <title>The Old New Thing - Dreamcatcher Edition</title>
	<atom:link href="https://devblogs.microsoft.com/oldnewthing/feed" rel="self" type="application/rss+xml" />
	<link>https://devblogs.microsoft.com/oldnewthing</link>
	<description>Practical development throughout the evolution of Windows.</description>
	<lastBuildDate>Thu, 16 Apr 2026 14:59:30 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2021/03/Microsoft-Favicon.png</url>
	
  <title>The Old New Thing - Dreamcatcher Edition</title>
	<link>https://devblogs.microsoft.com/oldnewthing</link>
	<width>32</width>
	<height>32</height>
</image> 
	
  <item>
    <title>What&#8217;s up with window message 0x0091? We&#8217;re getting it with unexpected parameters</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260416-00/?p=112240</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260416-00/?p=112240#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Thu, 16 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112240</guid>
    <content:encoded><![CDATA[<p>A customer, via their customer liaison, reported quite some time ago that their program stopped working on Windows XP. (I told you it was quite some time ago.)</p>
<p>The customer&#8217;s investigations revealed that the problem occurred because their window was receiving message <code>0x0091</code>, and the parameters are wrong. Who is sending this message with the wrong parameters?</p>
<p>Okay, first of all, how do you even know that the parameters are wrong? The message is not listed in <code>winuser.h</code> or in MSDN (as it was then called).</p>
<p>We explained that message <code>0x0091</code> is an internal message that they should just pass to <code>Def­Window­Proc</code> unchanged. What makes the customer think that the message is being received with the wrong parameters?</p>
<p>The customer said that their program was using that message as a custom message, and now, in addition to getting it when their program sends the message, they are also getting spurious copies of the message with <code>WPARAM</code> and <code>LPARAM</code> values that don&#8217;t correspond to any values that the program itself sent.</p>
<p>We informed them that they shouldn&#8217;t have been using that message for their own purposes. Those messages are <a title="Which message numbers belong to whom?" href="https://devblogs.microsoft.com/oldnewthing/20031202-00/?p=41653"> in the system-defined range</a>, which means that they are off-limits to applications. If they want to send a private message, use one in the application space.</p>
<p>It&#8217;s like finding an empty closet in an office building and using it to store your bicycle, but now, when you come to work, you find that the closet is filled with other stuff and there&#8217;s no room for your bicycle any more. &#8220;Why is there stuff in that closet?&#8221; Because it wasn&#8217;t your closet in the first place.</p>
<p>The liaison took our advice back to the customer, but mentioned that the customer probably won&#8217;t like that answer. The message <code>0x0091</code> was not the only message they were using. They also used other messages below <code>WM_<wbr />USER</code>, and they were all causing problems; they just wanted to start their investigation with <code>0x0091</code>.</p>
<p>Oh well. But I hope it&#8217;s as simple as just changing a macro definition from</p>
<pre>#define WM_MYSECRETMESSAGE 0x0091
</pre>
<p>to</p>
<pre>#define WM_MYSECRETMESSAGE (WM_APP + 1020) // or something
</pre>
<p>Pick a message in the range available to applications for custom use.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260416-00/?p=112240">What&#8217;s up with window message &lt;CODE&gt;0x0091&lt;/CODE&gt;? We&#8217;re getting it with unexpected parameters</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260416-00/?p=112240/feed</wfw:commentRss>
    <slash:comments>4</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>Why is there a long delay between a thread exiting and the Wait&#173;For&#173;Single&#173;Object returning?</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260415-00/?p=112235</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260415-00/?p=112235#respond</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Wed, 15 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112235</guid>
    <content:encoded><![CDATA[<p>A customer reported that they were using the <code>Wait­For­Single­Object</code> function to wait for a thread to exit, but they found that even though the thread had exited, the <code>Wait­For­Single­Object</code> call did not return for over a minute. What could explain this delay in reporting the end of a thread? Can we do something to speed it up?</p>
<p>My psychic powers tell me that the thread didn&#8217;t actually exit.</p>
<p>What the customer is observing is probably that their thread procedure has returned, signaling the end of the thread. But a lot of stuff happens after the thread procedure exits. The system needs to send <code>DLL_<wbr />THREAD_<wbr />DETACH</code> notifications to all of the DLLs (unless the DLL has opted out via <code>Disable­Thread­Library­Calls</code>), and doing so requires the loader lock.</p>
<p>I would use the debugger to look for the thread you <i>thought</i> had exited and see what it&#8217;s doing. It might be blocked waiting for the loader lock because some other thread is hogging it. Or it could be running a DLL&#8217;s detach code, and that detach code has gotten stuck on a long-running operation.</p>
<p>I suspect it&#8217;s the latter: One of the DLLs is waiting for something in its detach code, and that something takes about a minute.</p>
<p>We didn&#8217;t hear back from the customer, which could mean that this was indeed the problem. Or it could mean that this didn&#8217;t help, but they decided that we weren&#8217;t being helpful and didn&#8217;t pursue the matter further. Unfortunately, in a lot of these customer debugging engagements, we never hear back whether our theory worked. (Another possibility is that the customer wrote back with a &#8220;thank you&#8221;, but the customer liaison didn&#8217;t forward it to the engineering team because they didn&#8217;t want to bother them any further.)</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260415-00/?p=112235">Why is there a long delay between a thread exiting and the &lt;CODE&gt;Wait&shy;For&shy;Single&shy;Object&lt;/CODE&gt; returning?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260415-00/?p=112235/feed</wfw:commentRss>
    <slash:comments>0</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>Why was there a red telephone at every receptionist desk?</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260414-00/?p=112231</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260414-00/?p=112231#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Tue, 14 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[History]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112231</guid>
    <content:encoded><![CDATA[<p>Some time ago, I noted that there was <a title="A walkthrough of the original Microsoft Building 3" href="https://devblogs.microsoft.com/oldnewthing/20250708-00/?p=111357"> a walkthrough of the original Microsoft Building 3</a>. If you go behind the receptionist desk, you&#8217;ll see a telephone at the receptionist&#8217;s station, but off to side, there was also <a href="https://my.matterport.com/show/?m=SZSV6vjcf4L&amp;ss=12&amp;sr=-.38,.94"> a red telephone</a> resting between a tape dispenser and a small pamphlet labelled &#8220;Quick Reference Guide&#8221;.</p>
<p><img fetchpriority="high" decoding="async" src="data:image/jpeg;base64,
/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAsICAoIBwsKCQoNDAsNERwSEQ8PESIZGhQcKSQrKigk
JyctMkA3LTA9MCcnOEw5PUNFSElIKzZPVU5GVEBHSEX/2wBDAQwNDREPESESEiFFLicuRUVFRUVF
RUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUVFRUX/wAARCAFWAYYDASIA
AhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQA
AAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3
ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWm
p6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEA
AwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSEx
BhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElK
U1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3
uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD0Ggij
r16Uh96koUDHbiig/TNGaAEpMd6Ueo596TPPvQAH35+lJ2o49R9KOvU8+goAQkn19hmkxx0/SnHp
imkYx0oAQ+2Pemt0p36CmkZ5HNMQw5z/APWppAJ5xxTyD+FNOBQA6EfvgfY1Z/Wq8I/ej6GpycHk
0mMQ49abjPJX6U7t1x7mjgdetICpdpcM4NvHG5Ix+8k2/wBKpGDUgM/Z4W9hN/8AWrXwOnBFNx2y
xz3NS4pjuZG3UR/y4MfpKv8AjSBrwfe0+YfQqf61sdeuaBxyM/lS5EO5jmW4HLWNyB7KD/I1G16y
fftbsD/rg1bnPXH60buvrRyILmCuoRHqkwPvE3+FB1S1Xhpdp9GUit0nAPJP1o3MBjgilyBcwhql
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" alt="Red telephone on side table" width="390" height="342" /></p>
<p>What was this red telephone for? Was it <a title="When irate product support customers demand to speak to Bill Gates" href="https://devblogs.microsoft.com/oldnewthing/20251223-00/?p=111896"> a direct line to Bill Gates&#8217;s office</a>? Or maybe it was a direct line to Security?</p>
<p>Nope.</p>
<p>It was just a plain telephone.</p>
<p>And that&#8217;s what made it special.</p>
<p>As is customary at large companies, the telephones on the Microsoft campus were part of a corporate PBX (private branch exchange). A PBX is a private telephone system within a company, and companies use them to save on telephone costs, as well as to provide auxiliary telephone services. For example, you could call another office by dialing just the extension, and the call would be routed entirely within the PBX without having to interact with the public telephone systems. Generally, most calls are typically from one office to another, so a PBX saves considerable money by reducing demand for outside communications services. Also, a PBX allows integration with other systems. For example, if somebody leaves you a voicemail, the system can email you a message.</p>
<p>But what if the PBX is down, and there is an emergency?</p>
<p>The red telephones are plain telephones with standard telephone service. They are not part of the PBX and therefore operate normally even if there is a PBX outage. If there is an emergency, the receptionist can use the red telephone to call emergency services. Presumably, each red telephone was registered in the telephone system with the address of its building, allowing emergency services to dispatch assistance quickly.</p>
<p><b>Bonus chatter</b>: What was the &#8220;Quick Reference Guide&#8221;? It was a guide to emergency procedures. It makes sense that it was kept next to the emergency telephone.</p>
<p><b>Bonus bonus chatter</b>: Bill Gates kept a red telephone in his own office as well. If the PBX went down, I guess it was technically true that the red telephones could be used to call Bill Gates&#8217;s office.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260414-00/?p=112231">Why was there a red telephone at every receptionist desk?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260414-00/?p=112231/feed</wfw:commentRss>
    <slash:comments>2</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>Finding a duplicated item in an array of N integers in the range 1 to N &#8722; 1</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260413-00/?p=112227</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260413-00/?p=112227#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Mon, 13 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112227</guid>
    <content:encoded><![CDATA[<p>A colleague told me that there was an <var>O</var>(<var>N</var>) algorithm for finding a duplicated item in an array of <var>N</var> integers in the range <var>1</var> to <var>N</var> − 1. There must be a duplicate due to the pigeonhole principle. There might be more than one duplicated value; you merely have to find any duplicate.¹</p>
<p>The backstory behind this puzzle is that my colleague had thought this problem was solvable in <var>O</var>(<var>N</var> log <var>N</var>), presumably by sorting the array and then scanning for the duplicate. They posed this as an interview question, and the interviewee found an even better linear-time algorithm!</p>
<p>My solution is to interpret the array as a linked list of 1-based indices, and borrow the sign bit of each integer as a flag to indicate that the slot has been visited. We start at index 1 and follow the indices until they either reach a value whose sign bit has already been set (which is our duplicate), or they return to index 1 (a cycle). If we find a cycle, then move to the next index which does not have the sign bit set, and repeat. At the end, you can restore the original values by clearing the sign bits.²</p>
<p>I figured that modifying the values was acceptable given that the <var>O</var>(<var>N</var> log <var>N</var>) solution also modifies the array. At least my version restores the original values when it&#8217;s done!</p>
<p>But it turns out the interview candidate found an even better <var>O</var>(<var>N</var>) algorithm, one that doesn&#8217;t modify the array at all.</p>
<p>Again, view the array values as indices. You are looking for two nodes that point to the same destination. You already know that no array entry has the value <var>N</var>, so the entry at index <var>N</var> cannot be part of a cycle. Therefore, the chain that starts at <var>N</var> must eventually join an existing cycle, and that join point is a duplicate. Start at index <var>N</var> and use <a href="https://en.wikipedia.org/wiki/Cycle_detection#Floyd's_tortoise_and_hare"> Floyd&#8217;s cycle detector algorithm</a> to find the start of the cycle in <var>O</var>(<var>N</var>) time.</p>
<p>¹ If you constrain the problem further to say that there is exactly one duplicate, then you can find the duplicate by summing all the values and then subtracting <var>N(N−1)/2</var>.</p>
<p>² I&#8217;m pulling a fast one. This is really <var>O</var>(<var>N</var>) space because I&#8217;m using the sign bit as a convenient &#8220;initially zero&#8221; flag bit.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260413-00/?p=112227">Finding a duplicated item in an array of &lt;VAR&gt;N&lt;/VAR&gt; integers in the range 1 to &lt;VAR&gt;N&lt;/VAR&gt; &minus; 1</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260413-00/?p=112227/feed</wfw:commentRss>
    <slash:comments>5</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>How do you add or remove a handle from an active Wait&#173;For&#173;Multiple&#173;Objects?, part 2</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260410-00/?p=112223</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260410-00/?p=112223#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Fri, 10 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112223</guid>
    <content:encoded><![CDATA[<p>Last time, we looked at <a title="How do you add or remove a handle from an active Wait­For­Multiple­Objects?" href="https://devblogs.microsoft.com/oldnewthing/20260409-00/?p=112220"> adding or removing a handle from an active <code>Wait­For­Multiple­Objects</code></a>, and we developed an asynchronous mechanism that requests that the changes be made soon. But asynchronous add/remove can be a problem bcause you might remove a handle, clean up the things that the handle was dependent upon, but then receive a notification that the handle you removed has been signaled, even though you already cleaned up the things the handle depended on.</p>
<p>What we can do is wait for the waiting thread to acknowledge the operation.</p>
<pre>_Guarded_by_(desiredMutex) DWORD desiredCounter = 1;
DWORD activeCounter = 0;

void wait_until_active(DWORD value)
{
    DWORD current = activeCounter;
    while (static_cast&lt;int&gt;(current - value) &lt; 0) {
        WaitOnAddress(&amp;activeCounter, &amp;current,
                      sizeof(activeCounter), INFINITE);
        current = activeCounter;
    }
}
</pre>
<p>The <code>wait_<wbr />until_<wbr />active</code> function waits until the value of <code>active­Counter</code> is at least as large as <code>value</code>. We do this by subtracting the two values, to avoid wraparound problems.¹ The comparison takes advantage of the guarantee in C++20 that conversion from an unsigned integer to a signed integer converts to the value that is numerically equal modulo 2ⁿ where <var>n</var> is the number of bits in the destination. (Prior to C++20, the result was implementation-defined, but in practice all modern implementations did what C++20 mandates.)²</p>
<p>You can also use <code>std::<wbr />atomic</code>:</p>
<pre>_Guarded_by_(desiredMutex) DWORD desiredCounter = 1;
std::atomic&lt;DWORD&gt; activeCounter;

void wait_until_active(DWORD value)
{
    DWORD current = activeCounter;
    while (static_cast&lt;int&gt;(current - value) &lt; 0) {
        activeCounter.wait(current);
        current = activeCounter;
    }
}
</pre>
<p>As before, the background thread manipulates the <code>desiredHandles</code> and <code>desiredActions</code>, then signals the waiting thread to wake up and process the changes. But this time, the background thread blocks until the waiting thread acknowledges the changes.</p>
<pre>// Warning: For expository purposes. Almost no error checking.
void waiting_thread()
{
    bool update = true;
    std::vector&lt;wil::unique_handle&gt; handles;
    std::vector&lt;std::function&lt;void()&gt;&gt; actions;

    while (true)
    {
        if (std::exchange(update, false)) {
            std::lock_guard guard(desiredMutex);

            handles.clear();
            handles.reserve(desiredHandles.size() + 1);
            std::transform(desiredHandles.begin(), desiredHandles.end(),
                std::back_inserter(handles),
                [](auto&amp;&amp; h) { return duplicate_handle(h.get()); });
            // Add the bonus "changed" handle
            handles.emplace_back(duplicate_handle(changed.get()));

            actions = desiredActions;

            <span style="border: solid 1px currentcolor; border-bottom: none;">if (activeCounter != desiredCounter) {</span>
            <span style="border: 1px currentcolor; border-style: none solid;">    activeCounter = desiredCounter;   </span>
            <span style="border: solid 1px currentcolor; border-top: none;">    WakeByAddressAll(&amp;activeCounter); </span>
            }
        }

        auto count = static_cast&lt;DWORD&gt;(handles.size());
                        
        auto result = WaitForMultipleObjects(count,
                        handles.data()-&gt;get(), FALSE, INFINITE);
        auto index = result - WAIT_OBJECT_0;
        if (index == count - 1) {
            // the list changed. Loop back to update.
            update = true;
            continue;
        } else if (index &lt; count - 1) {
            actions[index]();
        } else {
            // deal with unexpected result
        }
    }
}

void change_handle_list()
{
    <span style="border: solid 1px currentcolor;">DWORD value;</span>
    {
        std::lock_guard guard(desiredMutex);
        ⟦ make changes to desiredHandles and desiredActions ⟧
        <span style="border: solid 1px currentcolor;">value = ++desiredCounter;</span>
        SetEvent(changed.get());
    }
    <span style="border: solid 1px currentcolor;">wait_until_active(value);</span>
}
</pre>
<p>The pattern is that after the background thread makes the desired changes, they increment the <code>desiredCounter</code> and signal the event. It&#8217;s okay if multiple threads make changes before the waiting thread wakes up. The changes simply accumulate, and the event just stays signaled. Each background thread then waits for the waiting thread to process the change.</p>
<p>On the waiting side, we process changes as usual, but we also publish our current change counter if it has changed, to let the background threads know that we made some progress. Eventually, we will make enough progress that all of the pending changes have been processed, and the last ackground thread will be released from <code>wait_<wbr />until_<wbr />active</code>.</p>
<p>¹ You&#8217;ll run into problems if the counter increments 2 billion times without the worker thread noticing. At a thousand increments per second, that&#8217;ll last you a month. I figure that if you have a worker thread that is unresponsible for that long, then you have bigger problems. But you can avoid even that problem by switching to a 64-bit integer, so that the overflow won&#8217;t happen before the sun is expected to turn into a red giant.</p>
<p>² The holdouts would be compilers for systems that are not two&#8217;s-complement.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260410-00/?p=112223">How do you add or remove a handle from an active &lt;CODE&gt;Wait&shy;For&shy;Multiple&shy;Objects&lt;/CODE&gt;?, part 2</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260410-00/?p=112223/feed</wfw:commentRss>
    <slash:comments>3</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>How do you add or remove a handle from an active Wait&#173;For&#173;Multiple&#173;Objects?</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260409-00/?p=112220</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260409-00/?p=112220#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Thu, 09 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112220</guid>
    <content:encoded><![CDATA[<p>Last time, we looked at <a title="How do you add or remove a handle from an active Msg­Wait­For­Multiple­Objects?" href="https://devblogs.microsoft.com/oldnewthing/20260408-00/?p=112218"> adding or removing a handle from an active <code>Msg­Wait­For­Multiple­Objects</code></a>, and observed that we could send a message to both break out of the wait <i>and</i> update the list of handles. But what if the other thread is waiting in a <code>Wait­For­Multiple­Objects</code>? You can&#8217;t send a message since <code>Wait­For­Multiple­Objects</code> doesn&#8217;t wake for messages.</p>
<p>You can fake it by using an event which means &#8220;I want to change the list of handles.&#8221; The background thread can add that handle to its list, and if the &#8220;I want to change the list of handles&#8221; event is signaled, it updates its list.</p>
<p>One of the easier ways to represent the desired change is to maintain two lists, the &#8220;active&#8221; list (the one being waited on) and the &#8220;desired&#8221; list (the one you want to change it to). The background thread can make whatever changes to the &#8220;desired&#8221; list it wants, and then it signals the &#8220;changed&#8221; event. The waiting thread sees that the &#8220;changed&#8221; event is set and copies the &#8220;desired&#8221; list to the &#8220;active&#8221; list. This copying needs to be done with <code>Duplicate­Handle</code> because the background thread might close a handle in the &#8220;desired&#8221; list, and we can&#8217;t close a handle while it is being waited on.</p>
<pre>wil::unique_handle duplicate_handle(HANDLE other)
{
    HANDLE result;
    THROW_IF_WIN32_BOOL_FALSE(
        DuplicateHandle(GetCurrentProcess(), other,
            GetCurrentProcess(), &amp;result,
            0, FALSE, DUPLICATE_SAME_ACCESS));
    return wil::unique_handle(result);
}
</pre>
<p>This helper function duplicates a raw <code>HANDLE</code> and returns it in a <code>wil::unique_handle</code>. The duplicate handle has its own lifetime separate from the original. The waiting thread operates on a copy of the handles, so that it is unaffected by changes to the original handles.</p>
<pre>std::mutex desiredMutex;
_Guarded_by_(desiredMutex) std::vector&lt;wil::unique_handle&gt; desiredHandles;
_Guarded_by_(desiredMutex) std::vector&lt;std::function&lt;void()&gt;&gt; desiredActions;
</pre>
<p>The <code>desiredHandles</code> is a vector of handles we want to be waiting for, and the The <code>desiredActions</code> is a parallel vector of things to do for each of those handles.</p>
<pre>// auto-reset, initially unsignaled
wil::unique_handle changed(CreateEvent(nullptr, FALSE, FALSE, nullptr));

void waiting_thread()
{
    while (true)
    {
        std::vector&lt;wil::unique_handle&gt; handles;
        std::vector&lt;std::function&lt;void()&gt;&gt; actions;
        {
            std::lock_guard guard(desiredMutex);

            handles.reserve(desiredHandles.size() + 1);
            std::transform(desiredHandles.begin(), desiredHandles.end(),
                std::back_inserter(handles),
                [](auto&amp;&amp; h) { return duplicate_handle(h.get()); });
            // Add the bonus "changed" handle
            handles.emplace_back(duplicate_handle(changed.get()));

            actions = desiredActions;
        }

        auto count = static_cast&lt;DWORD&gt;(handles.size());
                        
        auto result = WaitForMultipleObjects(count,
                        handles.data()-&gt;addressof(), FALSE, INFINITE);
        auto index = result - WAIT_OBJECT_0;
        if (index == count - 1) {
            // the list changed. Loop back to update.
            continue;
        } else if (index &lt; count - 1) {
            actions[index]();
        } else {
            // deal with unexpected result
            FAIL_FAST(); // (replace this with your favorite error recovery)
        }
    }
}
</pre>
<p>The waiting thread makes a copy of the <code>desiredHandles</code> and <code>desiredActions</code>, and adds the <code>changed</code> handle to the end so we will wake up if somebody changes the list. We operate on the copy so that any changes to <code>desiredHandles</code> and <code>desiredActions</code> that occur while we are waiting won&#8217;t affect us. Note that the copy in <code>handles</code> is done via <code>Duplicate­Handle</code> so that it operates on a separate set of handles. That way, if another thread closes a handle in <code>desiredHandles</code>, it won&#8217;t affect us.</p>
<pre>void change_handle_list()
{
    std::lock_guard guard(desiredMutex);
    ⟦ make changes to desiredHandles and desiredActions ⟧
    SetEvent(changed.get());
}
</pre>
<p>Any time somebody wants to change the list of handles, they take the <code>desiredMutex</code> lock and can proceed to make whatever changes they want. These changes won&#8217;t affect the waiting thread because it is operating on duplicate handles. When finished, we set the <code>changed</code> event to wake up the waiting thread so it can pick up the new set of handles.</p>
<p>Right now, the purpose of the <code>changed</code> event is to wake up the blocking call, but we could also use it as a way to know whether we should update our captured handles. This allows us to reuse the handle array if there were no changes.</p>
<pre>void waiting_thread()
{
    <span style="border: solid 1px currentcolor; border-bottom: none;">bool update = true;                        </span>
    <span style="border: 1px currentcolor; border-style: none solid;">std::vector&lt;wil::unique_handle&gt; handles;   </span>
    <span style="border: solid 1px currentcolor; border-top: none;">std::vector&lt;std::function&lt;void()&gt;&gt; actions;</span>

    while (true)
    {
        <span style="border: solid 1px currentcolor;">if (std::exchange(update, false))</span> {
            std::lock_guard guard(desiredMutex);

            <span style="border: solid 1px currentcolor;">handles.clear();</span>
            handles.reserve(desiredHandles.size() + 1);
            std::transform(desiredHandles.begin(), desiredHandles.end(),
                std::back_inserter(handles),
                [](auto&amp;&amp; h) { return duplicate_handle(h.get()); });
            // Add the bonus "changed" handle
            handles.emplace_back(duplicate_handle(changed.get()));

            actions = desiredActions;
        }

        auto count = static_cast&lt;DWORD&gt;(handles.size());
                        
        auto result = WaitForMultipleObjects(count,
                        handles.data()-&gt;get(), FALSE, INFINITE);
        auto index = result - WAIT_OBJECT_0;
        if (index == count - 1) {
            // the list changed. Loop back to update.
            <span style="border: solid 1px currentcolor;">update = true;</span>
            continue;
        } else if (index &lt; count - 1) {
            actions[index]();
        } else {
            // deal with unexpected result
            FAIL_FAST(); // (replace this with your favorite error recovery)
        }
    }
}
</pre>
<p>In this design, changes to the handle list are asynchronous. They don&#8217;t take effect immediately, because the waiting thread might be busy running an action. Instead, they take effect when the waiting thread gets around to making another copy of the <code>desiredHandles</code> vector and call <code>Wait­For­Multiple­Objects</code> again. This could be a problem: You ask to remove a handle, and then clean up the things that the handle depended on. But before the worker thread can process the removal, the handle is signaled. The result is that the worker thread calls your callback after you thought had told it to stop!</p>
<p>Next time, we&#8217;ll see what we can do to make the changes synchronous.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260409-00/?p=112220">How do you add or remove a handle from an active &lt;CODE&gt;Wait&shy;For&shy;Multiple&shy;Objects&lt;/CODE&gt;?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260409-00/?p=112220/feed</wfw:commentRss>
    <slash:comments>4</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>How do you add or remove a handle from an active Msg&#173;Wait&#173;For&#173;Multiple&#173;Objects?</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260408-00/?p=112218</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260408-00/?p=112218#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Wed, 08 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112218</guid>
    <content:encoded><![CDATA[<p>A customer had a custom message loop that was built out of <code>Msg­Wait­For­Multiple­Objects</code>. Occasionally, they needed to change the list of handles that the message loop was waiting for. How do you add or remove a handle from an active <code>Msg­Wait­For­Multiple­Objects</code>?</p>
<p>You can&#8217;t.</p>
<p>Even if you could, it meant that the return value of <code>Msg­Wait­For­Multiple­Objects</code> would not be useful. Suppose it returns to say &#8220;Handle number 2 was signaled.&#8221; You don&#8217;t know whether handle 2 was signaled before the handle list was updated, or whether it was signaled after. You don&#8217;t know whether it&#8217;s referring to the handle number 2 or the new one.</p>
<p>So maybe it&#8217;s not a bad thing that you can&#8217;t change the list of handles in an active <code>Msg­Wait­For­Multiple­Objects</code>, since the result wouldn&#8217;t be useful. But you can ask the thread to stop waiting, update its handle list, and then go back to waiting.</p>
<p>Since the thread is in a <code>Msg­Wait­For­Multiple­Objects</code>, it will wake if you send a message to a window that belongs to the thread. You can have a &#8220;handle management window&#8221; to receive these messages, say</p>
<pre>#define WM_ADDHANDLE    (WM_USER+0) // wParam = index, lParam = handle
#define WM_REMOVEHANDLE (WM_USER+1) // wParam = index
</pre>
<p>The background thread could send one of these messages if it wanted to add or remove a handle, and the message procedure would perform the corresponding operation.</p>
<p>In reality, you probably need more information than just the handle; you also need to know what to do if that handle is signaled. The <code>lParam</code> is more likely to be a pointer to a structure containing the handle as well as instructions on what the handle means. Those instructions could take the form of a callback function, or it could just be a value from an enum. Pick the design that works for you.</p>
<p>Next time, we&#8217;ll look at the case where you don&#8217;t want to block the background thread, or if the waiting thread is waiting in <code>Wait­For­Multiple­Objects</code> so the message option is not available.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260408-00/?p=112218">How do you add or remove a handle from an active &lt;CODE&gt;Msg&shy;Wait&shy;For&shy;Multiple&shy;Objects&lt;/CODE&gt;?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260408-00/?p=112218/feed</wfw:commentRss>
    <slash:comments>4</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>Were there any Windows 3.1 programs that were so incompatible with Windows 95 that there was no point trying to patch them?</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260407-00/?p=112213</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260407-00/?p=112213#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Tue, 07 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[History]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112213</guid>
    <content:encoded><![CDATA[<p>In a comment to my discussion of the Windows 95 patch system, commenter word merchant wondered <a href="https://devblogs.microsoft.com/oldnewthing/20251111-00/?p=111781&amp;commentid=143427#comment-143427"> whether there were any Windows 3.1 programs or drivers that were so incompatible with Windows 95 that there was no point trying to patch them</a>.</p>
<p>Yes, there were problems that were so bad that the program was effectively unfixable. The largest category of them were those which took various types of handles and figured out how to convert them to pointers, and then used those pointers to access (and sometimes modify!) the internal implementation details of those objects.¹ Not only did the implementation details change, but the mechanism they used to convert handles to pointers also stopped working because Windows 95 used a 32-bit heap for user interface and graphics objects, whereas Windows 3.1 used a 16-bit heap.</p>
<p>Sometimes the programs were kind enough to do strict version checks to confirm that they were running on a system whose internals they understood. Sometimes their version checks were themselves broken, like one program that assumed that if the Windows version is not 3.0, 3.1, or 2.1, then it must be 2.0!</p>
<p>There were other one-off problems, like programs which detoured APIs in a way that no longer worked, but the ones that dug into operating system internals were by far the most common.</p>
<p>¹ What&#8217;s particularly frustrating is the cases where the program did this to access internal implementation details, when the information they wanted was already exposed by a public and supported API.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260407-00/?p=112213">Were there any Windows 3.1 programs that were so incompatible with Windows 95 that there was no point trying to patch them?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260407-00/?p=112213/feed</wfw:commentRss>
    <slash:comments>9</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>Learning to read C++ compiler errors: Illegal use of -&#062; when there is no -&#062; in sight</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260406-00/?p=112208</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260406-00/?p=112208#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Mon, 06 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112208</guid>
    <content:encoded><![CDATA[<p>A customer reported a problem with a system header file. When they included <tt>ole2.h</tt>, the compiler reported an error in <tt>oaidl.h</tt>:</p>
<pre>    MIDL_INTERFACE("3127CA40-446E-11CE-8135-00AA004BB851")
    IErrorLog : public IUnknown
    {
    public:
        <span style="border: solid 1px currentcolor;">virtual HRESULT STDMETHODCALLTYPE AddError(</span> // error here
            /* [in] */ __RPC__in LPCOLESTR pszPropName,
            /* [in] */ __RPC__in EXCEPINFO *pExcepInfo) = 0;
        
    };
</pre>
<p>The error message is</p>
<pre style="white-space: pre-wrap;">oaidl.h(5457,43): error C3927: '-&gt;': trailing return type is not allowed after a non-function declarator
oaidl.h(5457,43): error C3613: missing return type after '-&gt;' ('int' assumed)
oaidl.h(5457,43): error C3646: 'Log': unknown override specifier
oaidl.h(5457,43): error C2275: 'LPCOLESTR': expected an expression instead of a type
oaidl.h(5457,43): error C2146: syntax error: missing ')' before identifier 'pszPropName'
oaidl.h(5459,60): error C2238: unexpected token(s) preceding ';'
</pre>
<p>The compiler is seeing ghosts: It&#8217;s complaining about things that aren&#8217;t there, like <tt>-&gt;</tt> and Log.</p>
<p>When you see the compiler reporting errors about things that aren&#8217;t in the code, you should suspect a macro, because macros can insert characters into code.</p>
<p>In this case, I suspected that there is a macro called <code>AddError</code> whose expansion includes the token <tt>-&gt;</tt>.</p>
<p>The customer reported that they had no such macro.</p>
<p>I asked them to generate a preprocessor file for the code that isn&#8217;t compiling. That way, we can see what is being produced by the preprocessor before it goes into the part of the compiler that is complaining about the illegal use of <tt>-&gt;</tt>. Is there really no <tt>-&gt;</tt> there?</p>
<p>The customer reported back that, oops, they did indeed have a macro called <code>AddError</code>. Disabling the macro fixed the problem.</p>
<p>The compiler can at times be obtuse with its error messages, but as far as I know, it isn&#8217;t malicious. If it complains about a misused <tt>-&gt;</tt>, then there is probably a <tt>-&gt;</tt> that is being misused.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260406-00/?p=112208">Learning to read C++ compiler errors: Illegal use of &lt;TT&gt;-&gt;&lt;/TT&gt; when there is no &lt;TT&gt;-&gt;&lt;/TT&gt; in sight</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260406-00/?p=112208/feed</wfw:commentRss>
    <slash:comments>3</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
		
  <item>
    <title>How can I use Read&#173;Directory&#173;ChangesW to know when someone is copying a file out of the directory?</title>
    <link>https://devblogs.microsoft.com/oldnewthing/20260403-00/?p=112202</link>
    <comments>https://devblogs.microsoft.com/oldnewthing/20260403-00/?p=112202#comments</comments>
    <dc:creator><![CDATA[Raymond Chen]]></dc:creator>
    <pubDate>Fri, 03 Apr 2026 14:00:00 +0000</pubDate>
    <category><![CDATA[Old New Thing]]></category>
    <category><![CDATA[Code]]></category>
    <guid isPermaLink="false">https://devblogs.microsoft.com/oldnewthing/?p=112202</guid>
    <content:encoded><![CDATA[<p>A customer was using <code>Read­Directory­ChangesW</code> in the hopes of receiving a notification when a file was copied. They found that when a file was copied, they received a <code>FILE_<wbr />NOTIFY_<wbr />CHANGE_<wbr />LAST_<wbr />ACCESS</code>, but <a href="https://www.betaarchive.com/wiki/index.php?title=Microsoft_KB_Archive/245214"> only once an hour</a>. And they also got that notification even for operations unrelated to file copying.</p>
<p>Recall that <code>Read­Directory­ChangesW</code> and <code>Find­First­Change­Notification</code> are for <a title="ReadDirectoryChangesW reads directory changes, but what if the directory doesn't change?" href="https://devblogs.microsoft.com/oldnewthing/20110812-00/?p=9913"> detecting changes to information that would appear in a directory listing</a>. Your program can perform a <code>Find­First­File</code>/<code>Find­Next­File</code> to cache a directory listing, and then use <code>Read­Directory­ChangesW</code> or <code>Find­First­Change­Notification</code> to be notified that the directory listing has changed, and you have to invalidate your cache.</p>
<p>But there are a lot of operations that don&#8217;t affect a directory listing.</p>
<p>For example, a program could open a file in the directory with last access time updates suppressed. (Or the volume might have last access time updates suppressed globally.) There is no change to the directory listing, so no event is signaled.</p>
<p>Functions like <code>Read­Directory­ChangesW</code> and <code>Find­First­Change­Notification</code> functions operate at the file system level, so the fundamental operations they see are things like &#8220;read&#8221; and &#8220;write&#8221;. They don&#8217;t know <i>why</i> somebody is reading or writing. All they know is that it&#8217;s happening.</p>
<p>If you are a video rental store, you can see that somebody rented a documentary about pigs. But you don&#8217;t know <i>why</i> they rented that movie. Maybe they&#8217;re doing a school report. Maybe they&#8217;re trying to make illegal copies of pig movies. Or maybe they simply like pigs.</p>
<p>If you are the file system, you see that somebody opened a file for reading and read the entire contents. Maybe they are loading the file into Notepad so they can edit it. Or maybe they are copying the file. You don&#8217;t know. <b>Related</b>: <a title="If you let people read a file, then they can copy it" href="https://devblogs.microsoft.com/oldnewthing/20061206-00/?p=28813"> If you let people read a file, then they can copy it</a>.</p>
<p>In theory, you could check, when a file is closed, whether all the write operations collectively combine to form file contents that match a collective set of read operations from another file. Or you could hash the file to see if it matches the hash of any other file.¹ But these extra steps would get expensive very quickly.</p>
<p>Indeed, we found during user research that a common way for users to copy files is to load them into an application, and then use <i>Save As</i> to save a copy somewhere else. In many cases, this &#8220;copy&#8221; is not byte-for-byte identical to the original, although it is functionally identical. (For example, it might have a different value for <i>Total editing time</i>.) Therefore, detecting copying by comparing file hashes is not always successful.²</p>
<p>If your goal is to detect files being &#8220;copied&#8221; (however you choose to define it), you&#8217;ll have to operate at another level. For example, you could use various data classification technologies to attach security labels to files and let the data classification software do the work of preventing files from crossing security levels. These technologies usually work best in conjunction with programs that have been updated to understand and enforce these data classification labels. (My guess is that they also use heuristics to detect and classify usage by legacy programs.)</p>
<p>¹ It would also generate false positives for files that are identical merely by coincidence. For example, every empty file would be flagged as a copy of every other empty file.</p>
<p>Windows 2000 Server had a feature called Single Instance Store which looked for identical files, but it operated only when the system was idle. It didn&#8217;t run during the copy operation. This feature was subsequently deprecated in favor of <a href="https://learn.microsoft.com/en-us/windows-server/storage/data-deduplication/understand"> Data Deduplication</a>, which looks both for identical files as well as identical blocks of files. Again, Data Deduplication runs during system idle time. It doesn&#8217;t run during the copy operation. The duplicate is detected only after the fact. (Note the terminology: It is a &#8220;duplicate&#8221; file, not a &#8220;copy&#8221;. Two files could be identical without one being a copy of the other.)</p>
<p>² And besides, even if the load-and-save method produces byte-for-byte identical files, somebody who wanted to avoid detection would just make a meaningless change to the document before saving it.</p>
<p>The post <a href="https://devblogs.microsoft.com/oldnewthing/20260403-00/?p=112202">How can I use &lt;CODE&gt;Read&shy;Directory&shy;ChangesW&lt;/CODE&gt; to know when someone is copying a file out of the directory?</a> appeared first on <a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>.</p>
]]></content:encoded>
    <wfw:commentRss>https://devblogs.microsoft.com/oldnewthing/20260403-00/?p=112202/feed</wfw:commentRss>
    <slash:comments>3</slash:comments>
    <image type="image/png" url="https://devblogs.microsoft.com/oldnewthing/wp-content/uploads/sites/38/2025/10/banner-oldnewthing-blue.webp"/>
  </item>
	</channel>
</rss>
