使用BitBlt的屏幕截图在Windows 10上显示黑色图像

时间:2017-04-24 18:29:08

标签: c# windows-10 screenshot bitblt

我使用下面的代码捕获当前活动窗口的屏幕截图。这段代码来自Capture screenshot Including Semitransparent windows in .NET,有一些小的补充,即它使用GetForegroundWindow和一个计时器,以便我可以选择所需的窗口。

在Windows 10(x64)上,这适用于Firefox浏览器,但它不适用于Chrome或Edge。

我觉得很奇怪Screenshot captured using BitBlt in C# results a black image on Windows 10 [duplicate]被标记为重复,因为上面的答案(第一个链接)无法解决这个问题。

为什么它不能用于Chrome或Edge的任何想法?

代码:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace App1
{
    /// <summary>
    /// Description of MainForm.
    /// </summary>
    public partial class MainForm : Form
    {
        public MainForm()
        {
            //
            // The InitializeComponent() call is required for Windows Forms designer support.
            //
            InitializeComponent();

            //
            // TODO: Add constructor code after the InitializeComponent() call.
            //
        }

        void DoCapture()
        {
            label1.Text = "Capturing...";

              try
              {
              IntPtr hDesk = GetForegroundWindow();
              //IntPtr hDesk = GetDesktopWindow();

              var windowRect = new RECT();
              GetWindowRect(hDesk, out windowRect);

              int width = (int)(windowRect.Right - windowRect.Left);
              int height = (int)(windowRect.Bottom - windowRect.Top);      

              Size sz = new Size(width, height);
              sz.Width = (int)(sz.Width * 1.25); // this is just an adjustment for the Windows zoom factor of 125%
              sz.Height = (int)(sz.Height * 1.25);

              IntPtr hSrce = GetWindowDC(hDesk);
              IntPtr hDest = CreateCompatibleDC(hSrce);
              IntPtr hBmp = CreateCompatibleBitmap(hSrce, sz.Width, sz.Height);
              IntPtr hOldBmp = SelectObject(hDest, hBmp);
              bool b = BitBlt(hDest, 0,0, sz.Width, sz.Height, hSrce, 
                   0, 0, CopyPixelOperation.SourceCopy | CopyPixelOperation.CaptureBlt);
              Bitmap bmp = Bitmap.FromHbitmap(hBmp);
              SelectObject(hDest, hOldBmp);
              DeleteObject(hBmp);
              DeleteDC(hDest);
              ReleaseDC(hDesk, hSrce);
              bmp.Save(@"c:\temp\test.png");
              bmp.Dispose();
              label1.Text = "Done";
              }
              catch (Exception e){
                label1.Text = "Exception Occurred";
                textBox1.Text = e.ToString();
              }
        }

        void Button1Click(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }

        // P/Invoke declarations
        [DllImport("gdi32.dll")]
        static extern bool BitBlt(IntPtr hdcDest, int xDest, int yDest, int
        wDest, int hDest, IntPtr hdcSource, int xSrc, int ySrc, CopyPixelOperation rop);
        [DllImport("user32.dll")]
        static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDc);
        [DllImport("gdi32.dll")]
        static extern IntPtr DeleteDC(IntPtr hDc);
        [DllImport("gdi32.dll")]
        static extern IntPtr DeleteObject(IntPtr hDc);
        [DllImport("gdi32.dll")]
        static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
        [DllImport("gdi32.dll")]
        static extern IntPtr CreateCompatibleDC(IntPtr hdc);
        [DllImport("gdi32.dll")]
        static extern IntPtr SelectObject(IntPtr hdc, IntPtr bmp);
        [DllImport("user32.dll")]
        public static extern IntPtr GetDesktopWindow();
        [DllImport("user32.dll")]
        public static extern IntPtr GetForegroundWindow();      
        [DllImport("user32.dll")]
        public static extern IntPtr GetWindowDC(IntPtr ptr);
        [DllImport("user32.dll")]
        static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;        // x position of upper-left corner
            public int Top;         // y position of upper-left corner
            public int Right;       // x position of lower-right corner
            public int Bottom;      // y position of lower-right corner
        }

        void Timer1Tick(object sender, EventArgs e)
        {
            timer1.Enabled = false;
            DoCapture();
        }       
    }
}

在SharpDevelop 5.1中运行它

2 个答案:

答案 0 :(得分:1)

可能它不适用于这两种浏览器,因为它们使用硬件加速的图形上下文(基于OpenGL或DirectX)来呈现其内容,这与基于GDI的调用不兼容。

答案 1 :(得分:1)

我可以建议一个简单的解决方法:

首先使用GetForegroundWindow来获取活动窗口rect。然后调用GetDesktopWindow并使用该句柄调用BitBlt:

只需在上面的代码中添加一行:

          IntPtr hDesk = GetForegroundWindow();
          ...       // get dimensions of active window    
          hDesk = GetDesktopWindow();  // add this line
          IntPtr hSrce = GetWindowDC(hDesk);
          IntPtr hDest = CreateCompatibleDC(hSrce);

工作正常。

相关问题