2009-09-16 8 views
13

Ich arbeite gerade mit WatiN, und finde es ein großartiges Werkzeug zur Automatisierung der Internetsuche. Ab der letzten Version scheint die Bildschirmaufnahmefunktion jedoch zu fehlen. Ich habe eine praktikable Lösung für die Aufnahme von Screenshots vom Bildschirm (unabhängig von der Generierung von Code ähnlich this StackOverflow question) neben einigen code by Charles Petzold. Leider gibt es eine fehlende Komponente: Wo ist das eigentliche Fenster?Wie finde ich die Position/Position eines Fensters mit einer hWnd ohne NativeMethods?

WatiN bietet bequem die hWnd Sie den Browser, so können wir (mit diesem vereinfachten Beispiel) gesetzt bekommen ein Bild aus dem Bildschirm zu kopieren, etwa so:

// browser is either an WatiN.Core.IE or a WatiN.Core.FireFox... 
IntPtr hWnd = browser.hWnd; 
string filename = "my_file.bmp"; 
using (Graphics browser = Graphics.FromHwnd(browser.hWnd)) 
using (Bitmap screenshot = new Bitmap((int)browser.VisibleClipBounds.Width, 
             (int)browser.VisibleClipBounds.Height, 
             browser)) 
using (Graphics screenGraphics = Graphics.FromImage(screenshot)) 
{ 
    int hWndX = 0; // Upper left of graphics? Nope, 
    int hWndY = 0; // this is upper left of the entire desktop! 

    screenGraphics.CopyFromScreen(hWndX, hWndY, 0, 0, 
          new Size((int)browser.VisibileClipBounds.Width, 
            (int)browser.VisibileClipBounds.Height)); 
    screenshot.Save(filename, ImageFormat.Bmp); 
} 

Erfolg! Wir erhalten Screenshots, aber es gibt dieses Problem: hWndX und hWndY zeigen immer auf die obere linke Ecke des Bildschirms, nicht die Position des Fensters, aus dem wir kopieren möchten.

Ich sah dann in Control.FromHandle, aber dies scheint nur mit Formularen arbeiten Sie erstellt; Diese Methode gibt einen Nullzeiger zurück, wenn Sie die hWnd darin übergeben.

Dann führte mich eine weitere Lektüre dazu, meine Suchkriterien zu wechseln ... Ich hatte nach 'Standort des Fensters' gesucht, als die meisten Leute wirklich die 'Position' des Fensters wollen. Dies führte zu another SO question, die darüber sprachen, aber ihre Antwort war, native Methoden zu verwenden.

Also, Gibt es eine native C# Möglichkeit, die Position eines Fensters zu finden, nur mit der hWnd (vorzugsweise mit nur .NET 2.0 Ära Bibliotheken)?

Antwort

29

Ich bin gerade durch dieses Projekt gegangen und konnte keinen verwalteten C# Weg finden.

Reed Antwort ein Die P/Invoke-Code ist:

[DllImport("user32.dll", SetLastError = true)] 
[return: MarshalAs(UnmanagedType.Bool)] 
static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); 
[StructLayout(LayoutKind.Sequential)] 
private struct RECT 
{ 
    public int Left; 
    public int Top; 
    public int Right; 
    public int Bottom; 
    } 

Nennen Sie es wie:

RECT rct = new RECT(); 
    GetWindowRect(hWnd, ref rct); 
+0

Dank! Sieht so aus, als würde es das tun. –

+0

Hallo Robert, Konnten Sie Ihre komplette Lösung bekannt geben? Ich würde gerne screencapture-Funktionalität für Firefox und andere Browser (Chrome) hinzufügen. Vielen Dank im Voraus! Jeroen (Blei Entwickler WatiN) –

+0

hey! Sicher, kann tun. –

6

Nein - wenn Sie das Formular nicht erstellt haben, müssen Sie P/Invoke GetWindowRect. Ich glaube nicht, dass es ein verwaltetes Äquivalent gibt.

4

Die Antwort ist wie andere gesagt haben, wahrscheinlich „Nein, Sie nicht nehmen Screenshot eines zufälligen Fensters von einem HWND ohne native Methoden. ". Paar Einschränkungen, bevor ich zeigen es:

Vorwarnung:

Für alle, die diesen Code verwenden möchte, beachten Sie, dass die Größe von den VisibleClipBounds gegeben ist nur innerhalb das Fenster, und tut nicht Fügen Sie die Rahmen- oder Titelleiste hinzu. Es ist die Zeichnungsfläche. Wenn Sie das hätten, könnten Sie dies ohne p/invoke tun.

(Wenn Sie den Rand des Browserfensters berechnen, könnte man die VisibleClipBounds nutzen könnten. Wenn Sie wollten, können Sie die SystemInformation Objekt verwenden könnten wichtige Informationen wie Border3DSize zu bekommen, oder man könnte versuchen, es zu berechnen, indem ein Dummy-Erstellung Form und deriving the border and title bar height from that, aber das klingt alles wie die schwarze Magie, die Bugs gemacht werden.)

Dies entspricht der Strg + Drucktaste des Fensters. Dies macht auch nicht die Feinheiten, die die WatiN-Screenshot-Fähigkeit tut, wie zum Beispiel den Browser scrollen und ein Bild der ganzen Seite machen. Dies ist für mein Projekt geeignet, aber möglicherweise nicht für Ihr Projekt.

Erweiterungen:

Dies könnte geändert werden eine Erweiterungsmethode zu sein, wenn Sie in .NET 3 und up-Land und eine Option für den Bildtyp sind ziemlich leicht hinzugefügt werden könnte (I Standard zu ImageFormat.Bmp für dieses Beispiel).

Code:

using System.Drawing; 
using System.Drawing.Imaging; 
using System.Runtime.InteropServices; 

public class Screenshot 
{ 
    class NativeMethods 
    { 
     // http://msdn.microsoft.com/en-us/library/ms633519(VS.85).aspx 
     [DllImport("user32.dll", SetLastError = true)] 
     [return: MarshalAs(UnmanagedType.Bool)] 
     public static extern bool GetWindowRect(IntPtr hWnd, ref RECT lpRect); 

     // http://msdn.microsoft.com/en-us/library/a5ch4fda(VS.80).aspx 
     [StructLayout(LayoutKind.Sequential)] 
     public struct RECT 
     { 
      public int Left; 
      public int Top; 
      public int Right; 
      public int Bottom; 
     } 
    } 
    /// <summary> 
    /// Takes a screenshot of the browser. 
    /// </summary> 
    /// <param name="b">The browser object.</param> 
    /// <param name="filename">The path to store the file.</param> 
    /// <returns></returns> 
    public static bool SaveScreenshot(Browser b, string filename) 
    { 
     bool success = false; 
     IntPtr hWnd = b.hWnd; 
     NativeMethods.RECT rect = new NativeMethods.RECT(); 
     if (NativeMethods.GetWindowRect(hWnd, ref rect)) 
     { 
      Size size = new Size(rect.Right - rect.Left, 
           rect.Bottom - rect.Top); 
      // Get information about the screen 
      using (Graphics browserGraphics = Graphics.FromHwnd(hWnd)) 
      // apply that info to a bitmap... 
      using (Bitmap screenshot = new Bitmap(size.Width, size.Height, 
                browserGraphics)) 
      // and create an Graphics to manipulate that bitmap. 
      using (Graphics imageGraphics = Graphics.FromImage(screenshot)) 
      { 
       int hWndX = rect.Left; 
       int hWndY = rect.Top; 
       imageGraphics.CopyFromScreen(hWndX, hWndY, 0, 0, size); 
       screenshot.Save(filename, ImageFormat.Bmp); 
       success = true; 
      } 
     } 
     // otherwise, fails. 
     return success; 
    } 
}