BUG: AppDomainUnloaded exception when you use managed extensions for Visual C++ components (309694)
The information in this article applies to:
- Microsoft Visual C++ .NET (2002)
- Microsoft .NET Framework 1.0
This article was previously published under Q309694 SYMPTOMS This problem occurs when a call is made from unmanaged code
to managed code, including direct unmanaged-to-managed calls within a single
DLL. For example, the problem may occur when MEC++/IJW is used in ASP.NET
applications. In ASP.NET, various events can cause applications to be reloaded
into a new AppDomain. If you are using MEC++ components and IJW in this
application, you may receive an AppDomainUnloadException error message. CAUSE As part of the implementation of IJW, when a managed DLL
that you created by using the C++ compiler loads, the runtime creates thunks
for transitions from unmanaged code to managed code. These thunks contain a
reference to the AppDomain in which the DLL loads. The runtime does not
re-create these thunks if the DLL loads again; also, the runtime does not
update the reference when the original AppDomain unloads and the DLL loads in
another AppDomain.
When the program performs a transition from
unmanaged code to managed code, the program uses the outdated AppDomain
reference to run the managed code. Even if the original AppDomain is still
loaded, the code cannot access static fields because the fields are specific to
the AppDomain. WORKAROUND The following workarounds are grouped according to two
scenarios:
- A transition from unmanaged code to managed code across two
DLLs
- A transition from unmanaged code to managed code in the
same DLL
Unmanaged Code to Managed Code Transition Across Two DLLs Use either of the following methods to resolve this specific
problem. Workaround 1 For ASP.NET clients, allow the ASP.NET host process to shut down
by trapping the DomainUnload event. However, you must first register a delegate for the DomainUnload event. To do this, follow these steps:
- In the Application_Start method of the ASP.NET Application class, register a delegate to be called when the AppDomain
unloads.
- In the registered delegate, shut down the Aspnet_wp.exe
process.
Note This workaround causes all of the ASP.NET applications on the
computer to restart; the in-process session state data for all of these
applications is lost.
In Internet Information Service (IIS) 6.0 on a computer that is running
Windows 2003 Server, you can configure the program for one application per
process mode. For more information about configuing application pools, visit the following Microsoft Web site:
//Register a delegate to be called when the DomainUnload event fires.
protected void Application_Start(Object sender, EventArgs e)
{
AppDomain.CurrentDomain.DomainUnload+= new EventHandler(ADUnloading);
}
//This method is called when the AppDomain is about to unload.
public void ADUnloading(object s, EventArgs e)
{
System.Environment.Exit(0);
}
Workaround 2 Replace all transitions from unmanaged code to managed code with
calls through an unmanaged function pointer that you create by using a delegate
(which is AppDomain specific). The delegate is marshaled to the unmanaged code
by using Platform Invocation Services ( P/Invoke) instead of IJW. For the unmanaged DLL described in the
"More Information" section of this article, the following sample code
demonstrates how to use P/Invoke to use the callback method:
using namespace System::Runtime::InteropServices; // For DllImportAttribute.
namespace ManagedLib
{
//Managed delegate declaration.
public __delegate int ManagedFuncDelg();
public __gc class Class1
{
public:
[DllImport("Win32.dll", EntryPoint="callback")]//Assumes that you have a DEF file for the exports.
static int Mgdcallback(ManagedFuncDelg*);
//This method is called from the unmanaged DLL.
static int InternalMethod()
{
return 123;
}
static ManagedFuncDelg* pd = new ManagedFuncDelg(0, &ManagedLib::Class1::InternalMethod);
//This method is called by the client application.
int Func()
{
int ret = ManagedLib::Class1::Mgdcallback(ManagedLib::Class1::pd);
return ret;
}
};
}
Unmanaged Code to Managed Code Transition in the Same DLL In this scenario, you can have unmanaged methods (marked with #pragma unmanaged) calling methods on a managed component in the same DLL, as shown
in the "More Information" section of this article. Use either of the following
methods to resolve this specific issue: Workaround 1 Marshal your function pointer as a delegate and use that
delegate. Because you cannot use P/Invoke on the same DLL, create a wrapper DLL that helps you to marshal a
delegate to a function pointer. This exported function returns the address of
the delegate that is passed to it. The following sample code is an example of
this workaround:
//This is the helper DLL that enables you to marshal the delegate.
//Helper.cpp.
//Helper DLL code.
extern "C" __declspec(dllexport) void* __stdcall FuncInUmDll(void* pv)
{
return pv;
}
The following sample code is for the Managed Extensions for C++
assembly that uses the previous Helper.dll:
#using <mscorlib.dll>
using namespace System;
using namespace System::Runtime::InteropServices; // for DllImportAttribute
namespace ManagedLib
{
//Forward declaration.
__delegate int delg();
int nativefunc(int(__stdcall*)());
[System::Runtime::InteropServices::DllImport("helper.dll", EntryPoint="FuncInUmDll")] int FuncInUmDll(delg*);
//Managed component.
public __gc class Class1{
public:
static int InternalMethod()
{
return 123;
}
//This method is called by the client application.
int Func()
{
delg* d= new delg(0, &Class1::InternalMethod);
int ret = nativefunc((int(__stdcall*)())FuncInUmDll(d));
return ret;
}
};
#pragma unmanaged
//Unmanaged function calling the managed delegate.
int nativefunc(int(__stdcall*pf)())
{
return pf();
}
}
Workaround 2 Split your MEC++ assembly into two DLLs, one that contains only
managed components and other that contains only unmanaged components, and then
use P/Invoke as described in workaround 2 of scenario 1. STATUSMicrosoft has confirmed that this is a bug in the Microsoft
products that are listed at the beginning of this article.
REFERENCES For more information, visit the following Microsoft
Developer Network (MSDN) Web sites:
Modification Type: | Minor | Last Reviewed: | 1/7/2006 |
---|
Keywords: | kbbug kbIJW kbManaged kbpending KB309694 kbAudDeveloper |
---|
|