Domanda

Sto cercando di automatizzare terze parti applicazione Win32 dove voglio catturare il contenuto grafico di una particolare finestra a intervalli di tempo definiti. Sono nelle prime fasi di questo, e attualmente sto cercando di utilizzare il Microsoft UI Automation API tramite C # per fare la maggior parte delle interazioni tra la mia applicazione client e l'applicazione esterna. Ora posso ottenere l'applicazione esterna di fare quello che voglio fare, ma ora voglio catturare la grafica da una finestra specifica che sembra essere un po 'di terze parti di controllo proprietario-disegnato. Come posso fare questo? La finestra che voglio di acquisizione è quella contrassegnata dal rettangolo rosso in questa immagine:

ho bisogno di ciò che è nel rettangolo rosso

Ho un'implementazione che tipo di opere, ma è dipendente sull'interfaccia utente dell'applicazione esterna essere in cima, e che non è garantito per me, così io preferirei di trovare qualcosa di più generale.

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

I lavori di cui sopra abbastanza bene quando l'applicazione automatica è in cima, ma semplicemente ciecamente copia lo schermo nel rettangolo, quindi il mio codice è in balia di tutto ciò che accade di essere in esecuzione sulla macchina e potrebbe coprire la finestra del mio app.

Ho letto alcuni suggerimenti per inviare il messaggio WM_PRINT alla finestra. Questo domanda / risposta da qualche mese fa sembrava promettente, ma quando uso questo codice, ottengo solo un rettangolo bianco con nessuno dei contenuti effettivi del mio controllo.

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

Quindi, in primo luogo, è ancora possibile per me in modo affidabile salvare una bitmap del contenuto di una finestra? Se sì, qual è il modo migliore, e ciò che è sbagliato con la mia WM_PRINT con il tentativo SendMessage?

È stato utile?

Soluzione

Questa modifica della PrintWindow API esempio sul PInvoke. sito rete sembra aver fatto il trucco.

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

Questo funziona se l'applicazione è coperta da un'altra finestra, ma non funziona se l'applicazione è ridotto al minimo. Penso di poter vivere con questo.

Altri suggerimenti

Non c'è affidabile modo per ottenere una bitmap da un'altra applicazione, se tale applicazione non è in cima. Questo perché i controlli della app non hanno nemmeno rendono se l'applicazione non è visibile, e Windows non necessariamente nemmeno ricordare ciò che gli ultimi contenuti noti del controllo sono stati, dopo che il controllo perde la posizione più alta in ordine z.

La cosa migliore è quello di spostare l'applicazione di destinazione per la parte anteriore del ordine Z nel momento in cui è necessario prendere screenshot, e poi eventualmente ripristinare l'ordine Z originale dopo la cattura dell'immagine.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top