Unmanaged dll hell and AppDomains

Hi all,

I've been struggling with an assembly loading problem for some time now, and I figured it was finally about time to ask someone about it.

I'm building an application that integrates data between two different versions of an accounting application. Both versions of the accounting application are managed/unmanaged hybrids with the high-level interfaces implemented in .Net, the deep internals implemented in C++, and an interop layer in managed C++. My integration application loads some of the managed dlls from each application and uses some common interfaces to transfer data between them.

Within my integration application, each version of the accounting application is loaded in its own AppDomain. This allows me to load different versions of the same .Net assembly within the same process. The problem is that some of the assemblies depend on the interop assemblies which in turn depend on unmanaged dlls. It seems like even though the assemblies are being loaded from different AppDomains, there are collisions when each tries to load different versions of the same unmanaged dlls.

A (very) simplified example:
Integrate.exe loads DataAccess.dll (V1) assembly into AppDomainV1 and DataAccess.dll (V2) into AppDomainV2. Each version of DataAccess.dll depends on its own version of Interop.dll (the managed C++ interop layer) which in turn depends on its own version of UnmanagedDataAccess.dll.

To illustrate:
Integrate.exe
AppDomainV1 loads:
DataAccess.dll (V1), Interop.dll (V1), UnmanagedDataAccess.dll (V2)
AppDomainV2 loads:
DataAccess.dll (V2), Interop.dll (V2), UnmanagedDataAccess.dll (V2)

Unfortunately, it seems that I have a first-come, first-serve situation for UnmanagedDataAccess.dll. If AppDomainV1 loads it first, it uses the V1 version, and AppDomainV2 fails to load (see exception below). If AppDomainV2 loads it first, it uses the V2 version, and AppDomainV1 fails to load.

Here's the exception I'm getting:

System.IO.FileLoadException: A procedure imported by 'c:\AcctV2\Interop.dll, Version=2.0.2546.29630, Culture=neutral, PublicKeyToken=null' could not be loaded.
File name: 'Interop.dll, Version=2.0.2546.29630, Culture=neutral, PublicKeyToken=null' ---> System.Runtime.InteropServices.COMException (0x8007007F): The specified procedure could not be found. (Exception from HRESULT: 0x8007007F)
at System.Reflection.Assembly.nLoad(AssemblyName fileName, String codeBase, Evidence assemblySecurity, Assembly locationHint, StackCrawlMark& stackMark, Boolean throwOnFileNotFound, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoad(AssemblyName assemblyRef, Evidence assemblySecurity, StackCrawlMark& stackMark, Boolean forIntrospection)
at System.Reflection.Assembly.InternalLoadFrom(String assemblyFile, Evidence securityEvidence, Byte[] hashValue, AssemblyHashAlgorithm hashAlgorithm, Boolean forIntrospection, StackCrawlMark& stackMark)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)


I was hoping that using AppDomains would solve this problem, and they do for pure managed assemblies, but if those assemblies have unmanaged dependencies, you are right back in good ol' DLL hell.

Any suggestions

--Matt



Answer this question

Unmanaged dll hell and AppDomains

  • Muhammad Adel

    Yes, managed C++ Dlls behave like unmanaged C++ Dlls when you try to load them. They need all their C++ dependencies (dependent Dlls like the CRT) as well as requiring all the entrypoints to match. So you might be missing a dependent Dll like the CRT, or an entrypoint. I recently came across an issue where a managed C++ assembly would not load on a Windows 2000 system, giving a FileLoadException. It was failing because there was a reference to the Win32 API GetProcessId, and this does not exist in kernel32 on Windows 2000. So something as seemingly as minor as this can cause a load failure. A dependency walker from www.dependencywalker.com could help.

  • dustin034

    Thanks again for the input.

    I took a look at the DLL/COM redirection article you pointed me to and the whitepaper it references. I might be missing something, but this doesn't seem to help with my situation. In my situation, I need a single process to load two different versions of a particular unmanaged DLL and/or COM component. The DLL/COM redirection you referred to seems to allow two separate processes to load different, private versions of shared Win32 and COM global components.

    From the whitepaper: "Side-by-side sharing allows multiple versions of the same component (COM or Win32R) to run at the same time in different processes."

    Am I missing something I didn't see anything that helps solve the problem that I'm trying to do this from the a single process...

    Thanks again...

    --Matt


  • BLACKDOG2

    You would need to turn to your 3rd party tool vendor, they put you in this pickle. You might get relief from DLL/COM redirection, start reading here...


  • nabeelfarid

    Thanks for the response.

    I think that is the direction we are looking to go. Unfortunately while we can rename the dlls for the unmanaged dependencies we own, we employ a couple of third-party components who's dlls we don't own. If we take a new version of the third party dll with the same name as the previous version (which is the case), we are in trouble. We may be able to work around this issue for the current third party dlls, but it is a fragile solution, and it might bite us in the future with other third party components.

    I'm disappointed that AppDomains don't solve the problem for unmanaged dlls. I guess I understand why they don't, but it seems like AppDomain are essentially broken for a key segment of use scenarios - anything involving managed/unmanaged hybrid solutions with unmanaged dependencies.

    Thanks again...

    --Matt


  • glenna

    Yes, unmanaged DLLs are process aware, not AppDomain aware. Why don't you just give the UnmanagedDataAccess.dll version 2 a different name If it is actually a COM component, you must give it different GUIDs according to COM rulez.


  • Leonard Lee

    You're right, you'd need a different process name. Sounds do-able...


  • Unmanaged dll hell and AppDomains