BitBlt 屏幕截图在 Windows 10 上不起作用
Posted
技术标签:
【中文标题】BitBlt 屏幕截图在 Windows 10 上不起作用【英文标题】:BitBlt screen capture not working on Windows 10 【发布时间】:2018-05-27 20:56:33 【问题描述】:我正在使用此代码在后台捕获进程窗口:
IntPtr = Process.GetProcessByName("memu")[0].MainWindowHandle;
RECT rc;
GetClientRect(hwnd, out rc);
IntPtr hdcFrom = GetDC(hwnd);
IntPtr hdcTo = CreateCompatibleDC(hdcFrom);
int Width = rc.right;
int Height = rc.bottom;
Bitmap bmp = null;
IntPtr hBitmap = CreateCompatibleBitmap(hdcFrom, Width, Height);
if (hBitmap != IntPtr.Zero)
IntPtr hLocalBitmap = SelectObject(hdcTo, hBitmap);
BitBlt(hdcTo, 0, 0, Width, Height, hdcFrom, 0, 0, CopyPixelOperation.SourceCopy);
SelectObject(hdcTo, hLocalBitmap);
DeleteDC(hdcTo);
ReleaseDC(hwnd, hdcFrom);
bmp = Image.FromHbitmap(hBitmap);
DeleteObject(hBitmap);
return bmp;
此代码是捕获一个名为 MEmu 的 android 模拟器,它使用 DirectX 来呈现内容。但是这段代码在 Windows 10 更新到 16299 版本后停止工作(之前可以正常工作),它仍然可以在启用 Aero 模式的 Windows 7 上工作。
当我在 Windows 10 Pro v16299.X 中使用此方法时,它只会返回白色图像,或者返回模拟器“加载屏幕”,而不是运行内容。在 Windows 7 上,如果我删除 Aero 模式,它的行为也会相同,捕获“加载屏幕”,因此看起来新 Windows 10 专业版更新中透明度的工作方式发生了某种变化。
我已经尝试了一切,尝试安装一些模块以强制 Aero 模式在 Windows 10 上运行,尝试 PrintWindow 在后台捕获屏幕,但仍然相同。
任何想法可能会发生什么?还是可能的解决方案?或者在最新的 Windows 10 Pro 版本中发生了哪些可能破坏该代码的变化?
谢谢!
【问题讨论】:
16299.64 更改日志显示“Microsoft 图形组件的安全更新”,可能这些更新破坏了 DWM 中的某些内容作为副作用。没有其他 API 可以捕获隐藏的窗口,因此您可以希望 MS 修复它,或者使用 DirectX 挂钩等一些技巧。 仅供参考,它不在我们的 Windows 10 Pro 64 位版本 1607 中工作:获取全黑位图。 在调用BitBlt
之后,立即执行以下操作:var error = Marshal.GetLastWin32Error();
,如果您得到不同于 0(零)的任何值,请验证错误代码 HERE。为了使其正常工作,您需要在 DllImport
语句中添加 SetLastError = true
。这将只给出最后一次 Win32 API 调用的错误,因此您可能需要对每个调用都执行此操作。
@IgorM - 至于报告错误的位置 - Windows 10 附带名为“Centrum Feedback”的应用程序,您可以使用它来报告建议/错误。
几个月后问题依然存在,经过一些研究和测试,我和一些朋友找到了一些可能的“解决方案”解决问题HERE,但它仍然不是100%有效,也有API 调用中没有错误,有人在这个问题上运气好吗?
【参考方案1】:
希望这能解决问题。 .net 框架中内置了一种捕获屏幕的方法,该方法可能有效。不确定它是否会捕获 DirectX 内容,但可能值得一试。
请注意,此解决方案捕获当前屏幕,但您可能可以对其进行修改以仅捕获您感兴趣的区域。
我在这里找到了这个解决方案:https://www.c-sharpcorner.com/UploadFile/2d2d83/how-to-capture-a-screen-using-C-Sharp/
private void CaptureMyScreen()
try
//Creating a new Bitmap object
Bitmap captureBitmap = new Bitmap(1024, 768, PixelFormat.Format32bppArgb);
//Bitmap captureBitmap = new Bitmap(int width, int height, PixelFormat);
//Creating a Rectangle object which will
//capture our Current Screen
Rectangle captureRectangle = Screen.AllScreens[0].Bounds;
//Creating a New Graphics Object
Graphics captureGraphics = Graphics.FromImage(captureBitmap);
//Copying Image from The Screen
captureGraphics.CopyFromScreen(captureRectangle.Left,captureRectangle.Top,0,0,captureRectangle.Size);
//Saving the Image File (I am here Saving it in My E drive).
captureBitmap.Save(@"E:\Capture.jpg",ImageFormat.Jpeg);
//Displaying the Successfull Result
MessageBox.Show("Screen Captured");
catch (Exception ex)
MessageBox.Show(ex.Message);
【讨论】:
【参考方案2】:对我来说,这适用于 Windows 10 11.02.2021:
static void hflipAndSwapRandB(unsigned char* data, int w, int h, int dim)
int y = 0;
int x = 0;
int d;
unsigned char swap = 0;
int hh = h / 2;
for (y = 0; y < hh; y++)
for (x = 0; x < w; x++)
for (d = 0; d < dim; d++)
swap = data[y * dim * w + dim * x + d];
data[y * dim * w + dim * x + d] = data[(h - 1 - y) * dim * w + dim * x + dim - 1 - d];
data[(h - 1 - y) * dim * w + dim * x + dim - 1 - d] = swap;
static void copyScreen(unsigned char* pixels_out, int x, int y, int width, int height)
HDC hScreenDC = GetDC(GetDesktopWindow());
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);
if (width == -1 || height == -1)
width = GetDeviceCaps(hScreenDC, HORZRES);
height = GetDeviceCaps(hScreenDC, VERTRES);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);
BitBlt(hMemoryDC, x, y, width, height, hScreenDC, x, y, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width-x;
bi.biHeight = height-y;
bi.biPlanes = 1;
bi.biBitCount = 24;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
GetDIBits(hMemoryDC, hBitmap, 0, height-y, pixels_out, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
hflipAndSwapRandB(pixels_out, width, height, 3);
DeleteDC(hMemoryDC);
DeleteDC(hScreenDC);
DeleteObject(hBitmap);
【讨论】:
以上是关于BitBlt 屏幕截图在 Windows 10 上不起作用的主要内容,如果未能解决你的问题,请参考以下文章