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

<channel>
	<title>voyce &#187; dll</title>
	<atom:link href="http://www.voyce.com/index.php/tag/dll/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.voyce.com</link>
	<description>Programming and debugging tidbits</description>
	<lastBuildDate>Sun, 15 Jan 2012 13:10:46 +0000</lastBuildDate>
	
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Quick post: Using Mono.Cecil and F# to get assembly dependencies</title>
		<link>http://www.voyce.com/index.php/2010/10/31/quick-post-using-mono-cecil-and-f-to-get-assembly-dependencies/</link>
		<comments>http://www.voyce.com/index.php/2010/10/31/quick-post-using-mono-cecil-and-f-to-get-assembly-dependencies/#comments</comments>
		<pubDate>Sun, 31 Oct 2010 13:31:43 +0000</pubDate>
		<dc:creator>ian</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[F#]]></category>
		<category><![CDATA[cecil]]></category>
		<category><![CDATA[DGML]]></category>
		<category><![CDATA[dll]]></category>
		<category><![CDATA[gac]]></category>
		<category><![CDATA[mono]]></category>

		<guid isPermaLink="false">http://www.voyce.com/?p=996</guid>
		<description><![CDATA[Using Mono.Cecil and F# to list assembly dependencies.]]></description>
			<content:encoded><![CDATA[<p>One of the tools I use a lot when doing C++ development and debugging is <a href="http://www.dependencywalker.com/">&#8220;dependency walker&#8221;</a>; an app that displays all the static dependencies of an executable. These are dependencies created by referencing functions from an import library (.lib file) at compile time. If any of the imported DLLs are missing at run-time, the executable will fail to load, normally with error 2: file not found. Obviously pretty disastrous in production. The .NET equivalent is the binding failure. You can track down what went wrong at runtime using fuslogvw, but I&#8217;ve often wished for a tool like &#8216;depends&#8217; to work out up-front what dependencies are required. Luckily because assemblies includes a list of dependent libraries in the form of a manifest this information can be accessed using reflection.</p>
<p><img src="http://www.voyce.com/wp-content/uploads/2010/10/Mono-gorilla-aqua.100px.png" alt="Mono-gorilla-aqua.100px" title="Mono-gorilla-aqua.100px" width="100" height="120" class="alignleft size-full wp-image-1095" />I&#8217;m a big fan of the <a href="http://www.mono-project.com/Cecil">Mono.Cecil</a> library for doing reflection (and more!) with .NET. I&#8217;ve had issues in the past where the built-in .NET reflection (using Assembly.ReflectionOnlyLoad) attempts to load dependent libraries as you iterate over exposed types, even though it&#8217;s not supposed to (unfortunately I don&#8217;t have a repro to hand). This makes it very difficult to work on an assembly without having all of its dependencies available. Cecil doesn&#8217;t have this problem because it accesses the assembly in a lower-level way.<br />
<span id="more-996"></span><br />
I downloaded and installed <a href="http://www.go-mono.com/mono-downloads/download.html">Mono</a> (the latest version is 2.8) and referenced it from the installed Mono GAC location. Then it was just a matter of a handful of lines of F# (after a bit of spelunking through the Cecil API to find the methods relating to assembly references).</p>

<div class="wp_syntax"><div class="code"><pre class="fsharp" style="font-family:monospace;"><span style="color: #066; font-weight: bold;">#r @&quot;C:\Program Files (x86)\Mono-2.8\lib\mono\gac\Mono.Cecil\0.6.9.0__0738eb9f132ed756\Mono.Cecil.dll&quot;</span>
<span style="color: #066; font-weight: bold;">#r @&quot;gachelper.dll&quot;</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">open</span> System
<span style="color: #06c; font-weight: bold;">open</span> System<span style="color: #000080;">.</span><span style="color: #505090;">IO</span>
<span style="color: #06c; font-weight: bold;">open</span> Mono<span style="color: #000080;">.</span><span style="color: #505090;">Cecil</span>
&nbsp;
<span style="color: #06c; font-weight: bold;">let</span> getReferencedAssemblies <span style="color: #000080;">&#40;</span>asm <span style="color: #000080;">:</span> string<span style="color: #000080;">&#41;</span> <span style="color: #000080;">:</span> string list <span style="color: #000080;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> ad <span style="color: #000080;">=</span> AssemblyFactory<span style="color: #000080;">.</span><span style="color: #505090;">GetAssembly</span> asm
    <span style="color: #06c; font-weight: bold;">let</span> refs <span style="color: #000080;">=</span> ad<span style="color: #000080;">.</span><span style="color: #505090;">MainModule</span><span style="color: #000080;">.</span><span style="color: #505090;">AssemblyReferences</span>
    refs 
    <span style="color: #000080;">|&gt;</span> Seq<span style="color: #000080;">.</span><span style="color: #505090;">cast</span> 
    <span style="color: #000080;">|&gt;</span> Seq<span style="color: #000080;">.</span><span style="color: #505090;">fold</span> <span style="color: #000080;">&#40;</span><span style="color: #06c; font-weight: bold;">fun</span> found <span style="color: #000080;">&#40;</span>r <span style="color: #000080;">:</span> AssemblyNameReference<span style="color: #000080;">&#41;</span> <span style="color: #000080;">-&gt;</span> 
        <span style="color: #06c; font-weight: bold;">let</span> fullPath <span style="color: #000080;">=</span> ref <span style="color: #008080;">&quot;&quot;</span>
        <span style="color: #06c; font-weight: bold;">match</span> gachelper<span style="color: #000080;">.</span><span style="color: #505090;">GAC</span><span style="color: #000080;">.</span><span style="color: #505090;">TryGetFullPath</span> <span style="color: #000080;">&#40;</span>r<span style="color: #000080;">.</span><span style="color: #505090;">Name</span>, fullPath<span style="color: #000080;">&#41;</span> <span style="color: #06c; font-weight: bold;">with</span>
        <span style="color: #000080;">|</span> <span style="color: #06c; font-weight: bold;">false</span> <span style="color: #000080;">-&gt;</span> found @ <span style="color: #000080;">&#91;</span> Path<span style="color: #000080;">.</span><span style="color: #505090;">Combine</span> <span style="color: #000080;">&#91;</span><span style="color: #000080;">|</span><span style="color: #000080;">&#40;</span>System<span style="color: #000080;">.</span><span style="color: #505090;">IO</span><span style="color: #000080;">.</span><span style="color: #505090;">Path</span><span style="color: #000080;">.</span><span style="color: #505090;">GetDirectoryName</span> asm<span style="color: #000080;">&#41;</span><span style="color: #000080;">;</span> r<span style="color: #000080;">.</span><span style="color: #505090;">Name</span> <span style="color: #000080;">+</span> <span style="color: #008080;">&quot;.dll&quot;</span><span style="color: #000080;">|</span><span style="color: #000080;">&#93;</span> <span style="color: #000080;">&#93;</span>
        <span style="color: #000080;">|</span> <span style="color: #06c; font-weight: bold;">true</span> <span style="color: #000080;">-&gt;</span> found @ <span style="color: #000080;">&#91;</span><span style="color: #000080;">!</span>fullPath<span style="color: #000080;">&#93;</span>        
        <span style="color: #000080;">&#41;</span> <span style="color: #000080;">&#91;</span><span style="color: #000080;">&#93;</span></pre></div></div>

<p>As you can see I&#8217;ve also used a little C++/CLI wrapper around the GAC to get access to full paths of installed assemblies (which only works with the Microsoft CLR), but I&#8217;ll talk about that in a separate post, or you can grab the code <a href="http://github.com/voyce/gachelper">here</a>.</p>
<p>Now, we can call our function to get the set of dependencies, e.g. by using F# interactive, we also happen to be getting the dependencies *of* FSI:</p>

<div class="wp_syntax"><div class="code"><pre class="fsharp" style="font-family:monospace;"><span style="color: #000080;">&gt;</span> getReferencedAssemblies <span style="">@&quot;C:\Program Files (x86)\FSharp-2.0.0.0\bin\fsi.exe&quot;</span><span style="color: #000080;">;;</span>
<span style="color: #06c; font-weight: bold;">val</span> it <span style="color: #000080;">:</span> string list <span style="color: #000080;">=</span>
  <span style="color: #000080;">&#91;</span><span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_32<span style="color: #008080; font-weight: bold;">\m</span>scorlib<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b77a5c561934e089<span style="color: #008080; font-weight: bold;">\m</span>scorlib.dll&quot;</span><span style="color: #000080;">;</span>
   <span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_MSIL<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Core<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b03f5f7f11d50a3a<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Core.dll&quot;</span><span style="color: #000080;">;</span>
   <span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_MSIL<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Compiler<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b03f5f7f11d50a3a<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Compiler.dll&quot;</span><span style="color: #000080;">;</span>
   <span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_MSIL<span style="color: #008080; font-weight: bold;">\S</span>ystem.Windows.Forms<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b77a5c561934e089<span style="color: #008080; font-weight: bold;">\S</span>ystem.Windows.Forms.dll&quot;</span><span style="color: #000080;">;</span>
   <span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_MSIL<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Compiler.Interactive.Settings<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b03f5f7f11d50a3a<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Compiler.Interactive.Settings.dll&quot;</span><span style="color: #000080;">;</span>
   <span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_MSIL<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Compiler.Server.Shared<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b03f5f7f11d50a3a<span style="color: #008080; font-weight: bold;">\F</span>Sharp.Compiler.Server.Shared.dll&quot;</span><span style="color: #000080;">;</span>
   <span style="color: #008080;">&quot;C:<span style="color: #008080; font-weight: bold;">\W</span>indows<span style="color: #008080; font-weight: bold;">\M</span>icrosoft.Net<span style="color: #008080; font-weight: bold;">\a</span>ssembly<span style="color: #008080; font-weight: bold;">\G</span>AC_MSIL<span style="color: #008080; font-weight: bold;">\S</span>ystem<span style="color: #008080; font-weight: bold;">\v</span>4.0_4.0.0.0__b77a5c561934e089<span style="color: #008080; font-weight: bold;">\S</span>ystem.dll&quot;</span><span style="color: #000080;">&#93;</span></pre></div></div>

<p>This is, of course, the tip of the iceberg in terms of Cecil functionality; there are lots of far more interesting things you can do &#8211; like IL extraction and re-writing &#8211; things which are impossible to do with the Microsoft reflection API.</p>
<p>I ended up using this code to generate DGML graphs that can be opened and explored using VS2010. This functionality comes &#8220;in the box&#8221; with VS2010 Architecture Explorer in the Ultimate Edition &#8211; but who can afford that&#8230;? We can do much the same ourselves by just using the information we get from Cecil and spitting out DGML directly. The files can be opened read-only in the Premium edition for perusal.</p>
<p>For the curious, here&#8217;s the (somewhat fugly and imperative) F# code to generate the DGML file. It creates a minimal file that only contains <code>Link</code> elements; Visual Studio will &#8220;fill in the blanks&#8221; by adding the nodes themselves when you open the file.</p>

<div class="wp_syntax"><div class="code"><pre class="fsharp" style="font-family:monospace;"><span style="color: #06c; font-weight: bold;">let</span> genDgml asm <span style="color: #000080;">&#40;</span>out <span style="color: #000080;">:</span> string<span style="color: #000080;">&#41;</span> <span style="color: #000080;">=</span>
    <span style="color: #06c; font-weight: bold;">let</span> doc <span style="color: #000080;">=</span> XmlDocument<span style="color: #000080;">&#40;</span><span style="color: #000080;">&#41;</span>
    <span style="color: #06c; font-weight: bold;">let</span> nsURI <span style="color: #000080;">=</span> <span style="color: #008080;">&quot;http://schemas.microsoft.com/vs/2009/dgml&quot;</span>
    <span style="color: #06c; font-weight: bold;">let</span> nsmgr <span style="color: #000080;">=</span> XmlNamespaceManager<span style="color: #000080;">&#40;</span>doc<span style="color: #000080;">.</span><span style="color: #505090;">NameTable</span><span style="color: #000080;">&#41;</span>
    nsmgr<span style="color: #000080;">.</span><span style="color: #505090;">AddNamespace</span><span style="color: #000080;">&#40;</span><span style="color: #008080;">&quot;&quot;</span>, nsURI<span style="color: #000080;">&#41;</span>
    <span style="color: #06c; font-weight: bold;">let</span> root <span style="color: #000080;">=</span> doc<span style="color: #000080;">.</span><span style="color: #505090;">CreateElement</span><span style="color: #000080;">&#40;</span><span style="color: #008080;">&quot;DirectedGraph&quot;</span>, nsURI<span style="color: #000080;">&#41;</span>
    <span style="color: #06c; font-weight: bold;">let</span> links <span style="color: #000080;">=</span> doc<span style="color: #000080;">.</span><span style="color: #505090;">CreateElement</span><span style="color: #000080;">&#40;</span><span style="color: #008080;">&quot;Links&quot;</span>, nsURI<span style="color: #000080;">&#41;</span>
    <span style="color: #06c; font-weight: bold;">let</span> <span style="color: #06c; font-weight: bold;">rec</span> genRefs added asm <span style="color: #000080;">=</span>
        getReferencedAssemblies asm
        <span style="color: #000080;">|&gt;</span> List<span style="color: #000080;">.</span><span style="color: #505090;">fold</span> <span style="color: #000080;">&#40;</span><span style="color: #06c; font-weight: bold;">fun</span> added dep <span style="color: #000080;">-&gt;</span> 
            <span style="color: #06c; font-weight: bold;">let</span> link <span style="color: #000080;">=</span> doc<span style="color: #000080;">.</span><span style="color: #505090;">CreateElement</span><span style="color: #000080;">&#40;</span><span style="color: #008080;">&quot;Link&quot;</span>, nsURI<span style="color: #000080;">&#41;</span>
            link<span style="color: #000080;">.</span><span style="color: #505090;">SetAttribute</span><span style="color: #000080;">&#40;</span><span style="color: #008080;">&quot;Source&quot;</span>, Path<span style="color: #000080;">.</span><span style="color: #505090;">GetFileNameWithoutExtension</span> asm<span style="color: #000080;">&#41;</span>
            link<span style="color: #000080;">.</span><span style="color: #505090;">SetAttribute</span><span style="color: #000080;">&#40;</span><span style="color: #008080;">&quot;Target&quot;</span>, Path<span style="color: #000080;">.</span><span style="color: #505090;">GetFileNameWithoutExtension</span> dep<span style="color: #000080;">&#41;</span>
            ignore <span style="color: #000080;">&lt;|</span> links<span style="color: #000080;">.</span><span style="color: #505090;">AppendChild</span> link
            <span style="color: #06c; font-weight: bold;">if</span> not <span style="color: #000080;">&lt;|</span> <span style="color: #000080;">&#40;</span>added <span style="color: #000080;">|&gt;</span> Map<span style="color: #000080;">.</span><span style="color: #505090;">containsKey</span> dep<span style="color: #000080;">&#41;</span>
            <span style="color: #06c; font-weight: bold;">then</span> genRefs <span style="color: #000080;">&#40;</span>added<span style="color: #000080;">.</span><span style="color: #505090;">Add</span> <span style="color: #000080;">&#40;</span>dep, <span style="color: #06c; font-weight: bold;">false</span><span style="color: #000080;">&#41;</span><span style="color: #000080;">&#41;</span> dep
            <span style="color: #06c; font-weight: bold;">else</span> added
        <span style="color: #000080;">&#41;</span> added
    ignore <span style="color: #000080;">&lt;|</span> genRefs Map<span style="color: #000080;">.</span><span style="color: #505090;">empty</span> asm
    ignore <span style="color: #000080;">&lt;|</span> root<span style="color: #000080;">.</span><span style="color: #505090;">AppendChild</span> links
    ignore <span style="color: #000080;">&lt;|</span> doc<span style="color: #000080;">.</span><span style="color: #505090;">AppendChild</span> root
    doc<span style="color: #000080;">.</span><span style="color: #505090;">Save</span> out</pre></div></div>

<p><div id="attachment_1101" class="wp-caption alignright" style="width: 310px"><a href="http://www.voyce.com/wp-content/uploads/2010/10/dgml.png"><img src="http://www.voyce.com/wp-content/uploads/2010/10/dgml-300x158.png" alt="The DGML in cluster view" title="dgml" width="300" height="158" class="size-medium wp-image-1101" /></a><p class="wp-caption-text">The DGML in cluster view</p></div>If you run it against the FSI.exe as we did before it will chug away for a while and then generate this file, which contains all of the dependencies.</p>
<p>It can be quite enlightening, as well as useful, to see your app dependencies laid-bare before you&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.voyce.com/index.php/2010/10/31/quick-post-using-mono-cecil-and-f-to-get-assembly-dependencies/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Don&#8217;t do anything in DllMain&#8230; Please</title>
		<link>http://www.voyce.com/index.php/2009/12/03/dont-do-anything-in-dllmain-please/</link>
		<comments>http://www.voyce.com/index.php/2009/12/03/dont-do-anything-in-dllmain-please/#comments</comments>
		<pubDate>Thu, 03 Dec 2009 23:27:13 +0000</pubDate>
		<dc:creator>ian</dc:creator>
				<category><![CDATA[Debugging]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[COM]]></category>
		<category><![CDATA[dll]]></category>
		<category><![CDATA[win32]]></category>

		<guid isPermaLink="false">http://www.voyce.com/?p=554</guid>
		<description><![CDATA[Thinking of adding some code to your DLLs DllMain function? STOP!]]></description>
			<content:encoded><![CDATA[<p>Novice Windows programmers can often think that <code>DllMain</code> is a good place to get that one-time set-up and tear-down work done. It seems to offer an ideal opportunity to know when your DLL has just been loaded, and when it&#8217;s about to be unloaded. What better place to add all that expensive, complicated initialisation&#8230;? STOP! WAIT! Before you add anything in <code>DllMain</code>, make sure you understand what state the process will be in when it gets called. Once you know that, you may well change your mind&#8230;<br />
<span id="more-554"></span><br />
Firstly, take a look at <a href="http://www.microsoft.com/whdc/driver/kernel/DLL_bestprac.mspx">this page</a>. It does a pretty good job of ramming home the point that there&#8217;s very little that it&#8217;s safe to do in <code>DllMain</code>. Essentially this is because while the function&#8217;s being called, the OS is holding a process-wide lock that isn&#8217;t re-entrant. As such, if you do anything that causes a DLL to be loaded, a deadlock may occur. There are many, many things that may have a side-effect of loading a DLL; calling COM functions, creating threads etc.</p>
<p>This is such a common source of bugs, and such an important requirement, that from Vista onwards Microsoft introduced a new set of functions in the Windows API explicitly to support it: <a href="http://msdn.microsoft.com/en-us/library/aa363808(VS.85).aspx">One-Time Initialization</a>.</p>
<p>And even if you get away with doing naughty things in <code>DllMain</code> now, don&#8217;t think that it&#8217;ll stay that way forever. We got away with it for years, then when .NET came along it introduced all sorts of additional correctness checks. For instance, the Managed Debugging Assistant (MDA) in Visual Studio will shout loudly should you attempt to run managed code during <code>DllMain</code>.<br />
<code><br />
Managed Debugging Assistant 'LoaderLock' has detected a problem in 'C:\YourApp.vshost.exe'.<br />
Additional Information: Attempting managed execution inside OS Loader lock. Do not attempt to run managed code inside a DllMain or image initialization function since doing so can cause the application to hang.<br />
</code><br />
And it&#8217;s easier than you think to do so. For example, calling something as innocuous as <code>GetWindowText</code> can result in managed code being run. </p>
<p>How can you get around this?</p>
<p>One of the approaches I&#8217;ve used has been to make use of Win32 asynchronous procedure calls. Specifically you can call <a href="http://msdn.microsoft.com/en-us/library/ms684954(VS.85).aspx">QueueUserAPC</a> to add a function to the queue, and this can contain the initialisation you would&#8217;ve otherwise done in <code>DllMain</code>. </p>
<p>However there is significant gotcha regarding use of APCs: your function will not be called until the thread is in an &#8220;alertable wait state&#8221;. This means you (or some other code on the thread) need to call an alertable wait function such as <a href="http://msdn.microsoft.com/en-us/library/ms686307(VS.85).aspx"><code>SleepEx</code></a>, <a href="http://msdn.microsoft.com/en-us/library/ms687036(VS.85).aspx"><code>WaitForSingleObjectEx</code></a> and specify TRUE for the alertable parameter. </p>
<p>Once your APC is getting called successfully you&#8217;ll be in much better place; your code will be executed outside of the scope of the dreaded OS loader lock and you&#8217;ll be doing things by the book, hopefully avoiding all the potential pitfalls that lie in wait within <code>DllMain</code>. </p>
]]></content:encoded>
			<wfw:commentRss>http://www.voyce.com/index.php/2009/12/03/dont-do-anything-in-dllmain-please/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Troubleshooting an InvalidProgramException</title>
		<link>http://www.voyce.com/index.php/2008/10/01/troubleshooting-an-invalidprogramexception/</link>
		<comments>http://www.voyce.com/index.php/2008/10/01/troubleshooting-an-invalidprogramexception/#comments</comments>
		<pubDate>Wed, 01 Oct 2008 18:58:53 +0000</pubDate>
		<dc:creator>ian</dc:creator>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[WinDbg]]></category>
		<category><![CDATA[Windows]]></category>
		<category><![CDATA[.local]]></category>
		<category><![CDATA[dll]]></category>
		<category><![CDATA[gac]]></category>
		<category><![CDATA[InvalidProgramException]]></category>
		<category><![CDATA[mscoree]]></category>
		<category><![CDATA[mscorjit]]></category>
		<category><![CDATA[mscorwks]]></category>

		<guid isPermaLink="false">http://www.voyce.com/?p=45</guid>
		<description><![CDATA[One of the developers who uses the .NET/COM interop DLL that I wrote recently informed me that when they used it in a certain way, they would get a fatal System.InvalidProgramException. Nasty. So I set about seeing how I could find out exactly why this was happening: here are the gory details&#8230;
To spoil the ending [...]]]></description>
			<content:encoded><![CDATA[<p>One of the developers who uses the .NET/COM interop DLL that I wrote recently informed me that when they used it in a certain way, they would get a fatal System.InvalidProgramException. Nasty. So I set about seeing how I could find out exactly why this was happening: here are the gory details&#8230;</p>
<p>To spoil the ending somewhat, we already knew the precise situation that was causing the problem. This is different to the average issue, where most of the time&#8217;s spent in isolating the conditions that cause it. In this case we had an excellent positive and negative repro case.</p>
<p>The users were attempting to use the legacy .local approach to changing DLL probing. This was originally implemented around the time of Windows 2000, before the current side-by-side system existed, and basically short-circuited the normal DLL search order to inject the current directory as the first potential location. See the <a href="http://msdn.microsoft.com/en-us/library/ms682600%28VS.85%29.aspx">DLL redirection</a> MSDN page for more information.</p>
<p>There was already a version of the assembly in question installed in the GAC, they just wanted to use the .local file to override it. The trouble was, with certain builds of the DLL (we&#8217;ll call it XYZ.dll) in the directory along with the redirection file (appname.exe.local), an fatal InvalidProgramException would be generated by the .NET execution engine. With other builds of the same DLL it worked. Mysterious.</p>
<p>So the first thing to do was to try and find out exactly where the exception was occurring. I ramped up WinDbg, and took a look at what exceptions were being thrown:<br />
<code><br />
(42c.1e90): CLR notification exception - code e0444143 (first chance)<br />
(42c.1e90): Unknown exception - code 02345678 (first chance)<br />
(42c.1e90): C++ EH exception - code e06d7363 (first chance)<br />
(42c.1e90): C++ EH exception - code e06d7363 (first chance)<br />
(42c.1e90): C++ EH exception - code e06d7363 (first chance)<br />
(42c.1e90): CLR exception - code e0434f4d (first chance)<br />
</code><br />
The last one generated a second chance exception and the exit. I changed the exception filter set to stop on .NET notifications &#8211; which are generated when assemblies are loaded &#8211; and for C++ exceptions:<br />
<code><br />
0:000&gt; sxe clrn<br />
0:000&gt; sxe eh<br />
</code><br />
After restarting and running on from the CLR notification (generated whenever an assembly is loaded) I got a stack trace on the C++ exception that was being generated within the CLR:<br />
<code><br />
0:000&gt; kP<br />
ChildEBP RetAddr<br />
0012eea4 78158e89 KERNEL32!RaiseException+0x53<br />
0012eedc 79fce58e MSVCR80!_CxxThrowException+0x46<br />
0012ef0c 7a015309 mscorwks!RealCOMPlusThrow+0xd8<br />
0012f2ac 79f0e795 mscorwks!UnsafeJitFunction+0x365<br />
0012f350 79e87f52 mscorwks!MethodDesc::MakeJitWorker+0x1c1<br />
0012f3a8 79e8809e mscorwks!MethodDesc::DoPrestub+0x486<br />
0012f3f8 00341f3e mscorwks!PreStubWorker+0xeb<br />
</code><br />
Hmmmm, interesting, so it looks like the JIT compiler is failing. I also noticed that there was a strange exception that I didn&#8217;t recognise:<br />
<code><br />
(42c.1e90): Unknown exception - code 02345678 (first chance)<br />
</code><br />
You&#8217;ve got to love those &#8220;made up&#8221; numbers. I added an exception filter for it and restarted again (good job this failure was quick to manifest).<code><br />
</code><br />
Now I got an even more precise fault location:<br />
<code><br />
0:000&gt; kP<br />
ChildEBP RetAddr<br />
0012ec44 790af56c KERNEL32!RaiseException+0x53<br />
0012ec60 7909deea mscorjit!getJit+0x38<br />
0012ec7c 79066362 mscorjit!Compiler::fgFindJumpTargets+0x33d<br />
0012ece0 790614c6 mscorjit!Compiler::fgFindBasicBlocks+0x4d<br />
0012ed20 79061236 mscorjit!Compiler::compCompile+0x2bf<br />
0012edb4 7906118c mscorjit!jitNativeCode+0xb8<br />
0012edec 79f0f9cf mscorjit!CILJit::compileMethod+0x3d<br />
0012ee58 79f0f945 mscorwks!invokeCompileMethodHelper+0x72<br />
0012ee9c 79f0f8da mscorwks!invokeCompileMethod+0x31<br />
0012eef4 79f0ea33 mscorwks!CallCompileMethodWithSEHWrapper+0x84<br />
0012f2ac 79f0e795 mscorwks!UnsafeJitFunction+0x230<br />
0012f350 79e87f52 mscorwks!MethodDesc::MakeJitWorker+0x1c1<br />
0012f3a8 79e8809e mscorwks!MethodDesc::DoPrestub+0x486<br />
0012f3f8 00341f3e mscorwks!PreStubWorker+0xeb<br />
</code><br />
So now its looking like something&#8217;s going wrong deep down in the JITter. After stepping through the disassembly for a while I decided to have a look at precisely what method was being compiled at this point. You can use the DumpMD command from the sos extension to examine the method, which is the first parameter to UnsafeJitFunction (you can see parameters in the stack trace by using kb):<br />
<code><br />
0:000&gt; !DumpMD 0161ad08<br />
Method Name: XXX()<br />
Class: 01670a40<br />
MethodTable: 0161ad18<br />
mdToken: 0601626b<br />
Module: 00d3323c<br />
IsJitted: no<br />
m_CodeOrIL: ffffffff<br />
</code><br />
Now this is suspicious; the method as listed (XXX &#8211; name changed to protect the innocent) isn&#8217;t what we were expecting. In fact, it&#8217;s completely different. Let&#8217;s see what IL is being JITted:<br />
<code><br />
0:000&gt; !DumpIL 161ad08<br />
error decoding IL<br />
</code><br />
OK, so this is completely broken metadata.</p>
<p>Now, given that we were using the .local, we would have expected to see the DLL being loaded from the same directory as the application, so lets take a look and see what we&#8217;ve got loaded:<br />
<code><br />
0:000&gt; !DumpDomain<br />
--------------------------------------<br />
System Domain: 7a3bc8b8<br />
...snip...<br />
Assembly: 001abe28 [C:\WINNT\assembly\GAC_MSIL\XYZ.DLL]<br />
ClassLoader: 001aa0b0<br />
SecurityDescriptor: 001aa018<br />
Module Name<br />
00d3323c C:\WINNT\assembly\GAC_MSIL\XYZ.DLL<br />
</code><br />
So this looks like the culprit; we&#8217;re still loading the version from the GAC, even though there&#8217;s a .local file present. Just to verify this I set a breakpoint on CreateFileW to show me which DLLs were being loaded and by what:<br />
<code><br />
0:000&gt; bu KERNEL32!CreateFileW "dpu (@esp+4) L1"<br />
</code><br />
This tells the debugger to display the unicode string that is the first parameter to CreateFileW whenever it&#8217;s hit.<br />
There are obviously lots of DLLs loaded, even in this simple case, but eventually it led me to the point where the GAC version was being loaded:<br />
<code><br />
0012cf44 001ac5a0 "C:\WINNT\assembly\GAC_MSIL\XYZ.dll"<br />
eax=00000000 ebx=00000001 ecx=79e7f683 edx=7c90eb94 esi=001ac4e0 edi=7c80ac0f<br />
eip=7c810760 esp=0012cf40 ebp=0012cf64 iopl=0 nv up ei pl nz na po nc<br />
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000202<br />
KERNEL32!CreateFileW:<br />
7c810760 8bff mov edi,edi</code></p>
<p><code>0:000&gt; kp L30<br />
ChildEBP RetAddr<br />
0012cf3c 79e90f12 KERNEL32!CreateFileW<br />
0012cf64 79f29306 mscorwks!WszCreateFile+0x72<br />
0012cfac 79ed27ac mscorwks!PEImage::GetFileHandle+0x60<br />
0012cfdc 79e981ae mscorwks!PEImage::GetLayoutInternal+0xcf<br />
0012d020 79e98e69 mscorwks!PEImage::GetLayout+0x8a<br />
0012d0bc 79e98934 mscorwks!RuntimeOpenImageInternal+0x103<br />
0012d104 79e988a9 mscorwks!GetAssemblyMDInternalImportEx+0x9d<br />
0012d11c 79ec314d mscorwks!CreateMetaDataImport+0x16<br />
0012d13c 79ec30ee mscorwks!CAssemblyManifestImport::Init+0x35<br />
0012d164 79ed39ca mscorwks!CreateAssemblyManifestImport+0x53<br />
0012d180 79ed3943 mscorwks!CreateAssemblyFromManifestFile+0x48<br />
0012d3e8 79ed380f mscorwks!CheckExistsInGAC+0x179<br />
0012d418 79ed320a mscorwks!CreateAssemblyFromCacheLookup+0x9b<br />
...snip...</code></p>
<p>So then I waited until the exception was fired, and used !dlls to show me what other DLLs were loaded:<br />
<code><br />
0:000&gt; !dlls<br />
...<br />
0x00243a68: C:\Temp\interopx\XYZ.dll<br />
Base 0x036a0000 EntryPoint 0x00000000 Size 0x0095c000<br />
Flags 0x90404000 LoadCount 0x00000001 TlsIndex 0x00000000<br />
LDRP_ENTRY_PROCESSED<br />
LDRP_COR_IMAGE<br />
...<br />
</code><br />
Ouch. We&#8217;ve loaded some metadata from the c:\winnt\assembly\GAC_MSIL\XYZ.dll version, and then we&#8217;ve actually loaded the c:\temp\interopx\XYZ.dll module. It turned out that in some cases the metadata matched, and we got away with it, and at other times (for different builds) it didn&#8217;t and we hit the InvalidProgramException.</p>
<p>So, the moral of the story is, don&#8217;t mix .local and the .NET assembly loader. And if you do, prepare to break out your WinDbg skills.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.voyce.com/index.php/2008/10/01/troubleshooting-an-invalidprogramexception/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Static libraries are Evil</title>
		<link>http://www.voyce.com/index.php/2008/09/24/static-libraries-are-evil/</link>
		<comments>http://www.voyce.com/index.php/2008/09/24/static-libraries-are-evil/#comments</comments>
		<pubDate>Wed, 24 Sep 2008 15:27:27 +0000</pubDate>
		<dc:creator>ian</dc:creator>
				<category><![CDATA[COM]]></category>
		<category><![CDATA[Excel]]></category>
		<category><![CDATA[Rant]]></category>
		<category><![CDATA[Software Development]]></category>
		<category><![CDATA[c++]]></category>
		<category><![CDATA[dll]]></category>
		<category><![CDATA[lib]]></category>

		<guid isPermaLink="false">http://www.voyce.com/?p=41</guid>
		<description><![CDATA[In my opinion.
Why? Well, because it&#8217;s too easy to use them as an excuse for not defining your shared library interfaces properly.
The reason this is on my mind recently is that several hundred, yes, you heard that right, several hundred DLLs have been released by my group over the last, ooh, 10 years or so. [...]]]></description>
			<content:encoded><![CDATA[<p>In my opinion.</p>
<p>Why? Well, because it&#8217;s too easy to use them as an excuse for not defining your shared library interfaces properly.</p>
<p>The reason this is on my mind recently is that several hundred, yes, you heard that right, several <em>hundred</em> DLLs have been released by my group over the last, ooh, 10 years or so. They are all still in use. Each of them has burned into it a copy of the library that deals with interfacing with Excel. That means each of these has it&#8217;s own little internal copy of the current state-of-the-art. The problem with that is; the state-of-the-art moves on. And how do you go about updating the DLLs that are already in production? You have to re-release them. In an environment where thes DLLs are used for marking the profit and loss on a large derivatives trading book, that&#8217;s not a small undertaking. And it&#8217;s made worse if, say the DLL in question was last released with a different version of the compiler.</p>
<p>My approach would be to refactor this shared static library (.lib) into a stand-alone DLL.</p>
<p>At this point, people start saying &#8220;oh, but then you&#8217;ve got a single point of failure, if you release a broken version of that DLL, everything will stop working!&#8221;. Not exactly a compelling argument. If the functionality of the DLL is well defined, and there are well known entry points it should be easy to put together a comprehensive black-box test suite. In fact we already do that with all our other DLLs (COM servers). The fact that this shared library *isn&#8217;t* a DLL has meant that it&#8217;s fallen through the testing cracks; another good reason to refactor it.</p>
<p>The internal interface to the shared library is already relatively well defined. It has a set of header files that define all of the functions and classes that are consumed by others. It&#8217;s a relatively small step to compile it as a DLL, rather than a static library. The problem then becomes one of maintenance, dealing with the inevitable changes to the external interface in a backwardly compatible way.</p>
<p>And that&#8217;s the problem. It requires some effort. Elsewhere in our codebase we use COM as a magic cure-all for avoiding having to deal with versioning: interface immutability rules. All interfaces are public, no published interface ever changes, object identity is based purely on interfaces supported. If you haven&#8217;t got these crutches to rely on, then you have to enforce the rules yourself, which can be both logistically and technically difficult when you&#8217;re dealing with C++.</p>
<p>But it&#8217;s not impossible. And I really think it would be better than having hundreds of DLLs all containing subtley different versions of the same code, and being unable to change behaviour across the board without having to build, test and release them all.</p>
<p>Maybe you&#8217;ve got a different opinion?</p>
]]></content:encoded>
			<wfw:commentRss>http://www.voyce.com/index.php/2008/09/24/static-libraries-are-evil/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

