How Are Dlls Loaded by the Clr

How are DLLs loaded by the CLR?

The following copied from Don Box's excellent Essential .Net. (available here)

(and, imho, a must have for any professional .Net developer)

The CLR Loader

The CLR Loader is responsible for loading and initializing assemblies, modules, resources, and types. The CLR loader loads and initializes as little as it can get away with. Unlike the Win32 loader, the CLR loader does not resolve and automatically load the subordinate modules (or assemblies).
Rather, the subordinate pieces are loaded on demand only if they are actually needed (as with Visual C++ 6.0's delay-load feature). This not only speeds up program initialization time but also reduces the amount of resources consumed by a running program.
In the CLR, loading typically is triggered by the just in time (JIT) compiler based on types. When the JIT compiler tries to convert a method body from CIL to machine code, it needs access to the type definition of the declaring type as well as the type definitions for the type's fields. Moreover, the JIT compiler also needs access to the type definitions used by any local variables or parameters of the method being JIT-compiled. Loading a type implies loading both the assembly and the module that contain the type definition.
This policy of loading types (and assemblies and modules) on demand means that parts of a program that are not used are never brought into memory. It also means that a running application will often see new assemblies and modules loaded over time as the types contained in those files are needed during execution. If this is not the behavior you want, you have two options. One is to simply declare hidden static fields of the types you want to interact with the loader explicitly.

The loader typically does its work implicitly on your behalf. Developers can interact with the loader explicitly via the assembly loader. The assembly loader is exposed to developers via the LoadFrom static method on the System.Reflection.Assembly class. This method accepts a CODEBASE string, which can be either a file system path or a uniform resource locator (URL) that identifies the module containing the assembly manifest. If the specified file cannot be found, the loader will throw a System.FileNotFoundException exception. If the specified file can be found but is not a CLR module containing an assembly manifest, the loader will throw a System.BadImageFormatException exception. Finally, if the CODEBASE is a URL that uses a scheme other than file:, the caller must have WebPermission access rights or else a System.SecurityException exception is thrown. Additionally, assemblies at URLs with protocols other than file: are first downloaded to the download cache prior to being loaded.

Listing 2.2 shows a simple C# program that loads an assembly located at file://C:/usr/bin/xyzzy.dll and then creates an instance of the contained type named AcmeCorp.LOB.Customer. In this example, all that is provided by the caller is the physical location of the assembly.
When a program uses the assembly loader in this fashion, the CLR ignores the four-part name of the assembly, including its version number.

Example 2. 2. Loading an Assembly with an Explicit CODEBASE

using System;
using System.Reflection;
public class Utilities {
public static Object LoadCustomerType() {
Assembly a = Assembly.LoadFrom(
"file: //C:/usr/bin/xyzzy. dll") ;
return a.CreateInstance("AcmeCorp.LOB.Customer") ;
}
}

Although loading assemblies by location is somewhat interesting, most assemblies are loaded by name using the assembly resolver. The assembly resolver uses the four-part assembly name to determine which underlying file to load into memory using the assembly loader. As shown in Figure 2.9, this name-to-location resolution process takes into account a variety of factors, including the directory the application is hosted in, versioning policies, and other configuration details (all of which are discussed later in this chapter).

The assembly resolver is exposed to developers via the Load method of the System.Reflection.Assembly class. As shown in Listing 2.3, this method accepts a four-part assembly name (either as a string or as an AssemblyName reference) and superficially appears to be similar to the LoadFrom method exposed by the assembly loader. The similarity is only skin deep because the Load method first uses the assembly resolver to find a suitable file using a fairly complex series of operations. The first of these operations is to apply a version policy to determine exactly which version of the desired assembly should be loaded.

Example 2.3. Loading an Assembly Using the Assembly Resolver

using System;
using System.Reflection;
public class Utilities {
public static Object LoadCustomerType() {
Assembly a = Assembly.Load(
"xyzzy, Version=1. 2. 3.4, " +
"Culture=neutral, PublicKeyToken=9a33f27632997fcc") ;
return a.CreateInstance("AcmeCorp.LOB.Customer") ;
}
}

When loading a C++ dll in C#, does the CLR load the dependencies of the C++ file automatically?

If its a native C++ dll, the dependencies are loaded at load time, unless that dependency is marked as delay loaded, which it will then get loaded when one of the functions from that dll is called.

If its a .Net C++ dll, dependencies are loaded when needed.

Loading a .NET DLL from Resources inside a Win32/clr DLL

C++/CLI mixed-mode DLLs have two sets of references: the native imports in the PE header, and the .NET assembly references. Problems finding the native imports will cause the symptom you observed, that loading the assembly fails early during load and cannot be intercepted and recovered.

It's not clear to me why the native dependency rules are applicable here. For a true native dependency that needs to be located using an alternate search order under your control, delay-loading could be applied. But that can't be used with a referenced .NET assembly.

In any case, the simplest fix is to not need a separate assembly at all. Your goal is single file deployment, and the ideal single file deployment scenario is when all the code is contained in a single DLL and you don't need to unpack a second file at runtime.

For pure .NET assemblies, there is an ILMerge tool that combines multiple DLLs into a single file. But your case has a C++/CLI mixed mode DLL, not pure MSIL.

Using multiple languages in a native program generally works a little bit differently. Instead of producing a complete executable from each toolset, native code standardizes an object file format (Windows .obj, Linux .o) which all the various toolsets know how to produce, and then the link step can link together object files from a variety of languages. The object files are often bundled into static libraries. (A static library is just an archive of object files, with a symbol index) Because the C++/CLI toolset is patterned on native C++, it uses this model as well.

The .NET version of this language-independent "object file" which can be further linked is a .netmodule file. Internally, it is a .NET assembly without a manifest. Functionally, it acts like a static library. And the C++/CLI link.exe can link together C# (and VB, and F#, etc) .netmodule static libraries together with the C++/CLI object files and static libraries, and native object files and libraries, when it creates the mixed-mode assembly.

This isn't the most straightforward process, because while it is supported by the underlying toolchains, the Visual Studio project options dialog boxes don't have a UI for either creating or consuming .netmodule static libraries.

For the C# side to produce a .netmodule, you should open your .csproj file and change the <OutputType> setting to module. Then reopen the project in Visual Studio and build as usual.

On the C++/CLI side, the project options dialog allows you to customize the compile and link command-lines. Change the linker command to include /link and the name of the .netmodule file.

If you've done it right, the C++/CLI linker will create a single mixed-mode DLL with all the types and code from both the C# and C++/CLI source files. And all the internal usage between C# and C++/CLI will be already resolved, so you won't have to worry about missing dependencies at run time. Well, at least not these dependencies; any you didn't choose to link in will still be handled normally.

Clr Dll loaded by test prog but not by calling app

After exhaustive search, I found nothing that helps to resolve this issue, including doing library load debugging.

My other related posting is here: Unexpected Stackoverflow exception using CLR in a dll

And finally, by doing several things, this exception is gone and everything works now:

1) In my CS project, I use the unmanagedexports package (use NuGet package manager to install it: Install-Package unmanagedexports) to export static methods using the __stdcall calling convention. In this project, you need to add these:

using System.Runtime.InteropServices;
using RGiesecke.DllExport;

2) add the path to the wrapper header files to the unmanaged C/C++ project's property page (C/C++->general->additional include directories)

3) put the managed and native wrapper into one project/dll (built with /clr option), separate them from the other two modules (one for the managed C# and one for the unmanaged C/C++)

4) optionally, I added a definition file for the unmanaged C/C++ functions

5) make sure all modules are built against the same framework and platform. In my case, I use framework 4.0 and x86 platform. In some case, you need to add an app.config file with the following:

<configuration>
<startup useLegacyV2RuntimeActivationPolicy="true">
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
</startup>
</configuration>"

6) set the path in the environment pointing to where the dlls are deployed

That's about it.

Getting a list of DLLs currently loaded in a process C#

There exists the Process.Modules property which you can enumerate all Modules (exe and .dll's) loaded by the process.

foreach (var module in proc.Modules)
{
Console.WriteLine(string.Format("Module: {0}", module.FileName));
}

Per the ProcessModule class which gives you the properties of a specific module.

IIS 7.5+ 64bit having trouble loading C++ CLR dlls

The typical way I debug this is in two phases.

First, I enable fusion logging to see if there are any .Net dependencies missing. Any assemblies that can't be found will have logs written to the specified location. Sometimes what can happen is an app pool will shadow copy assemblies during ASP.Net compilation and not include a dependency. This will help find it.

Second, I run Dependency Walker to get a set of dlls that are depended on by native code, and if I can't tell by just looking at the set, I run Process Monitor and filter on failed DLL loads (Path ends with ".dll" and Result is not "SUCCESS").

Procmon Filter



Related Topics



Leave a reply



Submit