Erro: Excepção AppDomainUnloaded quando utiliza geridos extensões para componentes do Visual C++

Traduções de Artigos Traduções de Artigos
Artigo: 309694 - Ver produtos para os quais este artigo se aplica.
Expandir tudo | Reduzir tudo

Nesta página

Sintomas

Este problema ocorre quando é efectuada uma chamada de código não gerido para código gerido, incluindo chamadas de unmanaged-to-managed directas dentro de uma única DLL. Por exemplo, o problema poderá ocorrer quando MEC + + / IJW é utilizado no ASP.NET aplicações. No ASP.NET, vários eventos podem causar aplicações ser recarregada para um novo domínio de aplicação. Se estiver a utilizar componentes MEC ++ e IJW nesta aplicação, poderá receber uma mensagem de erro AppDomainUnloadException .

Causa

Como parte da implementação do IJW, quando carrega uma DLL gerida que tiver criado utilizando o compilador C++, o tempo de execução cria thunks para transições a partir do código não gerido para código gerido. Estes thunks contêm uma referência para o domínio de aplicação na qual carrega a DLL. Se a DLL carrega novamente o tempo de execução não recriar estes thunks; além disso, o tempo de execução não actualiza a referência quando carrega o domínio de aplicação original e carrega a DLL de outro domínio de aplicação.

Quando o programa executa uma transição de código não gerido para código gerido, o programa usa o AppDomain desactualizado fazer referência a executar o código gerido. Mesmo que o domínio de aplicação original é carregado ainda, o código não é possível aceder campos estáticos porque os campos são específicos para o domínio de aplicação.

Como contornar

As seguintes soluções são agrupadas de acordo com dois cenários:
  • Uma transição de código não gerido para código gerido em dois dll
  • Uma transição de código não gerido para código gerido na mesma DLL

Código não gerido para gerido transição de código na dois dll

Utilize um dos seguintes métodos para resolver este problema específico.

Solução 1

Para clientes do ASP.NET, permita que o processo de anfitrião do ASP.NET seja encerrado pelo evento DomainUnload do véu. No entanto, tem de registar primeiro um delegado para o evento DomainUnload . Para o fazer, siga estes passos:
  1. Método Application_Start da classe de aplicações do ASP.NET, registe um delegado a ser chamado quando carrega o AppDomain.
  2. No delegado registado, encerre o Aspnet_wp.exe processo.
Nota Esta solução alternativa que todas as aplicações ASP.NET o reinício do computador; os dados de estado de sessão de processo para todas estas aplicações serão perdidos. Na Internet informações Service (IIS) 6.0 num computador com o Windows Server 2003, pode configurar o programa para uma aplicação por modo de processo. Para obter mais informações sobre agrupamentos de aplicações configuing, visite o seguinte Web site da 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);
}
				

Solução 2

Substitua todas as transições de código não gerido para código gerido chamadas através de um apontador de função não geridos que criar utilizando um delegado (que é o domínio de aplicação específico). O delegado é empacotar as referências ao código não gerido utilizando serviços de invocação de Platform ( P/Invoke ) em vez de IJW.

Para a DLL não gerida descrita na secção "Mais informação" deste artigo, o código de exemplo seguinte demonstra como utilizar P/Invoke para utilizar o método de chamada de retorno:
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;
		}
	};
}
				

Código não gerido para gerido transição de código na mesma DLL

Neste cenário, pode ter unmanaged métodos (marcados com não geridos # pragma ) chamar métodos num componente gerido na mesma DLL, tal como mostrado na secção "Mais informação" deste artigo. Utilize um dos seguintes métodos para resolver este problema específico:

Solução 1

Organizar o apontador de função como delegado e utilizar esse delegado. Uma vez que não pode utilizar P/Invoke DLL mesmo, criar um wrapper DLL que ajuda a organizar um delegado a um apontador de função. Esta função exportada devolve o endereço do delegado que é transmitido ao mesmo. O código de exemplo seguinte é um exemplo desta solução alternativa:
//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;
}
				
o seguinte código de exemplo é para extensões geridas para C++ assemblagem utiliza Helper.dll anterior:
#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();
     }
}
				

Solução 2

Dividir a assemblagem MEC ++ para dois dll, que contém apenas geridos componentes e outros que contém apenas os componentes não geridos e, em seguida, utilizar P/Invoke tal como descrito na solução alternativa 2 do cenário 1.

Ponto Da Situação

A Microsoft confirmou que este é um erro no Microsoft produtos listados no início deste artigo.

Mais Informação

O problema é mais prevalecente se a aplicação de anfitrião ou cliente deve descarregar e recarregar AppDomains e a aplicação contém transições de código não gerido para código gerido que utilizam componentes MEC ++ e IJW. O ASP.NET é um bom exemplo de tal um anfitrião. No ASP.NET, os eventos podem accionar um evento de descarregar AppDomain podem ser aquele transponham um limite de utilização de memória para tocar determinados ficheiros (por exemplo, Machine.config).

Passos para reproduzir o comportamento

Neste exemplo, tiver uma aplicação do ASP.NET que invoca um componente MEC ++ e este componente tem um apontador de função que aponta para um dos métodos do componente MEC ++. O componente passa o ponteiro de função para um dos seguintes procedimentos:
  • uma função que foi exportada por uma DLL não gerida
  • um método não gerido na mesma DLL
O código não gerido, em seguida, efectua uma chamada de retorno utilizando o apontador de função que foram recebido do componente MEC ++.

Nos seguintes cenários, é possível que, antes da função não gerida invoca o apontador de função, o AppDomain original em que foi carregada a DLL é descarregado. Essas condições, o código não gerido ainda referencia o domínio de aplicação original e tenta chamada para código gerido nesse contexto.
  • código não gerido para gerido pelo código transição entre dois dll

    Chamar uma função DLL não gerida exportada a partir de um MEC ++ assemblagem das formas seguintes:
    • utilizando IJW
    • utilizando P/Invoke
    O código de exemplo seguinte utiliza uma DLL não gerida (Win32.dll) exporta um método.
    //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;
    }
    					
    uma assemblagem C++ gerida pode chamar este método através do IJW por ligar a Win32.lib e incluindo o ficheiro de cabeçalho apropriado. O código de exemplo seguinte mostra como utilizar o método exportado. # pragma
    #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;
    		}
    	};
    }
    					
  • código não gerido para gerido transição de código na mesma DLL

    Neste cenário, a assemblagem MEC ++ contém métodos não geridos (marcados com não geridos # pragma ) que chamam métodos num componente MEC ++ na mesma DLL, conforme demonstrado no seguinte código de exemplo.
    #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();
         }
    }
    					

Referências

Para obter mais informações, visite os seguintes Web sites da Microsoft Developer Network (MSDN):
Domínios de aplicação
http://msdn2.microsoft.com/en-us/library/cxk374d9(vs.71).aspx?frame=true

Classe de domínio de aplicação
http://msdn2.microsoft.com/en-us/library/system.appdomain(vs.71).aspx

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

Extensões geridas para programação C++
http://msdn2.microsoft.com/en-us/library/aa712574(vs.71).aspx

Criar aplicações Web do ASP.NET
http://msdn.microsoft.com/en-us/library/aa719794.aspx

Modo de isolamento do processo de trabalho
http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/34604f82-9175-4d48-b5ea-1e11f19db5f3.mspx?mfr=true

Propriedades

Artigo: 309694 - Última revisão: 17 de maio de 2007 - Revisão: 4.7
A informação contida neste artigo aplica-se a:
  • Microsoft Visual C++ .NET 2002 Standard Edition
  • Microsoft .NET Framework 1.0
Palavras-chave: 
kbmt kbbug kbijw kbmanaged kbpending KB309694 KbMtpt
Tradução automática
IMPORTANTE: Este artigo foi traduzido por um sistema de tradução automática (também designado por Machine translation ou MT), não tendo sido portanto revisto ou traduzido por humanos. A Microsoft tem artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais. O objectivo é simples: oferecer em Português a totalidade dos artigos existentes na base de dados do suporte. Sabemos no entanto que a tradução automática não é sempre perfeita. Esta pode conter erros de vocabulário, sintaxe ou gramática? erros semelhantes aos que um estrangeiro realiza ao falar em Português. A Microsoft não é responsável por incoerências, erros ou estragos realizados na sequência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza actualizações frequentes ao software de tradução automática (MT). Obrigado.
Clique aqui para ver a versão em Inglês deste artigo: 309694

Submeter comentários

 

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