注意: 當您使用的 AppDomainUnloaded 例外狀況管理 Visual C++ 元件的副檔名

文章翻譯 文章翻譯
文章編號: 309694 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

在此頁中

徵狀

呼叫對從 Unmanaged 程式碼包括不受管理-至-管理的直接呼叫,單一 DLL 內的 Managed 碼時,就會發生這個問題。比方說可能會發生這個問題時 MEC + + / IJW 用於 ASP.NET 應用程式。在 ASP.NET 中,各種事件可以導致重新載入至新的應用程式網域的應用程式。如果您使用 MEC + + 元件和 IJW 此應用程式中,您可能會收到 AppDomainUnloadException 錯誤訊息。

發生的原因

IJW 實作的一部份時使用 C + + 編譯器所建立的 Managed 的 DLL 會載入,執行階段建立轉換的 Thunk Unmanaged 程式碼從 Managed 程式碼。這些 Thunk 包含 DLL 載入的應用程式網域的參考。執行階段不會不重建這些 Thunk,如果一次載入 DLL ; 也,執行階段並不會更新參考時原始 AppDomain 卸載 DLL 會載入另一個應用程式網域中。

當程式執行的轉換 Unmanaged 程式碼從 Managed 程式碼過時的應用程式網域參考執行 Managed 程式碼的程式使用。即使原始的應用程式網域是仍載入,程式碼無法存取靜態欄位,因為欄位是特定的應用程式網域。

其他可行方案

下列因應措施群組根據至兩個案例:
  • 從 Unmanaged 程式碼轉換以跨越兩個 DLL 的 Managed 程式碼
  • 從 Unmanaged 程式碼轉換至同一個 DLL 中的 Managed 程式碼

Unmanaged 程式碼來管理跨兩個 DLL 程式碼轉換

使用下列方法之一來解決此問題。

解決方法 1

ASP.NET 用戶端的允許 ASP.NET 主機處理序關閉透過截獲 DomainUnload 事件。但是,您必須先註冊 DomainUnload 事件的委派。要這麼做,請您執行下列步驟:
  1. ASP.NET 應用程式 類別的 Application_Start] 方法中註冊要在 AppDomain 卸載時被呼叫的委派。
  2. 已註冊的委派中關閉 [Aspnet_wp.exe 處理序。
附註這項因應措施會使所有的 ASP.NET 應用程式上電腦重新啟動 ; 同處理序工作階段狀態資料,所有這些應用程式遺失。在網際網路資訊服務 (IIS) 6.0 執行 Windows 2003 伺服器的電腦上,您可以設定每一處理程序模式的一個應用程式的程式。如需有關 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

取代透過您使用委派 (也就是特定的應用程式網域) 來建立一個 Unmanaged 函式指標呼叫 Unmanaged 程式碼從 Managed 程式碼的所有轉換。委派是使用平台叫用服務 (P/Invoke),而非 IJW,封送處理至 Unmanaged 程式碼。

為未受管理的 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;
		}
	};
}
				

Unmanaged 程式碼,在同一個 DLL 中的 Managed 程式碼轉換

在這種情況下您可以擁有 Unmanaged 方法 (以 # pragma Unmanaged 標示) 呼叫同一個 DLL 中的 Managed 元件上的方法,如本文 < 其他相關資訊 > 一節中所示。使用下列方法之一來解決這個特定問題:

解決方法 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 + + 組件,一個包含只管理元件,其他的包含只 Unmanaged 的元件,然後使用 P/Invoke,因應措施 2 的案例 1 中所述。

狀況說明

Microsoft 已確認這是在 Microsoft 中的錯誤,會列在本文開頭的產品。

其他相關資訊

如果主機或用戶端應用程式必須卸載和重新載入 AppDomain 以及應用程式包含轉換 Unmanaged 程式碼從 Managed 程式碼使用 MEC + + 和 IJW 元件的問題是更普遍的。ASP.NET 是一個這類主機極佳範例。在 ASP.NET,可以觸發 AppDomain 卸載事件的事件可以是從以接觸某些檔案,例如是 Machine.config 跨過記憶體使用量臨界值的任何項目。

重製行為的步驟

在此範例您有一個呼叫 MEC + + 元件的 ASP.NET 應用程式,而且此元件具有指向其中一個方法 MEC + + 元件中的函式指標。元件會將函式指標傳遞至下列其中一項:
  • 不受管理的 DLL 所匯出的函式
  • 同一個 DLL 中的 Unmanaged 的方法
Unmanaged 程式碼再讓回呼藉由使用接收自 MEC + + 元件將函式指標。

在下列情況中很可能,Unmanaged 函式會叫用函式指標之前,是卸載 DLL 已載入的原始應用程式網域。在這種情況下 Unmanaged 程式碼,仍會參考原始的應用程式網域,並且嘗試呼叫該內容中的 Managed 程式碼。
  • Unmanaged 程式碼] 來管理跨兩個 DLL 的程式碼轉換

    從 + 一個 MEC + 呼叫 Unmanaged 可匯出的 DLL 函式組件中的下列方法之一:
    • 藉由使用 IJW
    • 藉由使用 P/Invoke
    下列範例程式碼會使用匯出方法的 Unmanaged 的 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 Managed C + + 組件可以呼叫這個方法,透過 IJW,藉由連結到 [Win32.lib 以及包括適當的標頭檔。下列範例程式碼示範如何使用匯出的方法。
    #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;
    		}
    	};
    }
    					
  • Unmanaged 程式碼] 來管理相同 DLL 中的程式碼轉換

    在這種情況下 MEC + + 組件包含 Unmanaged 的方法 (以 # pragma Unmanaged 標示) 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

應用程式網域類別
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 Standard Edition
  • Microsoft .NET Framework 1.0
關鍵字:?
kbmt kbbug kbijw kbmanaged kbpending KB309694 KbMtzh
機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本: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