Guten Abend
Mein Ziel ist es, ein Screenshot von einem nicht aktiven Fenster zu erstellen.
Das Fenster sollte aber nicht aktiviert werden.
Ebenso soll nur ein bestimmter Bereich ausgewählt werden.
Im Internet bin ich auf folgenden Link gestossen:
http://dotnet-snippets.de/dns/klasse-zum-erstellen-von-screenshots-SID434.aspx
/// <summary>
/// Erzeugt ein Screenshot vom übergebenen Bereich.
/// </summary>
/// <param name="topleft">Punkt des Bereich oben - links</param>
/// <param name="bottomRight">Punkt des Bereich unten - rechts</param>
/// <returns>Bitmap</returns>
public Bitmap UserDefined(Point topleft, Point bottomRight)
{
return CreateScreenshot(topleft.X, topleft.Y, bottomRight.X, bottomRight.Y);
}
Dies wäre ja schon einmal perfekt für den Bereich.
Nur, wo muss ich nun das Handle übergeben?
Und wie kann ich einstellen, wo die Screenshots gespeichert werden?
Regenwurm
ServiceStack & Angular = =)
Sieht ja so aus, als ob die Funktion dir ein Bitmap zurückgibt (public **BITMAP **UserDefined).
Das du da ein Handle übergeben kannst, sieht nicht so aus. Könntestes dir mal die Funktion "CreateScreenshot" anschauen, ob die noch eine Überladung für das Handle hat, aber ansonsten schießt das Dingen nur einen Screenshot, vom Bildschirm, wie du ihn siehst.
//EDIT:
Steht doch ganz klar auf der Seite, die Funktion:
public Bitmap UserDefinedWindowHandle(IntPtr windowhandle)
{
return CreateScreenshot(windowhandle);
}
Da kannst du ein Handle übergeben.
private Bitmap CreateScreenshot(int left, int top, int width, int height)
{
Bitmap bmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(bmp);
g.CopyFromScreen(left, top, 0, 0, new Size(width, height));
g.Dispose();
return bmp;
}
private Bitmap CreateScreenshot(IntPtr windowhandle)
{
RECT windowRectangle;
GetWindowRect(windowhandle, out windowRectangle);
return CreateScreenshot(windowRectangle.Left, windowRectangle.Top, windowRectangle.Right - windowRectangle.Left, windowRectangle.Bottom - windowRectangle.Top);
}
Die Funktion CreateScreenshot kann allerdings keine Screenshot anhand eines Handles UND einer Location machen. Dafür musst du dir eine neue Überladung erstellen
private Bitmap CreateScreenshot(IntPtr windowhandle)
{
RECT windowRectangle;
GetWindowRect(windowhandle, out windowRectangle);
return CreateScreenshot(windowRectangle.Left, windowRectangle.Top, windowRectangle.Right - windowRectangle.Left, windowRectangle.Bottom - windowRectangle.Top);
}
Sowas?
Und, wie kann ich das Bitmap dann speichern?
ServiceStack & Angular = =)
Und, wie kann ich das Bitmap dann speichern? Siehe hierzu [ erledigt ]Graphics und Bitmaps speichern.
Vielleicht hilft dir auch Formular/Control drucken oder als Bitmap speichern. Einfach this
durch die Form
von Handle
ersetzen.
Hallo
Wie meinst du genau, "eine neue Überladung erstellen"? 😃
Noch zum Bitmap Speicher hinweis.
In dem Beispiel wird mit einer PictureBox gearbeitet, nur leider erstelle ich eine Konsolenanwendung.
Grüsse,
Regenwurm
ServiceStack & Angular = =)
OK, ich war desorientiert. Die Lösung ist ganz einfach mit
bitmap.Save(@"C:\...");
Zur Überladung:
Gemeint ist, eine Funktion, die als Parameter ein Handle
und die Position annimmt. Dadurch kannst du den "Bestimmten Bereich" mit der Fensterposition als Nullpunkt auswählen.
Ich bin mir nicht sicher wie weit du das Code Snippet getestet hast, aber bei mir macht er einfach kein Screenshot eines nicht aktiven Fenster.
Ich meine auch mal gelesen zu haben, dies sei nicht so einfach bzw. unmöglich.
Funktioniert dass den bei dir? Bei mir macht er zwar ein Screenshot mit der richtigen Größe des Screenshots, aber das Bild selbst ist vom aktiven Bild.
Daher würde ich meinen, dass entspricht nicht deinen Anforderungen, oder es funktioniert bei dir 😄
Lion
lg Lion
Ich meine auch mal gelesen zu haben, dies sei nicht so einfach bzw. unmöglich.
So ist es. In Formular/Control drucken oder als Bitmap speichern (oder zumindest in der englischen Version auf CodeProject) habe ich darauf hingewiesen: DrawToBitmap wird nur ausgeführt, wenn Windows tatsächlich etwas zu zeichnen hat. Ein verdecktes Fenster muss nicht gezeichnet werden; also ist auch kein Screenshot möglich. Wenn das nicht aktive Fenster sichtbar ist, kann es auch gezeichnet werden; dann muss ein Verweis auf das betreffende Formular übergeben werden (der z.B. durch Application.OpenForms erhalten werden kann).
Aber das bezieht sich wirklich auf WinForms, nicht auf Konsolenanwendungen. (Ich verstehe sowieso nicht, wieso man mit Console arbeiten und gleichzeitig auf GUI-Elemente zugreifen will.)
Jürgen
Hallo,
Im Prinzip funktioniert es mit PrintWindow.
Man benötigt nur ein Handle auf das Fenster. Aber das kann man aus _EnumWindows _ermitteln, wenn es den richtigen _GetWindowText _hat.
Hier ein passendes Snippet:
[DllImport("user32.dll", EntryPoint = "PrintWindow")]
public static extern bool PrintWindow(IntPtr hwnd, IntPtr hdcBlt, uint nFlags);
[StructLayout(LayoutKind.Sequential)]
public struct RECT {
public int Left;
public int Top;
public int Right;
public int Bottom;
}
[DllImport("user32.dll", SetLastError = true)]
static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
...
private Bitmap captureWindow(IntPtr hWnd)
{
RECT rc;
GetWindowRect(hWnd, out rc);
int width = rc.Right - rc.Left;
int height = rc.Bottom - rc.Top;
if (width == 0 || height == 0)
return null;
Bitmap bmp = new Bitmap(width, height);
Graphics g = Graphics.FromImage(bmp);
IntPtr gHDC = g.GetHdc();
PrintWindow(hWnd, gHDC, 0);
g.ReleaseHdc(gHDC);
g.Dispose();
return bmp;
}
beste Grüße
zommi
Hallo
Ich habe das ganze nun mal ausprobiert.
Es funktioniert an und für sich recht gut, nur wenn ich ein Game client ein Screen schiessen will, ist das Bild am Ende schwarz.
Weiss einer warum?
ServiceStack & Angular = =)
Mh...
Das Game wird wohl mit DirectX rendern. Da kommt das Bild dann direkt in den Videospeicher der Grafikkarte. Windows bekommt da über seine GDI-API gar nichts mit. Insofern bringt es auch nichts, per PrintWindow (was intern wahrscheinlich eine WM_PRINT-Message schickt) dem Fenster zu sagen, seinen GDI-inhalt zu zeichnen. Weil der nämlich keinen hat. (deshalb schwarz).
Um nun screenshots von DirectX programmen zu machen, müsstest du direkt den Videobuffer auslesen. Aber ob nun minimierte DirectX-Programme überhaupt was in irgendnen Speicher reinrendern... kA... vielleicht weiß das ja wer hier.
beste Grüße
zommi
Hallo!
@zommi:
Ich denke mal, dass minimierte DirectX-Programme nichts schreiben bzw. die DirectX-Schnittstelle dies unterbindet, da ja sonst etwas auf dem Bildschirm zu sehen wäre (da sie ja wie du schon geschrieben hast direkt in den Videobereich schreiben).
DirectX prüft ja auch, welcher Bereich des Fensters dargestellt werden soll, wenn das Fenster teilweise von anderen Fenstern verdeckt wird.
Evtl. gibt es in der DirectX-Schnittstelle ein Äquivalent zu PrintWindow.
Nobody is perfect. I'm sad, i'm not nobody 🙁