我正在尝试自动化第三方 Win32 应用程序,我想在定义的时间间隔捕获特定窗口的图形内容。我正处于这个的早期阶段,目前我正在尝试使用微软用户界面自动化 https://learn.microsoft.com/en-us/previous-versions/dotnet/netframework-4.0/ms747327(v=vs.100)通过 C# API 来完成客户端应用程序和外部应用程序之间的大部分交互。我现在可以让外部应用程序执行我想要的操作,但现在我想从特定窗口捕获图形,该窗口似乎是某些第三方所有者绘制的控件。我怎样才能做到这一点?我要捕获的窗口是该图像中用红色矩形标记的窗口:
我有一个可行的实现,但它依赖于外部应用程序的 UI 位于顶部,这对我来说并不能保证,所以我更愿意找到更通用的东西。
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);
}
}
当自动化应用程序位于顶部时,上面的方法效果很好,但它只是盲目地复制矩形中的屏幕,因此我的代码受机器上运行的任何内容的支配,并且可能会覆盖我的应用程序的窗口。
我已阅读一些发送的建议WM_PRINT
消息到窗口。这问题/答案 https://stackoverflow.com/questions/1881317/c-sharp-windows-form-control-to-image/1881662#1881662几个月前看起来很有希望,但是当我使用这段代码时,我只是得到一个白色矩形,其中没有控件的实际内容。
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
with SendMessage
试图?