C#实现窗体截图(代码+效果)

最近在做一个QQ找茬游戏的外挂,第一步便是窗体截图,因为以前从来没有涉及过图像处理方面的知识,感觉还是有点小难的。理论上讲做这个东西用C++会比较简单,但由于我一看到MFC就眼晕,所以还是选择了熟悉的C#语言。

C#写截图要用到传说中的.net没有提供的叫做BitBlt的函数,而BitBlt函数要求有被截窗体的设备驱动器句柄,需要用GetDC(hwnd)函数获得,当然之后还要用ReleaseDC(hdc)释放。但是要得到窗体的设备驱动器句柄又要求有被截窗体的窗体句柄,需要调用FindWindow()函数,有了窗体句柄再用GetClientRect()同时可以得到窗体的大小。看到这么多API,给我的第一感觉是头大。

然后我想到最简单的方法是用google搜到代码,直接考上去就得了,搜了半天却发现网上鲜有C#窗体截图的东西,铺天盖地都是屏幕截图。当然用屏幕截图也可以做,但是局限性太大,我又不愿意走弯路,所以宁愿麻烦点自己写窗体截图的代码。查了很多资料又调试了N次今天下午终于把窗体截图给搞定了,哈哈,虽然只是写出来了窗体截图,但是学到了好多知识,好高兴啊,吃饭都比前几天香了。

不多说了,上代码和我截出来的图吧,鼓励下自己,加油,后续工作更重要呢。

调用API相关:

[System.Runtime.InteropServices.DllImportAttribute("gdi32.dll")]
private static extern bool BitBlt
(
    IntPtr hdcDest,    //目标DC的句柄
    int nXDest,        //目标DC的矩形区域的左上角的x坐标
    int nYDest,        //目标DC的矩形区域的左上角的y坐标
    int nWidth,        //目标DC的句型区域的宽度值
    int nHeight,       //目标DC的句型区域的高度值
    IntPtr hdcSrc,     //源DC的句柄
    int nXSrc,         //源DC的矩形区域的左上角的x坐标
    int nYSrc,         //源DC的矩形区域的左上角的y坐标
    System.Int32 dwRo  //光栅的处理数值
);

[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public extern static IntPtr FindWindow(string lpClassName, string lpWindowName);

[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public static extern int GetWindowRect(IntPtr hWnd, out Rectangle lpRect);

[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public extern static IntPtr GetDC(IntPtr hWnd);

[System.Runtime.InteropServices.DllImportAttribute("user32.dll")]
public extern static int ReleaseDC(IntPtr hWnd, IntPtr hDC);

截图部分代码:

IntPtr hwnd1 = FindWindow(null, "**");
if (!hwnd1.Equals(IntPtr.Zero))
{
    GetWindowRect(hwnd1, out rect);  //获得目标窗体的大小
    Bitmap QQPic = new Bitmap(rect.Width, rect.Height);
    Graphics g1 = Graphics.FromImage(QQPic);
    IntPtr hdc1 = GetDC(hwnd1);
    IntPtr hdc2 = g1.GetHdc();  //得到Bitmap的DC
    BitBlt(hdc2, 0, 0, rect.Width, rect.Height, hdc1, 0, 0, 13369376);
    g1.ReleaseHdc(hdc2);  //释放掉Bitmap的DC
    QQPic.Save("QQpic.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
    //以JPG文件格式保存
}

截图效果:

10 thoughts on “C#实现窗体截图(代码+效果)

      • 哎,撒谎了,其实我是找截图的资料点进来的!
        由于BitBlt()函数对被遮盖的窗口不能截图,PrintWindow()可以,但在WindowXP下是有bug,所有到处找找资料了.

        赞一个,mm搞计算机的很少……..

        • 对的,BitBlt()虽然可以靠窗体句柄直接定位,但是不能截被遮盖的,我当时也为这个问题纠结了下。
          看来也是同行啊,哈哈,一开始差点以为你认识我呢O(∩_∩)O~~~

          • I am skeptical how much good conversation could do in this matter. All that mattered in the end for those most upset about Prop. 8 is that it passed. If it had failed then its opponents wou8ln&#d217;t care a fraction so much how it had been promoted. All the really big outcry came after election day, when the pro-8s were already finished with whatever vile things they had been doing. If every bit of advocacy for Prop. 8 had been uttered with the tongue of angels, the anti-8s’ feelings about Prop. 8 passage and its advocates would still be pretty much what they are in our reality.

  1. 为什么我执行这段代码,不过多少次,截图都和第一次截得一摸一样?
    在下很着急,请mm务必回答,期待。(qq:88271180)

    • 不好意思,刚刚看到留言,应该每执行一次BitBlt函数就绘一次的呀,你会不会是一次绘完之后没有释放句柄啊~

  2. 不是的,应该是系统Api不兼容的问题了。。
    那段代码在我的系统上面运行不正常,我的是Win7 Professional。拿到别的机器上,Win7 RTM 和Xp sp2都没问题。。郁闷了

  3. 呵呵,搜索资料进来的,下面的代码可以截被遮挡的窗口
    public Bitmap GetWindowImage(IntPtr hWnd)
    {
    IntPtr hscrdc = Win32API.User32.GetWindowDC(hWnd);
    // Control control = Control.FromHandle(hWnd);
    Win32API.User32.RECT windowRect = new Win32API.User32.RECT();
    Win32API.User32.GetWindowRect(hWnd, ref windowRect);
    int width = windowRect.right – windowRect.left;
    int height = windowRect.bottom – windowRect.top;

    IntPtr hbitmap = Win32API.GDI32.CreateCompatibleBitmap(hscrdc, width, height);
    IntPtr hmemdc = Win32API.GDI32.CreateCompatibleDC(hscrdc);
    Win32API.GDI32.SelectObject(hmemdc, hbitmap);
    Win32API.User32.PrintWindow(hWnd, hmemdc, 0);
    Bitmap bmp = Bitmap.FromHbitmap(hbitmap);
    Win32API.GDI32.DeleteDC(hscrdc);//删除用过的对象
    Win32API.GDI32.DeleteDC(hmemdc);//删除用过的对象
    return bmp;
    }
    如果愿意,楼主共享一份代码给我,9049021@qq.com省得我再折腾

Leave a Reply

Your email address will not be published. Required fields are marked *