GetFrontBufferData returns black screen on any game
Asked Answered
B

0

0

I am writing a screen capture application. I used the code mentioned on this link for the application.

Following is my entire code for your reference:

    // WangsNotesScrCapt2.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "WangsNotesScrCapt2.h"

//include d3d library
#include <d3d9.h>
#include <d3dx9tex.h>
#include <dinput.h>


//link d3d library
#pragma comment (lib, "d3d9.lib")
#pragma comment (lib, "D3dx9.lib")

#define MAX_LOADSTRING 100
#define WM_KEYDOWN 0x0100

// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

//d3d objects
LPDIRECT3D9 d3d = NULL;
LPDIRECT3DDEVICE9 d3ddev = NULL;


// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

void releaseD3d();
void captureScreenD3d();
void initD3d(HWND hwnd);


int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_WANGSNOTESSCRCAPT2, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WANGSNOTESSCRCAPT2));

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }

    }
        for (int k = 0; k < 10000; k++)
            {
                for (int j = 0; j < 10000; j++)
                {
                    for (int i = 0; i < 100; i++)
                    {
                    }
                }

            }


    //capture screen
    captureScreenD3d();


    //release d3d objects when this program is closed
    releaseD3d();

    return (int) msg.wParam;
}


#define BUFSIZE 65535 
#define SHIFTED 0x8000 


//
//  FUNCTION: MyRegisterClass()
//
//  PURPOSE: Registers the window class.
//
ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WANGSNOTESSCRCAPT2));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WANGSNOTESSCRCAPT2);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   //init d3d objects
   initD3d(hWnd);

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

//
//  FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT    - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code here...
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}

void initD3d(HWND hwnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hwnd;
    d3d->CreateDevice(D3DADAPTER_DEFAULT,
        D3DDEVTYPE_HAL,
        hwnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp,
        &d3ddev);
}

void captureScreenD3d()
{
    UINT screenW = GetSystemMetrics(SM_CXSCREEN);
    UINT screenH = GetSystemMetrics(SM_CYSCREEN);
    LPDIRECT3DSURFACE9 pSurface;
    d3ddev->CreateOffscreenPlainSurface(screenW, screenH, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL);
    d3ddev->GetFrontBufferData(0, pSurface);
    D3DXSaveSurfaceToFile(L"screen.bmp", D3DXIFF_BMP, pSurface, NULL, NULL);
    pSurface->Release();
}

void releaseD3d()
{
    d3ddev->Release();
    d3d->Release();
}

It returns the actual screen for any normal window but if i run a game it returns a black image.

Is there any way I can also make it work with all the fullscreen games as well?

EDIT:

So I changed the way I call the capturescreen() function.

Now I call it in main like this as suggested by @pauld

d3ddev->BeginScene();
//capture screen
captureScreenD3d();
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
releaseD3d();

I am still getting a black image for fullscreen games and it works fine for every other application.

Brisk answered 8/7, 2015 at 7:46 Comment(5)
So I noticed my screenshots are taken before Present() is called, and in your case they are after. That may be related to your problem.Gaius
So you are able to capture fullscreen games using getfrontbufferdata?Brisk
No i capture them using the method i mentioned hereGaius
Sorry, I didn't realize you were taking screenshots using GetFrontBufferData, so my original comment is not applicable.Gaius
@pauld I am trying to find fastest method to capture screen. And after some reading I got to know that reading from backbuffer is way faster than reading from frontbuffer. But I came across some threads likethis for example where it is mentioned that you can only capture the backbuffer data of the content you render and it cannot capture non d3d object. So can you once again explain me a bit more about your approach. Your are using GetBackBuffer to capture desktop applications or your own rendered device? Also can you help me out with an MCVEBrisk

© 2022 - 2024 — McMap. All rights reserved.