2013-05-21 13 views
6

W C jest funkcja atexit, które. Wykonywanie kodu .NET przy normalnym wychodzeniu procesu?

Funkcja atexit() Rejestruje funkcja do wykonania w normalnej zakończeniu procesu, albo przez wyjście (3) lub z powrotem z programu MAIN().

Python ma podobne możliwości.

.NET. Zapewnia sposób wywołania kodu przy normalnym zakończeniu procesu? Wiem, że są pewne rzeczy, takie jak DomainUnload i ProcessExit, ale przynajmniej z tego co wiem, są one niewiarygodne - albo wymagają, aby aplikacja była aplikacją Windows Forms (lub WPF), czy czymś innym. Piszę kod dla .dll, więc nie mogę polegać na takich rzeczach, jak mucking z główną funkcją programu - owijanie jej w try/catch.

Moim ostatecznym celem jest wykonanie czyszczenia niektórych plików (tj. Bufory płukania i zamknięcie). Jeśli mogę zadzwonić do niezarządzanego kodu, np. hak win32api czy coś takiego, jestem z tym doskonale w porządku.

+0

Możesz spróbować zdarzenia CTRL_CLOSE_EVENT SetConsoleCtrlHandler. http://msdn.microsoft.com/en-us/library/windows/desktop/ms686016%28v=vs.85%29.aspx –

Odpowiedz

6

Nie ma prostej odpowiedzi, którą znam.

Jeśli chcesz napisać solidną DLL, należy przygotować kilka scenariuszy:

  1. Kod jest obsługiwana w aplikacji .NET, w domyślnym AppDomain. (banalny scenariusz)
  2. Twój kod jest hostowany w aplikacji .NET w AppDomain utworzonym przez kod hosta.
  3. Twój kod jest przechowywany w niezarządzanej aplikacji (która jest hostem CLR).

Trzeci scenariusz jest najtrudniejszy do rozwiązania, ponieważ CLR może być wyłączony przez hosta, więc kod zarządzany nie będzie już wykonywany.

System.Windows.Forms.Application.ApplicationExit nie jest dobry, ponieważ dotyczy tylko aplikacji WinForm.

System.AppDomain.DomainUnload samo w sobie nie jest dobre, ponieważ nigdy nie jest wywoływane z domyślnym AppDomain.

AppDomain.ProcessExit samo w sobie nie jest dobre: ​​jeśli twój kod jest hostowany w oddzielnym AppDomain, host może zwolnić tę aplikację AppDomain, więc wydarzenie nigdy się nie podniesie.

zacząłbym od próby na pokrycie większości przypadków, używając coś takiego:

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

Ale zrobić zauważyć następującą uwagę (from MSDN):

Całkowity czas wykonania całej imprezy ProcessExit Obsługa handlowa jest ograniczona, podobnie jak całkowity czas wykonania wszystkich finalizatorów jest ograniczony przy zamykaniu procesu. Wartość domyślna to dwie sekundy. Host niezarządzany może zmienić ten czas wykonywania, wywołując metodę ICLRPolicyManager :: SetTimeout z wartością wyliczenia OPR_ProcessExit.

Powyższy kod nadal pozostawia trzeci scenariusz bez nadzoru. Istnieją dwie metody znam do czynienia z tego scenariusza (wraz z dwoma pierwszymi)

pierwsze, można użyć metody System.Runtime.CompilerServices.RuntimeHelpers.ExecuteCodeWithGuaranteedCleanup, w następujący sposób:

{ 
// 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 */ } 

Po drugie, można wykorzystać System.Runtime.ConstrainedExecution.CriticalFinalizerObject klasa (see MSDN here), dziedzicząc go i umieszczając kod oczyszczający w finalizatorze. Wymaga to, aby kod porządkowy był zgodny z wytycznymi Constrained Execution Region.

+0

Myślę, że albo mam zamiar użyć 'CriticalFinalizerObject', albo użyć "Krytyczne/SafeHandle". Właśnie natknąłem się na to dzisiaj, ale nie miałem czasu na wdrożenie/przetestowanie tego, ale myślę, że powinno to zapewnić to, czego chcę. –

Powiązane problemy