Я нашел здесь код захвата экрана, но когда я пытался его собрать, он не собирался, поэтому я сам исправил код, и теперь он собирается, но я не думаю, что он работает, потому что при отладке 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
}
Краткий ответ: в этом нет ничего плохого.
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
аргумент.
Посмотрим. Когда вы используете 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