Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Screenshot von Fenster das nicht aktiv ist
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

Screenshot von Fenster das nicht aktiv ist

beantworten | zitieren | melden

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 = =)
private Nachricht | Beiträge des Benutzers
Underscare
myCSharp.de - Member



Dabei seit:
Beiträge: 195

beantworten | zitieren | melden

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
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von Underscare am .
private Nachricht | Beiträge des Benutzers
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

    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 = =)
private Nachricht | Beiträge des Benutzers
SeeQuark
myCSharp.de - Member

Avatar #avatar-2825.jpg


Dabei seit:
Beiträge: 946

beantworten | zitieren | melden

Zitat
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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von SeeQuark am .
private Nachricht | Beiträge des Benutzers
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

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 = =)
private Nachricht | Beiträge des Benutzers
SeeQuark
myCSharp.de - Member

Avatar #avatar-2825.jpg


Dabei seit:
Beiträge: 946

beantworten | zitieren | melden

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.
private Nachricht | Beiträge des Benutzers
Lion1984
myCSharp.de - Member



Dabei seit:
Beiträge: 770
Herkunft: Österreich

beantworten | zitieren | melden

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 :D

Lion
lg Lion
private Nachricht | Beiträge des Benutzers
juetho
myCSharp.de - Member



Dabei seit:
Beiträge: 3.331
Herkunft: Berlin

beantworten | zitieren | melden

Zitat von Lion1984
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
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1.361
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
Regenwurm
myCSharp.de - Member



Dabei seit:
Beiträge: 295
Herkunft: Zentralschweiz

Themenstarter:

beantworten | zitieren | melden

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 = =)
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1.361
Herkunft: Berlin

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
tom-essen
myCSharp.de - Experte

Avatar #avatar-2140.png


Dabei seit:
Beiträge: 1.815
Herkunft: NRW

beantworten | zitieren | melden

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.
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von tom-essen am .
Nobody is perfect. I'm sad, i'm not nobody
private Nachricht | Beiträge des Benutzers