PrintScreen仅活动窗口

时间:2011-01-14 15:07:28

标签: c# winforms

我正在编写一个简单的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++;
        }

6 个答案:

答案 0 :(得分:2)

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

您需要获取当前窗口的句柄(使用get ForegroundWindow,然后使用Handle属性),然后找到要捕获图像的窗口,可能使用代码与TaskbarWindows中的类似。获得窗口后,您需要发送密钥Alt + PrtScn(可能再次使用user32 API,但我不会进入。)然后使用静态{ {1}}属性,使用您在开始时保存的句柄将orignal窗口设置为forground。

祝你好运!

答案 1 :(得分:1)

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

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

  1. 当用户按下“捕获”按钮时,捕获鼠标并启动拖动操作。
  2. 让用户将鼠标(可能现在有一个“靶心”或“相机”光标)拖到要捕捉的窗口。
  3. 当用户释放鼠标时,确定它位于顶部的窗口,并使用此窗口的位置和大小来捕获正确的像素。
  4. 您可能需要使用P / Invoke来获取有关桌面上所有顶级窗口的信息。

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

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

我最终采取了不同的路线。

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

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

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

        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();
        }

答案 4 :(得分:0)

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

答案 5 :(得分:0)

SendKeys怎么样?

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

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

比打电话

BitmapSource image = Clipboard.GetImage();

你可以恢复你的形象