Delphi - Tetszőleges alkalmazás képének lemásolása

forráskód letöltése
Nem, ne a PrintScreen funkcióra tessék gondolni! Úgy másoljuk le egy alkalmazás aktuális képét, hogy az alkalmazásnak nem kell látszódnia a képernyőn! Az alkalmazás futhat a háttérben, lehet akár minimalizált is. A trükk a következő lesz: létrehozunk egy Bitmap-et, majd azt mondjuk a kiválasztott programnak, hogy fesse újra magát (Invalidate), de azonosítónak a Bitmap azonosítóját adjuk át a számára. Erre az adott program elvégzi a teljes felületének kirajzolását nem is tudva arról, hogy valójában a mi Bitmap-ünkre rajzol. A rajzolás végeztével viszont rendelkezésünkre áll a Bitmap-en az adott program aktuális képe, amit persze tetszés szerint felhasználhatunk.
A program futtatása előtt nyissa meg a mellékelt 1.txt állományt. Ha Önnél nem magyar nyelvű az operációs rendszer és így az elindított Nodepad alkalmazás fejléce nem „1.txt - Jegyzettömb” szöveget tartalmazza, akkor változtassa meg a program Edit1 komponensében lévő szöveget.
A megvalósításban segítséget kapunk a PrintWindow függvény által, mely megvalósítja azt a trükköt, amit a bevezetőben leírtunk, így nekünk csak egy Bitmap-ről kell gondoskodnunk, illetve kiválasztanunk az alkalmazást, melynek képére szükségünk van. A PrintWindow függvényről ne felejtsük el, hogy csak Windows XP, illetve Windows .NET szerver verzióktól kezdve használható.
Jelen példában egy Notepad alkalmazás képét másoljuk le, de természetesen bármely más alkalmazás lemásolható ezzel a módszerrel.
Első lépésként megszerezzük az adott program azonosítóját, melyre sokféle módszert használhatunk. Most vegyük azt az egyszerű módszert, hogy az ablakot a fejlécének szövege alapján keressük meg a FindWindow függvénnyel.
procedure TForm1.FormPaint(Sender: TObject);
  ...
  hw:=FindWindow(nil, PChar(Edit1.Text));
Következő lépés lesz, hogy a kiválasztott program ablakának szélességét és magasságát meghatározzuk, mivel nekünk is egy ekkora méretű Bitmap-et kell majd létrehozni. Ebben a GetWindowsRect függvény segít, melyet használva megtudjuk a program bal felső, illetve jobb alsó sarkának koordináta pontját a képernyő koordinátarendszerben értelmezve. Ebből már tudjuk számítani a szélességet és magasságot.
  GetWindowRect(hw, rc);
  w:=rc.Right-rc.Left;
  h:=rc.Bottom-rc.Top;
Ha adott az ablak azonosítója, akkor az alapján lekérhető az ablak kirajzolásáért felelős objektum azonosítója is, melyhez a GetWindowsDC Windows függvényt kell meghívnunk.
  hdc:=GetWindowDC(hw);
Most létrehozunk egy a képernyővel azonos típusú, tulajdonságú memóriabeli Bitmap-et egy általunk megadott szélességben és magasságban, mely nyilván akkora lesz, mint a másolandó program ablaka.
  hdcMem:=CreateCompatibleDC(hdc);
  hbitmap := CreateCompatibleBitmap(hdc, w, h);
  SelectObject(hdcMem, hbitmap);
Miután aktuálissá tesszük ezt a memória Bitmap-et, már meghívhatjuk a PrintWindow függvényt, melynek első paramétere a másolandó program ablakának azonosítója, második a létrehozott memória Bitmap azonosítója, végül pedig arról rendelkezhetünk a harmadik paraméterben, hogy a teljes ablak, vagy csak annak kliens területe kerüljön e másolásra. Utóbbi esetben a PW_CLIENTONLY konstanst kell megadni.
  PrintWindow(hw, hdcMem, 0);
Ezek után már felhasználhatjuk a memória Bitmap-et és kirajzolhatjuk azt a Form területére.
  dd:=TrackBar1.Position/2;
  StretchBlt(Canvas.Handle, 10, 100, Round(w/dd), Round(h/dd), hdcMem, 0, 0, w, h, SRCCOPY);
Ezek után némi takarítást kell végeznünk, felszabadítjuk a lefoglalt erőforrásokat.
  DeleteObject(hbitmap);
  DeleteObject(hdcMem);
  ReleaseDC(hw, hdc);
end;