Pregunta

Estoy tratando de automatizar una aplicación Win32 de terceros donde quiero capturar el contenido de gráficos de una ventana en particular, a intervalos de tiempo definidos. Estoy en las primeras fases de este, y actualmente estoy tratando de utilizar el API de Microsoft UI Automation a través de C # para hacer la mayor parte de la interacción entre mi aplicación cliente y la aplicación externa. Ahora puedo obtener la aplicación externa para hacer lo que quiero que haga, pero ahora quiero capturar los gráficos desde una ventana específica que parece ser algún tipo de control dibujado por el propietario de terceros. ¿Cómo puedo hacer esto? La ventana que desea capturar es el marcado por el rectángulo rojo en esta imagen:

necesito lo que hay en el rectángulo rojo

Tengo una implementación ese tipo de obras, pero es dependiente de la interfaz de usuario de la aplicación externa de estar en la cima, y ??que no está garantizado para mí, así que prefiero encontrar algo más 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);
    }
}

Los trabajos anteriores lo suficientemente bien como cuando la aplicación automatizada es en la parte superior, pero a ciegas copia la pantalla en el rectángulo, por lo que mi código está a merced de lo que pase a estar en ejecución en la máquina y podría cubrir la ventana de mi aplicación.

He leído algunas sugerencias para enviar el mensaje WM_PRINT a la ventana. Este pregunta / respuesta desde hace unos meses parecía prometedor, pero cuando se utiliza este código, que acaba de obtener un rectángulo blanco con ninguno de los contenidos reales de mi control.

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

Por lo tanto, en primer lugar, es incluso posible que yo fiable guardar un mapa de bits del contenido de una ventana? Si es así, ¿cuál es la mejor manera, y lo que está mal con mi WM_PRINT con el intento SendMessage?

¿Fue útil?

Solución

Esta modificación de la PrintWindow API ejemplo en la PInvoke. sitio de la red parece haber hecho el truco.

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

Esto funciona si la aplicación está cubierta por otra ventana, pero no funciona si se minimiza la aplicación. Creo que puedo vivir con eso.

Otros consejos

No hay forma de confiable para obtener un mapa de bits de una aplicación diferente si esa aplicación no está en la parte superior. Esto se debe a los controles de la aplicación ni siquiera se hacen si la aplicación no es visible, y Windows no necesariamente incluso recordar lo que los últimos contenidos conocidas del control fueron después de que el control pierde la posición superior en el orden z.

Su mejor opción es mover la aplicación de destino a la parte delantera del orden z en el momento que usted necesita para tomar la captura de pantalla, y luego restaurar el original opcionalmente orden z después de capturar la imagen.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top