<?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>Larry Osterman's WebLog : Things you shouldn't do.</title><link>http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx</link><description>Tags: Things you shouldn't do.</description><dc:language>en-US</dc:language><generator>CommunityServer 2.1 SP1 (Build: 61025.2)</generator><item><title>I can make it arbitrarily fast if I don’t actually have to make it work.</title><link>http://blogs.msdn.com/larryosterman/archive/2009/09/29/i-can-make-it-arbitrarily-fast-if-i-don-t-actually-have-to-make-it-work.aspx</link><pubDate>Wed, 30 Sep 2009 00:49:37 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9901016</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>26</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9901016.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9901016</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9901016</wfw:comment><description>&lt;p&gt;Digging way back into my pre-Microsoft days, I was recently reminded of a story that I believe was told to me by &lt;a href="http://en.wikipedia.org/wiki/Mary_Shaw_(computer_scientist)"&gt;Mary Shaw&lt;/a&gt; back when I took her Computer Optimization class at Carnegie-Mellon…&lt;/p&gt;  &lt;p&gt;During the class, Mary told an anecdote about a developer “Sue” who found a bug in another developer’s “Joe” code that “Joe” introduced with a performance optimization.&amp;#160; When “Sue” pointed the bug out to “Joe”, his response was “Oops, but it’s WAY faster with the bug”.&amp;#160; “Sue” exploded “If it doesn’t have to be correct, I can calculate the result in 0 time!” [1].&lt;/p&gt;  &lt;p&gt;Immediately after telling this anecdote, she discussed a contest that the CS faculty held for the graduate students every year.&amp;#160; Each year the CS faculty posed a problem to the graduate students with a prize awarded to the grad student who came up with the most efficient (fastest) solution to the problem.&amp;#160; She then assigned the exact same problem to us:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“Given a copy of the “Declaration of Independence”, calculate the 10 most common words in the document”&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;We all went off and built programs to parse the words in the document, inserting them into a tree (tracking usage) and read off the 10 most frequent words.&amp;#160; The next assignment was “Now make it fast – the 5 fastest apps get an ‘A’, the next 5 get a ‘B’, etc.”&lt;/p&gt;  &lt;p&gt;So everyone in the class (except me :)) went out and rewrote their apps to use a hash table so that their insertion time was constant and then they optimized the heck out of their hash tables[2].&lt;/p&gt;  &lt;p&gt;After our class had our turn, Mary shared the results of what happened when the CS grad students were presented with the exact same problem.&lt;/p&gt;  &lt;p&gt;Most of them basically did what most of the students in my class did – built hash tables and tweaked them.&amp;#160; But a couple of results stood out.&lt;/p&gt;  &lt;ul&gt;   &lt;li&gt;The first one simply hard coded the 10 most common words in their app and printed them out.&amp;#160; This was disqualified because it was perceived as breaking the rules.&lt;/li&gt;    &lt;li&gt;The next one was quite clever.&amp;#160; The grad student in question realized that they could write the program much faster if they wrote it in assembly language.&amp;#160; But the rules of the contest required that they use Pascal for the program.&amp;#160; So the grad student essentially created an array on the stack and introduced a buffer overflow and he loaded his assembly language program into the buffer and used that as a way of getting his assembly language version of the program to run.&amp;#160; IIRC he wasn’t disqualified but he didn’t win because he circumvented the rules (I’m not sure, it’s been more than a quarter century since Mary told the class this story).&lt;/li&gt;    &lt;li&gt;The winning entry was even more clever.&amp;#160; He realized that he didn’t actually need to track all the words in the document.&amp;#160; Instead he decided to track only some of the words in the document in a fixed array.&amp;#160; His logic was that each of the 10 most frequent words were likely to appear in the first &amp;lt;n&amp;gt; words in the document so all he needed to do was to figure out what &amp;quot;”n” is and he’d be golden.&lt;/li&gt; &lt;/ul&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;So the moral of the story is “Yes, if it doesn’t have to be correct, you can calculate the response in 0 time.&amp;#160; But sometimes it’s ok to guess and if you guess right, you can get a huge performance benefit from the result”.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;[1] This anecdote might also come from Jon L. Bentley’s “Writing Efficient Programs”, I’ll be honest and say that I don’t remember where I heard it (but it makes a great introduction to the subsequent story).&lt;/p&gt;  &lt;p&gt;[2] I was stubborn and decided to take my binary tree program and make it as efficient as possible but keep the basic structure of the solution (for example, instead of comparing strings, I calculated a hash for the string and compared the hashes to determine if strings matched).&amp;#160; I don’t remember if I was in the top 5 but I was certainly in the top 10.&amp;#160; I do know that my program beat out most of the hash table based solutions.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9901016" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Software+Engineering/default.aspx">Software Engineering</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Fascinating+geek+stuff/default.aspx">Fascinating geek stuff</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>The story behind the mysterious “Ding” in Windows Vista.</title><link>http://blogs.msdn.com/larryosterman/archive/2009/09/03/the-story-behind-the-mysterious-ding-in-windows-vista.aspx</link><pubDate>Fri, 04 Sep 2009 03:29:20 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9891148</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>16</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9891148.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9891148</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9891148</wfw:comment><description>&lt;p&gt;I just ran into this fairly old post on Channel 9.&amp;#160; mstefan &lt;a href="http://channel9.msdn.com/forums/Coffeehouse/256901-Stop-the-Ding/"&gt;reported&lt;/a&gt; that his applications played a “Ding” noise when selecting an item in a listview (or tree) control.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;It turns out that I’d had the problem independently reported to me by one of the people here at Microsoft.&amp;#160; Here were his reproduction steps:&lt;/p&gt;  &lt;ol&gt;   &lt;li&gt;Clean Install Windows&lt;/li&gt;    &lt;li&gt;Open the sounds control panel&lt;/li&gt;    &lt;li&gt;Set the “Select” sound to a value&lt;/li&gt;    &lt;li&gt;Clear the “Select” sound (set it to “(None)”).&lt;/li&gt;    &lt;li&gt;Change the selection in a listview&lt;/li&gt; &lt;/ol&gt;  &lt;p&gt;Complicating matters is that this didn’t occur with many apps, just a couple of Windows Forms applications that the person at Microsoft had.&amp;#160; So I dug into it a bit.&lt;/p&gt;  &lt;p&gt;I quickly realized that the problem was that the application was calling PlaySound without the “SND_NODEFAULT” flag.&amp;#160; I’ve written about this flag &lt;a href="https://blogs.msdn.com/larryosterman/archive/2008/09/25/why-specify-snd-nodefault-when-calling-playsound.aspx"&gt;before&lt;/a&gt; (in fact I wrote that post shortly after investigating this issue, so that post contains part of the story).&lt;/p&gt;  &lt;p&gt;Digging in deeper, I realized that the application was using version 5 of the common controls (there are two versions in Windows, v5 and v6).&amp;#160; The problem didn’t occur in the version 6 common controls (this is why most applications didn’t reproduce the problem).&lt;/p&gt;  &lt;p&gt;So why did the problem occur?&lt;/p&gt;  &lt;p&gt;The common controls have a single routine which calls PlaySound and that code attempts to be somewhat clever.&amp;#160; Instead of simply calling PlaySound, the code instead read the HKEY_CURRENT_USER\AppEvents\Schemes\.Default\CCSelect registry key.&amp;#160; If the key didn’t exist, it skipped calling PlaySound.&amp;#160; If the CCSelect registry key existed, it would call PlaySound specifying the CCSelect alias.&lt;/p&gt;  &lt;p&gt;I’ve actually run into this pattern a bunch in WIndows – teams decided that calling PlaySound was “too slow”, or had “too much overhead” so they tried to avoid the call to PlaySound if the call to PlaySound wasn’t going to do anything (once upon a time it was important to avoid calling PlaySound because it could sometimes hang your application for several seconds – this isn’t the case any more if you specify SND_ASYNC).&lt;/p&gt;  &lt;p&gt;The problem is that when you hit step 2 above (setting the “Select” sound), the control panel created the CCSelect registry key with a default value of the sound file you’re setting.&amp;#160; When you set it to “None” the control panel cleared the value of the sound contained under the key.&amp;#160; But the key itself wasn’t deleted.&amp;#160; So the check above that checked for the registry key’s existence succeeded and it called PlaySound.&amp;#160; But because the call didn’t specify SND_NODEFAULT, the PlaySound API decided to play the default sound when it realized that there wasn’t a sound associated with the CCSelect alias.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;I wanted to understand how this bug was introduced so I looked back at the source history of the file containing the bug.&amp;#160; It turns out that this was actually a bug fix made to Windows XP that wasn’t incorporated into Windows Server 2003.&amp;#160; When Windows Vista was created, the team started with the Windows Server 2003 code base and incorporated all the bug fixes made since Windows XP forked into the Win2K3 code base.&amp;#160; For whatever reason, this particular fix was missed when the team did the merge.&amp;#160; Because the behavior was so subtle (to trigger the change you MUST go through steps 2 through 4 to get the registry key created and your app must use the v5 of the common controls).&lt;/p&gt;  &lt;p&gt;Needless to say, it’s fixed in WIndows 7.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9891148" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Microsoft+History/default.aspx">Microsoft History</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code, part 26 – the answer</title><link>http://blogs.msdn.com/larryosterman/archive/2009/06/29/what-s-wrong-with-this-code-part-26-the-answer.aspx</link><pubDate>Mon, 29 Jun 2009 21:22:11 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9808804</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>6</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9808804.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9808804</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9808804</wfw:comment><description>&lt;p&gt;Yesterday I posted a code snippet from inside a real piece of code inside the client side of a client/server utility in a Microsoft product.&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre&gt;static DWORD WINAPI _PlayBeep(__in void* pv)
{
    UNREFERENCED_PARAMETER(pv);
    PlaySound(L&amp;quot;.Default&amp;quot;, NULL, SND_SYNC | SND_ALIAS);
    return 0;
}

LRESULT WndProc(...)
{
    :
    :
    case WM_KEYDOWN:
        if (!_AcceptInputKeys(wParam, lParam))
        {
            QueueUserWorkItem(_PlayBeep, NULL, 0);
        }
        break;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;The bug here was that the call to PlaySound is synchronous.&amp;#160; Like many Win32 APIs, PlaySound is made thread-safe by taking a critical section around the code that does the work inside the call to PlaySound (since the semantics of PlaySound are that only one PlaySound call plays at any time, this is a reasonable thing to do).&amp;#160; Because the call to PlaySound specifies SND_SYNC, that processing is done on the thread that calls PlaySound and thus blocks the _PlayBeep call until the sound completes.&amp;#160; The “.Default” sound is approximately 1 second long, so the call to _PlayBeep takes about a second to complete.&lt;/p&gt;

&lt;p&gt;Unfortunately keyboards repeat at a lot faster than 1 keystroke/second and each keystroke causes a call to QueueUserWorkItem.&amp;#160; Because there’s no thread available to process the request, the thread pool logic creates a new thread to process the next work item for each keystroke.&amp;#160; This quickly backs up and eventually you run into the 500 thread limit in the default process threadpool.&amp;#160; So you’re going to have the machine play “Ding’s” for hours before this cleans itself up.&lt;/p&gt;

&lt;p&gt;But in this case the effects were was even worse.&amp;#160; &lt;/p&gt;

&lt;p&gt;Remember when I told you that it was a client/server utility?&amp;#160; In this case, it meant that it used async RPC to communicate with the server.&amp;#160; And async RPC uses the default thread pool for on certain applications.&amp;#160; When the response to a server request came in, there were no RPC threads running so RPC tried to create a thread in the default threadpool.&amp;#160; Which failed because the default threadpool was full.&lt;/p&gt;

&lt;p&gt;So the client/server utility stopped working.&amp;#160; It took about 15 seconds of hammering on invalid keys to get the utility into this state, NOT pretty.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The first fix was to change the WM_KEYDOWN to WM_KEYUP (so that you actually had to release the keys instead of letting the &lt;a href="http://www.answers.com/topic/typematic"&gt;typematic&lt;/a&gt; feature repeat for you).&amp;#160; That didn’t work because it still could be reproduced, it just took longer.&lt;/p&gt;

&lt;p&gt;The final fix was:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre&gt;static DWORD WINAPI _PlayBeep()
{
    PlaySound(L&amp;quot;.Default&amp;quot;, NULL, SND_&lt;strong&gt;&lt;font color="#ff0000"&gt;A&lt;/font&gt;&lt;/strong&gt;SYNC | SND_ALIAS);
    return 0;
}

LRESULT WndProc(...)
{
    :
    :
    case WM_KEYDOWN:
        if (!_AcceptInputKeys(wParam, lParam))
        {
            _PlayBeep();
        }
        break;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;So instead of queueing a work item, the team changed the code to simply call PlaySound with SND_ASYNC and they were done.&amp;#160; When you specify SND_ASYNC, the PlaySound call queues the request to an internal-to-playsound worker thread, and it cancels the old sound before it starts playing a new sound (thus the sounds don’t back up).&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;The object lesson here is: Don’t queue long running items to the thread pool because it can lead to unexpected results.&amp;#160; And even a 1 second “Ding” can count as “long running” if it can be queued rapidly enough.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9808804" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code, part 26 – a real-world example</title><link>http://blogs.msdn.com/larryosterman/archive/2009/06/25/what-s-wrong-with-this-code-part-26-a-real-world-example.aspx</link><pubDate>Thu, 25 Jun 2009 22:26:14 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9804115</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>28</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9804115.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9804115</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9804115</wfw:comment><description>&lt;p&gt;This is an example of a real-world bug that was recently fixed in an unreleased Microsoft product.&amp;#160; I was told about the bug because it involved the PlaySound API (and thus they asked me to code review the fix), but it could happen with any application.&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;static&lt;/span&gt; DWORD WINAPI _PlayBeep(__in &lt;span class="kwrd"&gt;void&lt;/span&gt;* pv)
{
    UNREFERENCED_PARAMETER(pv);
    PlaySound(L&lt;span class="str"&gt;&amp;quot;.Default&amp;quot;&lt;/span&gt;NULL, SND_SYNC | SND_ALIAS);
    &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;
}

LRESULT WndProc(...)
{
    :
    :
    &lt;span class="kwrd"&gt;case&lt;/span&gt; WM_KEYDOWN:
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (!_AcceptInputKeys(wParam, lParam))
        {
            QueueUserWorkItem(_PlayBeep, NULL, 0);
        }
        &lt;span class="kwrd"&gt;break&lt;/span&gt;;
}&lt;/pre&gt;

  &lt;p&gt;&lt;style type="text/css"&gt;

.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;This is actual code from inside the client side of a client/server component in Windows that was attempting to “beep” on invalid input (I’ve changed the code slightly to hide the actual origin and undoubtedly introduced issues).&amp;#160; And it has a whopper of a bug in it.&lt;/p&gt;

&lt;p&gt;Given the simplicity of the code above, to get the answer right, it’s not enough to say what’s wrong with the code (the problem should be blindingly obvious).&amp;#160; You also need to be able to explain &lt;em&gt;why&lt;/em&gt; this is so bad (in other words, what breaks when you do this).&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Bonus points if you can identify the fix that was eventually applied.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9804115" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>Delay Load is not a good way to check for functionality</title><link>http://blogs.msdn.com/larryosterman/archive/2009/03/06/delay-load-is-not-a-good-way-to-check-for-functionality.aspx</link><pubDate>Fri, 06 Mar 2009 23:19:26 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9463386</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>15</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9463386.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9463386</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9463386</wfw:comment><description>&lt;p&gt;On my &lt;a href="http://blogs.msdn.com/larryosterman/archive/2009/03/05/checking-file-versions-is-surprisingly-hard.aspx"&gt;previous post&lt;/a&gt;, Koro made the following &lt;a href="http://blogs.msdn.com/larryosterman/archive/2009/03/05/checking-file-versions-is-surprisingly-hard.aspx#9463283"&gt;comment&lt;/a&gt;:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;“Don't ever check windows versions.&amp;#160; Instead check for functionality being present or not.&amp;quot;&lt;/p&gt;    &lt;p&gt;You can't always do that.&lt;/p&gt;    &lt;p&gt;Do I want to add a __try/__except to catch delay-load exceptions around every UxTheme call or just do:&lt;/p&gt;    &lt;p&gt;g_bTheme=(g_bWinNT&amp;amp;&amp;amp;(g_nWinVer&amp;gt;0x00050001));&lt;/p&gt;    &lt;p&gt;Then check that flag before calling OpenThemeData?&lt;/p&gt;    &lt;p&gt;In some other cases too (all the Crypt Hash functions - trying to compute an MD5) the functions is documented as working fine in Win98 but it just fails - there is no way to know except of checking the version beforewards.&lt;/p&gt;    &lt;p&gt;At least, as implied earlier, I just pack the Windows version in a DWORD at program startup to avoid nasty version comparision errors.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;IMHO Koro’s misusing the &lt;a href="http://msdn.microsoft.com/en-us/library/151kt790.aspx"&gt;delayload functionality&lt;/a&gt;.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;DelayLoad is primarily a performance tool – when you DelayLoad a function, a tiny stub for the DelayLoad function is inserted into your application which calls LoadLibrary/GetProcAddress on the function.&amp;#160; That then means that when your application is launched, the loader doesn’t resolve references to the DelayLoaded function and thus your application will launch faster.&lt;/p&gt;  &lt;p&gt;For example many components in the OS delay load WINMM.DLL because all they use in WINMM is the PlaySound API, and even then they only use it on relatively rare circumstances.&amp;#160; By delayloading WINMM.DLL they avoid having the performance penalty of having WINMM.DLL loaded into their address until it’s needed.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;As Koro mentioned, DelayLoad &lt;em&gt;can&lt;/em&gt; also be used as a mechanism to check to see if a particular piece of OS functionality is present, but the challenge is that now you need to wrap every API call with an exception handler (or you need to specify a delay load handler that provides a more reasonable default behavior).&amp;#160; Personally I wouldn’t do that – instead I’d manually call LoadLibrary/GetProcAddress to load the required functions because it allows you to have complete control over when you access over your error handling.&amp;#160; It also allows you to avoid using structured exception handling (which should be avoided if at all possible).&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;If you DO have need to use DelayLoad as a functionality check, you could try this trick (which works only for Koro’s problem).&amp;#160; Instead of wrapping all the theme API calls with SEH, you just add code to your app like this (I haven’t compiled this code, it’s just an example):&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;BOOL g_EnableThemes = FALSE;
__try
{
    g_EnableThemes = IsThemeActive();
}
__except(&amp;lt;Your Exception Filter&amp;gt;)
{
}&lt;/pre&gt;

  &lt;pre class="csharpcode"&gt;if (g_EnableThemes)&lt;br /&gt;&lt;br /&gt;{&lt;br /&gt;    g_ThemeHandle = OpenThemeData(…)&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;pre class="csharpcode"&gt;&lt;style type="text/css"&gt;.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
&lt;/style&gt;&lt;/pre&gt;

&lt;p&gt;In other words check for functionality being enabled once with an exception handler and later on use just the EnableThemes global variable to key off the behavior.&lt;/p&gt;

&lt;p&gt;But this doesn’t change the fact that (IMHO) you’re abusing the DelayLoad functionality and using it as a versioning mechanism.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9463386" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Nifty+Win32+tricks_2E00_/default.aspx">Nifty Win32 tricks.</category></item><item><title>Checking file versions is surprisingly hard.</title><link>http://blogs.msdn.com/larryosterman/archive/2009/03/05/checking-file-versions-is-surprisingly-hard.aspx</link><pubDate>Fri, 06 Mar 2009 02:34:30 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9461009</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>28</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9461009.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9461009</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9461009</wfw:comment><description>&lt;p&gt;I was wandering around the web the other day and ran into &lt;a href="http://www.bootblock.co.uk/home/2009/02/13/using-windows-7-features-in-net/comment-page-1/#comment-1667"&gt;this&lt;/a&gt; post.&amp;#160; In general I don’t have many issues with the post, until you get to the bottom of the article.&amp;#160; The author mentions that his code only runs on Win7 or newer so he helpfully included a check to make sure that his code only runs on WIn7:&lt;/p&gt;  &lt;blockquote&gt;   &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// Example in C#.&lt;/span&gt;

&lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; SupportsTaskProgress() {
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (System.Environment.OSVersion.Version.Major &amp;gt;= 6) {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (System.Environment.OSVersion.Version.Minor &amp;gt;= 1) {
            &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;
        }
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is a great example of why it’s so hard to write code that checks for versions.&amp;#160; The problem here is that this code is highly likely to fail to work on the next version of Windows (or whenever Windows 7.0 is released).&amp;#160; In that case SupportsTaskProgress will incorrectly return false.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;Personally I wouldn’t even bother writing the SupportsTaskProgress function this way.&amp;#160; Instead I’d check for the “new TaskbarLib.TaskbarList()” call to return NULL and assume that if it returned NULL the API call wasn’t supported (the non COM interop equivalent would be to check for a failure on the call to CoCreateInstance).&amp;#160; That way the code would work even if (for some obscure reason) the taskbar logic was ported to a previous OS version.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;If I simply HAD to keep the SupportsTaskProgress function, I’d rewrite it as:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;pre class="csharpcode"&gt;&lt;span class="rem"&gt;// Example in C#.&lt;/span&gt;

&lt;span class="kwrd"&gt;internal&lt;/span&gt; &lt;span class="kwrd"&gt;bool&lt;/span&gt; SupportsTaskProgress() {
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (System.Environment.OSVersion.Version.Major &amp;gt;= 6) {
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (System.Environment.OSVersion.Version.Major == 6) {&lt;br /&gt;            if (System.Environment.OSVersion.Version.Minor &amp;gt;= 1) {
                &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;true&lt;/span&gt;;&lt;br /&gt;            }&lt;br /&gt;            return false;
        }&lt;br /&gt;        return true;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; &lt;span class="kwrd"&gt;false&lt;/span&gt;;
}&lt;/pre&gt;
&lt;/blockquote&gt;

&lt;p&gt;That way it would only check for minor version being greater than 1 if the major version is 6.&amp;#160; I suspect that this code could be tightened up further as well.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;This is a part of the reason that picking a version number for the OS is so complicated.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9461009" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>PlaySound(xxx, SND_MEMORY | SND_ASYNC) is almost always a bad idea.</title><link>http://blogs.msdn.com/larryosterman/archive/2009/02/19/playsound-xxx-snd-memory-snd-async-is-almost-always-a-bad-idea.aspx</link><pubDate>Fri, 20 Feb 2009 01:31:57 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9435071</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>0</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9435071.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9435071</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9435071</wfw:comment><description>&lt;p&gt;Whenever you submit a crash report to &lt;a href="http://oca.microsoft.com/en/windiag.asp"&gt;OCA&lt;/a&gt;, a bug gets filed in the relevant product database and gets automatically assigned to the developer responsible for the code.&amp;#160; I had a crashing bug in the PlaySound API assigned to me.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;In this case, the call was crashing deep inside of the waveOutOpen API and it was crashing because the input WAVEFORMATEX structure was bogus.&amp;#160; The strange thing is that the PlaySound API does some fairly thorough validation of the input WAVEFORMATEX read from the .WAV file and that validation had to have passed to get to the call to waveOutOpen.&lt;/p&gt;  &lt;p&gt;I looked a bit deeper and came to the realization that every single one of the crashes (in maybe a dozen different applications) had specified SND_MEMORY | SND_ASYNC in their call to PlaySound.&lt;/p&gt;  &lt;p&gt;I’ve talked about that particular combination &lt;a href="http://blogs.msdn.com/larryosterman/archive/2007/01/05/software-contracts-part-2-there-are-two-sides-to-every-contract.aspx"&gt;before&lt;/a&gt; in my blog, but I wanted to call it out in a top level post in the hopes that people will stop making this common mistake.&lt;/p&gt;  &lt;p&gt;When you call PlaySound with the SND_MEMORY flag, it tells the PlaySound API that instead of reading the audio data from a file, you’re passing in a pointer to memory which holds the wave contents for you.&amp;#160; That’s not controversial, and can be quite handy if (for instance) you want to build a .WAV file in memory instead of calling the wave APIs directly.&lt;/p&gt;  &lt;p&gt;When you call PlaySound with the SND_ASYNC flag, that flag tells PlaySound that instead of blocking until the sound has finished playing, the API should return immediately instead of blocking while the sound is played.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Neither of these flags is controversial and neither of them is particularly dangerous &lt;em&gt;until&lt;/em&gt; you combine the two together.&lt;/p&gt;  &lt;p&gt;The problem is that there’s really no way of knowing when the sound has finished playing and thus when the application frees the memory, it’s entirely possible that the PlaySound API is still using it.&amp;#160; That means that if you ever call PlaySound with both of these flags, you stand a very high chance of crashing due to the combination of these behaviors.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;The unfortunate thing is that this behavior has existed since the SND_MEMORY flag was added back in Windows 3.1.&amp;#160; The only safe way of dealing with this that works on all current Windows operating systems is to call PlaySound(NULL, 0, 0) before freeing the memory – the call to PlaySound(NULL, 0, 0) will block until the currently playing sound has completed playing (or abort the playsound if it hasn’t started yet).&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9435071" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Audio/default.aspx">Audio</category></item><item><title>Fixing a customer problem: “No Audio Device is Installed” when launching sndvol on Windows Vista</title><link>http://blogs.msdn.com/larryosterman/archive/2009/01/06/fixing-a-customer-problem-no-audio-device-is-installed-when-launching-sndvol-on-windows-vista.aspx</link><pubDate>Tue, 06 Jan 2009 22:26:03 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9286006</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9286006.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9286006</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9286006</wfw:comment><description>&lt;p&gt;Yesterday someone forwarded me an email from one of our DirectShow MVPs – he was having problems playing audio on his Windows Vista machine.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Fortunately David (the MVP) had done most of the diagnostic work – the symptoms he saw were that he was receiving a “No Audio Device is Installed” error launching sndvol (and other assorted problems).&amp;#160; &lt;/p&gt;  &lt;p&gt;David tried the usual things (confirming that the driver for his audio solution was correctly installed (this probably fixes 99% of the problems)).&amp;#160; He also tried reinstalling the driver to no avail.&lt;/p&gt;  &lt;p&gt;He next ran the Sysinternals &lt;a href="http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx"&gt;Process Monitor tool&lt;/a&gt; to see what was going on.&amp;#160; He very quickly found the following line in the output from process monitor:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;&amp;quot;RegOpenKey&amp;quot;, &amp;quot;HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\MMDevices\Audio\Render\{e4ee1234-fc70-4925-94e9-4117395f7995}&amp;quot;, &amp;quot;&lt;b&gt;ACCESS DENIED&lt;/b&gt;&amp;quot;, &amp;quot;Desired Access: Write&amp;quot;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;With that information, he looked for the ACL on that registry key:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/larryosterman/WindowsLiveWriter/FixingacustomerproblemNoAudioDeviceisIns_A0BB/clip_image002_2.jpg"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="clip_image002" border="0" alt="clip_image002" src="http://blogs.msdn.com/blogfiles/larryosterman/WindowsLiveWriter/FixingacustomerproblemNoAudioDeviceisIns_A0BB/clip_image002_thumb.jpg" width="381" height="458" /&gt;&lt;/a&gt;&lt;/p&gt;  &lt;p&gt;He then looked at the configuration for the Windows Audio service:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/larryosterman/WindowsLiveWriter/FixingacustomerproblemNoAudioDeviceisIns_A0BB/image_4.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="image" border="0" alt="image" src="http://blogs.msdn.com/blogfiles/larryosterman/WindowsLiveWriter/FixingacustomerproblemNoAudioDeviceisIns_A0BB/image_thumb_1.png" width="424" height="478" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;Woah – the Windows Audio service doesn’t have access rights to that registry key – the Windows Audio service is running as LocalService and the LocalService account doesn’t have any access to the registry key.&lt;/p&gt;  &lt;p&gt;At this point he decided to contact Microsoft with his problem.&lt;/p&gt;  &lt;p&gt;I looked at his info and quickly realized that the problem was that somehow the ACL on the registry key had been corrupted: something had removed the entries for the audio services.&amp;#160; On a normal Windows Vista installation this registry key’s ACL should look something like:&lt;/p&gt;  &lt;p&gt;&lt;a href="http://blogs.msdn.com/blogfiles/larryosterman/WindowsLiveWriter/FixingacustomerproblemNoAudioDeviceisIns_A0BB/endpointpermissions.png"&gt;&lt;img style="border-bottom: 0px; border-left: 0px; display: block; float: none; margin-left: auto; border-top: 0px; margin-right: auto; border-right: 0px" title="endpointpermissions" border="0" alt="endpointpermissions" src="http://blogs.msdn.com/blogfiles/larryosterman/WindowsLiveWriter/FixingacustomerproblemNoAudioDeviceisIns_A0BB/endpointpermissions_thumb.png" width="383" height="456" /&gt;&lt;/a&gt; &lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Something that ran on David’s machines went in and reset the permissions for this registry key to the ACL that is on the root node of the HKEY_LOCAL_MACHINE\Software registry hive.&amp;#160; I have no idea what did this, but messing with the ACLs on the registry is a known cause of various compatibility problems.&amp;#160; That’s why &lt;a href="http://support.microsoft.com/kb/885409/"&gt;Microsoft KB 885409&lt;/a&gt; has such strong warnings about why it’s important to not apply blind modifications to files or registry keys in Windows.&amp;#160; It’s unfortunate, but the warnings in the KB articles that say that modifying registry keys or permissions can cause your machine to malfunction are absolutely right – it’s not hard to make modifications to registry keys that can really screw up a machine, if you make the right ones.&amp;#160; From the KB article:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;For example, modifications to registry ACLs affect large parts of the registry hives and may cause systems to no longer function as expected. Modifying the ACLs on single registry keys poses less of a problem to many systems. However, we recommend that you carefully consider and test these changes before you implement them. Again, we can only guarantee that you can return to the recommended out-of-the-box settings if you reformat and reinstall the operating system.&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The good news is that it should be relatively simple to fix David’s problem – As far as I know, he has two options.&amp;#160; The first is to reinstall Windows Vista – that should reset the ACLs on the property key to their default values (because it will recreate the property keys), which should resolve the problem.&lt;/p&gt;  &lt;p&gt;The second solution is to add an ACL to the registry keys under the MMDevices registry key to allow the LocalService account to have permissions to modify this registry key.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9286006" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Fascinating+geek+stuff/default.aspx">Fascinating geek stuff</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Nifty+Win32+tricks_2E00_/default.aspx">Nifty Win32 tricks.</category></item><item><title>I get more spam :)</title><link>http://blogs.msdn.com/larryosterman/archive/2008/11/21/i-get-more-spam.aspx</link><pubDate>Sat, 22 Nov 2008 03:58:51 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9132464</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>11</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9132464.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9132464</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9132464</wfw:comment><description>&lt;p&gt;I just received this phishing letter, I liked it simply because it was so remarkably brazen:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;--&lt;/p&gt;    &lt;p&gt;Dear Webmail User,&lt;/p&gt;    &lt;p&gt;This message was sent automatically by a program on Webmail which periodically checks the size of inbox, where new messages are received. The program is run weekly to ensure no one's inbox grows too large. If your inbox becomes too large, you will be unable to receive new email.&lt;/p&gt;    &lt;p&gt;Just before this message was sent, you had 18 Megabytes (MB) or more of messages stored in your inbox on Webmail. To help us re-set your SPACE on our database prior to maintain our INBOX, you must reply &lt;/p&gt;    &lt;p&gt;to this e-mail and enter your Current UserID: ( ) and &lt;/p&gt;    &lt;p&gt;Password ( ) Select server ( ) if any&lt;/p&gt;    &lt;p&gt;You will continue to receive this warning message periodically if your&lt;/p&gt;    &lt;p&gt;inbox size continues to be between 18 and 20 MB. If your inbox size grows&lt;/p&gt;    &lt;p&gt;to 20 MB, then a program on Webmail will move your oldest &lt;/p&gt;    &lt;p&gt;email to a folder in your home directory to ensure that you will &lt;/p&gt;    &lt;p&gt;continue to be able to receive incoming email. You will be notified by email &lt;/p&gt;    &lt;p&gt;that this has taken place. If your inbox grows to 25 MB, you will be unable to &lt;/p&gt;    &lt;p&gt;receive new email as it will be returned to the sender.After you read a &lt;/p&gt;    &lt;p&gt;message, it is best to REPLY and SAVE it to another folder.&lt;/p&gt;    &lt;p&gt;Thank you for your cooperation.&lt;/p&gt;    &lt;p&gt;Webmail Help Desk&lt;/p&gt;    &lt;p&gt;---------------------------------------------------------------------------&lt;/p&gt;    &lt;p&gt;3webXS HiSpeed Dial-up...surf up to 5x faster than regular dial-up alone... &lt;/p&gt;    &lt;p&gt;just $14.90/mo...visit &lt;a href="http://www.get3web.com"&gt;www.get3web.com&lt;/a&gt; for details&lt;/p&gt;    &lt;p&gt;&amp;#160;&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;The email was in plain text from “Webmail Service Support [general@3web.net]” (I don’t feel bad about including their real email address on a post on the web, after all they deserve to get spam, right?&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;As I said, I thought it was remarkably brazen and very low budget.&amp;#160; Why bother trying to set up a domain when you can get the victim to send you their credentials by email :).&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9132464" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/It_2700_s+Funny+_3A002900_/default.aspx">It's Funny :)</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code, part 25</title><link>http://blogs.msdn.com/larryosterman/archive/2008/11/17/what-s-wrong-with-this-code-part-25.aspx</link><pubDate>Mon, 17 Nov 2008 19:43:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:9111194</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>12</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/9111194.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=9111194</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=9111194</wfw:comment><description>&lt;P&gt;Wow, 25 already.&lt;/P&gt;
&lt;P&gt;This one’s pretty straightforward.&amp;nbsp; Once again, it’s a UI issue, since I’ve been spending most of my time doing UI lately.&lt;/P&gt;
&lt;P&gt;In this particular case, the code comes from the constructor for an auto-layout class that is used internally in one of our tools.&amp;nbsp; It saves away window handles for a control and the dialog which holds the control, then saves the size of the dialog and relative location of the control within that dialog.&amp;nbsp; There’s other code that handles resizing and adjusting the layout of the control when the dialog is resized.&amp;nbsp; &lt;/P&gt;&lt;PRE class=csharpcode&gt;CControlLayout::CControlLayout(&lt;SPAN class=kwrd&gt;const&lt;/SPAN&gt; HWND hWndControl, &lt;SPAN class=kwrd&gt;const&lt;/SPAN&gt; HWND hWndDlg)
    : m_hWnd(hWndControl)
    , m_hWndDlg(hWndDlg)
{
    &lt;SPAN class=rem&gt;// Get the parent (dialog) rect, and the control rect&lt;/SPAN&gt;
    ::GetClientRect(m_hWndDlg, &amp;amp;m_rcRefDlg);
    ::GetWindowRect(m_hWnd, &amp;amp;m_rcRef);
    ScreenToClientRect(hWndDlg, m_rcRef);
}&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;void ScreenToClientRect(/* [in] */ const HWND hWndClient, &lt;BR&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; /* [in/out] */ RECT &amp;amp;rcInOut)&lt;BR&gt;{&lt;BR&gt;&amp;nbsp;CPoint ptTopLeft(rcInOut.left, rcInOut.top);&lt;BR&gt;&amp;nbsp;CPoint ptBottomRight(rcInOut.right, rcInOut.bottom);&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;::ScreenToClient(hWndClient, &amp;amp;ptTopLeft);&lt;BR&gt;&amp;nbsp;::ScreenToClient(hWndClient, &amp;amp;ptBottomRight);&lt;/PRE&gt;&lt;PRE class=csharpcode&gt;&amp;nbsp;rcInOut.left = ptTopLeft.x;&lt;BR&gt;&amp;nbsp;rcInOut.top = ptTopLeft.y;&lt;BR&gt;&amp;nbsp;rcInOut.right = ptBottomRight.x;&lt;BR&gt;&amp;nbsp;rcInOut.bottom = ptBottomRight.y;&lt;BR&gt;}&lt;BR&gt;&lt;/PRE&gt;
&lt;STYLE type=text/css&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/STYLE&gt;

&lt;P&gt;m_rcRefDlg holds the reference rect for the dialog and m_rcRef holds the reference rect for the control relative to the dialog.&lt;/P&gt;
&lt;P&gt;This code has been in the UI for quite a while and recently one of our testers discovered a nasty bug while running a test pass.&lt;/P&gt;
&lt;P&gt;The question is: What’s wrong with this code.&amp;nbsp; I believe we shipped Windows Vista with this bug (I’m not 100% sure, since I don’t have a Windows Vista machine to test it), so it’s pretty subtle.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Edit: OOPS - I forgot to include ScreenToClientRect.&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=9111194" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>I get spam :)</title><link>http://blogs.msdn.com/larryosterman/archive/2008/10/14/i-get-spam.aspx</link><pubDate>Tue, 14 Oct 2008 19:13:04 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8999685</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>18</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/8999685.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=8999685</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=8999685</wfw:comment><description>&lt;p&gt;I just received this spam message the other day:&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;From: Microsoft [mailto:customerservice@microsoft.com] &lt;/p&gt;    &lt;p&gt;Sent: Saturday, October 11, 2008 11:13 PM&lt;/p&gt;    &lt;p&gt;To: Larry Osterman&lt;/p&gt;    &lt;p&gt;Subject: Security Update for OS Microsoft Windows&lt;/p&gt;    &lt;p&gt;Dear Microsoft Customer,&lt;/p&gt;    &lt;p&gt;Please notice that Microsoft company has recently issued a Security Update for OS Microsoft Windows. The update applies to the following OS versions: Microsoft Windows 98, Microsoft Windows 2000, Microsoft Windows Millenium, Microsoft Windows XP, Microsoft Windows Vista.&lt;/p&gt;    &lt;p&gt;Please notice, that present update applies to high-priority updates category. In order to help protect your computer against security threats and performance problems, we strongly recommend you to install this update.&lt;/p&gt;    &lt;p&gt;Since public distribution of this Update through the official website &lt;a href="http://www.microsoft.com"&gt;http://www.microsoft.com&lt;/a&gt; would have result in efficient creation of a malicious software, we made a decision to issue an experimental private version of an update for all Microsoft Windows OS users.&lt;/p&gt;    &lt;p&gt;As your computer is set to receive notifications when new updates are available, you have received this notice.&lt;/p&gt;    &lt;p&gt;In order to start the update, please follow the step-by-step instruction:&lt;/p&gt;    &lt;p&gt;1. Run the file, that you have received along with this message.&lt;/p&gt;    &lt;p&gt;2. Carefully follow all the instructions you see on the screen.&lt;/p&gt;    &lt;p&gt;If nothing changes after you have run the file, probably in the settings of your OS you have an indication to run all the updates at a background routine. In that case, at this point the upgrade of your OS will be finished.&lt;/p&gt;    &lt;p&gt;We apologize for any inconvenience this back order may be causing you.&lt;/p&gt;    &lt;p&gt;Thank you,&lt;/p&gt;    &lt;p&gt;Steve Lipner&lt;/p&gt;    &lt;p&gt;Director of Security Assurance&lt;/p&gt;    &lt;p&gt;Microsoft Corp.&lt;/p&gt;    &lt;p&gt;-----BEGIN PGP SIGNATURE-----&lt;/p&gt;    &lt;p&gt;Version: PGP 7.1&lt;/p&gt;    &lt;p&gt;AN86DCS206WKI6IK8LIFD5S1VODA48SHXDCG6KT8V4C50MO21RUHP8O84T6P73YGX&lt;/p&gt;    &lt;p&gt;EO755U27OA5JVX3U51QF8N2E97FQQDOC6IRHH7T3TSQJRFYYPR3434M634A375LAO&lt;/p&gt;    &lt;p&gt;49ICIMQZ680BR307KVS857K6U9UYSBHE20RNI16HUB45SMTDF0DDMQZ4YIR2QIHLD&lt;/p&gt;    &lt;p&gt;UVPMVD54LRY8HNLDA020KWMIFYYD9B1A07AM1VWIA0YO8QZO2WLY27KAPXBFDN6DT&lt;/p&gt;    &lt;p&gt;48VYUVW7M7JZ5P2NIU7FGDRIGCM819WMKJ2==&lt;/p&gt;    &lt;p&gt;-----END PGP SIGNATURE-----&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;Attached to the message was an attachment named &lt;a href="http://support.microsoft.com/kb/266311"&gt;“KB266311&lt;/a&gt;.exe”. &lt;/p&gt;  &lt;p&gt;I’ve heard that these before but I’ve never received one.&amp;#160; Apparently the email was sent from “koln-5d8184e2.pool.einsundeins.de (93.129.132.226)”, which I suspect is a trojaned machine in Germany.&amp;#160;&amp;#160; In this case I’m pretty impressed with the email – it’s in plain text with the name of a real Microsoft employee, it has a PGP signature (which tends to give credence to the email).&amp;#160; On the other hand it has some grammatical errors (“Please notice that Microsoft company has…”, “We apologize for any inconvenience this back order may be causing you”) that give the scam away.&amp;#160; I also don’t know what trojan was inside KB266311 because it was filtered by our email servers before it got to me.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;For those that are wondering how I knew it came from koln-5d8184e2.pool.einsundeins.de, here’s what I did:&lt;/p&gt;  &lt;p&gt;I started with the raw email headers (some servers and IP addresses obscured):&lt;/p&gt;  &lt;blockquote&gt;   &lt;p&gt;Received: from XXX.microsoft.com (n.n.n.n) by     &lt;br /&gt; YYY.microsoft.com (m.m.m.m) with Microsoft SMTP      &lt;br /&gt; Server (TLS) id 8.2.83.0; Sat, 11 Oct 2008 23:13:52 -0700      &lt;br /&gt;Received: from koln-5d8184e2.pool.einsundeins.de (93.129.132.226) by      &lt;br /&gt; ZZZ.microsoft.com (o.o.o.o) with Microsoft SMTP Server id      &lt;br /&gt; 8.1.291.1; Sat, 11 Oct 2008 23:13:41 -0700      &lt;br /&gt;Received: from [93.129.132.226] by QQQ.hotmail.com; Sun, 12 Oct 2008 07:13:17      &lt;br /&gt; +0100      &lt;br /&gt;From: Microsoft &amp;lt;customerservice@microsoft.com&amp;gt;      &lt;br /&gt;To: &amp;lt;&amp;lt;Larry’s Email Address&amp;gt;&amp;gt;      &lt;br /&gt;Subject: Security Update for OS Microsoft Windows      &lt;br /&gt;Date: Sun, 12 Oct 2008 07:13:17 +0100      &lt;br /&gt;MIME-Version: 1.0      &lt;br /&gt;Content-Type: multipart/mixed;      &lt;br /&gt;&amp;#160;&amp;#160;&amp;#160; boundary=&amp;quot;----=_NextPart_000_000E_01C92C39.FF9CE480&amp;quot;      &lt;br /&gt;X-Mailer: Microsoft Office Outlook, Build 11.0.5510      &lt;br /&gt;Thread-Index: Aca6Q862Q89QD80AN22RHXR0U7WZ61==      &lt;br /&gt;X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4807.1700      &lt;br /&gt;Message-ID: &amp;lt;01c92c39$ff9ce480$e284815d@60GC7Q&amp;gt;      &lt;br /&gt;Return-Path: 60GC7Q@hotmail.com      &lt;br /&gt;X-MS-Exchange-Organization-PRD: microsoft.com      &lt;br /&gt;Received-SPF: TempError (XXX.microsoft.com: error in      &lt;br /&gt; processing during lookup of customerservice@microsoft.com: DNS timeout)      &lt;br /&gt;X-MS-Exchange-Organization-PCL: 2      &lt;br /&gt;X-MS-Exchange-Organization-Antispam-Report: DV:3.3.7011.600;SV:3.3.7011.1437;SID:SenderIDStatus      &lt;br /&gt; TempError;OrigIP:93.129.132.226      &lt;br /&gt;X-MS-Exchange-Organization-SCL: 0      &lt;br /&gt;X-MS-Exchange-Organization-SenderIdResult: TEMPERROR&lt;/p&gt; &lt;/blockquote&gt;  &lt;p&gt;RFC 2821 says that SMTP servers should prepend a Received: header to an email message whenever they process the email message.&amp;#160; In this case the last email server was XXX.microsoft.com.&amp;#160; XXX.microsoft.com received the message from YYY.microsoft.com which in turn received the message from koln-5d8184e2.pool.einsundeins.de (einsundeins.de appears to be a german ISP).&amp;#160;&amp;#160; The next bit of trace is confusing.&amp;#160; The machine at 93.129.132.226 says that it received the message from QQQ.hotmail.com.&amp;#160; &lt;/p&gt;  &lt;p&gt;It’s possible that this spam email originated from hotmail, but I don’t think so.&amp;#160; First off, as far as I know, you can’t relay through the hotmail SMTP servers and the sender of the email is “customerservice@microsoft.com” (the sender is included in the Received-SPF header which indicates that the “MAIL FROM” header in the SMTP exchange was &lt;a href="mailto:&amp;ldquo;customerservice@microsoft.com"&gt;“customerservice@microsoft.com&lt;/a&gt;”.&amp;#160; Secondly the hotmail servers don’t set the X-Mailer header, but this header indicates that it was sent from Outlook 2003.&amp;#160; Instead, I think that the bottom Received: header was forged to throw off people trying to figure out where the email came from.&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;Needless to say, Microsoft will never EVER send a security update to customers by mail, and customers should immediately delete any emails that claim to have security fixes from Microsoft.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8999685" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/It_2700_s+Funny+_3A002900_/default.aspx">It's Funny :)</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Fascinating+geek+stuff/default.aspx">Fascinating geek stuff</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code part 24 (From an MSDN article)?</title><link>http://blogs.msdn.com/larryosterman/archive/2008/10/06/what-s-wrong-with-this-code-part-24-from-an-msdn-article.aspx</link><pubDate>Tue, 07 Oct 2008 02:52:00 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8979804</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>23</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/8979804.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=8979804</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=8979804</wfw:comment><description>&lt;P&gt;I ran into this bug earlier today and realized that it’d make an awesome “What’s wrong with this code”.&lt;/P&gt;
&lt;P&gt;I started pulling together a test app when I realized that &lt;A href="http://msdn.microsoft.com/en-us/magazine/cc163384.aspx" mce_href="http://msdn.microsoft.com/en-us/magazine/cc163384.aspx"&gt;this&lt;/A&gt; MSDN magazine article contains sample code that perfectly exhibits the bug:&lt;/P&gt;
&lt;BLOCKQUOTE&gt;&lt;PRE class=csharpcode&gt;CRect rectangle;
VERIFY(m_splitButton.GetWindowRect(
    &amp;amp;rectangle));

TPMPARAMS &lt;SPAN class=kwrd&gt;params&lt;/SPAN&gt; = { &lt;SPAN class=kwrd&gt;sizeof&lt;/SPAN&gt;(TPMPARAMS) };
&lt;SPAN class=kwrd&gt;params&lt;/SPAN&gt;.rcExclude = rectangle;

CMenuHandle menu = m_menu.GetSubMenu(0);

VERIFY(menu.TrackPopupMenuEx(TPM_LEFTBUTTON,
    rectangle.left, rectangle.bottom,
    m_hWnd, &amp;amp;&lt;SPAN class=kwrd&gt;params&lt;/SPAN&gt;));&lt;/PRE&gt;&lt;/BLOCKQUOTE&gt;
&lt;P&gt;There’s not much to the code – it’s from the handler for the BCN_DROPDOWN notification message.&amp;nbsp; And it’s got a very &lt;STRIKE&gt;nasty&lt;/STRIKE&gt; subtle bug in it.&lt;/P&gt;
&lt;P&gt;So what’s the bug?&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;Edit: s/nasty/subtle/&lt;/P&gt;
&lt;P mce_keep="true"&gt;&amp;nbsp;&lt;/P&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8979804" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code, Part 23 – The Answers</title><link>http://blogs.msdn.com/larryosterman/archive/2008/09/08/what-s-wrong-with-this-code-part-23-the-answers.aspx</link><pubDate>Tue, 09 Sep 2008 01:19:05 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8935040</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>21</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/8935040.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=8935040</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=8935040</wfw:comment><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;My last post was all about a problem with what appeared to be some really simple ATL code.&lt;/p&gt;  &lt;p&gt;It turns out that the problem was easier than I had expected.&amp;#160; James Skimming came up with the answer on the second comment.&amp;#160; The problem here was that the following code (snipped a bit)&lt;/p&gt;  &lt;pre class="csharpcode"&gt;IMMDeviceEnumerator *GetDeviceEnumerator()
{
    CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator;

    HRESULT hr = deviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (FAILED(hr))
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; NULL;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; deviceEnumerator.Detach();

}
&lt;span class="kwrd"&gt;int&lt;/span&gt; _tmain(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    {
        CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator(GetDeviceEnumerator());
        CComPtr&amp;lt;IMMDeviceCollection&amp;gt; deviceCollection;

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (deviceEnumerator != NULL)
        {
            HRESULT hr = deviceEnumerator-&amp;gt;EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &amp;amp;deviceCollection);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(hr))
            {&lt;/pre&gt;

&lt;p&gt;That’s because the CComPtr&amp;lt;T&amp;gt; constructor takes a reference to the input T* object.&amp;#160; As a result, the code leaks a reference to the MMDeviceEnumerator object.&amp;#160; The correct fix for the problem generated a fair amount of discussion in the comments and on email internally. &lt;/p&gt;

&lt;p&gt;The root cause of the problem&amp;#160; is that the code in question mixes raw interface pointers and smart pointers.&amp;#160; In this case there’s an impedance mismatch between the GetDeviceEnumerator (which returns a raw pointer) and it’s caller (which is expecting a smart pointer).&lt;/p&gt;

&lt;p&gt;My preferred solution to the problem is:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; GetDeviceEnumerator()
{
    CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator;

    HRESULT hr = deviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (FAILED(hr))
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; NULL;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; deviceEnumerator;

}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The reason I prefer this solution is that it consistently uses the smart pointer class.&amp;#160; There are two downsides to it.&amp;#160; The first is that it loses the result of the call to CoCreateInstance.&amp;#160; The other downside is that it constructs a temporary object on the stack and has two additional calls to AddRef()/Release().&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;There are other possible solutions.&amp;#160; The second possible solution changes the GetDeviceEnumerator function:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;HRESULT GetDeviceEnumerator(IMMDeviceEnumerator *Enumerator)
{
    CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator;

    &lt;span class="kwrd"&gt;if&lt;/span&gt; (Enumerator == NULL)
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; E_POINTER;
    }
    HRESULT hr = deviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (FAILED(hr))
    {
        *Enumerator = NULL;
        &lt;span class="kwrd"&gt;return&lt;/span&gt; hr;
    }
    *Enumerator = deviceEnumerator.Detach();

    &lt;span class="kwrd"&gt;return&lt;/span&gt; S_OK;
}&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;With this change, the caller looks like:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;    {
        CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator;
        &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(GetDeviceEnumerator(&amp;amp;deviceEnumerator))
        {
            CComPtr&amp;lt;IMMDeviceCollection&amp;gt; deviceCollection;
            HRESULT hr = deviceEnumerator-&amp;gt;EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &amp;amp;deviceCollection);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(hr))&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;&lt;/p&gt;

&lt;p&gt;This solution fits closely with the COM usage pattern so it is quite attractive.&amp;#160; You also don’t lose the result of the CoCreateInstance API call, which can be extremely useful for diagnostics.&amp;#160; The major negative with this is that it depends on the fact that the CComPtr&amp;lt;T&amp;gt; operator&amp;amp; returns a raw pointer to the underlying object.&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;The third possible solution keeps the “return a value” idea of the original code but works around the additional reference applied in the constructor.&amp;#160; Keep the original implementation of GetDeviceEnumerator and change the tmain function as follows:&lt;/p&gt;

&lt;pre class="csharpcode"&gt;&lt;span class="kwrd"&gt;int&lt;/span&gt; _tmain(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    {
        CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator;
        deviceEnumerator.Attach(GetDeviceEnumerator());
        CComPtr&amp;lt;IMMDeviceCollection&amp;gt; deviceCollection;&lt;/pre&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;

&lt;p&gt;The big problem with this solution is that to me it’s “unnatural” – the whole point of using smart pointers is that their use is supposed to be intuitive, however in this case there’s nothing intuitive about the use – it certainly fixes the problem but it relies on internal behaviors of the smart pointer class.&amp;#160; To me this is the least attractive solution to the problem.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&amp;#160;&lt;/p&gt;

&lt;p&gt;As I mentioned, Kudos to James Skimming for figuring the problem out quickly.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8935040" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code, Part 23..</title><link>http://blogs.msdn.com/larryosterman/archive/2008/09/05/what-s-wrong-with-this-code-part-23.aspx</link><pubDate>Fri, 05 Sep 2008 18:45:38 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8926438</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>26</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/8926438.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=8926438</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=8926438</wfw:comment><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;I recently tracked down a bug that was causing problems in my code.&amp;#160; Once I figured out the bug, I realized it made a good “what’s wrong with this code”…&lt;/p&gt;  &lt;pre class="csharpcode"&gt;#include &lt;span class="str"&gt;&amp;quot;stdafx.h&amp;quot;&lt;/span&gt;
#include &amp;lt;mmdeviceapi.h&amp;gt;


IMMDeviceEnumerator *GetDeviceEnumerator()
{
    CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator;

    HRESULT hr = deviceEnumerator.CoCreateInstance(__uuidof(MMDeviceEnumerator));
    &lt;span class="kwrd"&gt;if&lt;/span&gt; (FAILED(hr))
    {
        &lt;span class="kwrd"&gt;return&lt;/span&gt; NULL;
    }
    &lt;span class="kwrd"&gt;return&lt;/span&gt; deviceEnumerator.Detach();

}
&lt;span class="kwrd"&gt;int&lt;/span&gt; _tmain(&lt;span class="kwrd"&gt;int&lt;/span&gt; argc, _TCHAR* argv[])
{
    CoInitialize(NULL);
    {
        CComPtr&amp;lt;IMMDeviceEnumerator&amp;gt; deviceEnumerator(GetDeviceEnumerator());
        CComPtr&amp;lt;IMMDeviceCollection&amp;gt; deviceCollection;

        &lt;span class="kwrd"&gt;if&lt;/span&gt; (deviceEnumerator != NULL)
        {
            HRESULT hr = deviceEnumerator-&amp;gt;EnumAudioEndpoints(eAll, DEVICE_STATE_ACTIVE, &amp;amp;deviceCollection);
            &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(hr))
            {
                UINT deviceCount;
                hr = deviceCollection-&amp;gt;GetCount(&amp;amp;deviceCount);
                &lt;span class="kwrd"&gt;if&lt;/span&gt; (SUCCEEDED(hr))
                {
                    printf(&lt;span class="str"&gt;&amp;quot;There are %d audio endpoints on the machine\n&amp;quot;&lt;/span&gt;, deviceCount);
                }
            }
        }
    }
    CoUninitialize();
    &lt;span class="kwrd"&gt;return&lt;/span&gt; 0;
}&lt;/pre&gt;

&lt;p&gt;&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }&lt;/style&gt;Simple code, right?&amp;#160; But there’s a nasty bug hidden in there, and it was NOT obvious to me what the bug was.&lt;/p&gt;

&lt;p&gt;As always, kudos to the person who gets the bug first.&amp;#160; And of course mea culpa's for bugs I accidentally included.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8926438" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category></item><item><title>What’s wrong with this code, part 22 – Drawing Text…</title><link>http://blogs.msdn.com/larryosterman/archive/2008/08/01/what-s-wrong-with-this-code-part-22-drawing-text.aspx</link><pubDate>Sat, 02 Aug 2008 01:07:43 GMT</pubDate><guid isPermaLink="false">91d46819-8472-40ad-a661-2c78acb4018c:8802540</guid><dc:creator>LarryOsterman</dc:creator><slash:comments>43</slash:comments><comments>http://blogs.msdn.com/larryosterman/comments/8802540.aspx</comments><wfw:commentRss>http://blogs.msdn.com/larryosterman/commentrss.aspx?PostID=8802540</wfw:commentRss><wfw:comment>http://blogs.msdn.com/larryosterman/rsscomments.aspx?PostID=8802540</wfw:comment><description>&lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;p&gt;Recently I’ve been working on something that I’ve never done before in my almost 24 years at Microsoft.&amp;#160; &lt;/p&gt;  &lt;p&gt;&amp;#160;&lt;/p&gt;  &lt;p&gt;For the past 23ish years, I’ve been a plumber – all the work I’ve done has been under the covers.&amp;#160; But for the next version of Windows, I decided to stretch my boundaries a bit and try some UI programming.&amp;#160; I’ve just spent the past few days working on a cool change to the volume control (it’s not important what it is, and most people will never know about the change, but those that do will probably agree with me :)).&lt;/p&gt;  &lt;p&gt;As part of the change, I needed to measure the dimensions of a text string.&amp;#160; This is a dummy version of some code I wrote, I simply called DrawText with the DT_CALCRECT into a memory DC that I created.&lt;/p&gt;  &lt;p&gt;&lt;/p&gt;  &lt;pre&gt;BOOL InitInstance(HINSTANCE hInstance, &lt;span style="color: blue"&gt;int&lt;/span&gt; nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; &lt;span style="color: green"&gt;// Store instance handle in our global variable&lt;/span&gt;

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, &lt;span style="color: maroon"&gt;0&lt;/span&gt;, CW_USEDEFAULT, &lt;span style="color: maroon"&gt;0&lt;/span&gt;, &lt;span style="color: blue"&gt;NULL&lt;/span&gt;, &lt;span style="color: blue"&gt;NULL&lt;/span&gt;, hInstance, &lt;span style="color: blue"&gt;NULL&lt;/span&gt;);

   &lt;span style="color: blue"&gt;if&lt;/span&gt; (!hWnd)
   {
      &lt;span style="color: blue"&gt;return&lt;/span&gt; &lt;span style="color: maroon"&gt;FALSE&lt;/span&gt;;
   }&lt;/pre&gt;

&lt;pre&gt;&amp;lt;BEGIN LARRYS CODE&amp;gt;
   HDC hdc = CreateCompatibleDC(&lt;span style="color: blue"&gt;NULL&lt;/span&gt;);

   RECT rcText = {&lt;span style="color: maroon"&gt;0&lt;/span&gt;, &lt;span style="color: maroon"&gt;0&lt;/span&gt;, &lt;span style="color: maroon"&gt;88&lt;/span&gt;, &lt;span style="color: maroon"&gt;34&lt;/span&gt;};

   DrawText(hdc, L&lt;span style="color: maroon"&gt;&amp;quot;My Text String&amp;quot;&lt;/span&gt;, -&lt;span style="color: maroon"&gt;1&lt;/span&gt;, &amp;amp;rcText, DT_CENTER | DT_END_ELLIPSIS | DT_EDITCONTROL | DT_WORDBREAK | DT_NOPREFIX | DT_CALCRECT);

   CAtlString &lt;span style="color: blue"&gt;string&lt;/span&gt;;
   &lt;span style="color: blue"&gt;string&lt;/span&gt;.Format(L&lt;span style="color: maroon"&gt;&amp;quot;Text String occupies: %d x %d pixels&amp;quot;&lt;/span&gt;, rcText.right - rcText.left, rcText.bottom - rcText.top);
   MessageBox(hWnd, &lt;span style="color: blue"&gt;string&lt;/span&gt;, L&lt;span style="color: maroon"&gt;&amp;quot;String Size&amp;quot;&lt;/span&gt;, &lt;span style="color: maroon"&gt;0&lt;/span&gt;);
&amp;lt;END LARRYS CODE&amp;gt; 
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   &lt;span style="color: blue"&gt;return&lt;/span&gt; &lt;span style="color: maroon"&gt;TRUE&lt;/span&gt;;
}&lt;/pre&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;This is just code I took by using Visual Studio to create a Windows Win32 project and inserting the code between “BEGIN LARRYS CODE” and “END LARRYS CODE”.&amp;#160; The meat of the code is just 3 lines of code.&lt;/p&gt;

&lt;p&gt;Even though there’s almost no code here, it &lt;em&gt;still &lt;/em&gt;has a bug in it that was quite subtle and took me several hours to find.&lt;/p&gt;&lt;img src="http://blogs.msdn.com/aggbug.aspx?PostID=8802540" width="1" height="1"&gt;</description><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Things+you+shouldn_2700_t+do_2E00_/default.aspx">Things you shouldn't do.</category><category domain="http://blogs.msdn.com/larryosterman/archive/tags/Nifty+Win32+tricks_2E00_/default.aspx">Nifty Win32 tricks.</category></item></channel></rss>