<?xml version="1.0" encoding="utf-8"?>
<rss xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:pingback="http://madskills.com/public/xml/rss/module/pingback/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
  <channel>
    <title>Wandering through the Wilderness - Debugging</title>
    <link>http://www.julmar.com/blog/mark/</link>
    <description>... a journey through WPF, MVVM and .NET4</description>
    <language>en-us</language>
    <copyright>Mark Smith</copyright>
    <lastBuildDate>Fri, 08 Dec 2006 19:25:29 GMT</lastBuildDate>
    <generator>newtelligence dasBlog 2.3.9074.18820</generator>
    <managingEditor>mark@julmar.com</managingEditor>
    <webMaster>mark@julmar.com</webMaster>
    <item>
      <trackback:ping>http://www.julmar.com/blog/mark/Trackback.aspx?guid=3670d081-0276-48e6-b97d-1b644093b52e</trackback:ping>
      <pingback:server>http://www.julmar.com/blog/mark/pingback.aspx</pingback:server>
      <pingback:target>http://www.julmar.com/blog/mark/PermaLink,guid,3670d081-0276-48e6-b97d-1b644093b52e.aspx</pingback:target>
      <dc:creator>Mark</dc:creator>
      <wfw:comment>http://www.julmar.com/blog/mark/CommentView,guid,3670d081-0276-48e6-b97d-1b644093b52e.aspx</wfw:comment>
      <wfw:commentRss>http://www.julmar.com/blog/mark/SyndicationService.asmx/GetEntryCommentsRss?guid=3670d081-0276-48e6-b97d-1b644093b52e</wfw:commentRss>
      <title>The Mystery of Concurrent GC</title>
      <guid isPermaLink="false">http://www.julmar.com/blog/mark/PermaLink,guid,3670d081-0276-48e6-b97d-1b644093b52e.aspx</guid>
      <link>http://www.julmar.com/blog/mark/2006/12/08/TheMysteryOfConcurrentGC.aspx</link>
      <pubDate>Fri, 08 Dec 2006 19:25:29 GMT</pubDate>
      <description>&lt;p&gt;
&lt;style type=text/css&gt;
.csharpcode, .csharpcode pre
{
	font-size: large;
	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;
There's been a discussion going on within DevelopMentor for a couple weeks regarding
concurrent GC and when it really applies. 
&lt;/p&gt;
&lt;p&gt;
The idea behind the concurrent collector is to do as much of the GC while the UI thread
continues to process UI stuff and then only interrupt the application threads when
memory is being shuffled around and fixups are occurring. This provides for more responsive
UI applications at the expense of slower collections and a higher memory utilization. 
&lt;/p&gt;
&lt;p&gt;
The instructors who are involved with .NET were discussing this because of a discrepancy
in various reliable sources - First, Maoni Stephens, the ultimate authority on all
things .NET GC, stated in her blog entries that concurrent GC was the default behavior
for the workstation version of GC (see &lt;a href="http://blogs.msdn.com/maoni/"&gt;http://blogs.msdn.com/maoni&lt;/a&gt; for
more information on this). 
&lt;/p&gt;
&lt;p&gt;
This is well known, and now well documented in various places. However, Jeff Richter
seems to say in his book "&lt;i&gt;CLR via C#&lt;/i&gt;" that concurrent collections occur &lt;u&gt;only&lt;/u&gt; on
multiprocessor machines. Several other authors back this up (notably Stephen Pratschner
in "&lt;i&gt;Customizing the .NET Framework Common Language Runtime&lt;/i&gt;" and Joe Duffy in
his "&lt;i&gt;Professional .NET Framework 2.0&lt;/i&gt;" book; both are excellent btw). 
&lt;/p&gt;
&lt;p&gt;
So, we had some differing opinions from people in the "know". Our &lt;a href="http://www.develop.com/training/course.aspx?id=344"&gt;Effective
.NET&lt;/a&gt; and &lt;a href="http://www.develop.com/training/course.aspx?id=267"&gt;Essential
.NET&lt;/a&gt; courses were written around Maoni's blogs and so the diagram we presented
showed concurrent collections even on single-processor machines since she didn't explicitly
say it required multiple processors to turn it on. One of the guys noticed this and
said &lt;i&gt;"Wait! That's wrong!"&lt;/i&gt; 
&lt;/p&gt;
&lt;p&gt;
We tried to actually see the concurrent collection in action but it turns out that
it's actually quite difficult to get this to happen because concurrent collections
only occur on &lt;strong&gt;Gen2&lt;/strong&gt;, which for a well-written application shouldn't
occur that often. To add to the complexity, the CLR attempts to optimize this behavior
- just because it &lt;em&gt;can&amp;nbsp;&lt;/em&gt;do the GC&amp;nbsp;concurrently, it might not.&amp;nbsp;
Finally,&amp;nbsp;the thread which is used for this collection is actually created and
destroy as necessary so it doesn't exist most of the time. 
&lt;/p&gt;
&lt;p&gt;
So, to settle the argument, Jason Whittington and I spent some time spelunking into
the CLR this past week to see if we could spot the concurrent collection in action.
With a little WinDBG and some symbols, I think we've put the question to rest once
and for all (at least for us) :-).&amp;nbsp; If you scan the GC symbols in &lt;b&gt;mscorwks.dll&lt;/b&gt;,
you'll find a treasure trove of information; one of the things that caught my eye
was this: 
&lt;/p&gt;
&lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; x mscorwks!WKS::gcheap::*
79f8c5dd mscorwks!WKS::GCHeap::Relocate = &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;no&lt;/span&gt; &lt;span class=attr&gt;type&lt;/span&gt; &lt;span class=attr&gt;information&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; 7a0d09d9
mscorwks!WKS::GCHeap::ValidateObjectMember = &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;no&lt;/span&gt; &lt;span class=attr&gt;type&lt;/span&gt; &lt;span class=attr&gt;information&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; 7a088e2a &lt;b&gt;mscorwks!WKS::GCHeap::IsConcurrentGCInProgress&lt;/b&gt; = &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;no&lt;/span&gt; &lt;span class=attr&gt;type&lt;/span&gt; &lt;span class=attr&gt;information&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt; &lt;/pre&gt;Disassembling
that method showed me that it checks a flag in memory -- &lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; u
mscorwks!WKS::GCHeap::IsConcurrentGCInProgress mscorwks!WKS::GCHeap::IsConcurrentGCInProgress:
7a088e2a a1701b387a mov eax,dword ptr [&lt;b&gt;mscorwks!WKS::gc_heap::settings+0x10&lt;/b&gt; (7a381b70)]
7a088e2f c3 ret &lt;/font&gt;&lt;/pre&gt;I tried putting a breakpoint at the end of the GC process
and dumping that flag out when it was a Gen2 collection (the breakpoint itself stolen
shamelessly from &lt;a href="http://msdn.microsoft.com/msdnmag/issues/06/11/CLRInsideOut/default.aspx"&gt;Maoni's
MSDN article in November 2006&lt;/a&gt;): &lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; bp
mscorwks!WKS::GCHeap::RestartEE "j 
&lt;br&gt;
&lt;/font&gt;&lt;font size=3&gt;(dwo(mscorwks!WKS::GCHeap::GcCondemnedGeneration)==2) 
&lt;br&gt;
'dd mscorwks!WKS::gc_heap::settings+0x10 L1';'g'"&lt;/font&gt;&lt;/pre&gt;But I didn't get much
success seeing it set to "1" - I suspect that it requires a more complex application
than I was using to cause the CLR to decide a concurrent collection is worth the effort.
So I decided this was a dead end and started looking to see where the GC process determines
that concurrent collections are allowed at all. I figured &lt;b&gt;GCHeap::Initialize&lt;/b&gt; sounded
like a good spot -- &lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; u
mscorwks!WKS::GCHeap::Initialize mscorwks!WKS::GCHeap::Initialize: 79ed6924 a14412387a
mov eax,dword ptr [mscorwks!g_pConfig (7a381244)] 79ed6929 8b4058 mov eax,dword ptr
[eax+58h] ..... 79ed697b 51 push ecx 79ed697c e823040000 call mscorwks!WKS::gc_heap::initialize_gc
(79ed6da4) 79ed6981 85c0 test eax,eax &lt;/font&gt;&lt;/pre&gt;Going into that function yielded
what I was looking for -- &lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; u
mscorwks!WKS::gc_heap::initialize_gc mscorwks!WKS::gc_heap::initialize_gc: 79ed6da4
56 push esi 79ed6da5 e80cf1ffff call mscorwks!WKS::write_watch_api_supported (79ed5eb6)
79ed6daa 33f6 xor esi,esi ... 79ed6dc6 c70564ce387a01000000 mov dword ptr [&lt;b&gt;mscorwks!WKS::gc_heap::gc_can_use_concurrent&lt;/b&gt; (7a38ce64)],1 &lt;/font&gt;&lt;/pre&gt;Looking
at that particular memory location, I tried various configurations to make sure I
had the right spot. First, I did a simple console app with no config file and dumped
out the location on a multi-processor box: &lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; dd
mscorwks!WKS::gc_heap::gc_can_use_concurrent L1 7a38ce64 &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;00000001&lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;/font&gt;
&lt;/pre&gt;Next, I set the application up in server mode (also on a multi-processor box): &lt;pre class=csharpcode&gt;&lt;span class=kwrd&gt;&lt;?&lt;/span&gt;&lt;font size=3&gt;&lt;span class=html&gt;&lt;font color=#0000ff&gt;&amp;lt;&lt;/font&gt;xml&lt;/span&gt; &lt;span class=attr&gt;version&lt;/span&gt;&lt;span class=kwrd&gt;="1.0"&lt;/span&gt; &lt;span class=attr&gt;encoding&lt;/span&gt;&lt;span class=kwrd&gt;="utf-8"&lt;/span&gt; ?&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;configuration&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;runtime&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;gcServer&lt;/span&gt; &lt;span class=attr&gt;enabled&lt;/span&gt;&lt;span class=kwrd&gt;="true"&lt;/span&gt; &lt;span class=kwrd&gt;/&amp;gt;&lt;/span&gt; &amp;lt;/&lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;runtime&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;&lt;span class=kwrd&gt;&amp;lt;/&lt;/span&gt;configuration&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;
&lt;/pre&gt;&lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; dd mscorwks!WKS::gc_heap::gc_can_use_concurrent
L1 7a38ce64 &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;00000000&lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;/font&gt;
&lt;/pre&gt;Showing that it was now off.. next I tried a VM session which emulates a single
processor: &lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; dd
mscorwks!WKS::gc_heap::gc_can_use_concurrent L1 7a38ce64 &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;00000001&lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;/font&gt;
&lt;/pre&gt;
&lt;p&gt;
It appears that the CLR &lt;b&gt;is&lt;/b&gt; capable of doing concurrent collections on a single
processor! My final test was to try turning it off altogether via a configuration
switch: 
&lt;/p&gt;
&lt;pre class=csharpcode&gt;&lt;span class=kwrd&gt;&lt;?&lt;/span&gt;&lt;font size=3&gt;&lt;span class=html&gt;&lt;font color=#0000ff&gt;&amp;lt;&lt;/font&gt;xml&lt;/span&gt; &lt;span class=attr&gt;version&lt;/span&gt;&lt;span class=kwrd&gt;="1.0"&lt;/span&gt; &lt;span class=attr&gt;encoding&lt;/span&gt;&lt;span class=kwrd&gt;="utf-8"&lt;/span&gt; ?&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;configuration&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;runtime&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;gcConcurrent&lt;/span&gt; &lt;span class=attr&gt;enabled&lt;/span&gt;&lt;span class=kwrd&gt;="false"&lt;/span&gt; &lt;span class=kwrd&gt;/&amp;gt;&lt;/span&gt; &amp;lt;/&lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;runtime&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;&lt;span class=kwrd&gt;&amp;lt;/&lt;/span&gt;configuration&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;&lt;/font&gt;
&lt;/pre&gt;&lt;pre class=csharpcode&gt;&lt;font size=3&gt;0:000&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; dd mscorwks!WKS::gc_heap::gc_can_use_concurrent
L1 7a38ce64 &lt;span class=kwrd&gt;&amp;lt;&lt;/span&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt;00000000&lt;/font&gt;&lt;span class=kwrd&gt;&lt; span&gt;&lt;font size=3&gt;&lt;span class=html&gt;b&lt;/span&gt;&lt;span class=kwrd&gt;&amp;gt;&lt;/span&gt; &lt;/font&gt;
&lt;/pre&gt;
&lt;br&gt;
As a final note on this, Jason asked Maoni directly and her response was that concurrent
GC does &lt;strong&gt;not&lt;/strong&gt; depend on the number of processors - just as we are seeing
above. So, apparently several primary sources are actually incorrect on this behavior.
It just goes to show how complex the overall GC process really is -- simple in concept,
but boy there are a lot of moving parts! &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;</description>
      <comments>http://www.julmar.com/blog/mark/CommentView,guid,3670d081-0276-48e6-b97d-1b644093b52e.aspx</comments>
      <category>.NET</category>
      <category>Debugging</category>
    </item>
    <item>
      <trackback:ping>http://www.julmar.com/blog/mark/Trackback.aspx?guid=643649fc-0467-4f0d-9a95-323ed7ce4298</trackback:ping>
      <pingback:server>http://www.julmar.com/blog/mark/pingback.aspx</pingback:server>
      <pingback:target>http://www.julmar.com/blog/mark/PermaLink,guid,643649fc-0467-4f0d-9a95-323ed7ce4298.aspx</pingback:target>
      <dc:creator>Mark</dc:creator>
      <wfw:comment>http://www.julmar.com/blog/mark/CommentView,guid,643649fc-0467-4f0d-9a95-323ed7ce4298.aspx</wfw:comment>
      <wfw:commentRss>http://www.julmar.com/blog/mark/SyndicationService.asmx/GetEntryCommentsRss?guid=643649fc-0467-4f0d-9a95-323ed7ce4298</wfw:commentRss>
      <title>SOS: finding the method bound to an EventHandler&lt;T&gt; with WinDbg.</title>
      <guid isPermaLink="false">http://www.julmar.com/blog/mark/PermaLink,guid,643649fc-0467-4f0d-9a95-323ed7ce4298.aspx</guid>
      <link>http://www.julmar.com/blog/mark/2006/09/01/SOSFindingTheMethodBoundToAnEventHandlerWithWinDbg.aspx</link>
      <pubDate>Fri, 01 Sep 2006 18:18:41 GMT</pubDate>
      <description>I was preparing a sample memory leak application for an Advanced C# class at Microsoft this past week and debugging through it with SOS.DLL ("Son of Strike").  My prepared application was an ASP.NET application that would leak memory by holding references to the page objects after they had completed their work.  I did this by having the page hook up an event handler to a global event and then never remove the handler.
&lt;br /&gt;
&lt;br /&gt;
This, of course, is bad form because the System.Web.UI.Page object is intended to
be a transient object - it goes away at the end of the request - in production code,
I would really bind the event to a handler in &lt;b&gt;global.asax&lt;/b&gt; instead. But as I
said, this was a sample. 
&lt;br /&gt;
&lt;br /&gt;
So, I was debugging through it prior to the class just to make sure it exhibited the
behavior I was looking for. I run the web page a few times, noted my working set going
up and never coming back down. Next, I used &lt;b&gt;ADPLUS.VBS&lt;/b&gt; to take a hang dump
of the process. I then loaded this dump up into WinDBG and started poking around.
First, I looked at the heap and sure enough I saw a bunch of page objects: 
&lt;br /&gt;
&lt;!-- code formatted by http://manoli.net/csharpformat/ --&gt;
&lt;style type="text/css"&gt;
.csharpcode, .csharpcode pre
{
	font-size: medium;
	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 class="csharpcode"&gt;
0:000&gt; .load sos
0:000&gt; !DumpHeap -stat
total 36955 objects
Statistics:
      MT    Count    TotalSize Class Name
7b4ecd7c        1           12 System.Windows.Forms.ButtonInternal.ButtonPopupAdapter
7b481f00        1           12 System.Windows.Forms.LinkLabel+LinkComparer
7b475ca8        1           12 System.Windows.Forms.FormCollection
7b474f8c        1           12 System.Windows.Forms.Layout.DefaultLayout
7b4749e0        1           12 System.Windows.Forms.ClientUtils+WeakRefCollection
7b473ca8        1           12 System.Windows.Forms.Layout.ArrangedElementCollection
7a755834        1           12 System.Diagnostics.PerformanceCounterCategoryType
7a753394        1           12 System.Diagnostics.TraceOptions
7a71a710        1           12 System.Net.TimeoutValidator
.......
00166030      891       169744      Free
054d24d4     3128       187680 System.Web.UI.LiteralControl
&lt;b&gt;0548cbd4
519 197220 ASP.default_aspx &lt;/b&gt;791242ec 1545 297960 System.Collections.Hashtable+bucket[]
79124670 1185 1090500 System.Char[] 79124228 11961 1279380 System.Object[] 790fa3e0
19149 1561392 System.String Total 110069 objects &lt;/pre&gt;
So, next I used &lt;b&gt;DumpHeap&lt;/b&gt; to just look at this specific type by giving it a
metadata token: &lt;pre class="csharpcode"&gt;
0:000&gt; !DumpHeap -mt 0548cbd4        
 Address       MT     Size
.....     
01854ff0 0548cbd4      380     
01860130 0548cbd4      380     
0186b2b4 0548cbd4      380     
018773f8 0548cbd4      380     
01882538 0548cbd4      380     
0188d6bc 0548cbd4      380     
01898840 0548cbd4      380     
018a39c4 0548cbd4      380     
018aeb48 0548cbd4      380     
total 519 objects
Statistics:
      MT    Count    TotalSize Class Name
0548cbd4      519       197220 ASP.default_aspx
Total 519 objects
&lt;/pre&gt;
I then used the &lt;i&gt;very&lt;/i&gt; cool &lt;b&gt;GCRoot&lt;/b&gt; command to determine why a page instance
was still rooted and therefore not collectable. 
&lt;br /&gt;
&lt;br /&gt;
&lt;div style="border:thin solid;border-color:black;background-color:lightgrey;padding-top:10px;padding-left:10px;padding-right:10px;padding-bottom:10px;"&gt;
&lt;b&gt;Note: &lt;/b&gt;it appears that GCRoot doesn't work well inside VS.NET 2005 - apparently
the SOS debugging extension is using some debugger API which isn't fully supported
in VS.NET, so you need to familiarize yourself with WinDBG to do this. 
&lt;/div&gt;
 /&gt;
&lt;br /&gt;
&lt;pre class="csharpcode"&gt;
0:000&gt; !gcroot 018aeb48 
Note: Roots found on stacks may be false positives. Run "!help gcroot" for
more info.
Scan Thread 0 OSTHread 3a8
Scan Thread 2 OSTHread e8
Scan Thread 3 OSTHread 1a8
Scan Thread 6 OSTHread 7d4
Scan Thread 7 OSTHread 2b4
Scan Thread 8 OSTHread fdc
Scan Thread 9 OSTHread eac
DOMAIN(001E5E08):HANDLE(Pinned):12312f0:Root:0226c498(System.Object[])-&gt;
018af940(System.EventHandler)-&gt;
0186c0ac(System.Object[])-&gt;
018af920(System.EventHandler)-&gt;
018aeb48(ASP.default_aspx)
&lt;/pre&gt;
With this output, I can tell that my default_aspx object is being kept alive through
an EventHandler as I expected. The interesting thing about this output is I cannot
tell which event handler is keeping it alive - i.e. there is nothing in this root
list that points to a specific object holding it other than a object[]. That essentially
means this is a static event and there isn't an actual object around on the heap for
it. This just makes the debugging exercise more interesting - after all if it were
an instance event then I would see the class name at the top of the root list and
we could stop right here. 
&lt;br /&gt;
&lt;br /&gt;
So, my next step is to dump the event handler to try to identify what method it is
wrapping - I could then search the code for this method and find out where it is being
bound. I dump out the &lt;b&gt;EventHandler&lt;/b&gt; object: &lt;pre class="csharpcode"&gt;
0:000&gt; !do 018af920
Name: System.EventHandler
MethodTable: 7910d61c
EEClass: 790c3a7c
Size: 32(0x20) bytes
 (C:\WINDOWS\assembly\GAC_32\mscorlib\2.0.0.0__b77a5c561934e089\mscorlib.dll)
Fields:
      MT    Field   Offset                 Type VT     Attr    Value Name
790f9c18  40000f9        4        System.Object  0 instance 018aeb48 _target
79109208  40000fa        8 ...ection.MethodBase  0 instance 00000000 _methodBase
790fe160  40000fb        c        System.IntPtr  0 instance 88962888 _methodPtr
790fe160  40000fc       10        System.IntPtr  0 instance        0 _methodPtrAux
790f9c18  4000106       14        System.Object  0 instance 00000000 _invocationList
790fe160  4000107       18        System.IntPtr  0 instance        0 _invocationCount
&lt;/pre&gt;
From this I get the internals of the EventHandler object. It gives me some specific
information: 
&lt;ul&gt;
&lt;li&gt;
&lt;b&gt;_target&lt;/b&gt; is the object the delegate is holding onto - my default_aspx in this
case. The value &lt;i&gt;better&lt;/i&gt; match up with my original object! 
&lt;li&gt;
&lt;b&gt;_methodBase&lt;/b&gt; is used for dynamic code and is null here. 
&lt;li&gt;
&lt;b&gt;_methodPtr&lt;/b&gt; is the method associated with the instance, or possibly a dynamically
generated thunk for static methods. This is what I'm interested in. 
&lt;li&gt;
&lt;b&gt;_methodPtrAux&lt;/b&gt; is used for static methods; this holds the method descriptor
and the &lt;b&gt;_methodPtr&lt;/b&gt; is a dynamically generated block of code to remove the &lt;b&gt;this&lt;/b&gt; reference.
Noting that this is null, I can infer that this is an instance method bound to the
delegate. 
&lt;li&gt;
&lt;b&gt;_invocationList&lt;/b&gt; and &lt;b&gt;_invocationCount&lt;/b&gt; are used for Multicast Delegates
-- these are both zero indicating that this is a single delegate and there is no chain
to follow. 
&lt;/ul&gt;
&lt;br /&gt;
My next step is to try to get a valid method name from the &lt;b&gt;_methodPtr&lt;/b&gt; so I
convert that to hex and pass it into IP2MD. &lt;pre class="csharpcode"&gt;
0:000&gt; !ip2md 0n88962888 
Failed to request MethodData, not in JIT code range
&lt;/pre&gt;
This is a pretty common error and simply means that the method may not have been JITted
yet, or may be a dynamic block of code which never went through the JIT compiler.
In .NET 1.1 we could start dumping method descriptors and trying to match up the address
(DumpClass -md) for this class and it's base class. 
&lt;br /&gt;
&lt;br /&gt;
However, under .NET 2.0 this rarely works anymore - the address doesn't appear to
ever match up to a valid descriptor. However, it clearly is part of the managed heap
due to it's address. So, failing to locate this address, I tried disassembling the
code: &lt;pre class="csharpcode"&gt;
0:000&gt; !u 0n88962888 
Unmanaged code
054d7748 e862289b74      call    mscorwks!LogHelp_TerminateOnAssert+0x3f5f (79e89faf)
054d774d 5e              pop     esi
054d774e cc              int     3
054d774f cc              int     3
054d7750 38c8            cmp     al,cl
054d7752 48              dec     eax
054d7753 05a0774d05      add     eax,54D77A0h
054d7758 0100            add     dword ptr [eax],eax
054d775a 0011            add     byte ptr [ecx],dl
054d775c 0000            add     byte ptr [eax],al
&lt;/pre&gt;
Humph. This doesn't even look like valid code to me.. this looks like random data,
so I dumped it out: &lt;pre class="csharpcode"&gt;
0:000&gt; dd 0n88962888 
054d7748  9b2862e8 cccc5e74&lt;b&gt; 0548c838
054d77a0&lt;/b&gt; 054d7758 11000001 90000000 054d77a0 11000002 054d7768 90000004 00000000
054d77a0 00000000 &lt;/pre&gt;
The third and fourth DWORD look interesting because they appear to fall in the managed
heap as well -- so I began to dump them out trying to figure out what they were. I
found that the first value is a method descriptor: &lt;pre class="csharpcode"&gt;
0:000&gt; !dumpmd 0548c838 
Method Name: _Default.OnDatabaseHasChanged(System.Object, System.EventArgs)
Class: 054ab574
MethodTable: 0548c86c
mdToken: 06000004
Module: 0548c35c
IsJitted: no
m_CodeOrIL: ffffffff
&lt;/pre&gt;
It is the real method bound to the delegate instance. The other DWORD appears to be
an metadata reference to the event owner itself: &lt;pre class="csharpcode"&gt;
0:000&gt; !dumpmt 054d77a0
EEClass: 0551940c
Module: 048ac9ec
Name: DatabaseMonitor
mdToken: 02000002  (C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\Temporary ASP.NET Files\leakypage\2a399ab5\b1e04c63\App_Code.onwg1zqj.dll)
BaseSize: 0xc
ComponentSize: 0x0
Number of IFaces in IFaceMap: 0
Slots in VTable: 8
&lt;/pre&gt;
From here I can see the module that this code is defined in (the dynamically generated
App_Code directory) and the name (&lt;b&gt;DatabaseMonitor&lt;/b&gt;). This gives me enough information
to stop here and begin looking at the code itself - specifically where default.aspx
binds it's OnDatabaseHasChanged method to the DatabaseMonitor static class defined
somewhere in the App_Code directory. If I didn't have the source code available, I
could locate the module and then save it out to a file through the &lt;b&gt;savemodule&lt;/b&gt; command: &lt;pre class="csharpcode"&gt;
0:000&gt; lm m App_Code_onwg1zqj
start    end        module name
04de0000 04de8000   App_Code_onwg1zqj C (no symbols)           
0:000&gt; !savemodule 04de0000 c:\appcode.dll
3 sections in file
section 0 - VA=2000, VASize=504, FileAddr=200, FileSize=600
section 1 - VA=4000, VASize=2c8, FileAddr=800, FileSize=400
section 2 - VA=6000, VASize=c, FileAddr=c00, FileSize=200
&lt;/pre&gt;
I could then ILDasm or Reflector the generated assembly and look for my bug from that. 
&lt;br /&gt;
&lt;br /&gt;
I love SOS and WinDBG.. if only they could match up managed source code to the image I'd abandon VS.NET as a debugger altogether..
</description>
      <comments>http://www.julmar.com/blog/mark/CommentView,guid,643649fc-0467-4f0d-9a95-323ed7ce4298.aspx</comments>
      <category>.NET</category>
      <category>Code</category>
      <category>Debugging</category>
    </item>
    <item>
      <trackback:ping>http://www.julmar.com/blog/mark/Trackback.aspx?guid=3a275fbf-e292-4017-a783-5b40dc1f0ec7</trackback:ping>
      <pingback:server>http://www.julmar.com/blog/mark/pingback.aspx</pingback:server>
      <pingback:target>http://www.julmar.com/blog/mark/PermaLink,guid,3a275fbf-e292-4017-a783-5b40dc1f0ec7.aspx</pingback:target>
      <dc:creator>Mark</dc:creator>
      <wfw:comment>http://www.julmar.com/blog/mark/CommentView,guid,3a275fbf-e292-4017-a783-5b40dc1f0ec7.aspx</wfw:comment>
      <wfw:commentRss>http://www.julmar.com/blog/mark/SyndicationService.asmx/GetEntryCommentsRss?guid=3a275fbf-e292-4017-a783-5b40dc1f0ec7</wfw:commentRss>
      <body xmlns="http://www.w3.org/1999/xhtml">
        <p>
So, a question was asked "How do I determine what's happening in the TAPI3 wrapper"? 
The answer is you turn on the internal trace source -- ITapi3 was built with a build
in tracing facility to tell you when it had any underlying interface or COM failures
and it's easy to activate.  First, add an <strong>Application Configuration File</strong> to
your project.  Open that file and add the following lines:
</p>
        <font size="2">
          <span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent">
            <font color="#0000ff" size="2">
              <p>
&lt;?
</p>
            </font>
            <font color="#800000" size="2">xml</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">version</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">1.0</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">encoding</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">utf-8</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2"> ?&gt;<br />
&lt;</font>
            <font color="#800000" size="2">configuration</font>
            <font color="#0000ff" size="2">&gt;<br />
   &lt;</font>
            <font color="#800000" size="2">system.diagnostics</font>
            <font color="#0000ff" size="2">&gt;<br />
      &lt;</font>
            <font color="#800000" size="2">sources</font>
            <font color="#0000ff" size="2">&gt;<br />
         &lt;</font>
            <font color="#800000" size="2">source</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">name</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">ITapiTrace</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">switchName</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">tapiSwitch</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">switchType</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">System.Diagnostics.SourceSwitch</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">&gt;<br />
            &lt;</font>
            <font color="#800000" size="2">listeners</font>
            <font color="#0000ff" size="2">&gt;<br />
               </font>
            <font color="#0000ff" size="2">&lt;</font>
            <font color="#800000" size="2">add</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">name</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">MyTraceLog</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">type</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">System.Diagnostics.TextWriterTraceListener</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">initializeData</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">MyTrace.txt</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2"> /&gt;<br />
            &lt;/</font>
            <font color="#800000" size="2">listeners</font>
            <font color="#0000ff" size="2">&gt;<br />
         &lt;/</font>
            <font color="#800000" size="2">source</font>
            <font color="#0000ff" size="2">&gt;<br />
      &lt;/</font>
            <font color="#800000" size="2">sources</font>
            <font color="#0000ff" size="2">&gt;<br />
      &lt;</font>
            <font color="#800000" size="2">switches</font>
            <font color="#0000ff" size="2">&gt;<br />
         &lt;</font>
            <font color="#800000" size="2">add</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">name</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">tapiSwitch</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">
            </font>
            <font color="#ff0000" size="2">value</font>
            <font color="#0000ff" size="2">=</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2">All</font>
            <font size="2">"</font>
            <font color="#0000ff" size="2"> /&gt;<br />
      &lt;/</font>
            <font color="#800000" size="2">switches</font>
            <font color="#0000ff" size="2">&gt;<br />
   &lt;/</font>
            <font color="#800000" size="2">system.diagnostics</font>
            <font color="#0000ff" size="2">&gt;<br />
&lt;/</font>
            <font color="#800000" size="2">configuration</font>
            <font color="#0000ff" size="2">&gt;</font>
            <p>
              <font face="Verdana" color="#000000" size="2">This will create a file called "MyTrace.txt"
in your working directory.  The important line is the <strong>source</strong> tag
which identifies the internal <strong>TraceSource</strong> object used by the ITapi3
library.  Inside this file will be the internal TAPI3 calls being made for your
application.  As an example, the following trace shows me that several underlying
COM errors occurred in the running of a simple TAPI3 application -- it was unable
to retrieve the ITTerminal interface from the <strong>ITAddressEvent</strong> interface
(which actually isn't really an error), failed to open the line (because Unimodem
won't allow the media type VOICE to be passed for my modem), and failed to set the
play list for this MSP -- [<font face="Courier New">0x80040216</font><font face="Verdana">]
is actually a DirectShow error [VFW_E_NOT_FOUND].</font></font>
            </p>
            <p>
ITapiTrace Verbose: 0 : Creating ITTAPI instance<br />
ITapiTrace Verbose: 0 : Hooking up connection sink to ITTAPI interface<br />
ITapiTrace Information: 0 : ITTapi::put_EventFilter(0x8001F) hr=0x0<br />
ITapiTrace Error: 0 : COM Hresult 0x80040004 "The MEDIATYPE passed in to this method
was invalid." generated <br />
   at JulMar.Tapi3.TapiException.ThrowExceptionForHR(Int32 hr)<br />
   at JulMar.Tapi3.TTapi.RegisterCallNotifications(ITAddress* pitf, Int16
vbMonitor, Int16 vbOwner, Int32 supportedMediaTypes)<br />
   at JulMar.Tapi3.TAddress.Open(TAPIMEDIATYPES supportedMediaTypes)<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 5, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 4, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 3, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 2, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 1, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 0, Terminal=<br />
ITapiTrace Verbose: 0 : Processing TapiCallNotificationEventArgs: Event=CNE_OWNER,
Call=TCall: 171360625 CS_OFFERING<br />
ITapiTrace Verbose: 0 : Processing TapiCallStateEventArgs: Call=TCall: 171360625 CS_OFFERING,
State=CS_OFFERING, Cause=CEC_NONE<br />
ITapiTrace Error: 0 : COM Hresult 0x80040216 "" generated <br />
   at JulMar.Tapi3.TapiException.ThrowExceptionForHR(Int32 hr)<br />
   at JulMar.Tapi3.TTerminal.set_MediaPlayList(String[] fileList)<br />
   at AnsMachine.AutoAttendantForm.AnswerCall()<br />
   at AnsMachine.AutoAttendantForm.OnCallState(Object sender, TapiCallStateEventArgs
e)<br />
ITapiTrace Verbose: 0 : Processing TapiCallStateEventArgs: Call=TCall: 171360625 CS_DISCONNECTED,
State=CS_DISCONNECTED, Cause=CEC_DISCONNECT_NORMAL<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 5, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 4, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 3, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 2, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 1, Terminal=<br />
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055<br />
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 0, Terminal=<br />
ITapiTrace Error: 0 : ITTapi::Shutdown hr=0x0<br /></p>
            <p>
 
</p>
          </span>
        </font>
        <strong>
          <font color="#000000">
          </font>
        </strong>
      </body>
      <title>Debugging the underlying Telephony calls</title>
      <guid isPermaLink="false">http://www.julmar.com/blog/mark/PermaLink,guid,3a275fbf-e292-4017-a783-5b40dc1f0ec7.aspx</guid>
      <link>http://www.julmar.com/blog/mark/2006/03/07/DebuggingTheUnderlyingTelephonyCalls.aspx</link>
      <pubDate>Tue, 07 Mar 2006 23:18:50 GMT</pubDate>
      <description>&lt;p&gt;
So, a question was asked "How do I determine what's happening in the TAPI3 wrapper"?&amp;nbsp;
The answer is you turn on the internal trace source -- ITapi3 was built with a build
in tracing facility to tell you when it had any underlying interface or COM failures
and it's easy to activate.&amp;nbsp; First, add an &lt;strong&gt;Application Configuration File&lt;/strong&gt; to
your project.&amp;nbsp; Open that file and add the following lines:
&lt;/p&gt;
&lt;font size=2&gt;&lt;span style="FONT-SIZE: 11px; COLOR: black; FONT-FAMILY: Courier New; BACKGROUND-COLOR: transparent"&gt;&lt;font color=#0000ff size=2&gt; 
&lt;p&gt;
&amp;lt;?
&lt;/font&gt;&lt;font color=#800000 size=2&gt;xml&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;version&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;1.0&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;encoding&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;utf-8&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; ?&amp;gt;&lt;br&gt;
&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;configuration&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;system.diagnostics&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;sources&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;source&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;name&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;ITapiTrace&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;switchName&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;tapiSwitch&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;switchType&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;System.Diagnostics.SourceSwitch&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&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;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;listeners&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&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;&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;add&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;name&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;MyTraceLog&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;type&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;System.Diagnostics.TextWriterTraceListener&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;initializeData&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;MyTrace.txt&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; /&amp;gt;&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;lt;/&lt;/font&gt;&lt;font color=#800000 size=2&gt;listeners&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color=#800000 size=2&gt;source&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color=#800000 size=2&gt;sources&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;switches&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;&lt;/font&gt;&lt;font color=#800000 size=2&gt;add&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;name&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;tapiSwitch&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; &lt;/font&gt;&lt;font color=#ff0000 size=2&gt;value&lt;/font&gt;&lt;font color=#0000ff size=2&gt;=&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt;All&lt;/font&gt;&lt;font size=2&gt;"&lt;/font&gt;&lt;font color=#0000ff size=2&gt; /&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color=#800000 size=2&gt;switches&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;lt;/&lt;/font&gt;&lt;font color=#800000 size=2&gt;system.diagnostics&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;br&gt;
&amp;lt;/&lt;/font&gt;&lt;font color=#800000 size=2&gt;configuration&lt;/font&gt;&lt;font color=#0000ff size=2&gt;&amp;gt;&lt;/font&gt;&gt;
&lt;p&gt;
&lt;font face=Verdana color=#000000 size=2&gt;This will create a file called "MyTrace.txt"
in your working directory.&amp;nbsp; The important line is the &lt;strong&gt;source&lt;/strong&gt; tag
which identifies the internal &lt;strong&gt;TraceSource&lt;/strong&gt; object used by the ITapi3
library.&amp;nbsp; Inside this file will be the internal TAPI3 calls being made for your
application.&amp;nbsp; As an example, the following trace shows me that several underlying
COM errors occurred in the running of a simple TAPI3 application -- it was unable
to retrieve the ITTerminal interface from the &lt;strong&gt;ITAddressEvent&lt;/strong&gt; interface
(which actually isn't really an error), failed to open the line (because Unimodem
won't allow the media type VOICE to be passed for my modem), and failed to set the
play list for this MSP&amp;nbsp;--&amp;nbsp;[&lt;font face="Courier New"&gt;0x80040216&lt;/font&gt;&lt;font face=Verdana&gt;]
is actually a DirectShow error [VFW_E_NOT_FOUND].&lt;/font&gt;&lt;/font&gt;
&lt;/p&gt;
&lt;p&gt;
ITapiTrace Verbose: 0 : Creating ITTAPI instance&lt;br&gt;
ITapiTrace Verbose: 0 : Hooking up connection sink to ITTAPI interface&lt;br&gt;
ITapiTrace Information: 0 : ITTapi::put_EventFilter(0x8001F) hr=0x0&lt;br&gt;
ITapiTrace Error: 0 : COM Hresult 0x80040004 "The MEDIATYPE passed in to this method
was invalid." generated&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;at JulMar.Tapi3.TapiException.ThrowExceptionForHR(Int32 hr)&lt;br&gt;
&amp;nbsp;&amp;nbsp; at JulMar.Tapi3.TTapi.RegisterCallNotifications(ITAddress* pitf, Int16
vbMonitor, Int16 vbOwner, Int32 supportedMediaTypes)&lt;br&gt;
&amp;nbsp;&amp;nbsp; at JulMar.Tapi3.TAddress.Open(TAPIMEDIATYPES supportedMediaTypes)&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 5, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 4, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 3, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 2, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 1, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 0, Terminal=&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiCallNotificationEventArgs: Event=CNE_OWNER,
Call=TCall: 171360625 CS_OFFERING&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiCallStateEventArgs: Call=TCall: 171360625 CS_OFFERING,
State=CS_OFFERING, Cause=CEC_NONE&lt;br&gt;
ITapiTrace Error: 0 : COM Hresult 0x80040216 "" generated&amp;nbsp;&lt;br&gt;
&amp;nbsp;&amp;nbsp;&amp;nbsp;at JulMar.Tapi3.TapiException.ThrowExceptionForHR(Int32 hr)&lt;br&gt;
&amp;nbsp;&amp;nbsp; at JulMar.Tapi3.TTerminal.set_MediaPlayList(String[] fileList)&lt;br&gt;
&amp;nbsp;&amp;nbsp; at AnsMachine.AutoAttendantForm.AnswerCall()&lt;br&gt;
&amp;nbsp;&amp;nbsp; at AnsMachine.AutoAttendantForm.OnCallState(Object sender, TapiCallStateEventArgs
e)&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiCallStateEventArgs: Call=TCall: 171360625 CS_DISCONNECTED,
State=CS_DISCONNECTED, Cause=CEC_DISCONNECT_NORMAL&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 5, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 4, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 3, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 2, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 1, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITAddressEvent::get_Terminal failed hr=0x80040055&lt;br&gt;
ITapiTrace Verbose: 0 : Processing TapiAddressChangedEventArgs: Evt=AE_RINGING, Address=DSSP
Line #1 - Address 0, Terminal=&lt;br&gt;
ITapiTrace Error: 0 : ITTapi::Shutdown hr=0x0&lt;br&gt;
&lt;/p&gt;
&lt;p&gt;
&amp;nbsp;
&lt;/p&gt;
&lt;/span&gt;&lt;/font&gt;&lt;strong&gt;&lt;font color=#000000&gt;&lt;/font&gt;&lt;/strong&gt;</description>
      <comments>http://www.julmar.com/blog/mark/CommentView,guid,3a275fbf-e292-4017-a783-5b40dc1f0ec7.aspx</comments>
      <category>Code</category>
      <category>Tapi</category>
      <category>Debugging</category>
    </item>
  </channel>
</rss>