Скриншот C++ WinAPI возвращает неверное разрешение на дисплеях с высоким DPI, если масштабирование не равно 100%
Написал программу на 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;
}
Источник: Stack Overflow на русском