<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:atom="https://www.w3.org/2005/Atom" xmlns:sy="https://purl.org/rss/1.0/modules/syndication/" xmlns:dc="https://purl.org/dc/elements/1.1/" xmlns:content="https://purl.org/rss/1.0/modules/content/" xmlns:wfw="https://wellformedweb.org/CommentAPI/" xmlns:slash="https://purl.org/rss/1.0/modules/slash/"
  version="2.0">
  <channel>
    <title>Tone Poem</title>
    <atom:link
      href="https://docs.microsoft.com/archive/blogs/mattn/feed.xml"
      rel="self"
      type="application/rss+xml" />
    <link>https://docs.microsoft.com/archive/blogs/mattn/feed.xml</link>
    <description>Listen to your heart</description>
    <lastBuildDate>Tue, 16 Apr 2019 05:50:01 GMT</lastBuildDate>
    <language>en-US</language>
    <sy:updatePeriod>hourly</sy:updatePeriod>
    <sy:updateFrequency>1</sy:updateFrequency>
    <item>
      <title>Cannot Install Windows SDK :(</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/cannot-install-windows-sdk</link>
      <pubDate>Wed, 27 Jun 2012 09:11:27 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2012/06/27/cannot-install-windows-sdk/</guid>
      <description><![CDATA[&#160;  You try to install latest Windows SDK and it does not work.  If you look at the setup log...]]></description>
      <content:encoded><![CDATA[<p>&#160;</p>  <p>You try to install latest Windows SDK and it does not work.</p>  <p>If you look at the setup log file and you see:</p>  <p><strong>8:58:43 AM Wednesday, June 27, 2012:</strong> <strong>C:\WinSDK\Setup\SFX\vcredist_x64.exe installation failed with return code 5100</strong></p>  <p><strong>Reason for this is you have a newer C++ runtime installed on your machine, for example by Visual Studio 2012.&#160; The dumb Windows SDK installer will not install ANYTHING (even the simplest thing that does not depend on C runtime) if newer C++ runtime is installed.</strong></p>  <p><strong>Fix #1:&#160; Install Windows SDK on clean machine and copy files over (if you just want the tools like me).</strong></p>  <p><strong>Fix #2:&#160; Uninstall Microsoft Visual Studio C++ 2012 runtime (both x86 and x64 versions, then install Windows SDK</strong></p>]]></content:encoded>
    </item>
    <item>
      <title>Windows Diagnostics with Windows Azure Issue</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/windows-diagnostics-with-windows-azure-issue</link>
      <pubDate>Wed, 27 Jun 2012 08:48:00 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2012/06/27/windows-diagnostics-with-windows-azure-issue/</guid>
      <description><![CDATA[&nbsp;
Windows Azure Diagnostics does not work,&nbsp;you see following in the Compute Emulator...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<p><strong><span style="font-family: Courier New;" face="Courier New">Windows Azure Diagnostics does not work,&nbsp;you see following in the Compute Emulator =&gt;</span></strong></p>
<p><span style="font-family: Courier New;" face="Courier New">[Diagnostics]: Error starting diagnostics:<br /> <strong>System.FormatException: Invalid account string.</strong><br />&nbsp;&nbsp;&nbsp; at Microsoft.WindowsAzure.CloudStorageAccount.&lt;Parse&gt;b__0(String err)<br />&nbsp;&nbsp;&nbsp; at Microsoft.WindowsAzure.CloudStorageAccount.ParseStringIntoSettings(String s, Action`1 error)<br />&nbsp;&nbsp;&nbsp; at Microsoft.WindowsAzure.CloudStorageAccount.TryParse(String s, CloudStorageAccount&amp; accountInformation, Action`1 error)<br />&nbsp;&nbsp;&nbsp; at Microsoft.WindowsAzure.CloudStorageAccount.Parse(String value)<br />&nbsp;&nbsp;&nbsp; at Microsoft.WindowsAzure.Plugins.Diagnostics.DiagnosticsAgentManager.&lt;StartAgent&gt;b__0()</span></p>
<p><span style="font-family: Courier New;" face="Courier New"></span>&nbsp;</p>
<p><strong><span style="font-family: Courier New;" face="Courier New">Reason?&nbsp; The reason is a connecting string parsing bug in Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString =&gt;</span></strong></p>
<p><span style="font-family: Courier New;" face="Courier New"></span>&nbsp;</p>
<p><span style="font-family: Courier New;" face="Courier New">&lt;ConfigurationSettings&gt;<br /> &lt;Setting <br />&nbsp;&nbsp; name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"</span></p>
<p><span style="font-family: Courier New;" face="Courier New">&nbsp; value="DefaultEndpointsProtocol=https;AccountName=aaa;AccountKey=bbb<span style="font-size: x-large;" size="6"><strong>;</strong></span>" /&gt;<br /> &lt;/ConfigurationSettings&gt;</span></p>
<pre>&nbsp;</pre>
<pre><strong>Fix: Remove the trailing semi-colon at the end of the configuration string =&gt;</strong></pre>
<p><span style="font-family: Courier New;" face="Courier New">&lt;ConfigurationSettings&gt;<br />&lt;Setting <br /> name="Microsoft.WindowsAzure.Plugins.Diagnostics.ConnectionString"<br /> value="DefaultEndpointsProtocol=https;AccountName=aaa;AccountKey=bbb" /&gt;<br />&lt;/ConfigurationSettings&gt;</span></p>
<pre><strong></strong>&nbsp;</pre>]]></content:encoded>
    </item>
    <item>
      <title>Enabling Advanced Driver Tracing for the SQL Native Client ODBC Drivers</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/enabling-advanced-driver-tracing-for-the-sql-native-client-odbc-drivers</link>
      <pubDate>Tue, 15 May 2012 12:48:00 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2012/05/15/enabling-advanced-driver-tracing-for-the-sql-native-client-odbc-drivers/</guid>
      <description><![CDATA[&nbsp;
If you are using the SQL Native Client ODBC driver, there is built-in high performance very...]]></description>
      <content:encoded><![CDATA[<p>&nbsp;</p>
<p>If you are using the SQL Native Client ODBC driver, there is built-in high performance very detailed driver tracing, here is how you use it.</p>
<p><strong>#1. Create batch file to start tracing (this traces for all three versions of SQL Native Client ODBC Driver) named StartSNACTrace.cmd:</strong></p>
<p><code class="mysql">@echo off <br /> echo Starting SNAC tracing... <br /> echo {BA798F36-2325-EC5B-ECF8-76958A2AF9B5} 0xFFFFFFFF 128 SQLNCLI &gt; providers.txt <br /> echo {A9377239-477A-DD22-6E21-75912A95FD08} 0xFFFFFFFF 128 SQLNCLI10 &gt;&gt; providers.txt <br /> echo {2DA81B52-908E-7DB6-EF81-76856BB47C4F} 0xFFFFFFFF 128 SQLNCLI11 &gt;&gt; providers.txt <br /> reg add HKLM\SOFTWARE\Microsoft\BidInterface\Loader /v :Path /t REG_SZ /d "%systemroot%\system32\msdadiag.dll" /f <br /> del /Q *.etl <br /> logman create trace -n SnacTrace -ct perf -pf providers.txt -bs 10000 -nb 10000 50000 -o SnacTrace.etl -max 100 -cnf 00 <br /> logman start -n SnacTrace <br /> echo Run StopSnacTrace.cmd to stop tracing.</code><strong></strong></p>
<p>Note, replace <strong>0xFFFFFFFF</strong> with <strong>0x00000000</strong> to do minimum tracing.&nbsp; The number 128 indicates save trace data as ANSI, which reduces by about 1/2 the space for the ETL files.</p>
<p><strong>Note you MUST start the tracing before the process that uses the SQL Native Client ODBC driver starts (this is VERY IMPORTANT).&nbsp;&nbsp; </strong></p>
<p>Start the tracing then start the process that is using the SQL Native Client ODBC driver.&nbsp;&nbsp; You can stop tracing at any time, even before the process exits.</p>
<p><strong>#2. Create this batch file named StopSnacTrace.cmd to stop the tracing:</strong></p>
<p><code class="mysql">@echo off <br /> echo Stopping SNAC tracing... <br /> logman stop -n SnacTrace <br /> logman delete -n SnacTrace <br /> reg delete HKLM\SOFTWARE\Microsoft\BidInterface\Loader /v :Path /f <br /> echo SNAC tracing stopped</code><strong></strong></p>
<p>The above settings will create a new trace file of maximum size 100MB numbered SnacTrace_000001.etl, SnacTrace_000002.etl, etc&hellip;</p>
<p><strong>#3.&nbsp; To process the trace files, you need to register a special mof file on the trace processing machine (you do not have to do this on the trace gathering machine)</strong></p>
<p><strong>#4</strong>. <strong>Download and register the&nbsp;all.mof file</strong> from "<strong>Data Access Tracing in SQL Server 2012" </strong>MSDN article (last time I checked the URL is here <a href="https://technet.microsoft.com/en-us/library/hh880086">https://technet.microsoft.com/en-us/library/hh880086)</a></p>
<p>There is a section in this article that says "<strong>Download Sample and MOF Files". </strong> This file is named <strong>Setup.zip.</strong></p>
<p>Download this file to some temporary folder and extract the files.&nbsp; You will see a folder named <strong>MOF_Files</strong>, go into this folder and locate the snac*.mof files<strong>, </strong>then on the client machine where you want to do tracing,</p>
<p>run the following <strong>from an elevated command prompt</strong>:</p>
<p><code class="mysql">C:\&gt;<strong>mofcomp all.mof</strong></code></p>
<p><code class="mysql">Microsoft (R) MOF Compiler Version 6.1.7600.16385<br />Copyright (c) Microsoft Corp. 1997-2006. All rights reserved.<br />Parsing MOF file: all.mof<br />MOF file has been successfully parsed<br />Storing data in the repository...<br />Done!</code></p>
<p>This will register all the providers so you can now see them with logman, to verify they are registered, run:</p>
<p>C:\&gt;<strong>logman query providers | findstr SQL</strong><br />SQLNCLI.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {BA798F36-2325-EC5B-ECF8-76958A2AF9B5}<br />SQLNCLI10.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {A9377239-477A-DD22-6E21-75912A95FD08}<br />SQLNCLI11.1&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {2DA81B52-908E-7DB6-EF81-76856BB47C4F}</p>
<p>You should see all 3 SNAC driver versions in the output.&nbsp; You are now ready to process the&nbsp;traces (the *.etl files generated)</p>
<p><strong>#5.&nbsp;&nbsp;To process the traces to extract the data to CSV file, use&nbsp;tracerpt tool (comes with Windows) or LogParser (you need to download this tool).</strong></p>
<p>Run following from a command prompt:</p>
<p><code class="mysql">tracerpt SnacTrace_000001.etl -of CSV -en ANSI -gmt -o SnacTrace_000001.csv</code></p>
<p><strong>Note I find the LogParser tool (you can download from Microsoft) provides a nicer, more compact log file, try this command:</strong></p>
<p>LogParser.exe "select eventnumber, eventname, timestamp, userdata into SnacTrace_000001.csv from SnacTrace_000001.etl" <br /> -i:ETW -o:CSV -oTsFormat:"yyyy-MM-dd hh:mm:ss.n" -headers:off</p>
<p>This will give you a really nice looking trace file output, and LogParser is also very fast to process large traces.</p>]]></content:encoded>
    </item>
    <item>
      <title>PowerShell Command Separator Is ; and Not &amp;</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/powershell-command-separator-is-and-not</link>
      <pubDate>Sat, 28 Apr 2012 09:02:41 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2012/04/28/powershell-command-separator-is-and-not/</guid>
      <description><![CDATA[&#160;  Ahh PowerShell, I still cannot fully embrace your powerful weirdness.  With normal NT...]]></description>
      <content:encoded><![CDATA[<p>&#160;</p>  <p>Ahh PowerShell, I still cannot fully embrace your powerful weirdness.</p>  <p>With normal NT command prompt I can restart my SQL Server by running =&gt;</p>  <p><strong>net stop mssqlserver&#160; &amp; net start mssqlserver</strong></p>  <p>This does not work in PowerShell, you get the usual cryptic, nonsensical and useless error message:</p>  <p>PS C:\&gt; net stop mssqlserver &amp; net start mssqlserver   <br /><strong>Ampersand not allowed. The &amp; operator is reserved for future use; use &quot;&amp;&quot; to pass ampersand as a string.     <br />At line:1 char:23      <br />+ net stop mssqlserver &amp; &lt;&lt;&lt;&lt;&#160; net start mssqlserver      <br />&#160;&#160;&#160; + CategoryInfo&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; : ParserError: (:) [], ParentContainsErrorRecordException      <br />&#160;&#160;&#160; + FullyQualifiedErrorId : AmpersandNotAllowed</strong></p>  <p>Personally, I would change this error message to:</p>  <p><strong>Ampersand not allowed.&#160; You can use the semi-colon instead for a command separator in PowerShell.</strong></p>  <p>Ok, given this logic, then I try:</p>  <p>PS C:\&gt; net stop mssqlserver &quot;&amp;&quot; net start mssqlserver   <br /><strong>The syntax of this command is:</strong></p> <strong></strong>  <p><strong>NET STOP     <br />service      <br /></strong></p>  <p>Ok, I give up.&#160; Time to search the internet.</p>  <p>Found some mention of an <strong>undocumented semi-colon</strong> <strong>as command separator</strong>, this works =&gt;</p>  <p>PS C:\&gt; net stop mssqlserver ; net start mssqlserver   <br /><strong>The SQL Server (MSSQLSERVER) service is stopping.     <br />The SQL Server (MSSQLSERVER) service was stopped successfully.</strong></p> <strong></strong>  <p><strong>The SQL Server (MSSQLSERVER) service is starting.     <br />The SQL Server (MSSQLSERVER) service was started successfully.</strong></p>]]></content:encoded>
    </item>
    <item>
      <title>Disabling =&gt; CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/disabling-clrdll-no-clr-image-loaded-i-e-mscorwks-dll</link>
      <pubDate>Thu, 26 Apr 2012 12:55:40 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2012/04/26/disabling-clrdll-no-clr-image-loaded-i-e-mscorwks-dll/</guid>
      <description><![CDATA[I’m debugging using the Debugging Tools For Windows (WinDbg).&#160; Debugging a native C++ process...]]></description>
      <content:encoded><![CDATA[<p>I’m debugging using the Debugging Tools For Windows (WinDbg).&#160; Debugging a native C++ process (no CLR loaded).</p>  <p>I find with every debugger command I run, I get annoying amounts of debugger logging spew saying “<b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)”.</b></p>  <p>For example, when I dump a call stack I see:</p>  <p>0:000&gt; kC</p>  <p>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</p>  <p>KERNELBASE!RaiseException</p>  <p>myapp!_CxxThrowException</p>  <p>..</p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p><b>CLRDLL: No CLR image loaded (i.e. mscorwks.dll)</b></p>  <p>WARNING: Stack unwind information not available. Following frames may be wrong.</p>  <p>Etc…</p>  <p>The fix to disable this spew is running:</p>  <p><b>.cordll –vd</b></p>  <p>The reason I saw this in my debugger is I have a startup script that runs:</p>  <p><b>.cordll -ve -u –l</b></p>  <p>This <strong>–ve</strong> means “enable vebose logging for CLR”.&#160; Internally the debugger is trying to load CLR debugging support over and over and this is failing.&#160; Running .cordll –vd disables the extended logging.</p>  <p>Note you can disable CLR integration with debugger to speed up the debugger command execution when debugging native code by running:</p>  <p><strong>.cordll -d -u -vd</strong></p>  <p>Read help on .cordll for details.</p>]]></content:encoded>
    </item>
    <item>
      <title>Calculating read_only_routing_url for AlwaysOn</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/calculating-read_only_routing_url-for-alwayson</link>
      <pubDate>Wed, 25 Apr 2012 14:29:54 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2012/04/25/calculating-read_only_routing_url-for-alwayson/</guid>
      <description><![CDATA[&#160;  When setting up read-only routing for SQL Server AlwaysOn, you have to configure each...]]></description>
      <content:encoded><![CDATA[<p>&#160;</p>  <p>When setting up read-only routing for SQL Server AlwaysOn, you have to configure each availability replica with a read-only routing URL.</p>  <p>The read-only routing URL is just a “pointer” to the replica and determines what the replica will report back to the client driver when routing to the replica.</p>  <p>Suppose you have an AlwaysOn cluster with 3 cluster nodes, Node1, Node2, and Node3.&#160;&#160; On each of these nodes you will have a SQL Server instance running.&#160;&#160; For very simple configurations there will be one default SQL Server instance listening on tcp port 1433 on each node.&#160; With a more complex configuration you may have clustered SQL Server instances on these nodes.</p>  <p>Read-only routing uses the following algorithm to locate a readable secondary:</p>  <ul>   <li>Client connects to an Availability Group listener endpoint.</li>    <ul>     <li>Note this endpoint always points to the primary replica for the availability group</li>   </ul>    <li>Client specifies ApplicationIntent=ReadOnly in the connection string, this is transmitted to the server during login</li>    <li>On server side, server checks that incoming connection is using an Availability Group listener endpoint</li>    <ul>     <li>Otherwise, read-only routing is disabled</li>   </ul>    <li>Server checks the target database and determines if it is in an availability group</li>    <li>If database is in an availability group, we check if the read_only_routing_list is set on the primary replica</li>    <ul>     <li>If list is not set, routing is disabled</li>      <li>If list is set, then routing is enforced</li>   </ul>    <li>Server then enumerates the replicas in the read_only_routing_list and checks each replica in the list</li>    <li>First replica it finds that is synchronizing and accepts readers (allow_connections=read_only or all) is the routing target</li>    <li>Server next reads the read_only_routing_url from this replica and sends this response to the client</li>    <li>Client reads routing URL and re-directs to the readable secondary instance</li> </ul>  <p>Given above, you need to ensure that the read_only_routing_url is properly set for each replica when enabling read-only routing, otherwise the client will be redirected to the wrong instance.</p>  <p>I created a T-SQL script that you can run against any instance and it will tell you what the appropriate read_only_routing_url is for the instance.&#160;&#160; The script will detect if the instance is clustered or not an generate appropriate URL.&#160;&#160; Script is included below, enjoy!&#160; =&gt;</p>  <p>-- Read-only routing url generation script.   <br />-- Connect to each replica in your AlwaysOn cluster and run this script to get the read_only_routing_url for the replica.    <br />-- Then set this to the read_only_routing_url for the availability group replica =&gt;    <br />--&#160;&#160;&#160; alter availability group MyAvailabilityGroup modify replica on N'ThisReplica' with (secondary_role(read_only_routing_url=N'&lt;url&gt;'))    <br />print 'Read-only-routing url script v.2012.1.24.1'</p>  <p>print 'This SQL Server instance version is [' + cast(serverproperty('ProductVersion') as varchar(256)) + ']'</p>  <p>if (ServerProperty('IsClustered') = 1)    <br />begin    <br />&#160;&#160;&#160; print 'This SQL Server instance is a clustered SQL Server instance.'    <br />end    <br />else    <br />begin    <br />&#160;&#160;&#160; print 'This SQL Server instance is a standard (not clustered) SQL Server instance.'&#160;&#160;&#160; <br />end</p>  <p>if (ServerProperty('IsHadrEnabled') = 1)    <br />begin    <br />&#160;&#160;&#160; print 'This SQL Server instance is enabled for AlwaysOn.'    <br />end    <br />else    <br />begin    <br />&#160;&#160;&#160; print 'This SQL Server instance is NOT enabled for AlwaysOn.'    <br />end</p>  <p>-- Detect SQL Azure instance.   <br />declare @is_sql_azure bit    <br />set @is_sql_azure = 0</p>  <p>begin try   <br />&#160;&#160;&#160; set @is_sql_azure = 1    <br />&#160;&#160;&#160; exec('declare @i int set @i = sql_connection_mode()')    <br />&#160;&#160;&#160; print 'This SQL Server instance is a Sql Azure instance.'    <br />end try    <br />begin catch    <br />&#160;&#160;&#160; set @is_sql_azure = 0    <br />&#160;&#160;&#160; print 'This SQL Server instance is NOT a Sql Azure instance.'    <br />end catch</p>  <p>-- Check that this is SQL 11 or later, otherwise fail fast.   <br />if (@@microsoftversion / 0x01000000 &lt; 11 or @is_sql_azure &gt; 0)    <br />begin    <br />&#160;&#160;&#160; print 'This SQL Server instance does not support read-only routing, exiting script.'    <br />end    <br />else    <br />begin -- if server supports read-only routing</p>  <p>&#160;&#160;&#160; -- Fetch the dedicated admin connection (dac) port.   <br />&#160;&#160;&#160; -- Normally it's always port 1434, but to be safe here we fetch it from the instance.    <br />&#160;&#160;&#160; -- We use this later to exclude the admin port from read_only_routing_url.    <br />&#160;&#160;&#160; declare @dac_port int    <br />&#160;&#160;&#160; declare @reg_value varchar(255)    <br />&#160;&#160;&#160; exec xp_instance_regread     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'HKEY_LOCAL_MACHINE',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer\SuperSocketNetLib\AdminConnection\Tcp',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'TcpDynamicPorts',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; @reg_value output</p>  <p>&#160;&#160;&#160; set @dac_port = cast(@reg_value as int)</p>  <p>&#160;&#160;&#160; print 'This SQL Server instance DAC (dedicated admin) port is ' + cast(@dac_port as varchar(255))   <br />&#160;&#160;&#160; if (@dac_port = 0)    <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'Note a DAC port of zero means the dedicated admin port is not enabled.'    <br />&#160;&#160;&#160; end</p>  <p>&#160;&#160;&#160; -- Fetch ListenOnAllIPs value.   <br />&#160;&#160;&#160; -- If set to 1, this means the instance is listening to all IP addresses.    <br />&#160;&#160;&#160; -- If set to 0, this means the instance is listening to specific IP addresses.    <br />&#160;&#160;&#160; declare @listen_all int    <br />&#160;&#160;&#160; exec xp_instance_regread     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'HKEY_LOCAL_MACHINE',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer\SuperSocketNetLib\Tcp',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'ListenOnAllIPs',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; @listen_all output</p>  <p>&#160;&#160;&#160; if (@listen_all = 1)   <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'This SQL Server instance is listening to all IP addresses (default mode).'    <br />&#160;&#160;&#160; end    <br />&#160;&#160;&#160; else    <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'This SQL Server instance is listening to specific IP addresses (ListenOnAllIPs is disabled).'    <br />&#160;&#160;&#160; end</p>  <p>&#160;&#160;&#160; -- Check for dynamic port configuration, not recommended with read-only routing.   <br />&#160;&#160;&#160; declare @tcp_dynamic_ports varchar(255)    <br />&#160;&#160;&#160; exec xp_instance_regread     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'HKEY_LOCAL_MACHINE',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'SOFTWARE\Microsoft\Microsoft SQL Server\\MSSQLServer\SuperSocketNetLib\Tcp\IPAll',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; N'TcpDynamicPorts',    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; @tcp_dynamic_ports output</p>  <p>&#160;&#160;&#160; if (@tcp_dynamic_ports = '0')   <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'This SQL Server instance is listening on a dynamic tcp port, this is NOT A RECOMMENDED CONFIGURATION when using read-only routing, because the instance port can change each time the instance is restarted.'    <br />&#160;&#160;&#160; end    <br />&#160;&#160;&#160; else    <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'This SQL Server instance is listening on fixed tcp port(s) (it is not configured for dynamic ports), this is a recommended configuration when using read-only routing.'    <br />&#160;&#160;&#160; end</p>  <p>&#160;&#160;&#160; -- Calculate the server domain and instance FQDN.   <br />&#160;&#160;&#160; -- We use @server_domain later to build the FQDN to the clustered instance.    <br />&#160;&#160;&#160; declare @instance_fqdn varchar(255)    <br />&#160;&#160;&#160; declare @server_domain varchar(255)</p>  <p>&#160;&#160;&#160; -- Get the instance FQDN using the xp_getnetname API   <br />&#160;&#160;&#160; -- Note all cluster nodes must be in same domain, so this works for calculating cluster FQDN.    <br />&#160;&#160;&#160; set @instance_fqdn = ''    <br />&#160;&#160;&#160; exec xp_getnetname @instance_fqdn output, 1 </p>  <p>&#160;&#160;&#160; -- Remove embedded null character at end if found.   <br />&#160;&#160;&#160; declare @terminator int     <br />&#160;&#160;&#160; set @terminator = charindex(char(0), @instance_fqdn) - 1     <br />&#160;&#160;&#160; if (@terminator &gt; 0)     <br />&#160;&#160;&#160; begin     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; set @instance_fqdn = substring(@instance_fqdn, 1, @terminator)     <br />&#160;&#160;&#160; end</p>  <p>&#160;&#160;&#160; -- Build @server_domain using @instance_fqdn.   <br />&#160;&#160;&#160; set @server_domain = @instance_fqdn</p>  <p>&#160;&#160;&#160; -- Remove trailing portion to extract domain name.   <br />&#160;&#160;&#160; set @terminator = charindex('.', @server_domain)    <br />&#160;&#160;&#160; if (@terminator &gt; 0)     <br />&#160;&#160;&#160; begin     <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; set @server_domain = substring(@server_domain, @terminator+1, datalength(@server_domain))     <br />&#160;&#160;&#160; end    <br />&#160;&#160;&#160; print 'This SQL Server instance resides in domain ''' +&#160; @server_domain + ''''</p>  <p>&#160;&#160;&#160; if (ServerProperty('IsClustered') = 1)    <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; -- Fetch machine name, which for a clustered SQL instance returns the network name of the virtual server.    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; -- Append @server_domain to build the FQDN.    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; set @instance_fqdn = cast(serverproperty('MachineName') as varchar(255)) + '.' + @server_domain    <br />&#160;&#160;&#160; end</p>  <p>&#160;&#160;&#160; declare @ror_url varchar(255)   <br />&#160;&#160;&#160; declare @instance_port int</p>  <p>&#160;&#160;&#160; set @ror_url = ''</p>  <p>&#160;&#160;&#160; -- Get first available port for instance.   <br />&#160;&#160;&#160; select     <br />&#160;&#160;&#160; top 1&#160;&#160;&#160; -- Select first matching port    <br />&#160;&#160;&#160; @instance_port = port    <br />&#160;&#160;&#160; from sys.dm_tcp_listener_states     <br />&#160;&#160;&#160; where     <br />&#160;&#160;&#160; type=0 -- Type 0 = TSQL (to avoid mirroring endpoint)    <br />&#160;&#160;&#160; and     <br />&#160;&#160;&#160; state=0&#160;&#160;&#160; --&#160; State 0 is online&#160;&#160;&#160; <br />&#160;&#160;&#160; and     <br />&#160;&#160;&#160; port &lt;&gt; @dac_port -- Avoid DAC port (admin port)    <br />&#160;&#160;&#160; and     <br />&#160;&#160;&#160; -- Avoid availability group listeners    <br />&#160;&#160;&#160; ip_address not in (select ip_address from sys.availability_group_listener_ip_addresses agls)     <br />&#160;&#160;&#160; group by port&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160; order by port asc&#160; -- Pick first port in ascending order</p>  <p>&#160;&#160;&#160; -- Check if there are multiple ports and warn if this is the case.   <br />&#160;&#160;&#160; declare @list_of_ports varchar(max)    <br />&#160;&#160;&#160; set @list_of_ports = ''</p>  <p>&#160;&#160;&#160; select    <br />&#160;&#160;&#160; @list_of_ports = @list_of_ports +    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; case datalength(@list_of_ports)    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; when 0 then cast(port as varchar(max))    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; else ',' +&#160; cast(port as varchar(max))    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; end    <br />&#160;&#160;&#160; from sys.dm_tcp_listener_states     <br />&#160;&#160;&#160; where     <br />&#160;&#160;&#160; type=0&#160;&#160;&#160; --&#160;&#160;&#160;&#160; Type 0 = TSQL (to avoid mirroring endpoint)    <br />&#160;&#160;&#160; and     <br />&#160;&#160;&#160; state=0&#160;&#160;&#160; --&#160; State 0 is online&#160;&#160;&#160; <br />&#160;&#160;&#160; and     <br />&#160;&#160;&#160; port &lt;&gt; @dac_port -- Avoid DAC port (admin port)    <br />&#160;&#160;&#160; and     <br />&#160;&#160;&#160; -- Avoid availability group listeners    <br />&#160;&#160;&#160; ip_address not in (select ip_address from sys.availability_group_listener_ip_addresses agls)     <br />&#160;&#160;&#160; group by port&#160;&#160;&#160;&#160;&#160;&#160;&#160; <br />&#160;&#160;&#160; order by port asc</p>  <p>&#160;&#160;&#160; print 'This SQL Server instance FQDN (Fully Qualified Domain Name) is ''' + @instance_fqdn + ''''   <br />&#160;&#160;&#160; print 'This SQL Server instance port is ' + cast(@instance_port as varchar(10))</p>  <p>&#160;&#160;&#160; set @ror_url = 'tcp://' + @instance_fqdn + ':' + cast(@instance_port as varchar(10))</p>  <p>&#160;&#160;&#160; print '****************************************************************************************************************'   <br />&#160;&#160;&#160; print 'The read_only_routing_url for this SQL Server instance is ''' + @ror_url + ''''    <br />&#160;&#160;&#160; print '****************************************************************************************************************'</p>  <p>&#160;&#160;&#160; -- If there is more than one instance port (unusual) list them out just in case.   <br />&#160;&#160;&#160; if (charindex(',', @list_of_ports) &gt; 0)     <br />&#160;&#160;&#160; begin    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'Note there is more than one instance port, the list of available instance ports for read_only_routing_url is (' + @list_of_ports + ')'    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160; print 'The above URL just uses the first port in the list, but you can use any of these available ports.'    <br />&#160;&#160;&#160; end</p>  <p>end -- if server supports read-only routing   <br />go</p>]]></content:encoded>
    </item>
    <item>
      <title>Tracking Handle Misuse Using Application Verifier and Windbg</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/tracking-handle-misuse-using-application-verifier-and-windbg</link>
      <pubDate>Tue, 08 Sep 2009 13:26:44 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2009/09/08/tracking-handle-misuse-using-application-verifier-and-windbg/</guid>
      <description><![CDATA[In a recent MSDN forum post Connection Pooling randomly throwing COM exceptions I uncovered an issue...]]></description>
      <content:encoded><![CDATA[<p>In a recent MSDN forum post <a title="Connection Pooling randomly throwing COM exceptions" href="https://social.msdn.microsoft.com/Forums/en-US/adodotnetdataproviders/thread/b5b7a179-3737-4380-b6cf-843f3e71b317">Connection Pooling randomly throwing COM exceptions</a> I uncovered an issue where some code inside the process was closing handles owned by our pooling code.&#160; This caused our pooling code to get into a bad state triggering a SemaphoreFullException every single time a caller attempted to open a connection from the pool.</p>  <p>The root cause of this problem was code calling the Win32 API CloseHandle on a handle that it did not own.&#160;&#160; Since Windows can aggresively reuse handle values, it’s possible to hit a situation like below:</p>  <p>Thread1: CreateFile –&gt; Get handle #1.</p>  <p>Thread1: CloseHandle(#1)</p>  <p>Thread2: CreateFile –&gt; Get handle #1, store in member variable.</p>  <p>Thread1: CloseHandle (#1) &lt;- Mistake in code.</p>  <p>Thread1: CreateEvent –&gt; Get handle #1.</p>  <p>Now my code on Thread2 thinks it has a file handle, but it has an event handle!&#160;&#160; Thread2 did not make any coding mistake, the Thread1 code corrupted Thread2’s handle value.</p>  <p>This is an inherent issue when using handles, they are inherently dangerous you have to be very careful to only call CloseHandle 1 time.&#160; Now the operating system could mitigate this by handling out random values for handles, but in general the operating system does not always do this for performance reasons.&#160; The tradeoff is fast performance for all applications that behave correctly.</p>  <p>Now if you have a process where you suspect handles are getting misused (leaked or double closed), you can use Application Verifier to help track this down very quickly, this is what I want to talk about.</p>  <p>First download both <strong>Microsoft Application Verifier</strong> and <strong>Debugging Tools for Windows</strong>, both are free downloads from Microsoft.&#160; I would provide links but these always change, get the latest versions of both.&#160; Get the version that matches your operating system bitness as well for best results.</p>  <p>Install Microsoft Application Verifier and Debugging Tools for Windows on the machine where you have the problem.&#160; Both are very clean installers and remove easily so don’t worry about installing on production machine, they are easy to remove and don’t require any reboot during removal.&#160;&#160; If you are really worried you can install them on a separate machine and xcopy the files to the production machine, this works as well.</p>  <p>Next, figure out what process you want to debug.&#160; If you are running IIS application with .NET, most likely this is the w3wp.exe process.&#160; You don’t need the process ID yet.</p>  <p>First run Application Verifier to setup handle tracking, it looks like below:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_2.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_2.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb.png" width="244" height="146" /></a> </p>  <p>Not too fancy.&#160; :)&#160; You want to create the entry for the process name next, select File | Add Application.&#160;&#160; Let’s do the demonstration using notepad.exe for now.&#160;&#160; Just type in notepad.exe and click Open.&#160; You do not have to find and select the correct binary, just typing in the process name is sufficient, it does not need the full path:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_4.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_4.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_1.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_1.png" width="244" height="193" /></a> </p>  <p>Now that you’ve added the process, go to the right and select ONLY handles under the Basics options, like below:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_6.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_6.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_2.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_2.png" width="244" height="146" /></a> </p>  <p>The reason I only select handles here is to reduce the performance implications of all the other tracking inside the process.&#160; I just want to track handles, this is all.</p>  <p>Once you’ve selected handles only, click Save, then close Application Verifier.&#160; You will see this message:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_8.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_8.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_3.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_3.png" width="244" height="95" /></a> </p>  <p>This is fine, we will do this work later on (attach debugger).&#160; Click OK and exit App Verifier.</p>  <p>Now, VERY IMPORTANT!&#160; Re-open App Verifier.&#160; Verify you see your process name correctly and you see only Handles is checked.&#160; Do this step as a sanity check to ensure you selected the right thing AND it was saved correctly to registry.</p>  <p>Exit App Verifier again.</p>  <p>If your process is currently running,<strong> stop and restart the process</strong>.&#160;&#160; If for example you are using IIS, you want to run iisreset at this point to restart IIS.&#160; This step is required as the process reads the Application Verifier flags ONLY during startup.</p>  <p>In our case we are debugging notepad, so lets startup an instance of notepad.exe at this point (Start|Run –&gt; Notepad.exe)</p>  <p>Now open Windbg.exe (from Debugging Tools For Windows install).&#160; Select File | Attach To Process…</p>  <p><strong>VERY IMPORTANT!&#160; First thing to do is check the Non-invasive check box on the Attach to Process dialog, as below:</strong></p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_10.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_10.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_4.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_4.png" width="179" height="244" /></a> </p>  <p>You should ALWAYS check this when doing handle tracking work because this allows you to attach to the process in a special mode called non-invasive mode.&#160; This allows the debugger to be later detached and the process will continue normally.&#160; If you don’t check this checkbox, the debugger will fully attach to the process and you cannot shut down the debugger without terminating the process.</p>  <p>Next, locate your process, you will see here my process is notepad.exe, select this process:</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_12.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_12.png"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="image" border="0" alt="image" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_5.png" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/TrackingHandleMisuseUsingApplicationVeri_92C5/image_thumb_5.png" width="180" height="244" /></a> </p>  <p>Click OK to attach the debugger non-invasively.&#160;&#160; Once you are attached, go to the command window (select View|Command) and run the following commands:</p>  <p>0:000&gt; <strong>!htrace -enable</strong>    <br />Handle tracing enabled.    <br />Handle tracing information snapshot successfully taken.</p>  <p>This command is required to enable the tracing of handles.&#160; Once this is set, you can exit the debugger by running the q (quit) command:</p>  <p>0:000:&gt; <strong>q</strong></p>  <p>At this point handle tracking is enabled for the process.&#160; For this experiment, now go to notepad and open a single text file but do not exit notepad.exe yet.</p>  <p>Now we want to see what handle tracking can do for us.&#160; Startup Windbg.exe again and attach to notepad again in <strong>non-invasive mode</strong>.&#160; Run the following commands:</p>  <p>0:000&gt; <strong>.dump /ma c:\temp\notepad.dmp     <br /></strong>Creating c:\temp\notepad.exe - mini user dump    <br />Dump successfully written</p>  <p>Note the command is .dump /ma &lt;filename&gt; where &lt;filename&gt; can be anything you want here.&#160; I called my dump file c:\temp\notepad.dmp.</p>  <p>This creates a dump of the process.&#160; Now again run <strong>q </strong>(quit) command to exit debugger.</p>  <p>Re-open Windbg again, we are next going to examine the dump file.</p>  <p>In Windbg select File | Open Crash Dump… and select c:\temp\notepad.dmp and click Open.</p>  <p>In the command window, run the following 2 commands to load symbols:</p>  <p>0:000&gt; <strong>.sympath srv*</strong><a href="https://msdl.microsoft.com/download/symbols"><strong>https://msdl.microsoft.com/download/symbols</strong></a>    <br />Symbol search path is: srv*<a href="https://msdl.microsoft.com/download/symbols">https://msdl.microsoft.com/download/symbols</a>    <br />Expanded Symbol search path is: srv*<a href="https://msdl.microsoft.com/download/symbols">https://msdl.microsoft.com/download/symbols</a>    <br />0:000&gt; <strong>.reload /f     <br /></strong>..........................................*** ERROR: Symbol file could not be found.&#160; Defaulted to export symbols for AvCheck.dll -     <br />.....    <br />Loading unloaded module list</p>  <p>Note you may see errors here, this is fine for now.</p>  <p>Now we want to see a trace of our handle activity, run the !htrace command with no arguments:</p>  <p>0:000&gt;<strong> !htrace</strong></p>  <p>Next you will see tons of debugger spew like below:</p>  <p>--------------------------------------   <br />Handle = 0x00000000000002f0 - OPEN    <br />Thread ID = 0x0000000000001390, Process ID = 0x0000000000000b6c </p>  <p>0x0000000077835e3a: ntdll!ZwDuplicateObject+0x000000000000000a   <br />0x00000000776148a8: kernel32!DuplicateHandle+0x0000000000000055    <br />0x000007fefe6cb435: rpcrt4!THREAD::THREAD+0x00000000000000b5    <br />0x000007fefe6cb35c: rpcrt4!ThreadSelfHelper+0x0000000000000028    <br />0x000007fefe77444c: rpcrt4!NdrpClientCall2+0x0000000000000698    <br />0x000007fefe774ddd: rpcrt4!NdrClientCall2+0x000000000000001d    <br />0x000007fefe4c0e9a: ole32!BulkUpdateOIDs+0x000000000000008a    <br />0x000007fefe4c0d89: ole32!CRpcResolver::BulkUpdateOIDs+0x0000000000000109    <br />0x000007fefe4c0c36: ole32!CROIDTable::ClientBulkUpdateOIDWithPingServer+0x0000000000000224    <br />0x000007fefe4c94c3: ole32!CROIDTable::WorkerThreadLoop+0x0000000000000057    <br />0x000007fefe4c9406: ole32!CRpcThread::WorkerLoop+0x000000000000001e    <br />0x000007fefe4c9682: ole32!CRpcThreadCache::RpcWorkerThreadEntry+0x000000000000001a    <br />0x000000007761466d: kernel32!BaseThreadInitThunk+0x000000000000000d    <br />0x0000000077818791: ntdll!RtlUserThreadStart+0x000000000000001d    <br />--------------------------------------    <br />Handle = 0x000000000000031c – OPEN</p> …  <p>This shows you all the handle activity in the process.</p>  <p>You can locate a double close by searching for the CLOSE lines:</p>  <p><strong>Handle = 0x000000000000033c - CLOSE</strong></p>  <p>This will also have the stack trace of the code that closed the handle.</p>  <p>Now in my case what I did was gather a dump when some error case occurred in my process, then I examined the dump to determine what handle my code was using and then used !htrace to find out who closed it.&#160; All of the information is kept in the crash dump nicely for you.</p>  <p>You can also pass a parameter to !htrace to dump activity for a single handle, like below:</p>  <p>0:000&gt; <strong>!htrace 33c</strong>     <br />--------------------------------------    <br />Handle = 0x000000000000033c - CLOSE    <br />Thread ID = 0x0000000000000744, Process ID = 0x0000000000000b6c </p>  <p>0x0000000077835faa: ntdll!ZwTerminateThread+0x000000000000000a   <br />0x000000007780b508: ntdll!RtlExitUserThread+0x0000000000000048    <br />0x000000007780b8a7: ntdll!TppWorkerThread+0x0000000000000a23    <br />0x000000007761466d: kernel32!BaseThreadInitThunk+0x000000000000000d    <br />0x0000000077818791: ntdll!RtlUserThreadStart+0x000000000000001d    <br />--------------------------------------    <br />Handle = 0x000000000000033c - OPEN    <br />Thread ID = 0x0000000000000744, Process ID = 0x0000000000000b6c </p>  <p>0x000000007773d57a: user32!ZwUserCallOneParam+0x000000000000000a   <br />0x000000007773d95f: user32!RealMsgWaitForMultipleObjectsEx+0x00000000000000b3    <br />0x000000007773da2e: user32!MsgWaitForMultipleObjectsEx+0x0000000000000046    <br />0x0000000077732af4: user32!MsgWaitForMultipleObjects+0x0000000000000020    <br />0x000007fef5fbb198: browseui!CShellTaskScheduler::_TT_MsgWaitForMultipleObjects+0x0000000000000038    <br />0x000007fef5fbb11d: browseui!CShellTaskScheduler::TT_TransitionThreadToRunningOrTerminating+0x00000000000000a1    <br />0x000007fef5fbaea1: browseui!CShellTaskThread::ThreadProc+0x0000000000000076    <br />--------------------------------------</p>  <p>You will notice a specific handle is closed and reopened many times over a period of time, this is normal.&#160; What you want to look for is cases where CLOSE is called 2 times in a row to find cases of handle misuse.&#160; Likewise if a handle is leaked you will not see a final CLOSE called, the last trace will be an OPEN.</p>  <p>Now, when you are finished debugging, <strong>BE ABSOLUTELY SURE</strong> to start App Verifier again and <strong>DELETE</strong> the process entry for your process!&#160; You want to always do this since the App Verifier settings are persisted in the registry, they will survive even a server reboot.&#160; Right click on the Image Name and select “Delete Application”.&#160; Then click Save and close and re-open App Verifier to ensure that the entry is gone.&#160; As well if you are debugging some service you want to restart the service to stop the tracking, run iisreset for example again to reset IIS to normal state if you are debugging IIS.</p>  <p>Hope this helps you debug the next handle misuse case you encounter, have fun!</p>]]></content:encoded>
    </item>
    <item>
      <title>Nice day</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/nice-day</link>
      <pubDate>Wed, 11 Feb 2009 00:30:01 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2009/02/11/nice-day/</guid>
      <description><![CDATA[Yes.  ]]></description>
      <content:encoded><![CDATA[<p>Yes.</p>  <p><a href="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/Herelelrer_12E44/IMG_9487.jpg" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/Herelelrer_12E44/IMG_9487.jpg"><img style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" title="IMG_9487" border="0" alt="IMG_9487" src="https://msdnshared.blob.core.windows.net/media/TNBlogsFS/BlogFileStorage/blogs_msdn/mattn/WindowsLiveWriter/Herelelrer_12E44/IMG_9487_thumb.jpg" original-url="https://blogs.msdn.com/blogfiles/mattn/WindowsLiveWriter/Herelelrer_12E44/IMG_9487_thumb.jpg" width="244" height="164" /></a></p>]]></content:encoded>
    </item>
    <item>
      <title>How to tell if binary is x86 or amd64?</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/how-to-tell-if-binary-is-x86-or-amd64</link>
      <pubDate>Tue, 25 Nov 2008 12:17:59 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2008/11/25/how-to-tell-if-binary-is-x86-or-amd64/</guid>
      <description><![CDATA[First get dumpbin tool, ships with any Windows SDK.  Run dumpbin /headers on the binary, then look...]]></description>
      <content:encoded><![CDATA[<p>First get dumpbin tool, ships with any Windows SDK.</p>  <p>Run dumpbin /headers on the binary, then look at the <strong>magic number</strong>.</p>  <p><strong></strong></p>  <p><strong>This is an amd64 binary:</strong></p>  <p>&#160;</p>  <p>c:\&gt;dumpbin /headers c:\amd64\msvcr100.dll | findstr magic   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 20B magic # <strong>(PE32+)</strong></p>  <p><strong></strong></p>  <p><strong>This is a 32-bit binary:</strong></p>  <p>&#160;</p>  <p>c:\DPMedusa1&gt;dumpbin /headers c:\x86\msvcr100.dll | findstr magic   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 10B magic # (<strong>PE32</strong>)</p>  <p>&#160;</p>  <p>dumpbin also works on executables, for example on my amd64 machine:</p>  <p>&#160;</p>  <p>c:\&gt;dumpbin /headers c:\Windows\System32\calc.exe | findstr magic   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 20B magic # (PE32+)</p>  <p>&#160;</p>  <p>c:\&gt;dumpbin /headers c:\Windows\SysWOW64\calc.exe | findstr magic   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; 10B magic # (PE32)</p>]]></content:encoded>
    </item>
    <item>
      <title>TrustedInstaller</title>
      <link>https://docs.microsoft.com/archive/blogs/mattn/trustedinstaller</link>
      <pubDate>Tue, 07 Oct 2008 17:09:52 GMT</pubDate>
      <dc:creator><![CDATA[Matt Neerincx [MSFT]]]></dc:creator>
      <guid
        isPermaLink="false">https://blogs.msdn.microsoft.com/mattn/2008/10/07/trustedinstaller/</guid>
      <description><![CDATA[Just a note to self, when typing in TrustedInstaller into security dialogs in Vista/Windows 2008, be...]]></description>
      <content:encoded><![CDATA[<p>Just a note to self, when typing in TrustedInstaller into security dialogs in Vista/Windows 2008, be sure to prefix with:</p>  <p><strong>&#160;&#160;&#160; NT SERVICE\TrustedInstaller</strong></p>  <p>C:\Windows&gt;icacls c:\windows\winsxs   <br />c:\windows\winsxs </p>  <p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; NT SERVICE\TrustedInstaller:(OI)(CI)(F)   <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BUILTIN\Administrators:(OI)(CI)(RX)    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; NT AUTHORITY\SYSTEM:(OI)(CI)(RX)    <br />&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160; BUILTIN\Users:(OI)(CI)(RX)</p>  <p>&#160;</p>  <p>The security UI dialogs do not recognize TrustedInstaller just by itself (don't know why).</p>]]></content:encoded>
    </item>
  </channel>
</rss>