屏幕截图

时间:2017-02-28 20:30:34

标签: c# .net winforms graphics

我正在构建一个WinForms应用程序,它通过每500毫秒获取一次屏幕截图来记录外部进程的步骤。我使用以下代码:

Bitmap bmp = new Bitmap(width, height,PixelFormat.Format32bppArgb);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(rect.left,
                 rect.top,
                 0,
                 0,
                 new Size(width, height),
                 CopyPixelOperation.SourceCopy);

代码工作正常但唯一的问题是当我从外部进程的窗口打开一个对话框时(例如,在记事本中打开Save As...对话框),屏幕截图冻结到原始窗口而不是显示对话框。

我的理论是,由于我正在使用以下代码来检测应用程序是否失去焦点,然后只是恢复到上次保存的屏幕截图:

if (GetForegroundWindow() != proc.MainWindowHandle) //proc is just a process from system process list by Process.GetProcessesByName()
{
   return LastScreenShot;
}
[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
private static extern IntPtr GetForegroundWindow();

但是,此代码对于向用户仅显示正在记录的应用程序而不是在记录区域内部拖动的任何其他应用程序或记录区域内的桌面部分是必要的。此外,当我点击菜单时,它有时会显示菜单在褪色位置冻结,有时根本不显示或显示但导航突出显示在屏幕截图中不可见。

那么有什么方法可以解决这个问题吗?

  

这里有类似的问题   Screen Capture Not Capturing Dialog Boxes in My application   但它没有解决我的问题,因为答案使用相同的代码   我的应用程序没有截取整个桌面的截图。

2 个答案:

答案 0 :(得分:1)

除非你能掌握那个对话框窗口句柄,并确定它是否是你所关心的句柄的孩子(不太可能),你基本上必须使用它。

您可以构建延迟,以便在对话框情况发生时允许屏幕截图持续一段时间,希望在给定时间段后控件将返回到原始句柄,并且只有在没有在那个时间段之后停止你的捕获过程。

您可以使用类似的东西来掌握窗口句柄的进程信息....

Find process id by window's handle

...如果拥有过程是相同的,应用程序可能仍然具有焦点(除非发生一些非常奇怪的事情)。

答案 1 :(得分:0)

  

但是这个代码对于向用户显示只有应用程序是必要的   正在记录的不是任何其他被拖动的应用程序   录制区域内部或录制内部桌面部分   区域。

  

我正在获取子窗口的句柄,但问题是如何   将它们包含在主窗口的屏幕截图中?

我认为在这种情况下,您唯一的选择是捕获两个屏幕(主窗口和对话框)并使用BitBlt()或类似的东西自行组合。

另请注意,对话框可以移动到主窗口区域之外,甚至可以移动到第二个屏幕。因此,即使你可以一次拍摄两者,这可能不是你想要的。通过自己组合它们,您可以将对话框放回主屏幕的顶部。

当然,您必须在窗口句柄上进行捕获(使用PrintWindow()),而不是屏幕或桌面区域。有关如何执行此操作的示例,请参阅herehere

if (GetForegroundWindow() != proc.MainWindowHandle)

这可能是未捕获对话框的原因(即根本没有捕获),但即使您修复或删除了该对话框,即使打开对话框,也可以在该区域内拖动另一个窗口。