Delphi - A képernyő tartalmának elmentése úgy, hogy a kurzor is látható

forráskód letöltése
Számos esetben szükség lehet arra, hogy ne csak a képernyő tartalmát, vagy az aktuális ablakot mentsük el, hanem magát a kurzort is. Így például szemléltetni tudjuk a felhasználó számára, hogy hova is kell kattintania. Ebben a cikkben készítünk egy olyan komponenst, amely lehetővé teszi a teljes képernyő, vagy az aktuális ablak képének elmentését kurzorral együtt. A mentés történhet vágólapra és BMP állományba egyaránt.
A mellékelt példaprogram megnyitása előtt az ScrCapture.pas-ban lévő komponenst telepítenie kell a Delphi alá. Ehhez válassza a Component - Install Component menüpontot.
A komponens használata
A komponens CaptureType tulajdonságban válasszuk ki, hogy a teljes képernyő tartalmát (FullScreen), vagy csak az aktuális ablakot (CurrentWindow) akarjuk elmenteni. Ha a BMPFileName tulajdonságban megadunk egy állománynevet, akkor az elmentett kép abba kerül. Ha a BMPFileName értéke null sztring marad, akkor a kép a vágólapra kerül.
Ezután nincs más dolgunk, mint meghívni a Capture metódust.
A komponens elkészítése
Komponensünket a TComponent osztályból származtatjuk.
Az elmentendő kép beállításához hozzunk létre egy új típust.
TCaptureType = (FullScreen, CurrentWindow);
A CaptureType tulajdonság beállításakor a fenti értékeket használhatjuk majd.
A kép elmentése a Capture metódus meghívásával történik meg. Ebben a metódusban kell megvizsgálnunk azt, hogy a teljes képernyőt vagy csak az aktuális ablakot kell elmenteni. Ennek megfelelően két külön eljárásra van szükség. A CaptureScreen metódus a teljes képernyőt, a CaptureWindow pedig az aktuális ablak elmentését valósítja meg. Mindkét metódus függvény, amely egy TBitmap-et ad visszatérési értékként.
Mielőtt létrehoznánk a két fenti metódust, el kell készítenünk egy olyan metódust, amellyel lekérdezhetjük az egérkurzor információit. Ez lesz a GetCursorInfo metódus.
GetCursorInfo
function TScrCapture.GetCursorInfo: TCursorInfo;
A kurzor meghatározása API függvények segítségével történik.
ZeroMemory(@Result,SizeOf(Result));
A ZeroMemory API függvény nulla értékekkel tölti fel a visszatérési értéket.
Azonosítanunk kell azt az ablakot, amely fölött az egérkurzor található.
WindowHandle:=WindowFromPoint(p);
Miután megvan az ablak azonosítója, meg kell határoznunk az ablakhoz tartozó műveleti szálat és az aktuális szálat.
if IsWindow(WindowHandle) then begin
  dwThreadID:=GetWindowThreadProcessId(WindowHandle,Nil);
  dwCurrentThreadID:=GetCurrentThreadId;
...
Ha a két szál nem ugyanaz, akkor a kurzor képét az alatta elhelyezkedő ablaknak megfelelően kell beállítanunk.
if AttachThreadInput(dwCurrentThreadID,dwThreadID,True) then begin
  Result.hCursor:=GetCursor;
  AttachThreadInput(dwCurrentThreadID,dwThreadID,False);
end;
A kurzor adatait és azonosítóját (Handle) a TCursorInfo struktúrán keresztül tudjuk visszatérési értékként átadni a hívó függvénynek.
CaptureWindow
function TScrCapture.CaptureWindow: TBitmap;
Szükséges egy Bitmap: TBitmap segédváltozó, amelybe ideiglenesen eltároljuk és összeállítjuk a képet, mielőtt azt visszatérési értékként visszaadnánk.
Az adott ablak grafikus tartalmát a DC: HDC objektumon keresztül tudjuk elérni.
DC:=GetDC(0);
Ahhoz, hogy a programablakot el tudjuk menteni, a komponens Create metódusában el kell mentenünk az AOwner paramétert. Ezt a paramétert a Form globális változóba mentjük el.
Bitmap.Height:=(Form as TForm).Height;
A Form változóra a kép méretezéséhez van szükségünk.
A képernyő tartalmát a BitBlt API függvény segítségével tudjuk átmásolni a Bitmap.Canvas-ba. A kép ekkor még csak az ablakot tartalmazza, így az ikon képét is rá kell rajzolnunk. Ezt a Bitmap.Canvas.Draw metódus megfelelő paraméterezésével tehetjük meg.
var
  CursorIcon: TIcon;
  CursorInfo: TCursorInfo;
  IconInfo: TIconInfo;
...
CursorIcon.Handle:=CursorInfo.hCursor;
GetIconInfo(CursorInfo.hCursor,IconInfo);
Bitmap.Canvas.Draw(CursorInfo.ptScreenPos.X-IconInfo.xHotspot-(Form as TForm).Left,CursorInfo.ptScreenPos.Y-IconInfo.yHotspot-(Form as TForm).Top,CursorIcon);
Az ikon adatait a GetIconInfo API függvénnyel kérdezhetjük le.
A CaptureWindow függvény visszatérési értékeként a Bitmap objektumot adjuk, amely már tartalmazza az ablak képét és a kurzort is.
CaptureScreen
Ebben a függvényben is hasonlóan kell eljárnunk, mint a CaptureWindow-ban. A képernyőhöz a DC: HDC objektumon keresztül férhetünk hozzá, csak itt a GetDesktopWindow paramétert kell megadnunk.
DC:=GetDC(GetDesktopWindow);
A képernyő szélességi és magassági paramétereit az alábbi API függvénnyel kérdezhetjük le.
Bitmap.Width:=GetDeviceCaps(DC,HORZRES);
Bitmap.Height:=GetDeviceCaps(DC,VERTRES);
Innentől ugyanazokat a lépéseket kell megvalósítanunk, mint amikor egyetlen ablak képét mentettük el.