C#屏幕捕捉编程之C#使用Screen类等方式截屏
本文将介绍给大家通过C#代码来获得Windows操作系统的桌面位图的方法,截屏的结果就是要获得一个位图。
主要方式有两个:
1、C#类库
2、Windows32API
先介绍使用C#类库的方式
主要使用Screen类
http://msdn.microsoft.com/zh-cn/library/system.windows.forms.screen.aspx
表示单个系统上的一个或多个显示设备。
命名空间: System.Windows.Forms
程序集: System.Windows.Forms(在 System.Windows.Forms.dll 中)
代码:
Image img = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height);
Graphics g = Graphics.FromImage(img);
g.CopyFromScreen(new Point(0, 0), new Point(0, 0), Screen.PrimaryScreen.Bounds.Size);
通过这3行,img已经获得了对一个位图的引用了。
简单得很哦
第二种:使用Win32API
主要参考这个版本的代码
http://www.csharphelp.com/2006/11/capturing-the-screen-image-using-c/
具体不想多做介绍了
简单说明,Windows操作系统本身拥有丰富的代码,能完成很多系统级功能,并且非常高效。
而C#以及各种.net程序,以及其他高级语言完成类似功能时都需要程序员为之编码,且运行效率多数是不行的。
所以干吗要重复造轮子呢
在.net这里可以使用上述的方式来引用Windows的系统函数来完成我们需要的功能
探讨的部分是,在很多Win32调用的程序中,释放句柄一直是非常要紧的一件事
但是在我实际使用中发现不是必须如此的
原始代码:
public static Bitmap GetDesktopImage()
{
//Variable to keep the handle of the btimap.
IntPtr m_HBitmap=null;
//Variable to keep the refrence to the desktop bitmap.
System.Drawing.Bitmap bmp=null;
//In size variable we shall keep the size of the screen.
SIZE size;
//Here we get the handle to the desktop device context.
IntPtr hDC = PlatformInvokeUSER32.GetDC(PlatformInvokeUSER32.GetDesktopWindow());
//Here we make a compatible device context in memory for screen device context.
IntPtr hMemDC = PlatformInvokeGDI32.CreateCompatibleDC(hDC);
//We pass SM_CXSCREEN constant to GetSystemMetrics to get the X coordinates of screen.
size.cx = PlatformInvokeUSER32.GetSystemMetrics (PlatformInvokeUSER32.SM_CXSCREEN);
//We pass SM_CYSCREEN constant to GetSystemMetrics to get the Y coordinates of screen.
size.cy = PlatformInvokeUSER32.GetSystemMetrics(PlatformInvokeUSER32.SM_CYSCREEN);
//We create a compatible bitmap of screen size and using screen device context.
m_HBitmap = PlatformInvokeGDI32.CreateCompatibleBitmap(hDC, size.cx, size.cy);
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0,PlatformInvokeGDI32.SRCCOPY);
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//We delete the memory device context.
PlatformInvokeGDI32.DeleteDC(hMemDC);
//We release the screen device context.
PlatformInvokeUSER32.ReleaseDC(PlatformInvokeUSER32.GetDesktopWindow(), hDC);
//Image is created by Image bitmap handle and assigned to Bitmap variable.
bmp=System.Drawing.Image.FromHbitmap(m_HBitmap);
//Delete the compatible bitmap object.
PlatformInvokeGDI32.DeleteObject(m_HBitmap);
return bmp;
}
//If m_HBitmap is null retunrn null.
return null;
}
对比代码:
public static Bitmap GetDesktopImage()
{
//As m_HBitmap is IntPtr we can not check it against null. For this purspose IntPtr.Zero is used.
if (m_HBitmap!=IntPtr.Zero)
{
//Here we select the compatible bitmap in memeory device context and keeps the refrence to Old bitmap.
IntPtr hOld = (IntPtr) PlatformInvokeGDI32.SelectObject(hMemDC, m_HBitmap);
//We copy the Bitmap to the memory device context.
PlatformInvokeGDI32.BitBlt(hMemDC, 0, 0,size.cx,size.cy, hDC, 0, 0, PlatformInvokeGDI32.SRCCOPY);
//We select the old bitmap back to the memory device context.
PlatformInvokeGDI32.SelectObject(hMemDC, hOld);
//老外的原始代码中,静态构造里是没东西的。所有那些都是在本函数中声明、使用并且销毁的。
//如果有喜欢销毁东西癖好的,可以在这里销毁hDC、hMemDC以及m_HBitmap
//不过我觉得没有这个必要,并且不销毁能提高点点速度
return System.Drawing.Image.FromHbitmap(m_HBitmap);
}
//If m_HBitmap is null retunrn null.
return null;
}
因为我觉得hDC在本程序使用中永远是指向桌面窗口的句柄,简单说这个指针的值是永远不变的。除非桌面窗口被释放、重建。
同理hMemDC也是一样和桌面窗口关联的
m_HBitmap则是一个位图对象的引用,也就是申请了一块内存。
反复多次对同一片内存写入数据是不会有问题的
因此我在代码中把这几个的初始化都转移到了静态构造里,只运行一次。实际看速度是快了一点的。
由于对C/C++的理解不是很深(本人本质是VB5.0+VBA office程序员出身),希望有关达人能指点一下上述理由是否成立。