2013-05-21 35 views
6

C存在atexit函數,它正常進程退出時的.NET代碼執行?

的atexit對()函數註冊給定的功能在正常的過程終止時被調用,或者通過出口(3),或通過從返回程序的main()。

Python有類似的功能。

.NET是否提供了在正常進程終止時調用代碼的方法?我知道有一些像DomainUnloadProcessExit這樣的東西,但至少據我所知,這些都不可靠 - 要麼將應用程序變成Windows窗體(或WPF應用程序)或其他東西。我正在編寫一個.dll的代碼,所以我不能依賴像主程序函數那樣的東西 - 將它封裝在try/catch中。

我的最終目標是執行一些文件清理(即刷新緩衝區並關閉)。如果我可以調用一些非託管代碼,例如一個win32api鉤子什麼的,我完全沒錯。

+0

您可以嘗試SetConsoleCtrlHandler的CTRL_CLOSE_EVENT事件。 http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx – 2013-05-21 15:16:54

回答

6

我知道沒有直截了當的答案。

如果你想要寫一個強大的DLL,你應該幾個場景做準備:

  1. 你的代碼是在.NET應用程序託管,在默認的AppDomain。 (微不足道的場景)
  2. 您的代碼託管在.NET應用程序中,位於由主機代碼創建的AppDomain中。
  3. 您的代碼託管在非託管應用程序(託管CLR)中。

第三種情況是最難處理的,因爲CLR可以被其主機禁用,所以託管代碼將不再執行。

System.Windows.Forms.Application.ApplicationExit是不好的,因爲它只適用於WinForm應用程序。

System.AppDomain.DomainUnload本身並不好,因爲它從來沒有爲默認AppDomain提出。

AppDomain.ProcessExit本身並不好:如果您的代碼託管在單獨的AppDomain中,主機可能會卸載該AppDomain,因此事件永遠不會升起。

我試圖覆蓋大多數情況下,使用類似的開始:

if (AppDomain.CurrentDomain.IsDefaultAppDomain()) 
    AppDomain.CurrentDomain.ProcessExit += MyTerminationHandler; 
else 
    AppDomain.CurrentDomain.DomainUnload += MyTerminationHandler; 

但做注意到下面的備註(from MSDN):

所有ProcessExit事件的總執行時間處理程序是有限的,就像在過程關閉時所有終結器的總執行時間是有限的。默認值是兩秒。非託管主機可以通過使用OPR_ProcessExit枚舉值調用ICLRPolicyManager :: SetTimeout方法來更改此執行時間。

上述代碼仍然使第三種情況無人看管。 有兩種方法,我知道的與該方案處理(連同前兩個)

首先,你可以使用System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup方法,如下所示:

{ 
// this goes at your code's entry point 
    RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup(MyExecutionCode, MyCleanupCode, null); 
} 
static void MyExecutionCode(object data) { /* your execution code here */} 
static void MyCleanupCode(object data, bool exceptionThrown) { /* your cleanup code here */ } 

其次,你可以利用System.Runtime.ConstrainedExecution.CriticalFinalizerObject類(see MSDN here)通過繼承它並將清理代碼放入終結器中。這要求您的清理代碼遵守Constrained Execution Region準則。

+0

我認爲要麼我要去'CriticalFinalizerObject',要麼使用'Critical/SafeHandle'。實際上,我今天偶然發現了這個,但沒有時間來實現/測試它,但我認爲它應該提供我想要的。 –