【问题标题】:Dialog Boxes and Menu Changes not captured in Screenshot屏幕截图中未捕获的对话框和菜单更改
【发布时间】:2017-03-11 01:12:27
【问题描述】:

我正在构建一个 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 但这并不能解决我的问题,因为答案是使用相同的代码 而且我的应用程序不会截取整个桌面的屏幕截图。

【问题讨论】:

  • 这可能值得一试:stackoverflow.com/questions/1363167/…。因此,也许您可​​以针对所有子窗口进行验证,而不仅仅是针对 proc.MainWindowHandle
  • @Johan 感谢您的链接,但我已经阅读了该主题。我正在获取子窗口的句柄,但问题是如何将它们包含在主窗口的屏幕截图中?我也在验证,但 OpenFileDialog 和 SaveFileDialog 等对话框仍然没有出现在屏幕截图中。
  • 啊,好吧。我想到了你所说的你认为这可能是因为当主句柄不是前台窗口时你恢复到上次保存的屏幕截图。
  • @Johan 问题是当我打开主菜单和对话框时它们变成了前台窗口。
  • 如您所说,也许只是您的测试GetForegroundWindow() != proc.MainWindowHandle 无效。为什么不检查前景或模态窗口是否属于您正在录制的进程? (您可以在这里使用我的回答中的GetModalWindowstackoverflow.com/questions/19147/…

标签: c# .net winforms graphics


【解决方案1】:

除非您可以获取对话框窗口句柄并确定它是否是您关心的句柄的子句柄(不太可能),否则您基本上必须使用它。

当对话情况发生时,您可以构建延迟以允许在设定的时间段内继续截屏,希望在给定时间段后控制权将返回到原始句柄,并且仅当它没有't return after that time period stop your capture process.

或者

您可以使用类似这样的方式获取窗口句柄的进程信息 ....

Find process id by window's handle

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

【讨论】:

  • 我试过这个int activeProcId, threadProcId ; GetWindowThreadProcessId(proc.MainWindowHandle, out activeProcId); GetWindowThreadProcessId(GetForegroundWindow(), out threadProcId); if (activeProcId == threadProcId) MessageBox.Show("Yes, the threads are from same process."); 它适用于主窗口,但不适用于对话框。
  • 据此:stackoverflow.com/questions/12597599/… ...这意味着您可以将其与对话框一起使用。可能缺少某些设置或参数?
【解决方案2】:

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


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

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

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

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


if (GetForegroundWindow() != proc.MainWindowHandle)

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    相关资源
    最近更新 更多