我正在尝试在C#.net中创建一个应用程序,它捕获当前活动窗口的屏幕截图,包括必须使用滚动条滚动的区域。我找到了以下代码来截取屏幕截图。为了清楚起见,我希望代码能够获取活动窗口的屏幕截图,包括未显示的区域,并且只能使用滚动条显示。
public class ScreenShot
{
/// <summary>
/// Captures the screenshot of the entire desktop
/// </summary>
/// <returns>Image object containing the screenshot of the desktop</returns>
private Image CaptureDesktop()
{
return CaptureWindow(User32.GetDesktopWindow());
}
public Image CaptureAciveWindow()
{
return CaptureWindow(User32.GetForegroundWindow());
}
/// <summary>
/// An Internal method, that captures the screenshot of any given Application window, given its Handle.
/// </summary>
/// <param name="handle">The handle of the window you want to Capture</param>
/// <returns>An Image object containing the screenshot of the active application window</returns>
private Image CaptureWindow(IntPtr handle)
{
// get te hDC of the target window
IntPtr hdcSrc = User32.GetWindowDC(handle);
// get the size
User32.RECT windowRect = new User32.RECT();
User32.GetWindowRect(handle, ref windowRect);
int width = windowRect.right - windowRect.left;
int height = windowRect.bottom - windowRect.top;
// create a device context we can copy to
IntPtr hdcDest = GDI32.CreateCompatibleDC(hdcSrc);
// create a bitmap we can copy it to,
// using GetDeviceCaps to get the width/height
IntPtr hBitmap = GDI32.CreateCompatibleBitmap(hdcSrc, width, height);
// select the bitmap object
IntPtr hOld = GDI32.SelectObject(hdcDest, hBitmap);
// bitblt over
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, GDI32.SRCCOPY);
// restore selection
GDI32.SelectObject(hdcDest, hOld);
// clean up
GDI32.DeleteDC(hdcDest);
User32.ReleaseDC(handle, hdcSrc);
// get a .NET image object for it
Image img = Image.FromHbitmap(hBitmap);
// free up the Bitmap object
GDI32.DeleteObject(hBitmap);
return img;
}
/// <summary>
/// Helper class containing Gdi32 API functions
/// </summary>
private class GDI32
{
public const int SRCCOPY = 0x00CC0020; // BitBlt dwRop parameter
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest,
int nWidth, int nHeight, IntPtr hObjectSource,
int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hDC, int nWidth,
int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hDC);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hDC, IntPtr hObject);
}
/// <summary>
/// Helper class containing User32 API functions
/// </summary>
private class User32
{
[StructLayout(LayoutKind.Sequential)]
public struct RECT
{
public int left;
public int top;
public int right;
public int bottom;
}
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("user32.dll")]
public static extern IntPtr ReleaseDC(IntPtr hWnd, IntPtr hDC);
[DllImport("user32.dll")]
public static extern IntPtr GetWindowRect(IntPtr hWnd, ref RECT rect);
/// <summary>
/// Gets the Handle for current active window
/// </summary>
/// <returns>Active windows Handle</returns>
[DllImport("user32.dll")]
public static extern IntPtr GetForegroundWindow();
}
}
答案 0 :(得分:4)
你在这里做出一个假设并不一定是真的:那里有一些已经在未展开区域等待的东西。应用程序可以为某个高度或宽度构建滚动条,并且实际上不会向表面渲染任何内容,直到用户实际拖动滚动条。您要捕获的图像仅存在于潜在的图像中。这可用于提高性能 - 考虑即时加载或减少内存使用。这是一种相当常见的技术,所以你所要求的并没有多大意义。
答案 1 :(得分:3)
在不使用任何Win32 API调用的情况下捕获屏幕内容,只需在CodeProject使用.NET 2.0。
答案 2 :(得分:1)
如果您尝试获取屏幕外的内容,则WM_PRINT
可能有效。 BitBlt
肯定不会。
见:
答案 3 :(得分:1)
您需要将整个窗口/表单重绘到图形对象上。可以在this CodeProject article中找到如何完成此操作的(简单)示例。您需要实现对项目中所需的所有控件的支持。此外,如果您在示例应用程序中调整窗口大小(隐藏一些控件)并进行测试打印,您将看到主窗体(它只是另一个控件)被绘制在其他控件上,这不是真正的问题但是看起来不太好 - 如果这是一个问题,你可以删除绘制主表单的支持。
或者,如果使用或切换到WPF,您可以使用PrintDialog.PrintVisual()打印控件(包括主窗口)。