Можно ли получить растровое изображение произвольного окна в другом процессе приложения? - PullRequest
2 голосов
/ 14 мая 2010

Я пытаюсь автоматизировать стороннее приложение Win32, в котором я хочу захватывать графическое содержимое определенного окна через определенные промежутки времени. Я нахожусь на ранних стадиях этого, и в настоящее время я пытаюсь использовать Microsoft UI Automation API через C # для большей части взаимодействия между моим клиентским приложением и внешним приложением. Теперь я могу заставить внешнее приложение делать то, что я от него хочу, но теперь я хочу захватить графику из определенного окна, которое кажется сторонним элементом управления, нарисованным владельцем. Как я могу это сделать? Окно, которое я хочу запечатлеть, помечено красным прямоугольником на этом изображении:

Мне нужно, что находится в красном прямоугольнике http://img168.imageshack.us/img168/8169/5142010110014am.png

У меня есть такая реализация, но она зависит от того, какой интерфейс внешнего приложения находится сверху, и это не гарантировано для меня, поэтому я предпочел бы найти что-то более общее.

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 в окно. Этот вопрос / ответ из нескольких месяцев назад казался многообещающим, но когда я использую этот код, я просто получаю белый прямоугольник без фактического содержимого моего элемента управления.

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?

Ответы [ 2 ]

4 голосов
/ 14 мая 2010

Эта модификация PrintWindow примера API на сайте pinvoke.net, похоже, добилась цели.

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 голос
/ 14 мая 2010

Нет надежного способа получить растровое изображение из другого приложения, если это приложение не находится сверху. Это связано с тем, что элементы управления приложения даже не отображаются, если приложение не видно, а Windows не обязательно даже запоминает, каким было последнее известное содержимое элемента управления после того, как элемент управления теряет верхнюю позицию в z-порядке.

Лучше всего переместить целевое приложение в начало z-порядка в тот момент, когда вам нужно сделать снимок экрана, а затем при необходимости восстановить исходный z-порядок после захвата изображения.

...