我尝试使用我一直用于PrintWindow
的方法捕获窗口RECT rc;
GetClientRect(hwnd, out rc); //The process window handler
Bitmap bmp = new Bitmap(rc.right, rc.bottom, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr hdcBitmap = gfxBmp.GetHdc();
PrintWindow(hwnd, hdcBitmap, 1);
gfxBmp.ReleaseHdc(hdcBitmap);
gfxBmp.Dispose();
bmp.Save("test.png");
问题在于,在这个特定的游戏过程中,当窗口调用Printwindow函数时,窗口会非常快,因此有时保存的图像是完全白色的。
所以我尝试使用BitBlt:
Bitmap bmp = new Bitmap(rc.right, rc.bottom, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
Graphics gfxBmp = Graphics.FromImage(bmp);
IntPtr dest = gfxBmp.GetHdc();
IntPtr source = GetWindowDC(hwnd);
BitBlt(dest, 0, 0, rc.width, rc.height, source, 0, 0, 13369376);
bmp.Save("test.png");
但使用保存图像上方的代码完全是黑色的。
有任何方法可以阻止PrintWindow使进程窗口轻弹"白色层" ?如果可能BitBtl应该为我解决这个问题吧?但是我的代码有什么问题?
谢谢
答案 0 :(得分:1)
您可以尝试使用此代码,它对我有用。如果您仍然看到黑色图像,可能您需要使用DWM解决方案。
更新:修复缺失的窗口参数
public Bitmap CaptureWindowImage(IntPtr hWnd, System.Drawing.Rectangle wndRect)
{
IntPtr hWndDc = GetDC(hWnd);
IntPtr hMemDc = CreateCompatibleDC(hWndDc);
IntPtr hBitmap = CreateCompatibleBitmap(hWndDc, wndRect.Width, wndRect.Height);
SelectObject(hMemDc, hBitmap);
BitBlt(hMemDc, 0, 0, wndRect.Width, wndRect.Height, hWndDc, 0, 0, TernaryRasterOperations.SRCCOPY);
Bitmap bitmap = Bitmap.FromHbitmap(hBitmap);
DeleteObject(hBitmap);
ReleaseDC(window.hWnd, hWndDc);
ReleaseDC(IntPtr.Zero, hMemDc);
return bitmap;
}
private enum TernaryRasterOperations : uint
{
/// <summary>dest = source</summary>
SRCCOPY = 0x00CC0020,
/// <summary>dest = source OR dest</summary>
SRCPAINT = 0x00EE0086,
/// <summary>dest = source AND dest</summary>
SRCAND = 0x008800C6,
/// <summary>dest = source XOR dest</summary>
SRCINVERT = 0x00660046,
/// <summary>dest = source AND (NOT dest)</summary>
SRCERASE = 0x00440328,
/// <summary>dest = (NOT source)</summary>
NOTSRCCOPY = 0x00330008,
/// <summary>dest = (NOT src) AND (NOT dest)</summary>
NOTSRCERASE = 0x001100A6,
/// <summary>dest = (source AND pattern)</summary>
MERGECOPY = 0x00C000CA,
/// <summary>dest = (NOT source) OR dest</summary>
MERGEPAINT = 0x00BB0226,
/// <summary>dest = pattern</summary>
PATCOPY = 0x00F00021,
/// <summary>dest = DPSnoo</summary>
PATPAINT = 0x00FB0A09,
/// <summary>dest = pattern XOR dest</summary>
PATINVERT = 0x005A0049,
/// <summary>dest = (NOT dest)</summary>
DSTINVERT = 0x00550009,
/// <summary>dest = BLACK</summary>
BLACKNESS = 0x00000042,
/// <summary>dest = WHITE</summary>
WHITENESS = 0x00FF0062
}
[DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)]
static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll", SetLastError = true)]
private static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
private static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
private static extern IntPtr CreateBitmap(int nWidth, int nHeight, uint cPlanes, uint cBitsPerPel, IntPtr lpvBits);
[DllImport("user32.dll")]
private static extern IntPtr GetDC(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("gdi32.dll")]
private static extern bool BitBlt(IntPtr hdc, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);
答案 1 :(得分:0)
弗朗切斯科的答案几乎奏效,但是由于尝试调用ReleaseDC(IntPtr.Zero, hMemDc);
而导致内存泄漏,如果调用DeleteDC(hMemDc);
则不会泄漏。
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-releasedc
对于每次调用,应用程序必须调用ReleaseDC函数。 GetWindowDC函数以及对于每次调用GetDC函数的 检索公共DC。
应用程序无法使用ReleaseDC功能来释放DC 是通过调用 CreateDC函数创建的;相反,它必须使用 DeleteDC函数。 必须从与该线程相同的线程中调用ReleaseDC。 称为GetDC。
已通过任务管理器中GDI Objects
的数量以及内存使用情况进行了验证