Ingame Screenshot speichern möglich? Wie?



  • 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.

    http://imgur.com/lF62wcz

    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:

    http://imgur.com/pTrDmXP

    Programm und Timer laufen weiter, beide Funktionen wurden aufgerufen, Bild lässt sich in Paint importieren:

    http://imgur.com/voRqVSM



  • 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/


Anmelden zum Antworten