C# - Események regisztrációja konzolalkalmazásokban

forráskód letöltése
A konzolalkalmazások világában nem beszélhetünk eseményvezérelt működésről, hiszen alapvetően nem a felhasználói bevitel határozza meg a program működésének menetét. A Windows API metódusok között azonban találunk egy függvényt, melynek segítségével bizonyos eseményeket elkaphatunk a programban, és ehhez a pillanathoz egy tetszőleges kezelőmetódust rendelhetünk (regisztrálhatunk). Ugyanitt van lehetőségünk ezt törölni is. Cikkünkben ennek részleteit tárjuk fel.
Minden konzol-process rendelkezik egy saját listával az alkalmazás számára definiált eseménykezelő rutinokból, melyek a CTRL+C és a CTRL+BREAK inputokat kezelik. Szintén ezek kezelik azokat az eseményeket, amikor az üzenetet a rendszer küldi, amikor a felhasználó bezárja az alkalmazást, kijelentkezik, vagy leállítja a rendszert.
A process-ek alapértelmezett működése szerint a kezelőrutin-lista kezdetben egyetlen kezelőfüggvényt tartalmaz, melynek neve ExitProcess. E mellé (az alapértelmezett működést felülírandó) van lehetőség programból eseménykezelőket deklarálni, melyekben már tetszőleges műveletek végezhetők el. Ennek módja, hogy egy tetszőleges, a programban definiált kezelőfüggvényt kell átadni a SetConsoleCtrlHandler metódusnak, mely regisztrálja a kezelőfüggvényt az adott eseményhez. Amennyiben a metódus második logikai paramétere TRUE értékű, akkor regisztráció, FALSE esetén annak törlésére kerül sor.
A kezelőrutin paramétere kötelezően a következő konstansok valamelyike kell, hogy legyen, melyek felölelik azoknak a billentyűkombinációknak az értékét, melyekre a kezelő regisztrálható.
CTRL_C_EVENT A CTRL+C üzenet érkezik az alkalmazáshoz, melyet a felhasználó küldött, vagy a GenerateConsoleCtrlEvent függvénnyel generáltunk.
CTRL_BREAK_EVENT A CTRL+BREAK üzenet érkezik az alkalmazáshoz, melyet a felhasználó küldött, vagy a GenerateConsoleCtrlEvent függvénnyel generáltunk.
CTRL_CLOSE_EVENT Az üzenet akkor érkezik a konzolhoz, amikor a felhasználó a konzolt bezárja manuálisan vagy a Feladatkezelő segítségével. Az üzenetet minden, a konzolt megosztó alkalmazás megkapja.
CTRL_LOGOFF_EVENT Az üzenet akkor érkezik, amikor a felhasználó kijelentkezik. Az üzenetet minden, a konzolt megosztó alkalmazás megkapja.
CTRL_SHUTDOWN_EVENT Az üzenet akkor érkezik, amikor a rendszer leáll.
Az alkalmazás egy új szálat indít az üzenet elfogására, és a kezelőmetódus futtatására, így előfordul, hogy a metódus egy másik szál jóvoltából terminál.
Az alkalmazásban két osztályt hoztunk létre. A UtilClass osztályban deklaráltuk a kezelőket, míg a MainClass osztály implementálja az alkalmazás belépési pontját a Main függvénnyel.
UtilClass osztály
A fenti táblázatban megismert konstansokhoz létrehoztunk egy felsorolt típust.
public enum EventList
{
  CTRL_C = 0,
  CTRL_BREAK = 1,
  CTRL_CLOSE = 2,
  CTRL_LOGOFF = 5,
  CTRL_SHUTDOWN = 6
}
Az API függvényt is deklarálnunk kell.
[DllImport("kernel32.dll")]
static extern bool SetConsoleCtrlHandler(CEHandler e, bool add);
Létrehozunk egy delegáltat, mely a kezelő típusa lesz.
public delegate void CEHandler(EventList e);
Továbbá létrehozunk egy eseményt, mely bekövetkezik, amikor a fenti üzenet valamelyike eljut a konzolhoz.
public event CEHandler MyEvent;
Az osztály konstruktorában létrehozunk egy példányt a delegáltból, majd regisztráljuk az eseménykezelőt.
CEHandler handler;
public UtilClass()
{
  handler = new CEHandler(HandlerMethod);
  SetConsoleCtrlHandler(handler, true);      
}
A paraméter metódusban példányosítjuk az eseményt, melyet a MainClass osztályban elkapunk.
private void HandlerMethod(EventList e)
{
  if (MyEvent != null)
    MyEvent(e);
}
MainClass osztály
Itt fogjuk a kezelőmetódust megvalósítani a fenti eseményekhez. Ennek neve MyHandler lesz.
public static void MyHandler(UtilClass.EventList e)
{
  Console.WriteLine("A következő esemény következett be: {0}", e);
}
A metódus kiírja a konstans üzenet nevét, mely a felhasználótól érkezett éppen, ha az alkalmazás indítása után például lenyomjuk a CRTL+C billentyűkombinációt.
A Main metódusban példányosítjuk a UtilClass osztályt, majd a kezelőmetódust megadjuk kezelőként.
UtilClass uc = new UtilClass();
uc.MyEvent += new UtilClass.CEHandler(MyHandler);
A program az „exit” szó beírásával bezárható.