Ingame Screenshot speichern möglich? Wie?
-
Dieser Thread wurde von Moderator/in SeppJ aus dem Forum C++ (alle ISO-Standards) in das Forum WinAPI verschoben.
Im Zweifelsfall bitte auch folgende Hinweise beachten:
C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?Dieses Posting wurde automatisch erzeugt.
-
Hi schrieb:
Oder das Programm/Spiel benutzt eine seltsame Render-Methode, die von der "Print Screen"-Taste nicht erfasst wird.
Ist das nicht der Normalfall bei Spielen?
-
SeppJ schrieb:
Hi schrieb:
Oder das Programm/Spiel benutzt eine seltsame Render-Methode, die von der "Print Screen"-Taste nicht erfasst wird.
Ist das nicht der Normalfall bei Spielen?
Seltsame Rendermethoden ohne Fenster? Oder dass Screenshots mit der Druck-Taste nicht funktionieren?
Jedenfalls kenne ich kein Spiel ohne Fenster und ich konnte in Spielen auch schon immer ganz normal Screenshots machen. Sowohl mit Win XP (ohne DWM) als auch mit Win 7 (mit DWM).Was aber mit DWM glaube ich nicht geht ist GetDesktopWindow + GetDC + BitBlt. Da erhält man entweder ein schwarzes Bild oder den Desktopinhalt.
Wobei ich mich gerade frage, ob dann nicht FindWindow (anstatt GetDesktopWindow) eine Alternative wäre (sofern es ein Fenster gibt..).Hm ich seh grade im Code oben.. GetClipboardData mit CF_BITMAP müsste doch ein HBITMAP zurückgeben, nicht HWND..
-
Ich meinte, dass die Druck-Taste nicht (korrekt) funktioniert. Viele Spiele rendern hardwarebeschleunigt direkt auf den Bildschirm. Wenn man die normale Print Screen Funktion von Windows benutzt, erhält man an der Stelle des zu sehenden Bildes dann nur ein schwarzes Bild. Es gibt Third-Party Werkzeuge dafür (Fraps und ähnliche), aber wenn man es selber machen will, muss man weiter gehen als nur die normale Print Screen Funktion zu kapern.
-
Danke erstmal schon für die vielen Antworten und Entschuldigung für die Fehlpositionierung im falschen Forum.
@Hi: Aber zu der Frage:
Es handelt sich um CS:GO, kann aber auch jedes andere Spiel aus der Steam-Familie sein.Komischerweise Print-Screen bzw. die Taste Druck funktionieren ja. Starte ich nur die Funktion "makescreenshot" kann ich aus dem Spiel tabben und per Paint den Screen abspeichern, der müsste dann doch irgendwo liegen. Ich schaffe es nur nicht, den Screen aus der Zwischenablage direkt abzuspeichern, da macht er nur den "normalen" Desktopinhalt der quasi im Hintergrund liegt.
GetClipboardData sollte eigentlich ein HBITMAP zurückgeben, das stimmt wohl. Schreibe ich das aber so das ich das hier einbaue
CImage image; image.Attach(hBitmap); image.Save(szName, Gdiplus::ImageFormatJPEG);
Dann gibt es Fehlermeldungen zu atlimage.h das hBitmap != NULL wäre. Das verstehe ich nicht und habe deswegen eine andere Methode probiert.
-
Ich habe gerade nochmal etwas anderes probiert, das Spiel "windowed" laufen lassen und die Funktionen gestartet. Der Screenshot der dann erzeugt wird enthält auch den Inhalt des Spiels.
Wie zuvor schon gesagt, die Zwischenablage enthält ja die Informationen mit dem "Full"-Bild des Spiels, bekomme diese nur nicht abgespeichert.
-
eXc schrieb:
GetClipboardData sollte eigentlich ein HBITMAP zurückgeben, das stimmt wohl. Schreibe ich das aber so das ich das hier einbaue
CImage image; image.Attach(hBitmap); image.Save(szName, Gdiplus::ImageFormatJPEG);
Dann gibt es Fehlermeldungen zu atlimage.h das hBitmap != NULL wäre. Das verstehe ich nicht und habe deswegen eine andere Methode probiert.
HWND hClipboard = (HWND)GetClipboardData(CF_BITMAP); HDC hScreen = GetDC(hClipboard); // Handle to clipboard
Du benutzt das API falsch. Es ist zB. noch OpenClipboard() nötig.
Mindestens deshalb gibt dir GetClipboardData() 0 zurück.
Die 0 übergibst du an GetDC() und deshalb bekommst du das Desktopfenster ("entire screen") zurück. Steht so in der Doku.Ich empfehle wie immer die Grundlagen :p
-
Aber was müsste ich denn dem OpenClipboard() für eine Handle übergeben das das richtige geöffnet wird? Habe es mit GetDesktopWindow()versucht, aber das funktioniert nicht.
Werde mal weiter lesen. Vielleicht finde ich da in der API ja was.
-
Gib NULL als Parameter an, wie es auch in OpenClipboard steht.
-
MSDN OpenClipboard schrieb:
If this parameter is NULL, the open clipboard is associated with the current task.
Was ist eigentlich ein "task"? Ein Win 3.1 Prozess?
-
Das mit Handle=NULL funktioniert leider auch nicht.
Folgende Funktion funktioniert auf jeden Fall schonmal und macht Bilder sofern Daten vorhanden sind:
void TakeScreenShot() { HBITMAP hBitmap; OpenClipboard(NULL); hBitmap = (HBITMAP)GetClipboardData(CF_BITMAP); CloseClipboard(); if (hBitmap == NULL) { cout << "Kein Bild-Inhalt in der Zwischenablage!" << endl; return; } // Bitmap speichern TCHAR szName[MAX_PATH] = { 0 }; SYSTEMTIME st = { 0 }; ::GetLocalTime(&st); _stprintf_s(szName, _T("X_%02d-%02d-%02d-%03d.jpg"), st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); CImage image; image.Attach(hBitmap); image.Save(szName, Gdiplus::ImageFormatJPEG); // Aufräumen DeleteObject(hBitmap);
Drücke ich nun irgendwann die "Print-Screen" oder "Druck(en)" Taste, dann wird das Bild abgespeichert, auch ein Bild Ingame.
Nutze ich nun folgende Funktion zum Erstellen eines Screenshots per Fake-Keypress, funktioniert das so nicht mehr.
void makescreenshot() { INPUT ip; // Set up a generic keyboard event. ip.type = INPUT_KEYBOARD; ip.ki.wScan = 0; // hardware scan code for key ip.ki.time = 0; ip.ki.dwExtraInfo = 0; ip.ki.wVk = 0x2C; // virtual-key code for the "SNAPSHOT" key - https://msdn.microsoft.com/en-us/library/dd375731(v=vs.85).aspx ip.ki.dwFlags = 0; // 0 for key press SendInput(1, &ip, sizeof(INPUT)); ip.ki.dwFlags = KEYEVENTF_KEYUP; // KEYEVENTF_KEYUP for key release SendInput(1, &ip, sizeof(INPUT)); if (IsClipboardFormatAvailable(CF_BITMAP)) { cout << "CF_BITMAP vorhanden!" << endl; } if (IsClipboardFormatAvailable(CF_TEXT)) { cout << "CF_TEXT vorhanden!" << endl; } }
Es wird wohl ein Screenshot gemacht, da ich den Inhalt per Paste in Paint importieren kann, komischerweise wird mir aber weder CF_TEXT, noch CF_BITMAP angezeigt und die Funktion TakeScreenShot() wird deshalb nicht ausgeführt. Gibt es vielleicht verschiedene Clipboards parallel?
Programm gestartet, Timer läuft, vor dem Aufruf der beiden Funktionen:
Programm und Timer laufen weiter, beide Funktionen wurden aufgerufen, Bild lässt sich in Paint importieren:
-
Nehme ich übrigens folgende Funktion macht er auch Bilder, leider sind die Bilder aus einem Spiel heraus aber schwarz.
void screenshot() { int horizontal = 0; int vertical = 0; RECT desktop; HWND hDesktop = GetDesktopWindow(); // Größe des Rechtecks berechnen GetWindowRect(hDesktop, &desktop); horizontal = desktop.right; vertical = desktop.bottom; POINT a, b; a.x = 0; a.y = 0; b.x = horizontal; b.y = vertical; // Kopiere Screen in Bitmap HDC hScreen = GetDC(hDesktop); HDC hDC = CreateCompatibleDC(hScreen); HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, abs(b.x - a.x), abs(b.y - a.y)); HGDIOBJ old_obj = SelectObject(hDC, hBitmap); BOOL bRet = BitBlt(hDC, 0, 0, abs(b.x - a.x), abs(b.y - a.y), hScreen, a.x, a.y, SRCCOPY); // Bitmap in Zwischenspeicher OpenClipboard(NULL); EmptyClipboard(); SetClipboardData(CF_BITMAP, hBitmap); CloseClipboard(); // Bitmap speichern TCHAR szName[MAX_PATH] = { 0 }; SYSTEMTIME st = { 0 }; ::GetLocalTime(&st); _stprintf_s(szName, _T("%02d-%02d-%02d-%03d.jpg"), st.wHour, st.wMinute, st.wSecond, st.wMilliseconds); CImage image; image.Attach(hBitmap); image.Save(szName, Gdiplus::ImageFormatJPEG); // Aufräumen SelectObject(hDC, old_obj); DeleteDC(hDC); ReleaseDC(NULL, hScreen); DeleteObject(hBitmap); }
-
Man man man.. Liest du die Doku überhaupt? Kannst du Englisch?
MSDN GetClipboardData schrieb:
The application must not free the handle nor leave it locked. The application must not use the handle after the EmptyClipboard or CloseClipboard function is called
Beides machst du falsch.
Vor IsClipboardFormatAvailable() brauchst du wahrscheinlich auch ein OpenClipboard().
Warum der Screen bei deinem letzten Code schwarz ist, hab ich schon erklärt.
Versuch's mit dem Fensterhandle des Spiels anstatt dem Desktophandle.
In deinem Screenshot vorher sah man doch das Fenster des Spiels. Warum denkst du, dass da keines ist? Such mal mit Spy++ (ist bei Visual Studio dabei).Ansonsten ist die sauberste Methode per Direct3D-Hook. Aber da könnte ein ins Spiel integrierter AntiCheat was dagegen haben. Tja.
-
Hallo,
Entschuldigung das ich mich vielleicht dumm anstelle, aber bin kein Pro was programmieren angeht.
Du benutzt das API falsch. Es ist zB. noch OpenClipboard() nötig.
Mindestens deshalb gibt dir GetClipboardData() 0 zurück.Bin davon ausgegangen das du das damit meintest, habe das dann wohl falsch verstanden.
Vor IsClipboardFormatAvailable() brauchst du wahrscheinlich auch ein OpenClipboard().
Nein brauche ich nicht. Ich habe es hinbekommen und auch so wird mir jetzt die korrekte Auswahl angezeigt. Musste wirklich nur explizit das eine Fenster angeben, ansonsten aber alles ok.
Spy++ kenne ich natürlich auch nicht, werde es aber nachlesen.
DANKE aber für Eure Hilfe!
mfg Christian 'eXc'
-
Ich möchte zyklisch von einem Programm oder Game einen Screenshot machen.
..schau ob damit schlauer wirst:
https://github.com/nektra/AVRecorderTool/
http://blog.nektra.com/main/2013/07/23/instrumenting-direct3d-applications-to-capture-video-and-calculate-frames-per-second/