2012-03-27 19 views
8

Piszę aplikację C#, która musi przesłać plik, gdy konsola jest zamknięta (czy to za pomocą przycisku X, czy komputer jest zamknięty).Czy uruchomić kod na konsoli?

Jak mogę to zrobić?

AppDomain.CurrentDomain.ProcessExit += new EventHandler (OnExit); 

działa tylko kiedy wydać komendę exit do konsoli, a nie kiedy uderzę czerwony przycisk zamykania.

Odpowiedz tylko, jeśli rozwiązanie działa zarówno gdy konsola jest zamknięta za pomocą przycisku X, jak i po wyłączeniu komputera (zwykle przez system Windows, wiem, że nie można, jeśli zasilanie jest wyciągnięte xD).

+3

przykro mów ale istnieją scenariusze, gdzie proces zostanie zabity, więc nie można uzyskać to do pracy w każdym możliwym przypadku (może widziałeś go na Win7 gdzie uruchomisz wyłączenie i system poinformuje cię, że niektóre procesy uniemożliwiają zamknięcie systemu i możesz je zakończyć) – Carsten

+0

@ CarstenKönig Rozumiem, że są takie sytuacje, ale chcę, aby działały przynajmniej w normalnym procesie wyłączania w przypadku, gdy użytkownik nie wymusza zamknięcia aplikacji. –

+0

możliwy duplikat http://stackoverflow.com/questions/474679/capture-console-exit-c-sharp –

Odpowiedz

10

Trzeba wywołać Win32 API, aby to zrobić, wystarczy rzucić okiem na ten post tutaj http://social.msdn.microsoft.com/Forums/en-US/csharpgeneral/thread/707e9ae1-a53f-4918-8ac4-62a1eddb3c4a/

I skopiowany odpowiedni kod dla was stamtąd:

class Program 

{ 
    private static bool isclosing = false; 

    static void Main(string[] args) 
    { 
     SetConsoleCtrlHandler(new HandlerRoutine(ConsoleCtrlCheck), true); 

     Console.WriteLine("CTRL+C,CTRL+BREAK or suppress the application to exit"); 

     while (!isclosing) ; 
    } 

    private static bool ConsoleCtrlCheck(CtrlTypes ctrlType) 
    { 
     // Put your own handler here 

     switch (ctrlType) 
     { 
      case CtrlTypes.CTRL_CLOSE_EVENT: 
       isclosing = true; 
       Console.WriteLine("Program being closed!"); 
       break; 
     } 

     return true; 
    } 

    #region unmanaged 
    // Declare the SetConsoleCtrlHandler function 
    // as external and receiving a delegate. 

    [DllImport("Kernel32")] 
    public static extern bool SetConsoleCtrlHandler(HandlerRoutine Handler, bool Add); 

    // A delegate type to be used as the handler routine 
    // for SetConsoleCtrlHandler. 
    public delegate bool HandlerRoutine(CtrlTypes CtrlType); 

    // An enumerated type for the control messages 
    // sent to the handler routine. 

    public enum CtrlTypes 
    { 
     CTRL_C_EVENT = 0, 
     CTRL_BREAK_EVENT, 
     CTRL_CLOSE_EVENT, 
     CTRL_LOGOFF_EVENT = 5, 
     CTRL_SHUTDOWN_EVENT 
    } 

    #endregion 
} 

robi dokładnie czego potrzebujesz.

Pozdrowienia,

+0

To działa idealnie! –

0

Może być coś takiego (przy założeniu, że prawo rozumieć poprosić)

//get all command windows in the system 
Process[] processes = Process.GetProcessesByName("cmd"); 


// find that one you interested in 
Process mypro; 

Subskrybuj Process.Exited razie to jak

mypro.Exited += (s,e) => 
{ 
    //here upload the file 
} 

Jeżeli pracy dla Ciebie.

+0

Myślę, że nigdy nie powinieneś tego robić! bo co, jeśli istnieje więcej niż jeden proces zwany "cmd". Jeśli chcesz zasubskrybować ten proces, dodaj trochę filtrowania do kodu, e.h. nazwa okna procesu, a nie sam proces. –

+0

@ MarioFraiß: pewnie. W moim poście pominięto opowieść o tym, w jaki sposób zlokalizowany jest ten * proces cmd. Potrzebujesz "mocnego klucza", aby móc znaleźć żądanie 'cmd.exe'. – Tigran

1

Ja też chciałbym sugerować należy zapisać to, co chcesz, aby przesłać na później, więc nie zostały złamane/nieprawidłowych plików przesłanych. W ten sposób przy następnym uruchomieniu aplikacji można przesłać. Ten przynajmniej działa na układ wylogowanie/wyłączeń:

SystemEvents.SessionEnding += (SystemEvents_SessionEnding); 

private static void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e) 
{ 
    //code to run on when user is about to logoff or shutdown 
} 
Powiązane problemy