错误: AppDomainUnloaded 异常时,使用托管的 Visual c + + 组件的扩展

文章翻译 文章翻译
文章编号: 309694 - 查看本文应用于的产品
展开全部 | 关闭全部

本文内容

症状

当被调用从非托管代码包括在单个 DLL 内的直接非托管到托管调用的托管代码时,就会出现此问题。例如对于会出现此问题时 MEC + + / IJW 用于在 ASP.NET 应用程序。在 ASP.NET 中,各种事件会导致重新加载到一个新的 AppDomain 的应用程序。如果您在此应用程序中使用 MEC + + 的组件和 $ IJW,您可能会收到 AppDomainUnloadException 错误消息。

原因

一部分的 IJW 实现的使用 c + + 编译器创建的托管的 DLL 加载时,运行库创建过渡效果的 thunk 从非托管代码到托管代码。这些 thunk 包含对在其中加载 DLL 所 AppDomain 的引用。重新运行库不会不创建这些 thunk 如果再次加载 DLL ; 还,运行库不会更新该引用原始 AppDomain 卸载并在另一个的 AppDomain 中加载 DLL 时。

该程序已过时的 AppDomain 运行托管的代码引用的程序使用的托管代码从非托管代码执行的转换。即使原始 AppDomain 仍加载,代码无法访问静态字段,因为这些字段是特定于该 AppDomain。

替代方法

根据两种情况下,下列解决方法进行分组:
  • 从非托管代码到托管代码在两个 dll 之间的转换
  • 从非托管代码转换到同一个 DLL 中的托管代码

非托管的代码到托管代码转换跨两个 dll

使用下列方法之一来解决这一特定问题。

解决方法 1

为 ASP.NET 客户允许 ASP.NET 主机进程关闭的补漏白 DomainUnload 事件。但是,您必须先注册 DomainUnload 事件的委托。若要这样做,请按照下列步骤操作:
  1. 在 ASP.NET 应用程序Application_Start 方法中注册该 AppDomain 卸载时要调用的委托。
  2. 该注册代理在关闭该 Aspnet_wp.exe 过程。
注意此变通办法导致的所有 ASP.NET 应用程序上重新启动计算机,则所有这些应用程序的进程内会话状态数据都将丢失。在 Internet 信息服务 (IIS) 6.0 运行 Windows 2003 Server 的计算机上,您可以配置每个进程模式下的一个应用程序的程序。有关 configuing 应用程序池的详细信息,请访问下面的 Microsoft 网站:
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/2a231dcb-d786-4b6d-b3ba-bda04061a5e7.mspx?mfr=true
//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);
}
				

解决方法 2

通过使用委托 (这是特定的 AppDomain) 来创建非托管的函数指针调用替换从非托管代码到托管代码的所有过渡。该委托的封送到非托管代码使用平台调用服务 (P/invoke) 而不是 IJW。

为非托管 DLL 本文"更多信息"一节中描述的情况下,下面的代码示例演示如何使用回调方法使用 P/invoke
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;
		}
	};
}
				

非托管的代码到托管代码在同一 DLL 中的转换

在这种情况下您可以具有托管 (用 # pragma 非托管 标记) 的方法在同一 DLL 中的托管组件上调用方法,如本文"更多信息"一节中所示。若要解决此特定问题中使用下列方法之一:

解决方法 1

封送委托作为函数指针,并使用该委托。因为您不能在同一个 DLL 使用 P/invoke,创建包装 DLL,可帮助您封送到函数指针的委托。此导出的函数返回的委托传递给它的地址。下面的代码示例是这种解决方法的示例:
//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;
}
				
的下面的代码示例是 c + + 托管扩展使用以前 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();
     }
}
				

解决方法 2

拆分到两个 dll 在 MEC + + 程序集,包含仅托管组件和其他的包含仅非托管的组件,然后使用 P/invoke,解决方法 2 的方案 1 中所述。

状态

Microsoft 已经确认这是在 Microsoft 中的错误在本文开头列出的产品。

更多信息

如果主机或客户端应用程序必须卸载并重新加载 appdomain 和应用程序中包含从非托管代码到托管代码的转换使用 MEC + + 和 IJW 组件,该问题都更普遍。ASP.NET 是主机的此类的一个很好的示例。在 ASP.NET 中,可以触发的 AppDomain 卸载事件的事件可以是任何以接触某些文件 (例如对于 Machine.config) 穿过内存使用率阈值。

重现行为的步骤

在此的示例有调用 MEC + + 组件的 ASP.NET 应用程序,并且此组件具有指向一种方法在 MEC + + 组件中的函数指针。该组件将函数指针传递到下列值之一:
  • 由非托管 DLL 导出函数
  • 在同一 DLL 中非托管的方法
非托管的代码然后将使用从 MEC + + 组件接收到对函数指针的回调。

在下面的方案中就可能使,非托管的函数调用的函数指针之前,原始的 AppDomain 中加载了 DLL 被卸载。在这样的情况下非托管的代码仍引用原始 AppDomain,并试图在该上下文中的托管代码的调用。
  • 非托管的代码到托管代码转换跨两个 dll

    从 + 一个 MEC + 调用非托管的 DLL 导出的函数程序集在通过以下方法之一:
    • 通过使用 IJW
    • 通过使用 P/invoke
    下面的代码示例使用非托管的 DLL (Win32.dll) 将导出的方法
    //Win32.h.
    #ifdef WIN32_EXPORTS
    #define WIN32_API __declspec(dllexport)
    #else
    #define WIN32_API __declspec(dllimport)
    #endif
    
    //Declaration.
    typedef int (__stdcall *funcptr)(void);
    WIN32_API int __stdcall  callback(funcptr ptr);
    
    //Win32.cpp Implementation.
    //This method is called by the Managed C++ component either by using P/Invoke
    //or by using IJW.
    WIN32_API int __stdcall callback(funcptr ptr)
    {
    	int rtn= ptr();
    	return rtn;
    }
    					
    A 托管的 c + + 程序集可以调用此方法通过 IJW,通过链接到该 Win32.lib 和通过包括适当的头文件。下面的代码示例演示如何使用导出的方法。一旦 # include"win32.h"# using <mscorlib.dll> 使用系统的命名空间的
    #pragma once
    #include "win32.h"
    #using <mscorlib.dll>
    using namespace System;
    
    namespace ManagedLib
    {
    
    	public __gc class Class1
    	{
    		
    	public:
    		static int InternalMethod()
    		{
    			return 123;
    		}
    
                    //This method is called by the client application.
    		int Func()
    		{
    			int ret = callback((funcptr)Class1::InternalMethod);
    			return ret;
    		}
    	};
    }
    					
  • 非托管的代码到托管代码在同一 DLL 中的转换

    在这种情况下 MEC + + 程序集包含非托管 (用 # pragma 非托管 标记) 的方法调用的方法,MEC + + 组件在同一 DLL 中下面的代码示例所示
    #using <mscorlib.dll>
    using namespace System;
    namespace ManagedLib
    {
          //Forward declararion
          int nativefunc(int(__stdcall*)());
          //Managed component
          public __gc class Class1{
    
    	public:
    
                static int InternalMethod()
                {
                     return 123;
                }
                //This method is called by the client application.
                int Func()
                {
                     int ret = nativefunc((int(__stdcall*)())Class1::InternalMethod);
                     return ret;
                }
          };
    
          #pragma unmanaged
         //Unmanaged function calling the managed delegate.
         int nativefunc(int(__stdcall*pf)())
         {
                return pf();
         }
    }
    					

参考

有关更多的信息,请访问下面的 Microsoft 开发人员网络 (MSDN) 的网站:
应用程序域
http://msdn2.microsoft.com/en-us/library/cxk374d9(vs.71).aspx?frame=true

AppDomain 类
http://msdn2.microsoft.com/en-us/library/system.appdomain(vs.71).aspx

AppDomainUnloadedException 类
http://msdn.microsoft.com/en-us/library/system.appdomainunloadedexception(VS.71).aspx

c + + 编程的托管的扩展
http://msdn2.microsoft.com/en-us/library/aa712574(vs.71).aspx

创建 ASP.NET Web 应用程序
http://msdn.microsoft.com/en-us/library/aa719794.aspx

工作进程隔离模式
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/34604f82-9175-4d48-b5ea-1e11f19db5f3.mspx?mfr=true

属性

文章编号: 309694 - 最后修改: 2007年5月17日 - 修订: 4.7
这篇文章中的信息适用于:
  • Microsoft Visual C++ .NET 2002 标准版
  • Microsoft .NET Framework 1.0
关键字:?
kbmt kbbug kbijw kbmanaged kbpending KB309694 KbMtzh
机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 309694
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com