C# - Meghajtóban felejtett CD-lemez jelzése rendszerleálláskor

forráskód letöltése
Bizonyára mindenkivel előfordult már, hogy miután kikapcsolta a számítógépet, vette csak észre, hogy a CD-meghajtóban felejtett egy CD-lemezt, melyre szüksége lenne. Ilyenkor sajnos újra kell indítani a gépet. Cikkünkben elkészítünk egy példaalkalmazást, mely a háttérben futva figyeli a rendszerleállás eseményét, és lemez érzékelésekor a meghajtó tálcájának nyitásával jelzi ezt a felhasználónak.
Példaprogramunk a háttérben futva figyeli a rendszer leállításakor a rendszer által küldött WM_ENDSESSION üzenetet. Amikor ezt – mint minden alkalmazás – megkapja, akkor végigpásztázza a meghajtókat, és a CD-meghajtó foglaltsága – olvasásra kész állapota – esetén megnyitja a tálcát.
Ennek érdekében használnunk kell a Microsoft Scripting Runtime komponenst, melyet referenciaként a programunkhoz kell adnunk. Miután a COM komponens-palettáról ezt megtettük, a forráskód elején a következőképpen hivatkozhatunk rá:
using Scripting;
A háttérben futó alkalmazás DefWndProc függvényének felüldefiniálásával érhetjük el, hogy az alkalmazás figyelje a WM_ENDSESSION üzenetet. Ennek észlelésekor már nem tudjuk megakadályozni a rendszerleállást. Ha észrevesszük, hogy lemez van a meghajtóban – és elég gyorsak vagyunk - még kivehetjük azt onnan, de ha nem, az menthetetlenül bent marad. Kapjuk el tehát ezt az üzenetet.
protected override void WndProc(ref Message message)
{
  if (message.Msg == WM_ENDSESSION)
  {
Ha az üzenetet már elkaptuk, akkor már csak a meghajtó-lista végigpásztázása van hátra. Ehhez példányosítjuk a Scripting komponens néhány osztályát, elsőként a FileSystemObject osztályt.
    Scripting.FileSystemObject fso = new Scripting.FileSystemObject();
Az osztály segítségével lekérdezzük a meghajtók objektumait.
    IEnumerator ie = fso.Drives.GetEnumerator();
Egy-egy meghajtó objektumát az IDrive interfész reprezentálja.
    IDrive id;
Egy ciklussal végighaladunk a meghajtók listáján, majd az aktuális meghajtó típusának meghatározása következik.
    while (ie.MoveNext())
    {
      id = (Scripting.IDrive)ie.Current;
Amennyiben a meghajtó típusa CD-meghajtó, és készen áll a használatra – vagyis van bent egy lemez - akkor meghívjuk a Winmm.dll dinamikus könyvtár mciSendString metódusát, melyben egy szöveges paranccsal bírhatjuk rá a CD-meghajtónkat, hogy kinyissa az ajtaját.
      if (id.DriveType == Scripting.DriveTypeConst.CDRom && id.IsReady)
      {
        mciSendString("set cdaudio door open",out ptr,0,0);
      }
    }
A háttérben futó alkalmazáshoz rendeltünk egy gyorsmenüt, aminek megjelenítéséhez néhány API függvényt hívunk meg.
POINT point = new POINT();
Deklaráltunk egy struktúrát, mely az egérkurzor aktuális helyzetét tartalmazza a GetCursorPos metódus meghívása után.
GetCursorPos(out pp);
Aktivizáljuk az ikon objektumot reprezentáló Form-ot.
SetForegroundWindow(this.Handle);
Majd meghívjuk a ContextMenu objektum – mely az alkalmazás tagobjektuma – OnPopup metódusát.
contextMenu1.GetType().InvokeMember("OnPopup", BindingFlags.NonPublic|BindingFlags.InvokeMethod|BindingFlags.Instance, null, contextMenu1, new Object[] {System.EventArgs.Empty});
Végül a TrackPopupMenuEx metódus segítségével megjelenítjük a menüt az egér pozíciójában.
TrackPopupMenuEx(contextMenu1.Handle, 64, pp.x, pp.y, this.Handle, IntPtr.Zero);
A menü az egér jobb gombjának lenyomásakor aktivizálódik, és segítségével az alkalmazás leállítható.