Erro: Exceção AppDomainUnloaded quando você usa gerenciado extensões para componentes do Visual C++

Traduções deste artigo Traduções deste artigo
ID do artigo: 309694 - Exibir os produtos aos quais esse artigo se aplica.
Expandir tudo | Recolher tudo

Neste artigo

Sintomas

Esse problema ocorre quando é feita uma chamada do código não gerenciado para código gerenciado, inclusive chamadas diretas dentro de uma única DLL não gerenciado para gerenciado. Por exemplo, o problema pode ocorrer quando MEC + / IJW é usado no ASP.NET aplicativos. Em ASP.NET, vários eventos podem causar aplicativos ser recarregado em um AppDomain novo. Se você estiver usando componentes MEC ++ e IJW neste aplicativo, você receberá uma mensagem de erro AppDomainUnloadException .

Causa

Como parte da implementação de IJW, quando carrega uma DLL gerenciada que você criou usando o compilador do C++, o runtime cria thunks para transições do código não gerenciado para código gerenciado. Esses thunks contém uma referência para o AppDomain em que carrega a DLL. O runtime não recriar esses thunks se a DLL carrega novamente; Além disso, o tempo de execução não atualiza a referência ao descarrega o AppDomain original e a DLL é carregada no outro AppDomain.

Quando o programa executa uma transição do código não gerenciado para código gerenciado, usa o programa AppDomain desatualizado referência para executar o código gerenciado. Mesmo se o AppDomain original é carregado ainda, o código não poderá acessar campos estáticos porque os campos são específicos para o AppDomain.

Como Contornar

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

Código não gerenciado para gerenciado código transição entre duas DLLs

Use um dos seguintes métodos para resolver esse problema específico.

Solução alternativa 1

Para que clientes ASP.NET, permitir que o processo de host ASP.NET desligar por ajuste de registro o evento DomainUnload . No entanto, você deve primeiro registrar um delegado para o evento DomainUnload . Para fazer isso, execute as seguintes etapas:
  1. No método Application_Start da classe de aplicativo do ASP.NET, registre um delegado a ser chamado quando o AppDomain é descarregado.
  2. O delegado registrado, desligar o aspnet_wp.exe processo.
Observação Faz com essa solução alternativa que todos os aplicativos ASP.NET no computador para reiniciar; os dados de estado de sessão em processo para todos esses aplicativos serão perdidos. No Internet Information Service (IIS) 6.0 em um computador que está executando o Windows Server 2003, você pode configurar o programa para um aplicativo por modo de processo. Para obter mais informações sobre pools de aplicativos configuing, visite o seguinte site:
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 gerenciado para código gerenciado chamadas através de um ponteiro de função não gerenciada que criar usando um representante (que é específica de AppDomain). O delegado é empacotado para código não gerenciado usando serviços de invocação de plataforma ( P/Invoke ) em vez de IJW.

Para a DLL não gerenciada descrito na seção "Mais informações" deste artigo, o código de exemplo a seguir demonstra como usar P/Invoke para usar o método de retorno de chamada:
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 gerenciado para gerenciado transição de código na mesma DLL

Nesse cenário, você pode que ter não gerenciados métodos (marcados com # pragma não gerenciados ) chamar métodos em um componente gerenciado na mesma DLL, como mostrado na seção "Mais informações" deste artigo. Use um dos seguintes métodos para resolver esse problema específico:

Solução alternativa 1

Empacotar o ponteiro de função como um representante e usar esse representante. Porque você não pode usar P/Invoke na mesma DLL, crie um invólucro DLL que ajuda você a empacotar um delegado para um ponteiro de função. Esta função exportada retorna o endereço do representante é passado para ele. O código de exemplo a seguir é um exemplo dessa 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 as extensões gerenciadas para C++ assembly usa 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

Divida seu assembly MEC ++ em duas DLLs, uma que contenha somente componentes gerenciados e outros que contém somente componentes não gerenciados e em seguida, usar P/Invoke conforme descrito na solução alternativa 2 cenário 1.

Situação

A Microsoft confirmou que este é um bug no Microsoft produtos que estão listados no início deste artigo.

Mais Informações

O problema é mais predominante se o aplicativo host ou o cliente deve descarregar e recarregar AppDomains e o aplicativo contém transições de código não gerenciado para código gerenciado que usam componentes MEC ++ e IJW. ASP.NET é um bom exemplo de como um host. No ASP.NET, os eventos que podem disparar um evento de descarregamento do AppDomain podem ser qualquer ultrapassem um limite de uso de memória para tocar determinados arquivos (por exemplo, Machine.config).

Etapas para reproduzir o problema

Neste exemplo, você tiver um aplicativo ASP.NET que chama um componente MEC ++, e esse componente tiver um ponteiro de função que aponta para um dos métodos no componente MEC ++. O componente passa o ponteiro de função para um destes procedimentos:
  • uma função que foi exportada por uma DLL não gerenciada
  • um método não gerenciado na mesma DLL
O código não gerenciado, em seguida, faz um retorno de chamada, utilizando o ponteiro de função que foi recebido do componente MEC ++.

Em cenários a seguir, é possível que, antes da função não gerenciada invoca o ponteiro de função, o AppDomain original em que a DLL foi carregada é descarregado. Sob tais condições, o código não gerenciado ainda faz referência o AppDomain original e tenta chamada para código gerenciado nesse contexto.
  • código não gerenciado para gerenciado código transição entre duas DLLs

    Chamar uma função DLL não gerenciada exportada a partir um MEC ++ assembly em uma das seguintes maneiras:
    • usando IJW
    • usando P/Invoke
    O código de exemplo a seguir usa uma DLL não gerenciada (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;
    }
    					
    um assembly C++ gerenciado possível chamar esse método por meio de IJW vinculando o Win32.lib e incluindo o arquivo de cabeçalho apropriado. O código de exemplo a seguir mostra como usar 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 gerenciado para gerenciado transição de código na mesma DLL

    Nesse cenário, o assembly MEC ++ contém métodos não gerenciados (marcados com # pragma não gerenciados ) que chamam métodos em um componente MEC ++ na mesma DLL, como mostrado no código de exemplo a seguir.
    #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 sites do Microsoft Developer Network (MSDN) da:
Domínios de aplicativo
http://msdn2.microsoft.com/en-us/library/cxk374d9(vs.71).aspx?frame=true

Classe AppDomain
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

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

Criando aplicativos ASP.NET
http://msdn.microsoft.com/en-us/library/aa719794.aspx

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

Propriedades

ID do artigo: 309694 - Última revisão: quinta-feira, 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 traduzido ou revisto por pessoas. A Microsoft possui artigos traduzidos por aplicações (MT) e artigos traduzidos por tradutores profissionais, com o objetivo de oferecer em português a totalidade dos artigos existentes na base de dados de suporte. No entanto, a tradução automática não é sempre perfeita, podendo conter erros de vocabulário, sintaxe ou gramática. A Microsoft não é responsável por incoerências, erros ou prejuízos ocorridos em decorrência da utilização dos artigos MT por parte dos nossos clientes. A Microsoft realiza atualizações freqüentes 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