Using COM and Native DLLs in .Net (CLR Managed) Applications

how-to | home

Generally .Net applications consume win32 side-by-side definitions in the same way native applications do. They need a manifest file either external (*.exe.manifest) or embedded in the executable as a resource. The activation context is created by Windows when the executable is loaded and is used when one of the Windows APIs that participate in side-by-side is called.

It is important to remember that .Net assemblies are loaded by the CLR Fusion loader and this process doe not use Windows side-by-side.

Manifest Maker 'Examples' folder contains two examples of a .Net program using unmanaged DLLs. One is a Visual Studio 2005 project (vs2005\dotNetConsole5) and one is a Visual Studio 2008 project (vs2008\dotNetConsole8). These projects illustrate building a .Net application with an associated manifest and embedding the manifest in the executable as a resource. They both use the same technique: create a Manifest Maker project to build the necessary manifest and add a Post-Build Event to build the manifest and embed it in the executable. Visual Studio 2008 added a new option in the .Net build properties that allow you to specify an icon and a manifest for your .Net program. If you choose to use them you need to build the manifest in a Pre-Build event, add the resulting manifest to the Visual Studio project and then select it in the build properties dialog.

The Post-Build Event event is defined as (note that the text is wrapped here):

set path=$(path);$(ProgramFiles)\Maze Computer\Manifest Maker;$(DevEnvDir)..\Tools\bin;$(ProgramFiles)\Microsoft SDKs\Windows\v6.0A\bin

sxs32cmd.exe /w:msil /v:1 /q:1 /l:1 /t:"$(ProjectDir)obj\$(ConfigurationName)\$(TargetName).sxs32cmd.log"
             /y:2 /f:"$(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName).manifest" /r:"$(TargetDir)\"
             "$(ProjectDir)$(ProjectName).sxs32mm"
             
mt -nologo -manifest "$(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName).manifest" -outputresource:"$(TargetPath);#1"

The .Net build environment is much more primitive the the C++ build environment and many facilities are not available. There is no definition of additional paths to be used for the build. It is necessary to hard-code additional paths in the build event itself. The example above assumes that you installed Manifest Maker and Microsoft SDK in the default folders. You may need to adjust these paths otherwise.

Let us look at one of the example programs. First look at the embedded manifest: right-click the executable in Windows Explorer and choose View Manifests. There is one manifest resource and it contains three assembly references. Two private assemblies and one shared assembly. These are both console programs so to see the output you need to create a command prompt. Run the selected program. You should get output similar to this:

C:\Temp\Examples\vs2005\_Release>dotNetConsole5.exe
 .Net program calling a plain DLL and a COM DLL

 Program path: C:\Temp\Examples\vs2005\_Release\dotNetConsole5.exe
 Win DLL path: C:\Temp\Examples\vs2005\_Release\windowsDLL.dll
 COM DLL path: C:\Temp\Examples\vs2005\_Release\com.dll.assembly\serverDLL.dll

 C:\Temp\Examples\vs2005\_Release>

Notice an unexpected path for the windowsDLL.dll. One would expect:

 C:\Data\Temp\SxS.Examples-20090530\vs2005\_Release\win.dll.assembly\windowsDLL.dll

This is an idiosyncrasy of the .Net loader which instead of calling LoadLibraryEx with the name of the DLL and no path, explicitly uses the program path first and finds the DLL in the program folder. Once you rename or delete the DLL from the program folder, the CLR fails the first time so it tries again this time with no path and the output looks like this:

 C:\Data\Temp\SxS.Examples-20090530\vs2005\_Release>dotNetConsole5.exe
 .Net program calling a plain DLL and a COM DLL

 Program path: C:\Data\Temp\SxS.Examples-20090530\vs2005\_Release\dotNetConsole5.exe
 Win DLL path: C:\Data\Temp\SxS.Examples-20090530\vs2005\_Release\win.dll.assembly\windowsDLL.dll
 COM DLL path: C:\Data\Temp\SxS.Examples-20090530\vs2005\_Release\com.dll.assembly\serverDLL.dll

 C:\Data\Temp\SxS.Examples-20090530\vs2005\_Release>

There is no such issue with COM DLLs because CLR does not load the DLL, COM does.

Also note that to build a .Net program referencing a COM object you need to have the COM object registered on the build machine - MS Visual Studio fails if it cannot find the COM information in the registry.