2010-05-14 27 views
2

我正在尝试自动化第三方Win32应用程序,我希望以指定的时间间隔捕获特定窗口的图形内容。我处于早期阶段,目前我正尝试通过C#使用Microsoft UI Automation API来完成我的客户端应用程序和外部应用程序之间的大部分交互。现在我可以让外部应用程序执行我想要的操作,但是现在我想从特定窗口捕获图形,这似乎是一些第三方所有者绘制的控件。我怎样才能做到这一点?我想要捕捉的窗口是一个该图像中打上了红色矩形:我可以在另一个应用程序进程中获得任意窗口的位图吗?

I need what's in the red rectangle http://img168.imageshack.us/img168/8169/5142010110014am.png

我有一个实现那种作品,但它是依赖于外部应用程序的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消息发送到窗口。几个月前的这个question/answer似乎很有前途,但是当我使用这段代码时,我只是得到一个没有我的控件的实际内容的白色矩形。

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

因此,首先,我是否可以可靠地保存窗口内容的位图?如果是这样,什么是最好的方式,以及与SendMessage尝试有什么不对?

回答

4

pinvoke.net网站上PrintWindow API example的这种修改似乎已经成功了。

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"); 

如果应用程序被另一个窗口覆盖,但它在应用程序最小化时不起作用。我想我可以忍受这一点。

1

没有可靠如果该应用不在顶层,则可以从另一个应用获取位图。这是因为如果应用程序不可见,应用程序的控件甚至无法呈现,而Windows不一定记得控件的最后已知内容是在控件失去z顺序中的最高位置之后。

您最好的选择是在您需要拍摄屏幕截图时将目标应用程序移动到z顺序的前端,然后在捕获图像后可选择性恢复原始z顺序。

相关问题