从XP中隐藏或剪切的窗口复制内容?

我需要将隐藏窗口(BitBlt)的内容复制到另一个窗口。 问题是,一旦我隐藏源窗口,我得到的设备上下文不再绘制。

你需要的是自Windows XP以来在Win32 API中可用的PrintWindow函数。 如果您需要使用旧版本的Windows,则可以尝试使用WM_PRINT ,尽管我从未能使其工作。

这里有一篇不错的文章,展示了如何使用PrintWindow,以下是该文章的相关代码片段:

// Takes a snapshot of the window hwnd, stored in the memory device context hdcMem HDC hdc = GetWindowDC(hwnd); if (hdc) { HDC hdcMem = CreateCompatibleDC(hdc); if (hdcMem) { RECT rc; GetWindowRect(hwnd, &rc); HBITMAP hbitmap = CreateCompatibleBitmap(hdc, RECTWIDTH(rc), RECTHEIGHT(rc)); if (hbitmap) { SelectObject(hdcMem, hbitmap); PrintWindow(hwnd, hdcMem, 0); DeleteObject(hbitmap); } DeleteObject(hdcMem); } ReleaseDC(hwnd, hdc); } 

我应该有一些使用wxPython来实现相同的Python代码。 如果你想要的话,给我一个便条。

在关闭/隐藏窗口之前将源位图复制到内存位图。

您可以尝试发送WM_PRINT消息到窗口。 对于很多窗口(包括所有的标准窗口和通用控件),这将导致它画到所提供的DC中。

另外,如果将HDC作为WM_PAINT消息的wparam传递,许多窗口(如公共控件)将绘制到该DC中,而不是绘制到屏幕上。

也许你可以用InvalidateRect在窗口上触发重绘操作?

不幸的是,我认为你会有真正的问题得到这个工作可靠。 你并不是完全明白你在做什么,但是我假设,在给定窗口句柄的情况下,通过调用GetWindowDC()来获取与窗口相关的设备上下文,然后使用生成的设备上下文。

当窗口可见时,这将在XP上正常工作。 但是,在Vista上,如果启用了桌面合成功能,那么它将无法正常工作:您将从GetWindowDC()返回0。 从根本上讲,抓住窗口设备上下文不会可靠地工作。

如果你试图复制的窗口是你自己的应用程序的一部分,我建议修改你的代码来支持WM_PRINT消息:这就像WM_PAINT一样,但是允许你提供一个设备上下文来绘制。

如果该窗口不是来自您的应用程序,那么基本上是不幸的:如果该窗口是隐藏的,那么它将显示的图像在任何地方都不存在。

PrintWindow函数似乎不能在隐藏的窗口上工作,只能在可见的窗口上工作。

从不同的角度来看待事情,你确定这真的是你想要做的? 例如,您不希望使用CreateCompatibleDC和CreateCompatibleBitmap来创建不可见的绘图表面,然后使用BitBlt进行绘制?

一些关于背景的更多信息可能会使某人想出一个解决方案或一些横向思维。

我只是在Windows 7中测试这个,应该从XP工作正常。

在捕捉它之前,它将窗口置于前台,而不用关注它。 这并不完美,但如果无法使PrintWindow()正常工作,那么这是最好的选择。

这是一个静态的方法,所以你可以简单地这样调用它:

 Orwellophile.TakeScreenShotOfWindow("window.jpg", Form.Handle); 

不要乱,不要大惊小怪 这是从一个更大的班级,所以希望没有失踪。 原件是:

http://sfinktah.trac.cvsdude.com/vhddirector/browser/main/VHD%20Director/UnhandledExceptionManager.cs和http://sfinktah.trac.cvsdude.com/vhddirector/browser/main/CSharp.cc/Win32Messaging。虽然他们不像我粘贴在下面的例子那样整洁。

 using System; using System.Drawing; using System.Threading; using System.Runtime.InteropServices; using System.Windows.Forms; public class Orwellophile { public static void TakeScreenshotOfWindow(String strFilename, IntPtr hTargetWindow) { Rectangle objRectangle; RECT r; IntPtr hForegroundWindow = GetForegroundWindow(); GetWindowRect(hTargetWindow, out r); objRectangle = r.ToRectangle(); if (hTargetWindow != hForegroundWindow) { ShowWindow(hTargetWindow, SW_SHOWNOACTIVATE); SetWindowPos(hTargetWindow.ToInt32(), HWND_TOPMOST, rX, rY, r.Width, r.Height, SWP_NOACTIVATE); Thread.Sleep(500); } TakeScreenshotPrivate(strFilename, objRectangle); } private static void TakeScreenshotPrivate(string strFilename, Rectangle objRectangle) { Bitmap objBitmap = new Bitmap(objRectangle.Width, objRectangle.Height); Graphics objGraphics = default(Graphics); IntPtr hdcDest = default(IntPtr); int hdcSrc = 0; objGraphics = Graphics.FromImage(objBitmap); hdcSrc = GetDC(0); // Get a device context to the windows desktop and our destination bitmaps hdcDest = objGraphics.GetHdc(); // Copy what is on the desktop to the bitmap BitBlt(hdcDest.ToInt32(), 0, 0, objRectangle.Width, objRectangle.Height, hdcSrc, objRectangle.X, objRectangle.Y, SRCCOPY); objGraphics.ReleaseHdc(hdcDest); // Release DC ReleaseDC(0, hdcSrc); objBitmap.Save(strFilename); } [DllImport("gdi32.dll", SetLastError = true)] static extern IntPtr CreateCompatibleDC(IntPtr hdc); [DllImport("user32.dll")] static extern IntPtr GetWindowDC(IntPtr hWnd); [DllImport("gdi32.dll")] static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight); [DllImport("gdi32.dll", ExactSpelling = true, PreserveSig = true, SetLastError = true)] static extern IntPtr SelectObject(IntPtr hdc, IntPtr hgdiobj); [DllImport("User32.dll", SetLastError = true)] [return: MarshalAs(UnmanagedType.Bool)] static extern bool PrintWindow(IntPtr hwnd, IntPtr hDC, uint nFlags); // To capture only the client area of window, use PW_CLIENTONLY = 0x1 as nFlags [DllImport("gdi32.dll")] static extern bool DeleteObject(IntPtr hObject); [DllImport("user32.dll")] static extern bool ReleaseDC(IntPtr hWnd, IntPtr hDC); [DllImport("user32.dll", EntryPoint = "SetWindowPos")] static extern bool SetWindowPos( int hWnd, // window handle int hWndInsertAfter, // placement-order handle int X, // horizontal position int Y, // vertical position int cx, // width int cy, // height uint uFlags); // window positioning flags [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] [return: MarshalAs(UnmanagedType.Bool)] public static extern bool GetWindowRect(IntPtr hwnd, out RECT lpRect); [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)] static public extern IntPtr GetForegroundWindow(); private const int SW_SHOWNOACTIVATE = 4; private const int HWND_TOPMOST = -1; private const uint SWP_NOACTIVATE = 0x0010; private const int SRCCOPY = 0xcc0020; } 

请注意,您可以实现自己的轻量级RECT类/结构,但是这是我使用的。 由于它的大小,我已经单独附加了它

 [StructLayout(LayoutKind.Sequential)] public struct RECT { private int _Left; private int _Top; private int _Right; private int _Bottom; public RECT(System.Drawing.Rectangle Rectangle) : this(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom) { } public RECT(int Left, int Top, int Right, int Bottom) { _Left = Left; _Top = Top; _Right = Right; _Bottom = Bottom; } public int X { get { return _Left; } set { _Left = value; } } public int Y { get { return _Top; } set { _Top = value; } } public int Left { get { return _Left; } set { _Left = value; } } public int Top { get { return _Top; } set { _Top = value; } } public int Right { get { return _Right; } set { _Right = value; } } public int Bottom { get { return _Bottom; } set { _Bottom = value; } } public int Height { get { return _Bottom - _Top; } set { _Bottom = value - _Top; } } public int Width { get { return _Right - _Left; } set { _Right = value + _Left; } } public Point Location { get { return new Point(Left, Top); } set { _Left = value.X; _Top = value.Y; } } public Size Size { get { return new Size(Width, Height); } set { _Right = value.Height + _Left; _Bottom = value.Height + _Top; } } public Rectangle ToRectangle() { return new Rectangle(this.Left, this.Top, this.Width, this.Height); } static public Rectangle ToRectangle(RECT Rectangle) { return Rectangle.ToRectangle(); } static public RECT FromRectangle(Rectangle Rectangle) { return new RECT(Rectangle.Left, Rectangle.Top, Rectangle.Right, Rectangle.Bottom); } static public implicit operator Rectangle(RECT Rectangle) { return Rectangle.ToRectangle(); } static public implicit operator RECT(Rectangle Rectangle) { return new RECT(Rectangle); } static public bool operator ==(RECT Rectangle1, RECT Rectangle2) { return Rectangle1.Equals(Rectangle2); } static public bool operator !=(RECT Rectangle1, RECT Rectangle2) { return !Rectangle1.Equals(Rectangle2); } public override string ToString() { return "{Left: " + _Left + "; " + "Top: " + _Top + "; Right: " + _Right + "; Bottom: " + _Bottom + "}"; } public bool Equals(RECT Rectangle) { return Rectangle.Left == _Left && Rectangle.Top == _Top && Rectangle.Right == _Right && Rectangle.Bottom == _Bottom; } public override bool Equals(object Object) { if (Object is RECT) { return Equals((RECT)Object); } else if (Object is Rectangle) { return Equals(new RECT((Rectangle)Object)); } return false; } public override int GetHashCode() { return Left.GetHashCode() ^ Right.GetHashCode() ^ Top.GetHashCode() ^ Bottom.GetHashCode(); } } 

对于隐藏在另一个窗口后面的窗口,您可以将其设置为透明(具有较高的alpha值,以使其看起来不透明)。 那么应该可以用BitBlt捕获整个窗口。