С++ + WinAPI (захват изображения)
С++ + WinAPI (захват изображения)

С++ + WinAPI (захват изображения)

22 августа 2022       135 просмотров

Начнём с того, что после очередного обновления VS Community 2022 перестала работать на Windows 7. Просмотрев список «системных требований» быстро выяснилось, что на семёрке новая студия работать совсем не обязана. Well, shit…

Но бежать вприпрыжку перелезать на уютненькую десяточку или, прости Пажитнов, садиться на палки (барабанные) — спасибо, видели, пакетик для рвоты уже полон, так что решительным решением откатываемся на VS Community 2019 и не парим себе мозги — для наших грязных намерений великих целей этого более чем достаточно.

Итак, с нытьём закончили, переходим к делу. В текущей статье мы разберемся как нам делать скриншотики, не более того.

Для этого нам достаточно пустого как наше светлое будущее проекта:

йа картинко

Добавим воды файл для кода:

вот так

Итак, для начала ёбнем по Тбилиси попробуем сделать скриншот всей области рабочего стола:

#include <Windows.h> //это нам нужно для взаимодействия с WinAPI

HWND hwnd; //типо наше  «окошно»

int a0, a1, b0, b1, w, h; //да, вся это шалупонь целочисленная, и координаты, и ширина, и высота

int main  () { //погнали
	hwnd = GetConsoleWindow  (); //да, у нас консоль
	ShowWindow  (hwnd, SW_HIDE  ()); //но мы её тут же прячем с глаз долой

	a0 = GetSystemMetrics  (SM_XVIRTUALSCREEN); //и берем
	b0 = GetSystemMetrics  (SM_YVIRTUALSCREEN); //координаты
	a1 = GetSystemMetrics  (SM_CXVIRTUALSCREEN); //крайних точек
	b1 = GetSystemMetrics  (SM_CYVIRTUALSCREEN); //нашего экрана

	w = a1 — a0; //рассчитываем длину и ширину
	h = b1 — b0; //срочно зовите Перельмана!

	HDC hScreen = GetDC  (NULL); //получаем контекст
	HDC hDC = CreateCompatibleDC  (hScreen); //и создаем
	HBITMAP hbitmap = CreateCompatibleBitmap  (hScreen, w, h); //картинку
	HGDIOBJ myobj = SelectObject  (hDC, hbitmap); //далее выбираем
	BOOL bRet = BitBlt  (hDC, 0, 0, w, h, hScreen, a0, b0, SRCCOPY); //и заполняем пикселями
 //скопируем, наверное картинку в буфер обмена пока
	OpenClipboard  (NULL); //открываем буфер
	EmptyClipboard  (); //очищаем
	SetClipboardData  (CF_BITMAP, hbitmap); //вносим инфу
	CloseClipboard  (); //не забываем закрыть

	return 0; //фсё
}

Запустим бумеранг сборку и проверим работу вот этого всего:

содержимое буфера

Вы резонно заметите, что не хотите показывать своих 2D-тяночек, которые у вас там на рабочем столе или ещё чего. Ну, что ж…
В таком случае мы можем делать скриншот только отдельно взятого окна, создаем проект всё по той же гиблой схеме и немного наклоняем ось земли изменяем код:

#include <Windows.h> //это нам нужно для взаимодействия с WinAPI

int a0, a1, b0, b1, w, h; //тут всё то же самое

int main  () { //опять же стартуем
	FreeConsole  (); //консольку, в принципе, можно и так убрать
	keybd_event  (VK_MENU, 0, 0, 0); //только вот keybd_event  (VK_TAB, 0, 0, 0); //она, сволочь
	keybd_event  (VK_TAB, 0, KEYEVENTF_KEYUP, 0); //убирает фокус с окна
	keybd_event  (VK_MENU, 0, KEYEVENTF_KEYUP, 0); //так что мы обратно альт-табаемся
	Sleep  (500); //и немножечко ждём  (да, вроде костыль, а вроде и хитрость)
	
	RECT rcClient; //определяем прямоугольник, да можно через rcWindow, но я захотел так HWND hWnd; //наше окно
	hWnd = GetForegroundWindow  (); //берем то, что сейчас активно
	GetClientRect  (hWnd, &rcClient); //и забираем его крайние точки

	a0 = rcClient.left; //да, кстати
	b0 = rcClient.top; //а вот a1 = rcClient.right; //и наши
	b1 = rcClient.bottom; //точки

	w = a1 — a0; //тут всё так же h = b1 — b0; //очень сложные рассчеты

	HDC hScreen = GetDC  (NULL); //контекст
	HDC hDC = CreateCompatibleDC  (hScreen); //далее
	HBITMAP hbitmap = CreateCompatibleBitmap  (hScreen, w, h); //картинка
	HGDIOBJ myobj = SelectObject  (hDC, hbitmap); //прямо как в BOOL bRet = BitBlt  (hDC, 0, 0, w, h, hScreen, a0, b0, SRCCOPY); //примере выше

	OpenClipboard  (NULL); //опять
	EmptyClipboard  (); //копируем
	SetClipboardData  (CF_BITMAP, hbitmap); //картинку
	CloseClipboard  (); //в буфер

	return 0; //да, я обленился
}

Проверяем погоду за окном результат:

вуаля