我正在构建一个winforms应用程序,该应用程序每500毫秒每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);
该代码工作正常,但唯一的问题是,当我从外部进程的窗口打开一个对话框时(对于Notepad中的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();
但是,此代码对于仅向用户展示正在记录的应用程序中没有任何其他应用程序在录制区域内或记录区域内桌面部分的应用程序。另外,当我单击菜单时,有时会显示以褪色位置冻结的菜单,有时根本没有显示或显示出显示,但导航突出显示了屏幕截图中不可见的。
所以有什么办法可以解决此问题?
在这里问类似的问题 屏幕捕获不捕获我的应用程序中的对话框 但这不能解决我的问题,因为答案正在使用相同的代码 而且我的应用程序不使用整个桌面的屏幕截图。
,除非您可以保留该对话框窗口句柄并确定它是否是您关心的手柄的孩子(不太可能),您基本上必须使用它。
您可以在延迟中构建,以允许屏幕截图在对话框情况发生的情况下继续进行固定的时间,希望在给定时间段后将控制返回原始手柄,并且只有当它不在在那段时间之后返回您的捕获过程。
或
您可以使用类似的内容来掌握窗口句柄的过程信息。
通过Window的句柄查找过程ID
...如果拥有过程与应用程序可能仍然具有焦点相同(除非发生了非常奇怪的事情)。
但是,此代码对于仅向用户显示的应用程序是必需的 正在记录没有任何其他正在拖动的应用程序 在录制区域或录制内部的桌面部分 区域。
我正在为子窗户拿到手柄,但问题是如何 将它们包含在主窗口中的屏幕截图中?
我认为在这种情况下,您唯一的选择是捕获两个屏幕(主窗口和对话框),并使用BitBlt()
或类似的东西自己组合。
还请记住,对话框可以移动在主窗口区域外,甚至可以移至第二个屏幕。因此,即使您可以单镜头捕捉这两个,也可能不是您想要的。通过自己组合,您可以将对话框放回主屏幕顶部。
当然,您必须在窗口手柄(使用PrintWindow()
)而不是屏幕或桌面区域上进行捕获。请参阅此处和此处的一些有关如何执行此操作的示例。
if (GetForegroundWindow() != proc.MainWindowHandle)
这可能是对话框未捕获的原因(即根本没有捕获),但是即使您修复或删除了该对话框,即使打开对话框,也可以在区域内拖动另一个窗口。