问题
I am using the code below to capture a screenshot of the currently active window. This code comes from Capture screenshot Including Semitransparent windows in .NET, with a few small additions, i.e. it uses GetForegroundWindow and also a timer so that I can select the desired window.
On Windows 10 (x64) this works fine for Firefox browser, but it does not work with Chrome or Edge.
I find it strange that Screenshot captured using BitBlt in C# results a black image on Windows 10 [duplicate] is marked as a duplicate, because the answer from above (first link) does not solve this problem.
Any ideas why it does not work for Chrome or Edge?
Code:
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();
}
}
}
Running this in SharpDevelop 5.1
回答1:
Likely it doesn't work for these 2 browsers because they use a hardware-accelerated graphics context (OpenGL- or DirectX-based) to render their content, and this is incompatible with GDI-based calls.
回答2:
I can suggest a simple workaround:
First use GetForegroundWindow
to get the active window rect. Then call GetDesktopWindow
and use that handle with the call to BitBlt:
Just add a single line to above code:
IntPtr hDesk = GetForegroundWindow();
... // get dimensions of active window
hDesk = GetDesktopWindow(); // add this line
IntPtr hSrce = GetWindowDC(hDesk);
IntPtr hDest = CreateCompatibleDC(hSrce);
Works fine.
来源:https://stackoverflow.com/questions/43595289/screenshot-with-bitblt-results-in-black-image-on-windows-10