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.
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 .
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 :D
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.)
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;
}
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.
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.
@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 .