C ++, Windows (иногда) белый экран при съемке экрана приложения - PullRequest
0 голосов
/ 28 февраля 2019

У меня есть функция приложения, которая запускает снимок экрана окна указанного приложения.

Это выглядит так:

    void PlatformWindow::captureScreenshot()
{
    WIN32Window *window = (WIN32Window*)&g_window;
    if (window) {
        HWND handle = window->getWindow();
        if (handle){
            RECT client_rect = { 0 };
            GetClientRect(handle, &client_rect);
            int width = client_rect.right - client_rect.left;
            int height = client_rect.bottom - client_rect.top;


            HDC hdcScreen = GetDC(handle);
            HDC hdc = CreateCompatibleDC(hdcScreen);
            HBITMAP hbmp = CreateCompatibleBitmap(hdcScreen, width, height);
            SelectObject(hdc, hbmp);

            BitBlt(hdc, 0, 0, width, height, hdcScreen, 0, 0, SRCCOPY);

            BITMAPINFO bmp_info = { 0 };
            bmp_info.bmiHeader.biSize = sizeof(bmp_info.bmiHeader);
            bmp_info.bmiHeader.biWidth = width;
            bmp_info.bmiHeader.biHeight = height;
            bmp_info.bmiHeader.biPlanes = 1;
            bmp_info.bmiHeader.biBitCount = 24;
            bmp_info.bmiHeader.biCompression = BI_RGB;

            int bmp_padding = (width * 3) % 4;
            if (bmp_padding != 0) bmp_padding = 4 - bmp_padding;

            BYTE *bmp_pixels = new BYTE[(width * 3 + bmp_padding) * height];;
            GetDIBits(hdc, hbmp, 0, height, bmp_pixels, &bmp_info, DIB_RGB_COLORS);

            BITMAPFILEHEADER bmfHeader;
            //Make screenshot name as a time
            time_t currentTime = std::time(NULL);
            std::ostringstream oss;
            auto tm = *std::localtime(&currentTime);
            oss << std::put_time(&tm, "%d-%m-%Y_%H-%M");
            auto time_string = oss.str();
            uint id = 0;
            std::string name = "screens\\" + time_string +"_0.bmp";

            //Loop over its indexes
            while(true){
                name = "screens\\" + time_string + "_" + std::to_string(id) +".bmp";
                if (!file_exists(name)){
                    break;
                }
                id++;
            }
            LPSTR fileName = const_cast<char *>(name.c_str());
            HANDLE bmp_file_handle = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

            // Add the size of the headers to the size of the bitmap to get the total file size
            DWORD dwSizeofDIB = (width * 3 + bmp_padding) * height + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);

            //Offset to where the actual bitmap bits start.
            bmfHeader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER);

            //Size of the file
            bmfHeader.bfSize = dwSizeofDIB;

            //bfType must always be BM for Bitmaps
            bmfHeader.bfType = 0x4D42; //BM

            DWORD dwBytesWritten = 0;
            WriteFile(bmp_file_handle, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
            WriteFile(bmp_file_handle, (LPSTR)&bmp_info.bmiHeader, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
            WriteFile(bmp_file_handle, (LPSTR)bmp_pixels, (width * 3 + bmp_padding) * height, &dwBytesWritten, NULL);

            //Close the handle for the file that was created
            CloseHandle(bmp_file_handle);

            DeleteDC(hdc);
            DeleteObject(hbmp);
            ReleaseDC(NULL, hdcScreen);
            delete[] bmp_pixels;
        }
    }
}

И отлично работает на нескольких машинах (Windows 10, XPи так далее).Однако в Windows 7 есть редкий случай (и, возможно, другие, я не знаю, просто ли это неудача или что-то в этом роде), когда скриншот становится пустым.Просто все белое.Я выполнил некоторую диагностику, и мне очень удобно, что он, безусловно, захватывает правое окно, но каким-то образом он плохо захватывает пиксели.

Я копаю глубже и обнаруживаю, что всякий раз, когда я устанавливаю эту опцию в окнах ->параметры производительности -> «Настроить для лучшей производительности», он внезапно начинает работать, и снимок экрана положительно (больше нет белого экрана, что здорово).

Что мне сейчас интересно, так это то, могу ли я как-нибудьсделать мой код лучше, чтобы скрыть эти ситуации, поскольку принуждение пользователя к изменению параметров своего окна не является идеальным сценарием.

@ EDIT: я обнаружил, что это тот самый вариант, который заставляет его работать, если я отключаю рабочий столкомпозиция работает просто отлично.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...