我可以在另一个应用程序进程中获取任意窗口的位图吗? [英] Can I get a bitmap of an arbitrary window in another application process?

查看:108
本文介绍了我可以在另一个应用程序进程中获取任意窗口的位图吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使第三方Win32应用程序自动化,在该应用程序中我想按定义的时间间隔捕获特定窗口的图形内容.我正处于此阶段的早期阶段,目前正在尝试使用

I am trying to automate a third-party Win32 application where I want to capture the graphics content of a particular window at defined time intervals. I am in the early phases of this, and I'm currently trying to use the Microsoft UI Automation API via C# to do most of the interaction between my client app and the external app. I can now get the external app to do what I want it to do, but now I want to capture the graphics from a specific window that seems to be some third-party owner-drawn control. How can I do this? The window I want to capture is the one marked by the red rectangle in this image:

我有一个可以实现这种工作的实现,但是它取决于外部应用程序的UI是否位于顶部,并且我不能保证这是我的保证,因此,我希望找到更通用的东西.

I have an implementation that sort of works, but it's dependent on the external app's UI being on top, and that's not guaranteed for me, so I'd prefer to find something more general.

var p = Process.Start("c:\myapp.exe");
var mainForm = AutomationElement.FromHandle(p.MainWindowHandle);
// "workspace" below is the window whose content I want to capture.
var workspace = mainForm.FindFirst(TreeScope.Descendents,
                    new PropertyCondition(AutomationElement.ClassNameProperty, "AfxFrameOrView70u"));
var rect = (Rect) workspace.GetCurrentPropertyValue(AutomationElement.BoundingRectangleProperty);
using (var bmp = new Bitmap((int)rect.Width, (int)rect.Height))
{
    using (var g = Graphics.FromImage(bmp))
    {
        g.CopyFromScreen((int)rect.Left, (int)rect.Top, 0, 0, new Size((int)rect.Width, (int)rect.Height));
        bmp.Save(@"c:\screenshot.png", ImageFormat.Png);
    }
}

当自动化应用程序位于顶部时,上面的方法就足够好了,但是它只是盲目地将屏幕复制为矩形,因此我的代码受机器上正在运行的任何操作的影响,并且可能会覆盖我的应用程序的窗口.

The above works well enough when the automated app is on top, but it just blindly copies the screen in the rectangle, so my code is at the mercy of whatever happens to be running on the machine and might cover my app's window.

我已经阅读了一些将WM_PRINT消息发送到窗口的建议.几个月前的问题/答案很有希望,但是当我使用此代码时,我只会得到一个白色矩形,其中没有控件的实际内容.

I have read some suggestions to send the WM_PRINT message to the window. This question/answer from a few months back seemed promising, but when I use this code, I just get a white rectangle with none of my control's actual contents.

var prop = (int)workspace.GetCurrentPropertyValue(AutomationElement.NativeWindowHandleProperty);
var hwnd = new IntPtr(prop);
using ( var bmp2 = new Bitmap((int)rect.Width, (int)rect.Height))
{
    using (Graphics g = Graphics.FromImage(bmp2))
    {
        g.FillRectangle(SystemBrushes.Control, 0, 0, (int)rect.Width, (int)rect.Height);
        try
        {
            SendMessage(hwnd, WM_PRINT, g.GetHdc().ToInt32(), (int)(DrawingOptions.PRF_CHILDREN | DrawingOptions.PRF_CLIENT | DrawingOptions.PRF_OWNED));
        }
        finally
        {
            g.ReleaseHdc();
        }
        bmp2.Save(@"c:\screenshot.bmp");
    }
}

那么,首先,我什至可以可靠地保存窗口内容的位图吗?如果是这样,什么是最好的方法?我的WM_PRINT尝试SendMessage怎么了?

So, first, is it even possible for me to reliably save a bitmap of a window's contents? If so, what is the best way, and what is wrong with my WM_PRINT with SendMessage attempt?

推荐答案

PrintWindow API示例似乎可以解决问题.

This modification of the PrintWindow API example on the pinvoke.net site seems to have done the trick.

Bitmap bmp = new Bitmap((int)rect.Width, (int)rect.Height);
Graphics memoryGraphics = Graphics.FromImage(bmp);
IntPtr dc = memoryGraphics.GetHdc();
bool success = PrintWindow(hwnd, dc, 0);
memoryGraphics.ReleaseHdc(dc);
bmp.Save(@"c:\screenshot.bmp");

如果应用程序被另一个窗口覆盖,则此方法有效,但是如果应用程序最小化,则无效.我想我可以接受.

This works if the app is covered by another window, but it doesn't work if the app is minimized. I think I can live with that.

这篇关于我可以在另一个应用程序进程中获取任意窗口的位图吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆