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ó.
private void button1_Click(object sender, System.EventArgs e)
{
Ha egy tetszőleges alkalmazás képét szeretnénk lemásolni, akkor meg kell szereznünk annak azonosítóját. Például ha fut egy Internet Explorer, akkor ennek proccesszét az alábbi módon kérdezhetjük le.
Process[] p = Process.GetProcessesByName("iexplore");
IntPtr h;
Ha mondjuk csak a saját programunk képét szeretnénk kirajzoltatni a Bitmap-re, akkor egyszerű a dolgunk, mert a szükséges azonosítót a Handle property-ből kiolvashatjuk.
Ha az előbbi példánál maradva egy Internet Explorer aktuális képét szereznék meg, akkor a már meghatározott Process-ből a MainWindowsHandle property szolgáltatja a számunkra szükséges adatot.
// h = p[0].MainWindowHandle;
Bármelyik megoldást is válasszuk a lényeg az, hogy a h nevű változónkba kerüljön annak az alkalmazásnak az ablak azonosítója, melynek képét a Bitmap-en szeretnénk viszontlátni.
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.
Win32.RECT rect = new Win32.RECT();
Win32.GetWindowRect(h, ref rect);
int width = rect.right-rect.left;
int height = rect.bottom-rect.top;
Bitmap bmp = new Bitmap(width, height);
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.
IntPtr hdc = Win32.GetWindowDC(h);
if (hdc!=IntPtr.Zero)
{
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.
IntPtr hdcMem = Win32.CreateCompatibleDC(hdc);
IntPtr hbitmap = Win32.CreateCompatibleBitmap(hdc, width, height);
if (hbitmap!=IntPtr.Zero)
{
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.
Win32.SelectObject(hdcMem, hbitmap);
Win32.PrintWindow(h, hdcMem, 0);
Most már adott a program képe a memória bitmap-en. A könnyebb felhasználás érdekében ezt most átmásoljuk egy Bitmap osztályba, melyből már létrehoztunk egy példányt bmp névvel. A másoláshoz szükségünk lesz ennek a bmp-nek az azonosítójára. Ezt úgy tudjuk elérni, hogy a bmp-t felhasználva készítünk egy Grahpics osztályt. Ennek GetHdc függvénye pedig szolgáltatja a számunkra szükséges értéket. Most már csak a BitBlt-t kell meghívnunk, mely elvégzi a másolást. Ezek után a Bitmap osztály példányában elérhető lesz a lemásolt program képe.
Graphics gBmp = Graphics.FromImage(bmp);
IntPtr hb = gBmp.GetHdc();
Win32.BitBlt(hb, 0, 0, width, height, hdcMem, 0, 0, Win32.SRCCOPY);
Ezek után némi takarítást kell végeznünk, felszabadítjuk a lefoglalt erőforrásokat.
gBmp.ReleaseHdc(hb);
Win32.DeleteObject(hbitmap);
}
Win32.DeleteObject(hdcMem);
}
Win32.ReleaseDC(h, hdc);
Végső lépésként megjelenítjük a Bitmap osztályban tárolt képet a Form-on.
Graphics g2 = Graphics.FromHwnd(Handle);
g2.DrawImage(bmp, 30, 50);
}