BOGUE : exception AppDomainUnloaded si vous utilisez a géré des extensions pour les composants Visual C++

Traductions disponibles Traductions disponibles
Numéro d'article: 309694 - Voir les produits auxquels s'applique cet article
Agrandir tout | Réduire tout

Sommaire

Symptômes

Ce problème se produit lorsqu' un appel est effectué à partir de code non géré de code managé, permettant d'inclure des appels directs non managé-managé dans un seul DLL. Le problème peut se par exemple produire+/ IJW est utilisé dans les applications ASP.NET quand MEC+. Dans ASP.NET, les remarques différentes événement peuvent provoquer des applications à être rechargé dans un nouvel AppDomain. Si vous utilisez les composants MEC++ et IJW dans cette application, un message AppDomainUnloadException d'erreur peut s'afficher.

Cause

Lorsqu' est un DLL managé que vous avez créé en utilisant le compilateur C++ chargé, le runtime dans le cadre de la mise en ?uvre d'IJW, crée thunk pour transitions de code managé à partir de code non géré. Ces thunk contiennent une référence à AppDomain dans lequel le DLL se charge. Le runtime ne recrée pas ces thunk si le DLL se charge à nouveau; le runtime ne met également à jour pas la référence lorsque l'AppDomain d'origine est déchargé et est dans un autre AppDomain le DLL chargé.

Lorsque le programme effectue une transition de code managé à partir de code non géré, le programme utilise la référence obsolète AppDomain pour exécuter le code managé. Même si l'AppDomain d'origine est quand même chargé, le code ne peut pas accéder à des champs statiques parce que les champs sont spécifiques à AppDomain.

Contournement

Les solutions suivantes sont regroupées d'après deux scénarios :
  • Une transition de code managé à travers deux DLL à partir de code non géré
  • Une transition de code managé dans le même DLL à partir de code non géré

Code non géré a géré la transition de code à travers deux DLL

Appliquez une des méthodes suivantes pour résoudre ce problème spécifique en respectant.

Solution de contournement 1

Pour les clients ASP.NET, autorisez le processus ASP.NET hôte à s'arrêter en interceptant l'événement DomainUnload. Vous devez d'abord cependant enregistrer un délégué pour l'événement DomainUnload. Exécutez les procédures pour cela :
  1. Dans la méthode Application Start de la classe Application ASP.NET, enregistrez un délégué appelé quand l'AppDomain est déchargé.
  2. Dans le délégué enregistré, arrêtez le processus Aspnet_wp.exe.
Remarque cette solution de contournement provoque toutes les applications ASP.NET de l'ordinateur à redémarrer; la donnée in-process d'état de session pour toutes ces applications est perdue. Dans Internet Information Service ( IIS ) 6.0 sur un ordinateur qui exécute Windows Server 2003, vous pouvez configurer le programme pour une application par mode de processus. Pour plus d'informations sur le pool d'applications configuing, reportez-vous au site Web de Microsoft à l'adresse suivante :
http://www.microsoft.com/technet/prodtechnol/windowsserver2003/proddocs/standard/ca_cfgapppools.asp?frame=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);
}
				

Solution de contournement 2

Remplacer toutes les transitions de code managé à partir de code non géré appels via un pointeur de fonction non gérée que vous créez en utilisant un délégué (qui correspond à AppDomain spécifique). Le délégué est marshalé du code non géré en utilisant services d'appel de la plate-forme ( P/Invoke) au lieu d'IJW.

L'exemple de code suivant pour le DLL non géré décrit dans la section "Plus d'informations" de cet article illustre l'utilisation de P/Invoke pour utiliser la méthode de rappel :
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;
		}
	};
}
				

Code de code managé transition dans le même DLL non géré

Dans ce scénario vous pouvez avoir unmanage méthodes (marquées avec #pragma unmanaged) appeler des méthodes sur un composant managé dans le même DLL comme être montrées dans la section "Informations complémentaires" de cet article. Appliquez une des méthodes suivantes pour résoudre ce problème spécifique en respectant :

Solution de contournement 1

Assemblez votre pointeur de fonction en tant que délégué et utilisez le délégué. Parce que vous ne pouvez pas appliquer P/Invoke à même DLL, créez un wrapper DLL qui vous aide à assembler un délégué en un pointeur de fonction. Cette fonction exportée renvoie l'adresse du délégué qui est transmis à lui. L'exemple de code suivant est un exemple de cette solution de contournement :
//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;
}
				
L'exemple de code suivant est des extensions managées pour assemblys C++ qui utilise l'Helper.dll précédent :
#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();
     }
}
				

Solution de contournement 2

Une qui contient a votre assembly MEC++ en deux DLL fractionnés géré uniquement des composants, contient seulement les composants non gérés et autre qui utilise ensuite P/Invoke comme décrire à la solution de contournement 2 de scénario 1.

Statut

Microsoft a confirmé l'existence de ce bogue dans les produits Microsoft répertoriés au début de cet article

Plus d'informations

Le problème est plus répandu si l'application hôte ou client doit décharger et doit recharger AppDomains et si l'application contient les transitions de code managé à partir de code non géré qui utilisent les composants MEC++ et IJW. ASP.NET est de d'un tel hôte l'un bon exemple. Dans ASP.NET, les événements qui peuvent déclencher un événement de déchargement AppDomain peuvent faire quelque chose de traverser un seuil de mémoire d'utilisation à toucher certains fichiers (par exemple Machine.config).

Procédure à suivre pour reproduire le problèm

Dans cet exemple, vous possédez une application ASP.NET qui appelle un composant MEC++ et ce composant possède un pointeur de fonction qui pointe à une des méthodes dans le composant MEC++. Le composant passe le pointeur de fonction à l'un du suivant :
  • Une fonction qui a été exportée par un DLL non géré
  • Une méthode dans le même DLL non gérée
Le code non géré rend puis un rappel en utilisant le pointeur de fonction qui a été reçu à partir du composant MEC++.

Il est dans les scénarios suivants possible qu'avant que la fonction non gérée appelle le pointeur de fonction, l'AppDomain d'origine dans lequel le DLL a été chargé est déchargé. Dans les conditions telles le code non géré référence l'AppDomain d'origine et tente quand même d'appeler de code managé dans le contexte.
  • Code non géré a géré la transition de code à travers deux DLL

    Appelez une fonction exportée de DLL non gérée d'une des manières suivantes à partir d'un assembly MEC++ :
    • Par utiliser IJW
    • Par utiliser P/Invoke
    Le code exemple suivant utilise un DLL non géré (Win32.dll) qui exporte une méthode.
    //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;
    }
    					
    Un assemblys C++ managé peut appeler cette méthode à travers IJW en liant à Win32.lib et en incluant le fichier d'en-tête approprié. Le code exemple suivant montre comment utiliser la méthode exportée.
    #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;
    		}
    	};
    }
    					
  • Code de code managé transition dans le même DLL non géré

    Dans ce scénario, l'assembly MEC++ contient les méthodes non gérées (marquées avec #pragma unmanaged) qui appellent des méthodes sur un composant MEC++ dans le même DLL comme l'illustré dans le code exemple suivant.
    #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();
         }
    }
    					

Références

Pour plus d'informations reportez-vous aux sites Web MSDN (Microsoft Developer Network) aux adresses suivantes
Domaines d'application
http://msdn2.microsoft.com/en-us/library/cxk374d9(vs.71).aspx?frame=true

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

AppDomainUnloadedException Class
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemAppDomainUnloadedExceptionClassTopic.asp?frame=true

Extensions managées pour la programmation en C++
http://msdn2.microsoft.com/en-us/library/aa712574(vs.71).aspx

Création d'applications Web ASP.NET
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconcreatingaspwebapplications.asp?frame=true

Mode d'isolation du processus de travail
http://www.microsoft.com/technet/prodtechnol/windowsserver2003/proddocs/standard/ca_wpim.asp?frame=true

Propriétés

Numéro d'article: 309694 - Dernière mise à jour: jeudi 17 mai 2007 - Version: 4.6
Les informations contenues dans cet article s'appliquent au(x) produit(s) suivant(s):
  • Microsoft Visual C++ .NET 2002 Standard Edition
  • Microsoft .NET Framework 1.0
Mots-clés : 
kbbug kbijw kbmanaged kbpending KB309694 KbMtfr kbmt
Traduction automatique
IMPORTANT : Cet article est issu du système de traduction automatique mis au point par Microsoft (http://support.microsoft.com/gp/mtdetails). Un certain nombre d?articles obtenus par traduction automatique sont en effet mis à votre disposition en complément des articles traduits en langue française par des traducteurs professionnels. Cela vous permet d?avoir accès, dans votre propre langue, à l?ensemble des articles de la base de connaissances rédigés originellement en langue anglaise. Les articles traduits automatiquement ne sont pas toujours parfaits et peuvent comporter des erreurs de vocabulaire, de syntaxe ou de grammaire (probablement semblables aux erreurs que feraient une personne étrangère s?exprimant dans votre langue !). Néanmoins, mis à part ces imperfections, ces articles devraient suffire à vous orienter et à vous aider à résoudre votre problème. Microsoft s?efforce aussi continuellement de faire évoluer son système de traduction automatique. Si vous relevez des erreurs graves et souhaitez contribuer à l?amélioration du système, vous pouvez compléter l?enquête à votre disposition dans le bas des articles.
La version anglaise de cet article est la suivante: 309694
L'INFORMATION CONTENUE DANS CE DOCUMENT EST FOURNIE PAR MICROSOFT SANS GARANTIE D'AUCUNE SORTE, EXPLICITE OU IMPLICITE. L'UTILISATEUR ASSUME LE RISQUE DE L'UTILISATION DU CONTENU DE CE DOCUMENT. CE DOCUMENT NE PEUT ETRE REVENDU OU CEDE EN ECHANGE D'UN QUELCONQUE PROFIT.

Envoyer des commentaires

 

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