<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet type="text/xsl" href="http://blogs.msdn.com/utility/FeedStylesheets/rss.xsl" media="screen"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:wfw="http://wellformedweb.org/CommentAPI/"><channel><title>The Old New Thing</title><link>http://blogs.msdn.com/oldnewthing/default.aspx</link><description>not actually &lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2008/07/17/8741112.aspx#8750046"&gt;to establish a blogging point where individuals can enrich their learns on facilitating and leveraging .NET-related activities most effectively&lt;/A&gt;</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>The difference between assignment and attachment with ATL smart pointers</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/20/9925918.aspx</link><pubDate>Fri, 20 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9925918</guid><dc:creator>oldnewthing</dc:creator><slash:comments>4</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9925918.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9925918</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9925918</wfw:comment><description>&lt;P&gt;
Last time,
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2009/11/19/9924950.aspx"&gt;
I presented a puzzle regarding a memory leak&lt;/A&gt;.
Here's the relevant code fragment:
&lt;/P&gt;
&lt;PRE&gt;
&lt;FONT COLOR=red&gt;CComPtr&amp;lt;IStream&amp;gt; pMemoryStream;&lt;/FONT&gt;
CComPtr&amp;lt;IXmlReader&amp;gt; pReader;
UINT nDepth = 0;

//Open read-only input stream
&lt;FONT COLOR=red&gt;pMemoryStream = ::SHCreateMemStream(utf8Xml, cbUtf8Xml);&lt;/FONT&gt;
&lt;/PRE&gt;
&lt;P&gt;
The problem here is assigning the return value of
&lt;CODE&gt;SHCreateMemStream&lt;/CODE&gt; to a smart pointer
instead of attaching it.
&lt;/P&gt;
&lt;P&gt;
The &lt;CODE&gt;SHCreateMemStream&lt;/CODE&gt; function creates a memory stream
and returns a pointer to it.
That pointer has a reference count of one,
in accordance with COM rules that a function
&lt;A HRef="http://msdn.microsoft.com/en-us/library/ms692481.aspx"&gt;
which produces a reference calls &lt;CODE&gt;AddRef&lt;/CODE&gt;,
and the responsibility is placed upon the recipient
to call &lt;CODE&gt;Release&lt;/CODE&gt;&lt;/A&gt;.
The assignment operator for &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt; is a copy operation:
It &lt;CODE&gt;AddRef&lt;/CODE&gt;s the pointer and saves it.
You're still on the hook for the reference count of the original pointer.
&lt;/P&gt;
&lt;PRE&gt;
ATLINLINE ATLAPI_(IUnknown*) AtlComPtrAssign(IUnknown** pp, IUnknown* lp)
{
        if (lp != NULL)
                lp-&amp;gt;AddRef();
        if (*pp)
                (*pp)-&amp;gt;Release();
        *pp = lp;
        return lp;
}

template &amp;lt;class T&amp;gt;
class CComPtr
{
public:
        ...

        T* operator=(T* lp)
        {
                return (T*)AtlComPtrAssign((IUnknown**)&amp;amp;p, lp);
        }
&lt;/PRE&gt;
&lt;P&gt;
Observe that assigning a &lt;CODE&gt;T*&lt;/CODE&gt; to a &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt;
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2004/04/06/108395.aspx"&gt;
&lt;CODE&gt;AddRef&lt;/CODE&gt;s the incoming pointer&lt;/A&gt;
and
&lt;CODE&gt;Release&lt;/CODE&gt;s the old pointer (if any).
When the &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt; is destructed, it will release
the pointer, undoing the &lt;CODE&gt;AddRef&lt;/CODE&gt; that was performed by
the assignment operator.
In other words, assignment followed by destruction has a net effect
of zero on the pointer you assigned.
The operation behaves like a copy.
&lt;/P&gt;
&lt;P&gt;
Another way of putting a pointer into a &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt;
is with the &lt;CODE&gt;Attach&lt;/CODE&gt; operator.
This is a transfer operation:
&lt;/P&gt;
&lt;PRE&gt;
        void Attach(T* p2)
        {
                if (p)
                        p-&amp;gt;Release();
                p = p2;
        }
&lt;/PRE&gt;
&lt;P&gt;
Observe that there is no &lt;CODE&gt;AddRef&lt;/CODE&gt; here.
When the &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt; is destructed,
it will perform the &lt;CODE&gt;Release&lt;/CODE&gt;,
which doesn't undo any operation performed by the &lt;CODE&gt;Attach&lt;/CODE&gt;.
Instead, it releases the reference count held by the original pointer
you attached.
&lt;/P&gt;
&lt;P&gt;
Let's put this in a table, since people seem to like tables:
&lt;/P&gt;
&lt;TABLE BORDER=1 BORDERCOLOR=black STYLE="border-collapse: collapse"
       CELLPADDING=3&gt;
&lt;TR&gt;
    &lt;TH&gt;Operation&lt;/TH&gt;
    &lt;TH&gt;Behavior&lt;/TH&gt;
    &lt;TH&gt;Semantics&lt;/TH&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;Attach()&lt;/TD&gt;
    &lt;TD&gt;Takes ownership&lt;/TD&gt;
    &lt;TD&gt;Transfer semantics&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;operator=()&lt;/TD&gt;
    &lt;TD&gt;Creates a new reference&lt;/TD&gt;
    &lt;TD&gt;Copy semantics&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TABLE&gt;
&lt;P&gt;
You use the &lt;CODE&gt;Attach&lt;/CODE&gt; method when you want to assume
responsibility for releasing the pointer (ownership transfer).
You use the assignment operator when you want the original pointer
to continue to be responsible for its own release (no ownership transfer).
&lt;/P&gt;
&lt;P&gt;
There is also a &lt;CODE&gt;Detach&lt;/CODE&gt; method which is the opposite of
&lt;CODE&gt;Attach&lt;/CODE&gt;:
Detaching a pointer from the &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt;
means "I am taking over responsibility for releasing this pointer."
The &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt; gives you its pointer and then forgets
about it; you're now on your own.
&lt;/P&gt;
&lt;P&gt;
The memory leak in the code fragment above occurs because the
assignment operator has copy semantics, but we wanted transfer
semantics,
since we want the smart pointer to take the responsibility for
releasing the pointer when it is destructed.
&lt;/P&gt;
&lt;PRE&gt;
pMemoryStream.Attach(::SHCreateMemStream(utf8Xml, cbUtf8Xml));
&lt;/PRE&gt;
&lt;P&gt;
The &lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;::operator=(T*)&lt;/CODE&gt; method
is definitely one of the more dangerous methods in the
&lt;CODE&gt;CComPtr&amp;lt;T&amp;gt;&lt;/CODE&gt; repertoire,
because it's so easy to assign a pointer to a smart pointer
without giving it a moment's thought.
(Another dangerous method is the
&lt;CODE&gt;T** CComPtr&amp;lt;T&amp;gt;::operator&amp;()&lt;/CODE&gt;,
but at least that has an assertion to try to catch the bad usages.
Even nastier is
&lt;A HREF="http://blogs.msdn.com/jaredpar/archive/2009/11/04/type-safety-issue-when-assigning-ccomptr-t-instances.aspx"&gt;
the secret QI'ing assignment operator&lt;/A&gt;.)
I have to say that there is merit to
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2004/04/06/108395.aspx#108407"&gt;
Ben Hutchings' recommendation&lt;/A&gt; simply not to allow a simple pointer
to be assigned to a smart pointer, precisely because the semantics are
easily misunderstood.
(The boost library, for example, follows Ben's recommendation.)
&lt;/P&gt;
&lt;P&gt;
Here's another exercise based on what you've learned:
&lt;/P&gt;
&lt;BLOCKQUOTE CLASS=q&gt;
&lt;P&gt;
Application Verifier told us that we have a memory leak,
and we traced it back to the
function &lt;CODE&gt;GetTextAsInteger&lt;/CODE&gt;.
&lt;/P&gt;
&lt;PRE&gt;
BSTR GetInnerText(IXMLDOMNode *node)
{
    BSTR bstrText = NULL;
    node-&amp;gt;get_text(&amp;amp;bstrText);
    return bstrText;
}

DWORD GetTextAsInteger(IXMLDOMNode *node)
{
    DWORD value = 0;

    CComVariant innerText = GetInnerText(node);
    hr = VariantChangeType(&amp;amp;innerText, &amp;amp;innerText, 0, VT_UI4);
    if (SUCCEEDED(hr))
    {
        value = V_UI4(&amp;amp;innerText);
    }

    return value;
}
&lt;/PRE&gt;
&lt;P&gt;
Obviously, the problem is that we passed the same input and output
pointers to &lt;CODE&gt;VariantChangeType&lt;/CODE&gt;,
causing the output integer to overwrite the input &lt;CODE&gt;BSTR&lt;/CODE&gt;,
resulting in the leak of the &lt;CODE&gt;BSTR&lt;/CODE&gt;.
But when we fixed the function, we still got the leak:
&lt;/P&gt;
&lt;PRE&gt;
DWORD GetTextAsInteger(IXMLDOMNode *node)
{
    DWORD value = 0;

    CComVariant innerText = GetInnerText(node);
    &lt;FONT COLOR=blue&gt;CComVariant textAsValue;&lt;/FONT&gt;
    hr = VariantChangeType(&amp;amp;innerText, &amp;amp;&lt;FONT COLOR=blue&gt;textAsValue&lt;/FONT&gt;, 0, VT_UI4);
    if (SUCCEEDED(hr))
    {
        value = V_UI4(&amp;amp;&lt;FONT COLOR=blue&gt;textAsValue&lt;/FONT&gt;);
    }

    return value;
}
&lt;/PRE&gt;
&lt;P&gt;
Is there a leak in the &lt;CODE&gt;VariantChangeType&lt;/CODE&gt; function itself?
&lt;/P&gt;
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;
Hint: It is in fact explicitly documented that the output parameter
to &lt;CODE&gt;VariantChangeType&lt;/CODE&gt; can be equal to the input parameter,
which results in an in-place conversion.
There was nothing wrong with the original call to
&lt;CODE&gt;VariantChangeType&lt;/CODE&gt;.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9925918" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Code/default.aspx">Code</category></item><item><title>We're using a smart pointer, so we can't possibly be the source of the leak</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/19/9924950.aspx</link><pubDate>Thu, 19 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9924950</guid><dc:creator>oldnewthing</dc:creator><slash:comments>27</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9924950.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9924950</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9924950</wfw:comment><description>&lt;P&gt;
A customer reported that there was a leak in the shell,
and they included the output from
&lt;A HREF="http://msdn.microsoft.com/en-us/library/ms220948.aspx"&gt;
Application Verifier&lt;/A&gt;
as proof.
And yup, the memory that was leaked was in fact allocated
by the shell:
&lt;/P&gt;
&lt;PRE&gt;
VERIFIER STOP 00000900 : pid 0x3A4: A heap allocation was leaked.

        497D0FC0 : Address of the leaked allocation.
        002DB580 : Adress to the allocation stack trace.
        0D65CFE8 : Address of the owner dll name.
        6F560000 : Base of the owner dll.

1: kd&amp;gt; du 0D65CFE8
0d65cfe8  "SHLWAPI.dll"

1: kd&amp;gt; !heap -p -a 497D0FC0
...
    ntdll!RtlpAllocateHeap+0x0003f236
    ntdll!RtlAllocateHeap+0x0000014f
    Kernel32!LocalAlloc+0x0000007c
    shlwapi!CreateMemStreamEx+0x00000043
    shlwapi!CreateMemStream+0x00000012
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x000642de
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x0005e2af
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x0002d49a
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x0002a0fd
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x000289cb
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x0002a25c
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x00027225
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x0002252b
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x00025394
    &amp;lt;Unloaded_xyz.dll&amp;gt;+0x0004d70f
    Kernel32!BaseThreadInitThunk+0x0000000d
    ntdll!RtlUserThreadStart+0x0000001d

1: kd&amp;gt; dps 002DB580
shlwapi!CreateMemStreamEx+0x43
shlwapi!CreateMemStream+0x12
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x642de
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x5e2af
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x2d49a
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x2a0fd
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x289cb
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x2a25c
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x27225
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x2252b
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x25394
&amp;lt;Unloaded_xyz.dll&amp;gt;+0x4d70f
Kernel32!BaseThreadInitThunk+0xd
ntdll!RtlUserThreadStart+0x1d
&lt;/PRE&gt;
&lt;P&gt;
On the other hand, &lt;CODE&gt;SHCreateMemStream&lt;/CODE&gt; is
an object creation function,
so it's natural that the function allocate some memory.
The responsibility for freeing the memory belongs to the caller.
&lt;/P&gt;
&lt;P&gt;
We suggested that the customer appears to have leaked the
interface pointer.
Perhaps there's a hole where they called &lt;CODE&gt;AddRef&lt;/CODE&gt;
and managed to avoid the matching &lt;CODE&gt;Release&lt;/CODE&gt;.
&lt;/P&gt;
&lt;P&gt;
"Oh no," the customer replied,
"that's not possible.
We call this function in only one place,
and we use a smart pointer,
so a leak is impossible."
The customer was kind enough to include a code snippet
and even highlighted the lines that proved they weren't
leaking.
&lt;/P&gt;
&lt;PRE&gt;
&lt;FONT COLOR=red&gt;CComPtr&amp;lt;IStream&amp;gt; pMemoryStream;&lt;/FONT&gt;
CComPtr&amp;lt;IXmlReader&amp;gt; pReader;
UINT nDepth = 0;

//Open read-only input stream
&lt;FONT COLOR=red&gt;pMemoryStream = ::SHCreateMemStream(utf8Xml, cbUtf8Xml);&lt;/FONT&gt;
&lt;/PRE&gt;
&lt;P&gt;
The exercise for today is to identify the irony in the
highlighted lines.
&lt;/P&gt;
&lt;P&gt;
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2008/06/23/8640472.aspx"&gt;
Hint&lt;/A&gt;.
Answers (and more discussion) tomorrow.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9924950" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Code/default.aspx">Code</category></item><item><title>News flash: Healthy people live longer</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/18/9924191.aspx</link><pubDate>Wed, 18 Nov 2009 15:00:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9924191</guid><dc:creator>oldnewthing</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9924191.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9924191</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9924191</wfw:comment><description>&lt;P&gt;
Researchers have determined that
&lt;A HREF="http://seattletimes.nwsource.com/html/health/2004138996_apfitnessdeathrisk22.html"&gt;
people in good physical condition live longer&lt;/A&gt;.
Who'd'a thunk it?
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9924191" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Non-Computer/default.aspx">Non-Computer</category></item><item><title>How do I move the Windows.edb and other search index files?</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/18/9923996.aspx</link><pubDate>Wed, 18 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9923996</guid><dc:creator>oldnewthing</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9923996.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9923996</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9923996</wfw:comment><description>&lt;P&gt;
Nothing profound today, just a little tip.
&lt;/P&gt;
&lt;BLOCKQUOTE CLASS=q&gt;
My customer is looking out for a way to change the location
of the windows.edb file to another (larger) drive.
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;
From the Indexing Options Control Panel, click &lt;I&gt;Advanced&lt;/I&gt;,
and then under &lt;I&gt;Index location&lt;/I&gt;, click
&lt;I&gt;Select new&lt;/I&gt;.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9923996" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Tips_2F00_Support/default.aspx">Tips/Support</category></item><item><title>We found the author of Notepad, sorry you didn't go to the award ceremony</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/17/9923309.aspx</link><pubDate>Tue, 17 Nov 2009 15:00:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9923309</guid><dc:creator>oldnewthing</dc:creator><slash:comments>34</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9923309.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9923309</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9923309</wfw:comment><description>&lt;P&gt;
I've received independent confirmations as to
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2009/11/02/9915989.aspx"&gt;
the authorship of Notepad&lt;/A&gt;,
so I'm inclined to believe it.
Sorry you didn't get to go to the award ceremony.
&lt;/P&gt;
&lt;P&gt;
The original author of Notepad also served as
the development manager for Windows&amp;nbsp;95.
His job was to herd the cats that made up the programmers who worked
on Windows&amp;nbsp;95,
a job which you can imagine falls into the "not easy" category.
&lt;/P&gt;
&lt;P&gt;
After Windows&amp;nbsp;95, he retired from the software industry
and became a high school science teacher.
At a social event some years later, I met him again and asked
about the transition from software development manager
to high school science teacher.
&lt;/P&gt;
&lt;P&gt;
His response:
"You'd be surprised how many of the skills transfer."
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9923309" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/History/default.aspx">History</category></item><item><title>How to tell when your patent has been approved</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/17/9923301.aspx</link><pubDate>Tue, 17 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9923301</guid><dc:creator>oldnewthing</dc:creator><slash:comments>10</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9923301.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9923301</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9923301</wfw:comment><description>&lt;P&gt;
There are a variety of ways of
&lt;A HREF="http://blogs.msdn.com/bgroth/archive/2008/07/01/i-finally-got-my-patent.aspx"&gt;
finding out when your patent is granted&lt;/A&gt;,
but the quickest mechanism is to check your mailbox.
But the thing to look for is not what you might think.
&lt;/P&gt;
&lt;P&gt;
Even before you receive word from your company's patent department,
&lt;A HREF="http://blogs.msdn.com/robch/archive/2007/05/03/my-first-patent.aspx"&gt;
you will start receiving junk mail delivered to your home address&lt;/A&gt;
from companies that sell patent-related novelties,
pointless trinkets like pencils and mugs with your patent number on it.
Nevermind that you can probably order personalized pencils
for much less than what the patent-chasers were offering.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9923301" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Non-Computer/default.aspx">Non-Computer</category></item><item><title>How to pretend that you attended my talk at UIUC Reflections|Projections 2009</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/16/9922754.aspx</link><pubDate>Mon, 16 Nov 2009 15:00:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9922754</guid><dc:creator>oldnewthing</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9922754.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9922754</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9922754</wfw:comment><description>&lt;P&gt;
&lt;B&gt;Step 1&lt;/B&gt;:
Buy a
1.55-ounce Hershey's Milk Chocolate Bar
from a convenience store, supermarket, or (if truly desperate)
&lt;A HREF="http://www.amazon.com/gp/product/B000IXWCQO?tag=tholneth-20"&gt;
online&lt;/A&gt;.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Step 2&lt;/B&gt;:
Print out
&lt;A HREF="http://blogs.msdn.com/blogfiles/oldnewthing/WindowsLiveWriter/Draftfortesting_AA00/img30_thumb.jpg"&gt;
this candy bar wrapper&lt;/A&gt;.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Step 3&lt;/B&gt;:
Trim wrapper on registration marks and wrap around candy bar.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Step 4&lt;/B&gt;:
Stay up late the night before you plan on watching the video
by partying with
&lt;A HREF="http://www.qwantz.com/"&gt;
Ryan North&lt;/A&gt;
and
&lt;A HREF="http://twitter.com/mokudekiru/status/4973332645"&gt;
teaching him how to play beer pong&lt;/A&gt;.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Step 5&lt;/B&gt;:
Force yourself to wake up the next morning and watch
&lt;A HREF="http://www.acm.uiuc.edu/conference/2009/videos.html"&gt;
the recorded video&lt;/A&gt;
of
&lt;A HREF="http://www.acm.uiuc.edu/conference/2009/speakers/chen.html"&gt;
my talk&lt;/A&gt;
while trying desperately to stay awake.
The candy bar might help.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Note&lt;/B&gt;: Although most steps are optional, they
are essential if you want an accurate simulation.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9922754" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Other/default.aspx">Other</category></item><item><title>Why does shlwapi import a nonexistent function?</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/16/9922753.aspx</link><pubDate>Mon, 16 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9922753</guid><dc:creator>oldnewthing</dc:creator><slash:comments>26</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9922753.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9922753</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9922753</wfw:comment><description>Commenter charless asks
&lt;A HREF="http://blogs.msdn.com/oldnewthing/pages/407234.aspx#681765"&gt;
why shlwapi.dll imports a nonexistent function from mpr.dll&lt;/A&gt;,
which shows up in dependency tools as a broken import.
&lt;/P&gt;
&lt;P&gt;
Because that function did exist at one point,
although it doesn't exist any more.
&lt;/P&gt;
&lt;P&gt;
The function in question was available only on Windows&amp;nbsp;95-series
versions of Windows.
It never existed on Windows&amp;nbsp;NT or any of its successors.
But remember that &lt;CODE&gt;shlwapi.dll&lt;/CODE&gt; was originally developed
for Internet Explorer,
which ran on Windows&amp;nbsp;95 as well as Windows&amp;nbsp;NT.
Internet Explorer checked the operating system and called
the Windows&amp;nbsp;95-only function only after verifying that it
was running on Windows&amp;nbsp;95.
If it was running on Windows&amp;nbsp;NT, then it never called the
function and therefore never stepped on the land mine known
as &lt;CODE&gt;ERROR_PROC_NOT_FOUND&lt;/CODE&gt;.
&lt;/P&gt;
&lt;P&gt;
Okay, so why does &lt;CODE&gt;shlwapi&lt;/CODE&gt; still link to the function
long after the Windows&amp;nbsp;95 series of operating systems have
become obsolete?
&lt;/P&gt;
&lt;P&gt;
Removing a function, even a function that doesn't do anything,
even an &lt;I&gt;undocumented&lt;/I&gt; function that doesn't do anything,
is a dangerous endeavor.
Suppose you have a program that links to the function,
but just like Internet Explorer, it is clever and checks
whether it is running on Windows&amp;nbsp;NT before calling it.
If you remove the useless function from &lt;CODE&gt;shlwapi&lt;/CODE&gt;,
then that program will
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2003/09/16/54938.aspx"&gt;
fail to load&lt;/A&gt;,
even though it never calls the offending function,
and now you have an application compatibility problem on your hands.
&lt;/P&gt;
&lt;P&gt;
Since it's a small function that doesn't do anything,
it's a lot less risky simply to leave the function in.
&lt;/P&gt;
&lt;P&gt;
Even though it doesn't do anything except fail.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9922753" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/History/default.aspx">History</category></item><item><title>What a drag: You can be a drag in managed code, too</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/13/9921677.aspx</link><pubDate>Fri, 13 Nov 2009 15:00:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9921677</guid><dc:creator>oldnewthing</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9921677.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9921677</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9921677</wfw:comment><description>&lt;P&gt;
&lt;A HREF="http://blogs.msdn.com/delay/"&gt;
David Anson&lt;/A&gt;
digests
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/tags/What+a+drag/default.aspx"&gt;
my earlier series on virtual drag/drop&lt;/A&gt;
and
&lt;A HREF="http://blogs.msdn.com/delay/archive/2009/10/26/creating-something-from-nothing-developer-friendly-virtual-file-implementation-for-net.aspx"&gt;
translates it into managed code&lt;/A&gt;.
His example of dragging his entire RSS feed
is an excellent illustration of dragging dynamically-generated
virtual content.
(I didn't use an example like that because the purpose of the
&lt;I&gt;What a drag&lt;/I&gt; series was to get something done in the least
amount of code, and generating a stream from a URL takes an
awful lot of code when doing it from the unmanaged side,
which would ultimately detract from the point of the example.)
&lt;/P&gt;
&lt;P&gt;
Bonus: He takes the example further by
&lt;A HREF="http://blogs.msdn.com/delay/archive/2009/11/04/creating-something-from-nothing-asynchronously-developer-friendly-virtual-file-implementation-for-net-improved.aspx"&gt;
adding asynchronous support&lt;/A&gt;.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9921677" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Code/default.aspx">Code</category><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/What+a+drag/default.aspx">What a drag</category></item><item><title>You thought reasoning about signals was bad, reasoning about a total breakdown of normal functioning is even worse</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/13/9921676.aspx</link><pubDate>Fri, 13 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9921676</guid><dc:creator>oldnewthing</dc:creator><slash:comments>17</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9921676.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9921676</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9921676</wfw:comment><description>&lt;P&gt;
A customer came to the Windows team with a question,
the sort of question which on its face seems somewhat strange,
which is itself a sign that the question is merely the tip of a much
more dangerous iceberg.
&lt;/P&gt;
&lt;BLOCKQUOTE CLASS=q&gt;
Under what circumstances will the
&lt;CODE&gt;GetEnvironmentVariable&lt;/CODE&gt; function hang?
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;
This is kind of an open-ended question.
I mean, for example, somebody might sneak in and call
&lt;CODE&gt;SuspendThread&lt;/CODE&gt; on your thread while
&lt;CODE&gt;GetEnvironmentVariable&lt;/CODE&gt; is running,
which will look like a hang because the call never completes
because the thread is frozen.
&lt;/P&gt;
&lt;P&gt;
But the real question for the customer is,
"What sort of problem are you seeing that is manifesting itself
in an apparent hang in the &lt;CODE&gt;GetEnvironmentVariable&lt;/CODE&gt; function?"
&lt;/P&gt;
&lt;P&gt;
The customer was kind enough to elaborate.
&lt;/P&gt;
&lt;BLOCKQUOTE CLASS=q&gt;
We have a global unhandled exception filter in our application
so we can log all failures.
After we finish logging, we call &lt;CODE&gt;ExitProcess&lt;/CODE&gt;,
but we find that the application never actually exits.
If we connect a debugger to the stuck application, we see it hung
in &lt;CODE&gt;GetEnvironmentVariable&lt;/CODE&gt;.
&lt;/BLOCKQUOTE&gt;
&lt;P&gt;
Your gut response should be,
"Holy cow, I'm surprised you even got that far!"
&lt;/P&gt;
&lt;P&gt;
This isn't one of those global unhandled exception filters that got
installed because your program plays some really clever
game with exceptions,
No, this is an "Oh no, my program just
crashed and I want to log it" exception handler.
In other words, when this exception handler "handles" an exception,
it's because your program has encountered some sort of
serious internal programming error for which the program
did not know how to recover.
We saw earlier that
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2008/07/28/8781423.aspx"&gt;
you can't do much in a signal handler&lt;/A&gt;
because you might have interrupted a block of code
which was in the middle of updating some data structures,
leaving them momentarily inconsistent.
But this exception filter is in an even worse state:
Not only is there a good chance that the program is in the middle
of updating something and left it in an inconsistent state,
you are in fact &lt;I&gt;guaranteed&lt;/I&gt; that the system is in a
corrupted state.
&lt;/P&gt;
&lt;P&gt;
Why is this a guarantee?
Because if the system were in a consistent state,
you wouldn't have crashed!
&lt;/P&gt;
&lt;P&gt;
Programming is about establishing invariants,
perturbing them, and then re-establishing them.
It is a game of stepping-stone from one island of consistency
to another.
But the code that does the perturbing and the re-establishing
assumes that it's starting from a consistent state to begin with.
For example, a function that removes a node from a doubly-linked list
manipulates some backward and forward link pointers
(temporarily violating the linked list invariant),
and then when it's finished, the linked list is back to a consistent state.
But this code assumes that the linked list is not corrupted to begin with!
&lt;/P&gt;
&lt;P&gt;
Let's look again at that call to &lt;CODE&gt;ExitProcess&lt;/CODE&gt;.
That's going to detach all the DLLs,
calling each DLL's &lt;CODE&gt;DllMain&lt;/CODE&gt; with the
&lt;CODE&gt;DLL_PROCESS_DETACH&lt;/CODE&gt; notification.
But of course, those &lt;CODE&gt;DllMain&lt;/CODE&gt; are going to assume
that the data structures are intact and nothing is corrupted.
On the other hand, you know for a fact that these prerequisites
are not met&amp;mdash;the program crashed precisely because something
is corrupted.
One DLL might
walk a linked list&amp;mdash;but you might have
crashed because that linked list is corrupted.
Another DLL might try to delete a critical section&amp;mdash;but
you might have crashed because the data structure containing the
critical section is corrupted.
&lt;/P&gt;
&lt;P&gt;
Heck, the crash might have been inside somebody's
&lt;CODE&gt;DLL_PROCESS_DETACH&lt;/CODE&gt; handler to begin with,
for all you know.
&lt;/P&gt;
&lt;P&gt;
"Yeah, but the documentation for &lt;CODE&gt;TerminateProcess&lt;/CODE&gt;
says that it does not clean up shared memory."
&lt;/P&gt;
&lt;P&gt;
Well, it depends on what you mean by &lt;I&gt;clean up&lt;/I&gt;.
The reference count on the shared memory is properly decremented
when the handle is automatically closed as part of process
cleanup,
and the shared memory will be properly freed once there are no
more references to it.
It is not cleaned up in the sense of
"corruption is repaired"&amp;mdash;but of course the operating system
can't do that because it doesn't know what the semantics
of your shared memory block are.
&lt;/P&gt;
&lt;P&gt;
But this is hardly anything to get concerned about because
&lt;I&gt;your program doesn't know how to un-corrupt the data either&lt;/I&gt;.
&lt;/P&gt;
&lt;P&gt;
"It also says that DLLs don't receive their
&lt;CODE&gt;DLL_PROCESS_DETACH&lt;/CODE&gt; notification."
&lt;/P&gt;
&lt;P&gt;
As we saw before, this is a good thing in the case of a corrupted process,
 because the code that runs in &lt;CODE&gt;DLL_PROCESS_DETACH&lt;/CODE&gt;
assumes that your process has not been corrupted in the first place.
There's no point running it
&lt;I&gt;when you know the process is corrupted&lt;/I&gt;.
You're just making a bad situation worse.
&lt;/P&gt;
&lt;P&gt;
"It also says that I/O will be in an indeterminate state."
&lt;/P&gt;
&lt;P&gt;
Well yeah, but that's no worse than what you have now,
which is that your I/O is in an indeterminate state.
You don't know what buffers your process hasn't flushed,
but since your process is corrupted,
you have no way of finding out anyway.
&lt;/P&gt;
&lt;P&gt;
"Are you seriously recommending that I use
&lt;CODE&gt;TerminateProcess&lt;/CODE&gt; to exit
the last chance exception handler?!?"
&lt;/P&gt;
&lt;P&gt;
Your process is unrecoverably corrupted.
(This is a fact, because if there were a way to recover from it,
&lt;I&gt;you would have done it instead of crashing&lt;/I&gt;.)
What other options are there?
&lt;/P&gt;
&lt;P&gt;
Quit while you're behind.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9921676" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Code/default.aspx">Code</category></item><item><title>Why can you create a PIF file that points to something that isn't an MS-DOS program?</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/12/9921112.aspx</link><pubDate>Thu, 12 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9921112</guid><dc:creator>oldnewthing</dc:creator><slash:comments>22</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9921112.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9921112</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9921112</wfw:comment><description>&lt;P&gt;
James MAstros
asked
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2006/01/30/519388.aspx#519544"&gt;
why it's possible to create a PIF file that
refers to a program that isn't an MS-DOS program&lt;/A&gt;.
(That's only part of the question; I
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2008/03/24/8332730.aspx"&gt;
addressed other parts last year&lt;/A&gt;.)
&lt;/P&gt;
&lt;P&gt;
Well, for one thing, there was indeed code to prevent you from
setting PIF properties for
something that isn't an MS-DOS program,
so the precaution was already there.
But it didn't stop anybody who was really determined to try.
All you had to do was create an MS-DOS program,
then create a PIF file for it,
and then overwrite the MS-DOS program file with something else.
Since time travel has not been invented,
the PIF creator code can't retroactively go back in and say,
"Well, if I knew you were going to pull this trick,
I wouldn't have let you create it in the first place!"
You can't even enforce it at the time the PIF file is launched,
because somebody could replace the file during the split second
between checking the file type and actually using it.
&lt;/P&gt;
&lt;P&gt;
Of course, the real question is "Why, if you create a PIF file
that describes something that isn't an MS-DOS program,
does it still work?"
It still works because the PIF file did exactly what it was supposed to do.
It created an MS-DOS virtual machine with the specified parameters
and then ran the program in it.
&lt;/P&gt;
&lt;P&gt;
Now, back in the days when PIF files were invented,
if you tried to run something that wasn't an MS-DOS program
inside an MS-DOS virtual machine,
all that happened was that the MS-DOS stub ran,
the same thing that happened if you tried to run the program
from MS-DOS.
The program was treated not as a Windows program but as an MS-DOS program.
&lt;/P&gt;
&lt;P&gt;
Windows&amp;nbsp;95 changed that.
If you tried to run a Windows application from the MS-DOS command prompt,
it would run the Windows application instead of telling you,
"This program cannot be run in DOS mode."
This change was made for two reasons.
&lt;/P&gt;
&lt;P&gt;
First, the existing behavior seemed pretty stupid.
You're running Windows, and if you open a command prompt and try
to run a Windows program, you're told,
"You need Windows to run this program."
It's like one of those bizarro-land government red tape nightmares,
where you go to the courthouse to file some papers in person,
and the clerk at the desk says,
"I'm sorry, you have to file this document in person at the courthouse."
&lt;/P&gt;
&lt;P&gt;
Second, it was necessary to allow 32-bit console programs to run
when launched from a MS-DOS command window.
Since Windows&amp;nbsp;95 used the MS-DOS prompt as its command line
interface (as opposed to Windows&amp;nbsp;NT which used a 32-bit
command prompt),
it was kind of important that you be
able to run 32-bit console programs from a virtual
machine.
Without it, the whole idea of a console program became kind of weak.
"Yeah, we have console programs, but you can't launch them from
a console."
&lt;/P&gt;
&lt;P&gt;
What happens, then, if you create PIF file that points to a 32-bit program?
Well, the operating system goes to all the effort to create a virtual
machine to the specifications you indicated in the PIF file.
You want a particular amount of extended memory? Okay, we'll set that up.
You want a custom icon? Sure, no problem.
You want it to disable DPMI memory? You got it.
Once that's all set up, the virtual MS-DOS driver says,
"Okay, and set the initial CS:IP for the virtual machine to
the MS-DOS EXEC call to run the program the PIF file specified."
The EXEC call executes, and the interop code kicks in and launches
the 32-bit Windows program.
&lt;/P&gt;
&lt;P&gt;
From the virtual machine's point of view,
nothing is actually wrong; you merely did something
in a really roundabout way.
It's like booking a meeting room,
specifying that you would like a slide projector,
that the chairs and tables be set in a particular arrangement,
that everybody be provided with water and a notebook,
and then putting a sign on the door that says,
"This meeting has moved to Location&amp;nbsp;Z."
You go to all this effort to get the conference room to be
set up exactly the way you want it, and then you end up not using it.
The conference center doesn't care (as long as it still gets paid).
&lt;/P&gt;
&lt;P&gt;
PIF files are like shortcuts,
but with the added effort of creating an MS-DOS virtual machine.
And just like with shortcuts,
bad guys can choose a dangerous target and make your day miserable.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9921112" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/History/default.aspx">History</category></item><item><title>Leave it to the Taiwanese to think of wrapping a donut inside another donut</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/11/9920544.aspx</link><pubDate>Wed, 11 Nov 2009 15:00:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9920544</guid><dc:creator>oldnewthing</dc:creator><slash:comments>19</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9920544.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9920544</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9920544</wfw:comment><description>&lt;P&gt;
The food known in Mandarin Chinese as
&lt;A HREF="http://en.wikipedia.org/wiki/Youtiao"&gt;
&amp;#x6CB9;&amp;#x689D; (y&amp;oacute;uti&amp;aacute;o)&lt;/A&gt;,
but which in Taiwanese goes by the name
&amp;#x6CB9;&amp;#x70B8;&amp;#x7CBF;,
is basically a fried stick of dough,
similar to a cruller, but puffier rather than cakey.
The traditional way of eating it is to wrap it inside a
&lt;A HREF="http://en.wikipedia.org/wiki/Shaobing"&gt;
&amp;#x71D2;&amp;#x9905;&lt;/A&gt;
(a sesame-coated flatbread),
and dip the entire combination into a bowl of
hot soy milk.
I prefer salty soy milk, but some people prefer sweet.
(Those people who prefer the sweet version are clearly wrong.)
&lt;/P&gt;
&lt;P&gt;
Obviously,
the &lt;I&gt;donut sandwich&lt;/I&gt; was invented before the low-carb diet craze.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Sidebar&lt;/B&gt;:
Salty soy milk (&amp;#x9E79;&amp;#x8C46;&amp;#x6F3F;)
is one of those nostalgia breakfasts for me,
or more accurately, one of those manufactured nostalgia breakfasts,
because I didn't actually eat it that much as a child.
&lt;/P&gt;
&lt;P&gt;
&lt;B&gt;Sidebar&amp;nbsp;2&lt;/B&gt;:
For authentic Chinese food in Seattle,
my choice is
&lt;A HREF="http://www.chiangsgourmet.com/"&gt;
Chiang's Gourmet&lt;/A&gt;.
They have an extensive menu of
standard Chinese breakfast foods.
The service is surly, but that somehow just adds to the experience.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9920544" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Non-Computer/default.aspx">Non-Computer</category></item><item><title>Trying to avoid double-destruction and inadvertently triggering it</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/11/9920543.aspx</link><pubDate>Wed, 11 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9920543</guid><dc:creator>oldnewthing</dc:creator><slash:comments>34</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9920543.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9920543</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9920543</wfw:comment><description>&lt;P&gt;
We saw some time ago the importance of
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2005/09/28/474855.aspx"&gt;
artificially bumping an object's reference count during destruction
to avoid double-destruction&lt;/A&gt;.
However, one person's attempt to avoid this problem ended up triggering it.
&lt;/P&gt;
&lt;PRE&gt;
ULONG MyObject::Release()
{
 LONG cRef = InterlockedDecrement(&amp;amp;m_cRef);
 if (cRef &amp;gt; 0) return cRef;
 m_cRef = MAXLONG; // avoid double-destruction
 delete this;
 return 0;
}
&lt;/PRE&gt;
&lt;P&gt;
The explanation for the line &lt;CODE&gt;m_cRef = MAXLONG&lt;/CODE&gt;
was that it was done
to avoid the double-destruction problem if the object receives
a temporary &lt;CODE&gt;AddRef/Release&lt;/CODE&gt; during destruction.
&lt;/P&gt;
&lt;P&gt;
While it's true that you should set the reference count to an artificial
non-zero value,
choosing &lt;CODE&gt;MAXLONG&lt;/CODE&gt; has its own problem:
integer overflow.
&lt;/P&gt;
&lt;P&gt;
Suppose that during the object's destruction,
the reference count is temporarily incremented twice and decremented
twice.
&lt;/P&gt;
&lt;TABLE BORDER=1 CELLPADDING=3&gt;
&lt;TR&gt;
    &lt;TH&gt;Action&lt;/TH&gt;
    &lt;TH&gt;m_cRef&lt;/TH&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;Just before call to Release()&lt;/TD&gt;
    &lt;TD&gt;1&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;InterlockedDecrement&lt;/TD&gt;
    &lt;TD&gt;0&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;m_cRef = MAXLONG&lt;/TD&gt;
    &lt;TD&gt;2147483647&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;destructor does temporary &lt;CODE&gt;AddRef()&lt;/CODE&gt;&lt;/TD&gt;
    &lt;TD&gt;&amp;minus;2147483648 (integer overflow)&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;destructor does temporary &lt;CODE&gt;AddRef()&lt;/CODE&gt;&lt;/TD&gt;
    &lt;TD&gt;&amp;minus;2147483647&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD&gt;destructor does temporary &lt;CODE&gt;Release()&lt;/CODE&gt;&lt;/TD&gt;
    &lt;TD&gt;&amp;minus;2147483648&lt;/TD&gt;
&lt;/TR&gt;
&lt;TR&gt;
    &lt;TD COLSPAN=2&gt;since &lt;CODE&gt;m_cRef&lt;/CODE&gt; &amp;lt; 0, we re-destruct&lt;/TD&gt;
&lt;/TR&gt;
&lt;/TABLE&gt;
&lt;P&gt;
Sure, choosing a huge &lt;CODE&gt;DESTRUCTOR_REFCOUNT&lt;/CODE&gt;
means that you have absolutely no chance of decrementing
the reference count back to zero prematurely.
However, if you choose a value too high, you introduce the
risk of &lt;I&gt;incrementing&lt;/I&gt; the reference count
so high that it overflows.
&lt;/P&gt;
&lt;P&gt;
That's why the most typical values for &lt;CODE&gt;DESTRUCTOR_REFCOUNT&lt;/CODE&gt;
are 1, 42, and 1000.
The value 1 is really all you need to avoid double-destruction.
Some people choose 42 because it's cute,
and other people choose 1000 because it's higher than any "normal"
refcount, so it makes it easier to spot during debugging.
But even then, the "high" value of 1000 still leaves room for over
two billion &lt;CODE&gt;AddRef()&lt;/CODE&gt;s before overflowing the
reference count.
&lt;/P&gt;
&lt;P&gt;
On the other hand, if you choose a value like &lt;CODE&gt;MAXLONG&lt;/CODE&gt;
or &lt;CODE&gt;MAXDWORD&lt;/CODE&gt;,
then you're taking something that previously never happened
(reference count integer overflow)
and turning it into an almost certainty.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9920543" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Code/default.aspx">Code</category></item><item><title>I reorganized your kitchen for you, sweetie</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/10/9919922.aspx</link><pubDate>Tue, 10 Nov 2009 15:00:01 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9919922</guid><dc:creator>oldnewthing</dc:creator><slash:comments>29</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9919922.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9919922</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9919922</wfw:comment><description>&lt;P&gt;
I suspect most people are familiar with the
&lt;A HREF="http://blogs.msdn.com/oldnewthing/archive/2008/03/07/8080064.aspx#8102228"&gt;
&lt;I&gt;It may be a mess, but it's my mess and I know where everything is&lt;/I&gt;&lt;/A&gt;
phenomenon.
That doesn't necessarily mean that items are in the best location,
but at least you know which suboptimal location you chose.
&lt;/P&gt;
&lt;P&gt;
&lt;A HREF="http://wendyhome.com/"&gt;
::&amp;nbsp;Wendy&amp;nbsp;::&lt;/A&gt;
told me a story some time ago about something that happened
while her parents were visiting.
When she returned from work, her mother said,
"Oh,
&lt;A HREF="http://en.wikipedia.org/wiki/Wendy_Darling"&gt;
Wendy, darling&lt;/A&gt;,
I reorganized your kitchen for you.
You had everything in the wrong place."
&lt;/P&gt;
&lt;P&gt;
Wendy's mother was trying to be helpful, but of course
it was a net loss for poor Wendy, who couldn't find anything
in her kitchen for weeks.
Yes, there was the whole
&lt;I&gt;Oh great where did my mother put my food processor?&lt;/I&gt;
problem, but even after she found it,
the "improved" location was far
worse than its original location.
In fact, in many cases, it was in the exact opposite location
from where it should be.
&lt;/P&gt;
&lt;P&gt;
You see, Wendy is left-handed, and her mother is right-handed.
&lt;/P&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9919922" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Non-Computer/default.aspx">Non-Computer</category></item><item><title>Little-known command line utility: clip</title><link>http://blogs.msdn.com/oldnewthing/archive/2009/11/10/9919908.aspx</link><pubDate>Tue, 10 Nov 2009 15:00:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9919908</guid><dc:creator>oldnewthing</dc:creator><slash:comments>55</slash:comments><comments>http://blogs.msdn.com/oldnewthing/comments/9919908.aspx</comments><wfw:commentRss>http://blogs.msdn.com/oldnewthing/commentrss.aspx?PostID=9919908</wfw:commentRss><wfw:comment>http://blogs.msdn.com/oldnewthing/rsscomments.aspx?PostID=9919908</wfw:comment><description>&lt;P&gt;
Windows Vista includes a tiny command line utility called &lt;CODE&gt;clip&lt;/CODE&gt;.
All it does is paste its stdin onto the clipboard.
&lt;/P&gt;
&lt;PRE&gt;
dir | clip
echo hey | clip
&lt;/PRE&gt;
&lt;P&gt;
For the opposite direction, I use a little perl script:
&lt;/P&gt;
&lt;PRE&gt;
use Win32::Clipboard;
print Win32::Clipboard::GetText();
&lt;/PRE&gt;
&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9919908" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/oldnewthing/archive/tags/Tips_2F00_Support/default.aspx">Tips/Support</category></item></channel></rss>