HyperLink


Bejelentkezés
E-mail: 
Jelszó: 






Skip Navigation Links
 

Vágólap tartalom változásának figyelése programból


Példaprogram letöltése

9975 bájt

Mellékelt példában készítünk egy olyan komponenst, melyet feltéve a Form-ra az adott alkalmazás képes lesz érzékelni azt, hogy ha a Windows vágólapján lévő tartalom megváltozik, attól függetlenül, hogy ezt a változtatást, mely program idézte elő. Amikor ez a változás bekövetkezik, akkor jön létre a komponens ClipboardChanged eseménye.

A megoldás a WM_DRAWCLIPBOARD esemény figyelésére épül. Minden olyan alkalmazás, mely kéri a Windows-tól, hogy kapjon értesítést akkor, ha a vágólap tartalma változott, az kap egy WM_DRAWCLIPBOARD eseményt. Ha tehát ezt figyeljük programból és amikor ez bekövetkezik nincs más dolgunk, mint kiolvasni a vágólap aktuális tartalmát és máris rendelkezdésünkre áll az az információ, hogy aktuálisan mi is került a vágólapra.
A megvalósítása ennek már valamivel bonyolultabb, főleg ha egy könnyen felhasználható komponens formájában szeretnénk elkészíteni. Problémába ütközünk ott például, hogy egy komponens nem kap Windows üzeneteket, gond az is, hogy olyan Windows függvények hívására van szükség, melyek a .NET-ben nincsenek meg közvetlenül. Ez persze nem jelenti azt, hogy a feladat kivitelezhetetlen. Kezdjük el a megoldást az alapoktól felépíteni.
Class3.cs
A Class3 forráskódjában létrehozunk egy osztályt Win32 névvel, melyben megadjuk azokat a Windows függvényeket, melyekre a későbbiekben szükségünk lesz. A függvényeket kívül néhány konstans értékét is tároljuk el.
  public class Win32
  {
    public const int WM_CHANGECBCHAIN = 0x030D;
    public const int WM_DRAWCLIPBOARD = 0x0308;
    public const int HWND_MESSAGE = -3;
Szükségünk lesz a SendMessage Windows függvényre, mellyel üzeneteket küldhetünk majd a Windows programjai, ablakai között.
    [DllImport("user32.dll", EntryPoint="SendMessageW")]
    public static extern int SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
A SetClipboardViewer függvény segítségével kérhetjük meg a Windows-t arra, hogy értesítse függvényünk a paraméterében megadott ablakot abban az esetben, ha változik a vágólap tartalma. Ennek az ablaknak fogja majd a WM_DRAWCLIPBOARD üzenetet küldeni.
    [DllImport("user32.dll", ExactSpelling=true)]
    public static extern IntPtr SetClipboardViewer(IntPtr hWndNewViewer);
A ChangeClipboardChain függvény hívásával azt tudathatjuk a Windows-al, hogy a továbbiakban már nem tartunk igényt a WM_DRAWCLIPBOARD üzenetre.
    [DllImport("user32.dll", ExactSpelling=true)]
    public static extern int ChangeClipboardChain(IntPtr hWndRemove, IntPtr hWndNewNext);
  } 
Class2.cs
Szükségünk lesz a készítendő komponensen belül egy olyan ablakra, mely képes a Windows üzenetek fogadására. Ezt az ablakkezelő osztályt hozzuk létre a Class2-ben. Ehhez a NativeWindow osztályt használjuk fel, mely rendelkezik ablakazonosítóval (Handle) és üzenetkezelő függvénnyel (WndProc). Új osztályunkat tehát ebből, valamint az IDisposable interfészből származtatjuk. Utóbbit arra használhatjuk, hogy kezelni tudjuk az objektumunk megszűnésének tényét, melyre nyilván akkor lesz szükségünk, mikor megszűnik a komponensünk. Ekkor értesítenünk kell a Windows-t, hogy a továbbiakban már nem kérjük a WM_DRAWCLIPBOARD üzenetet, hiszen megszűnt az eseménykezelő ablakunk.
  public class ClipboardViewerWindow: NativeWindow, IDisposable 
  {
Létrehozunk egy Create függvényt, melyet majd kívülről fogunk meghívni az objektum létrejötte után. Ez a függvény hozza létre az ablakkezelő azonosítóját, melyhez a NativeWindow osztály CreateHandle függvényét kell meghívni. Win 2000 felett jeleznünk kell, hogy az üzenetkezelő ablakunk semmi mással nem szeretne foglalkozni, mint az üzenetek kezelésével, vagyis nem jelenik meg valós ablak a képernyőn. Ezt a HWND_MESSAGE konstans felhasználásával tehetjük meg.
    public void Create() 
    {
      CreateParams cp = new CreateParams();
      if (Environment.OSVersion.Version.Major >= 5)
      {
        cp.Parent = (IntPtr)Win32.HWND_MESSAGE;
      }
      CreateHandle(cp);
    }
Felülírva a NativeWindow osztály CreateHandle függvényét, értesülhetünk arról, hogy melyik az a pillanat, amikor már rendelkezésre áll ablakkezelő osztályunk azonosítója. Ekkor van lehetőségünk arra, hogy a SetClipboardViewer függvény hívásával megadjuk a Windows-nak, hogy melyik az az azonosító (Handle), mely igényli a WM_DRAWCLIPBOARD üzenetet. A függvény visszatérési értékeként kapunk egy másik ablak azonosítóját. Ezt egyelőre csak tároljuk a későbbi felhasználás érdekében.
    public override void CreateHandle(CreateParams cp) 
    {
      base.CreateHandle(cp);
      nextHwnd = Win32.SetClipboardViewer(Handle);
    }
Amikor majd megszűnik az objektumunk, akkor kerül meghívásra a DestroyHandle is. Ezt szintén felülírjuk, hogy értesüljünk róla. Ekkor kell a Windows-t értesítünk arról, hogy a továbbiakban nem kérjük a WM_DRAWCLIPBOARD üzenetet. Ehhez a ChangeClipboardChain függvényt hívjuk, melynek első paraméterében a saját ablakunk azonosítóját adjuk meg, míg a második paraméterben a SetClipboardViewer függvény által adott értéket.
    public override void DestroyHandle() 
    {
      Win32.ChangeClipboardChain(Handle, nextHwnd);
      base.DestroyHandle();
    }
Ha most felülírjuk a NativeWindow osztály WndProc függvényét, akkor ezen keresztül figyelhetjük a Windows üzeneteket.
    protected override void WndProc(ref Message m) 
    {
      switch (m.Msg)
      {
Ha tehát a WM_DRAWCLIPBOARD üzenetet kapjuk, akkor biztosak lehetünk benne, hogy a vágólap tartalma megváltozott. Ekkor meghívjuk OnChanged belső függvényünket, mely elindítja majd a komponens eseményének aktivizálását. További teendőnk, hogy az üzenetet továbbítsuk a soron következő ablaknak, mely kérte a WM_DRAWCLIPBOARD üzenetet. Hogy melyik is ez az ablak, azt a SetClipboardViewer függvény visszatérési értékéből már tudhatjuk, melyet tároltunk is egy változóban. Így az alkalmazások szép sorban egymást értesítik a WM_DRAWCLIPBOARD üzenetről.
        case Win32.WM_DRAWCLIPBOARD:
            OnChanged();
            Win32.SendMessage(nextHwnd, Win32.WM_DRAWCLIPBOARD, m.WParam, m.LParam);
          break;
Van még egy esemény melyet figyelnünk kell a helyes működés érdekében. Ez a WM_CHANGECBCHAIN, mely akkor jön létre, hogy egy alkalmazás jelzi a Windows-nak, hogy a továbbiakban már nem kívánja megkapni a WM_DRAWCLIPBOARD üzenetet. Ekkor lehet, hogy pont az általunk eltárolt azonosítójú ablakról van szó. Ha ez így lenne, akkor cserélnünk kell a változónk tartalmát egy új ablak azonosítóra. Ha nem így van, akkor tovább küldjük a WM_CHANGECBCHAIN üzenetet is.
        case Win32.WM_CHANGECBCHAIN:
          if (nextHwnd == m.WParam)
          {
            nextHwnd = m.LParam;
          }
          else
          {
            Win32.SendMessage(nextHwnd, Win32.WM_CHANGECBCHAIN, m.WParam, m.LParam);
          }
          break;
      }
    }
Szükségünk lesz egy eseményre is, melyhez egy új delegate létrehozása is kell, mely paraméter nélküli.
    public delegate void VoidEventHandler();
Ha ez adott akkor már létrehozhatjuk a Changed nevű eseményt, melyen keresztül értesítést küldhetünk a vágólap tartalmának megváltozásáról.
    public event VoidEventHandler Changed 
    {
      add 
      {  
        changed += value; 
      }
      remove 
      {  
        changed -= value; 
      }
    }
A Changed eseményt az OnChanged belső függvényünk fogja aktivizálni, amikor a WM_DRAWCLIPBOARD üzenetet érzékeljük.
    protected void OnChanged() 
    {
      if (changed != null)
      {
        changed();
      }
    }           
Class1.cs
Elérkeztünk végre a felhasználható komponens létrehozásához, melyet a Component osztályból származtatunk.
Ebben létrehozunk egy Enabled property-t, mellyel indíthatjuk, megállíthatjuk a vágólap tartalmának figyelését.
    public bool Enabled 
    {
      ...
      set 
      {
        if (value != enabled)
        {
Ez abból áll, hogy ha igazra állítjuk a property-t, akkor létrehozzuk ClipboardViewerWindow osztályunk egy példányát és ezen keresztül figyeljük a vágólapot.
          if (value) 
          {
            viewerWindow = new ClipboardViewerWindow();
            viewerWindow.Changed += new VoidEventHandler(OnClipboardChanged);
            viewerWindow.Create();
          } 
Ha az Enabled property-t hamisra állítjuk, akkor egyszerűen megszüntetjük a ClipboardViewerWindow osztályunk példányát és ezzel a figyelést is megszüntetjük.
          else 
          {
            viewerWindow.Dispose();
            viewerWindow = null;
          }
          enabled = value;
        }
      }
    }
Ezt követően létrehozzuk a ClipboardChanged nevű eseményt, mely akkor jön létre, ha a ClipboardViewerWindow osztályunk Changed eseménye aktivizálódik.
    public event VoidEventHandler ClipboardChanged 
    {
      add 
      {  
        clipboardChanged += value; 
      }
      remove 
      {  
        clipboardChanged -= value; 
      }
    }
Form1.cs
A komponens ezzel elkészült. Ha lefordítjuk az EXE-t, akkor a Toolbox-ra már felvehető a ClipboardViewer nevű komponens és bármelyik Form-ra elhelyezhető. Használatához csak az Enabled property-t kell igazra állítani és a ClipboardChanged eseményét felhasználnunk.
Amikor ez az esemény létrejön, akkor biztos, hogy változott a vágólap, így itt ezt kiolvashatjuk és tetszés szerint felhasználhatjuk. A példa egyszerűségének kedvéért, most csak a szöveges vágólap tartalmat jelenítjük meg egy Label feliratán.
    private void clipboardViewer1_ClipboardChanged()
    {
      IDataObject ido = Clipboard.GetDataObject();
      if (ido.GetDataPresent(DataFormats.Text))
      {
        label1.Text = ido.GetData(DataFormats.Text).ToString();           
      }
      else
      {
        label1.Text = "A vágólap nem szöveget tartalmaz!";           
      }       
    }

Könyv
Ez a cikk megtalálható ebben a könyvben: C# Software Offline 2002 évkönyv 287. oldal

Felhasználási feltételek
A Software Online szoftverfejlesztői magazin mindegyik cikke, minden megjelent képe, és egyéb publikált anyaga szerzői jog védelme alatt áll! Bármilyen formában történő másodlagos terjesztésük, közzétételük vagy felhasználásuk kizárólag a kiadó előzetes írásbeli engedélyével történhet!

Copyright © 1999-2010 Animare Software Kft. Minden jog fenntartva!
| Készült: Animare Stúdió | Adatvédelem | Kapcsolat |