Скриншот C++ WinAPI возвращает неверное разрешение на дисплеях с высоким DPI, если масштабирование не равно 100%

Рейтинг: 2Ответов: 0Опубликовано: 31.07.2025

Написал программу на C++ для снятия скриншотов. Запускаю её на Windows 11. Программа работает, но разрешение экрана определяется некорректно: скриншот сохраняется с размером 1440×960 вместо физического разрешения дисплея 2160×1440. Проблема исчезает, если установить масштаб дисплея в системе на 100%. При любом другом значении масштаба скриншот снова получается с неправильным разрешением. Пробовал вызывать SetProcessDPIAware() в main, чтобы получить физическое разрешение экрана, но это не решает проблему. сам код:


#include <windows.h>
#include <gdiplus.h>
#include <string>
#include <iostream>

#pragma comment (lib,"Gdiplus.lib")

using namespace Gdiplus;

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
    UINT num = 0, size = 0;
    GetImageEncodersSize(&num, &size);
    if (size == 0) return -1;

    ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*) malloc(size);
    if (!pImageCodecInfo) return -1;

    GetImageEncoders(num, size, pImageCodecInfo);

    for (UINT j = 0; j < num; ++j) {
        if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
            *pClsid = pImageCodecInfo[j].Clsid;
            free(pImageCodecInfo);
            return j;
        }
    }

    free(pImageCodecInfo);
    return -1;
}

void TakeScreenshot(const std::wstring& filename) {
    HDC hScreenDC = GetDC(nullptr);
    HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

    int width = GetSystemMetrics(SM_CXSCREEN);
    int height = GetSystemMetrics(SM_CYSCREEN);

    HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, width, height);
    HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

    BitBlt(hMemoryDC, 0, 0, width, height, hScreenDC, 0, 0, SRCCOPY);
    SelectObject(hMemoryDC, hOldBitmap);

    Gdiplus::Bitmap bitmap(hBitmap, nullptr);
    CLSID pngClsid;
    GetEncoderClsid(L"image/png", &pngClsid);
    bitmap.Save(filename.c_str(), &pngClsid, nullptr);

    DeleteObject(hBitmap);
    DeleteDC(hMemoryDC);
    ReleaseDC(nullptr, hScreenDC);
}

int main() {
    
    SetProcessDPIAware();

    GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);

    CreateDirectoryW(L"screenshots", nullptr);
    TakeScreenshot(L"screenshots\\screenshot.png");

    std::wcout << L"Скриншот сохранён как screenshots\\screenshot.png" << std::endl;

    GdiplusShutdown(gdiplusToken);
    return 0;
}

Ответы

Ответов пока нет.