Что не так с этим кодом захвата экрана?

Я нашел здесь код захвата экрана, но когда я пытался его собрать, он не собирался, поэтому я сам исправил код, и теперь он собирается, но я не думаю, что он работает, потому что при отладке VS говорит, что может: читать из hBitmap (нет данных?). Я начинающий программист, поэтому я понятия не имею, что делать на этом этапе … и я, вероятно, не исправил код должным образом …

Я ценю вашу помощь.

#include <Windows.h>

int main()
{
// get the device context of the screen
HDC hScreenDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
// and a device context to put it in
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

int x = GetDeviceCaps(hScreenDC, HORZRES);
int y = GetDeviceCaps(hScreenDC, VERTRES);

// maybe worth checking these are positive values
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, x, y);

// get a new bitmap
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

BitBlt(hMemoryDC, 0, 0, 640, 480, hScreenDC, 0, 0, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);
// now your image is held in hBitmap. You can save it or do whatever with it
}

1

Решение

Краткий ответ: в этом нет ничего плохого.

hBitmap содержит дескриптор растрового изображения, в котором хранятся данные экрана, полученные с помощью BitBlt, Когда вы наводите hBitmap в Visual Studio он просто сообщает вам, что hBitmap не является допустимым указателем на память, который является правильным отчетом — дескрипторы окон — это просто токены, которые разрешают структуры, чье расположение в памяти и реализация управляются частным образом Windows API.

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

Вот быстрое консольное приложение, которое будет генерировать файл PNG, используя ваш код и вспомогательная функция GetEncoderClsid получить кодировщик PNG.

#include "stdafx.h"#include <Windows.h>
#include <gdiplus.h>

using namespace Gdiplus;

int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
{
UINT  num = 0;          // number of image encoders
UINT  size = 0;         // size of the image encoder array in bytes

ImageCodecInfo* pImageCodecInfo = NULL;

GetImageEncodersSize(&num, &size);
if (size == 0)
return -1;  // Failure

pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
if (pImageCodecInfo == NULL)
return -1;  // Failure

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;  // Success
}
}

free(pImageCodecInfo);
return -1;  // Failure
}

int _tmain(int argc, _TCHAR* argv[])
{
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

// get the device context of the screen
HDC hScreenDC = CreateDC(L"DISPLAY", NULL, NULL, NULL);
// and a device context to put it in
HDC hMemoryDC = CreateCompatibleDC(hScreenDC);

int x = GetDeviceCaps(hScreenDC, HORZRES);
int y = GetDeviceCaps(hScreenDC, VERTRES);

// maybe worth checking these are positive values
HBITMAP hBitmap = CreateCompatibleBitmap(hScreenDC, x, y);

// get a new bitmap
HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

BitBlt(hMemoryDC, 0, 0, 640, 480, hScreenDC, 0, 0, SRCCOPY);
hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);
// now your image is held in hBitmap. You can save it or do whatever with it

CLSID pngClsid;
GetEncoderClsid(L"image/png", &pngClsid);

Bitmap *bmp = new Bitmap(hBitmap, NULL);
bmp->Save(L"desktop_slice.png", &pngClsid, NULL);
delete bmp;

GdiplusShutdown(gdiplusToken);
return 0;
}

Обязательно добавьте gdiplus.lib в ваш список исходных библиотек в настройках вашего проекта. Выполнение этого создаст файл с именем «desktop_slice.png» для отправки.

Если вам необходимо выполнить дополнительную работу после извлечения растрового изображения, содержащего данные экрана, вы должны выбрать его в совместимом DC и вызвать дополнительные функции GDI с этим DC, или выполнить другие модификации для hMemoryDC перед заменой растрового изображения с SelectObject,

Если вам нужно выполнить работу более низкого уровня на уровне пикселей, вам следует рассмотреть создание раздела DIB с известным форматом пикселей, который соответствует вашим потребностям, и работу с указателем, возвращаемым из ppvBits аргумент.

CreateDIBSection @ MSDN

2

Другие решения

Посмотрим. Когда вы используете SelectObject() в первый раз

HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemoryDC, hBitmap);

Вы связываете hBitmap с hMemoryDC. Вы не могу удаляйте hBitmap, пока существует hMemoryDC! Так зовет

DeleteObject(hBitmap);

ничего не делает. Для того, чтобы правильно удалить hBitmap вы используете hOldBitmap и вы делаете

SelectObject(hMemoryDC, hOldBitmap);

После этого вы больше не можете использовать hMemoryDC. Так что сотри свою последнюю строку

hBitmap = (HBITMAP)SelectObject(hMemoryDC, hOldBitmap);

и ты должен быть в порядке. Освободите ресурсы, когда вам больше не нужен hMemoryDC.

редактировать

Правильный способ выпустить hBitmap и hMemoryDC:

SelectObject(hMemoryDC, hOldBitmap);
DeleteObject(hBitmap);
hBitmap = NULL;
DeleteDC(hMemoryDC);
hMemoryDC = NULL;

Valter

1

По вопросам рекламы [email protected]