【问题标题】:Screenshot with BitBlt results in black image on Windows 10使用 BitBlt 的屏幕截图在 Windows 10 上导致黑色图像
【发布时间】:2017-09-21 13:26:22
【问题描述】:

我正在使用下面的代码来捕获当前活动窗口的屏幕截图。此代码来自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 中运行它

【问题讨论】:

    标签: c# windows-10 screenshot bitblt


    【解决方案1】:

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

    【讨论】:

    • 不是真正的解决方案。 @RaelB 的一个是。
    【解决方案2】:

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

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

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

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

    工作正常。

    【讨论】:

    • 在使用 GDI 捕获时呈现黑色的 Citrix 窗口工作正常。关键是捕获桌面,好技巧。
    • 不幸的是,如果窗口部分或完全被其他窗口重叠,这将不起作用。
    • @Luaan, BitBlt 自从在 Windows Vista 中引入 DWM 组合以来,已经能够捕获重叠的窗口(包括重叠的部分)。不幸的是,对于硬件加速的窗口,BitBlt 根本不起作用。
    • @Luaan,问题是关于在 Windows 10 下捕获一个窗口。你说 “但 BitBlt 也是如此”。不,不是。 BitBlt 可以在 Windows 10 中捕获重叠的窗口。
    猜你喜欢
    • 2016-12-16
    • 2018-05-27
    • 1970-01-01
    • 2019-11-04
    • 1970-01-01
    • 2015-06-20
    • 2021-03-20
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多