PrintScreen仅活动窗口

我正在编写一个简单的Windows窗体实用程序来截取整个屏幕或活动窗口并保存文件。 winform有一个名为“Capture”的按钮,点击后会截取屏幕截图。

我的代码完全适用于整个屏幕,但无法弄清楚活动窗口。

通过我当前的代码,如果我选择“活动窗口”,它最终打印筛选应用程序本身,这不是我想要的。

这是我的代码(在Capture_Click方法下):

try { this.Hide(); bmpScreenshot = new Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height, PixelFormat.Format32bppArgb); //bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb); gfxScreenshot = Graphics.FromImage(bmpScreenshot); if (AltPrint.Checked) { gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy); } else { gfxScreenshot.CopyFromScreen(Screen.PrimaryScreen.Bounds.X, Screen.PrimaryScreen.Bounds.Y, 0, 0, Screen.PrimaryScreen.Bounds.Size, CopyPixelOperation.SourceCopy); } bmpScreenshot.Save(SaveLocation, ImageFormat.Png); number++; } 

据我所知,您的代码使用自己的表单边界来捕获“活动”窗口。 这可能不是你想要的。

如果您想使用鼠标“打印”一个窗口(而不是可能更容易实现的热键),您需要能够从您自己的表单中让用户指向另一个窗口进行捕获。 这是一个描述如何做到这一点的想法:

  1. 当用户按下“捕获”按钮时捕获鼠标并启动拖动操作。
  2. 让用户将鼠标(可能现在具有“靶心”或“相机”光标)拖动到要捕获的窗口。
  3. 当用户释放鼠标时,确定它位于顶部的窗口,并使用此窗口的位置和大小来捕获正确的像素。

您可能需要使用P / Invoke来获取有关桌面上所有顶级窗口的信息。

请注意,“鼠标捕获”与“屏幕捕获”非常不同。 当应用程序“捕获鼠标”时,它将获得鼠标光标的所有权,并且即使将鼠标移动到应用程序窗口的边界之外也无法跟踪鼠标。

在你的button_Click方法中,为了捕获除捕获之外的窗口,我唯一可以看到的方法是使用user32 Windows API。

您首先需要平台调用这样的方法:

 [DllImport("user32.dll", SetLastError = true)] private static extern int GetWindowLong(IntPtr hWnd, GetWindowLongNIndex nIndex); 

我推荐www.pinvoke.net/了解更多相关信息。

这是我自己的Window类(正在进行中,但可用),欢迎您使用它作为示例: http : //pastebin.com/fj2tEaPY

那里有一些有用的属性是:

  • 得到AllWindows
  • 获取TaskbarWindows
  • 设置ForegroundWindow

您需要获取当前窗口的句柄(使用获取ForegroundWindow ,然后使用Handle属性),然后找到要捕获图像的窗口,可能使用类似于TaskbarWindows代码。 一旦你有了窗口,你需要发送按键Alt + PrtScn (再次使用user32 API,但我不会进入它。)然后使用静态ForegroundWindow属性将orignal窗口设置为使用句柄的forground你在开始时保存的。

祝好运!

您的评论似乎明白,一旦您的应用获得焦点(当您点击它时),另一个应用程序已经丢失它并且不再“活跃”。

一种可能的替代方案:您的应用程序在获得焦点时会收到WM_SETFOCUS消息。 该消息的wParam是任何窗口刚刚放弃焦点的句柄 – 该窗口属于您要捕获的应用程序。

当然,该窗口只是一个子窗口或控件,但你可以找出哪个应用程序拥有该按钮。

我最终选择了不同的路线。

我允许用户调整表单窗口的大小以准确覆盖他们需要截屏的区域,然后当他们单击按钮时,表单隐藏自己,截取它覆盖的区域并再次显示。 与我最初的计划相反,我认为这将更有益,因为我的目标用户(我所参与的超频论坛的朋友)很少只截取一个窗口的屏幕截图。 它们大多需要覆盖几个窗口(温度监控,时钟速度监控,稳定性测试等)。

谢谢你们的所有答案。 他们肯定让我思考,并让我意识到我的选择是什么。

如果其他人需要它,这是我用于按钮的代码,它只捕获部分屏幕:

  try { this.Hide(); Thread.Sleep(250); bmpScreenshot = new Bitmap(this.Bounds.Width, this.Bounds.Height, PixelFormat.Format32bppArgb); gfxScreenshot = Graphics.FromImage(bmpScreenshot); gfxScreenshot.CopyFromScreen(this.Bounds.X, this.Bounds.Y, 0, 0, this.Bounds.Size, CopyPixelOperation.SourceCopy); bmpScreenshot.Save(SaveLocation, ImageFormat.Png); tbxStatus.AppendText(Environment.NewLine); tbxStatus.AppendText(Environment.NewLine); tbxStatus.AppendText("Screenshot saved at " + SaveLocation); numSuffix++; } catch (Exception ex) { tbxStatus.AppendText(Environment.NewLine); tbxStatus.AppendText(Environment.NewLine); tbxStatus.AppendText("Unable to take screenshot. Exception: " + ex.ToString()); } finally { this.Show(); } 

您需要借用商用屏幕捕获应用程序的设计,例如Psp。 我认为您需要使用“热”键来触发活动窗口的捕获。 而不是在Capture_Click事件上做它。 这样,您可以隐藏应用程序的窗口,使其不会成为活动窗口。 然后,当用户按下“热”键时,您可以捕获它。

SendKeys怎么样?

 Windows.Forms.SendKeys.Send("%{PRTSC}"); 

它会将当前选定的窗口复制到Clipboard对象中。

比打电话

 BitmapSource image = Clipboard.GetImage(); 

你可以恢复你的形象