C ++ функция Windows для сохранения содержимого окна в растровое изображение - PullRequest
0 голосов
/ 02 июня 2018

Я пытаюсь написать программу на C ++, которая включает обработку данных, захваченных из окна.Я намеренно пытаюсь написать это сам, используя Windows для опыта, поэтому, пожалуйста, не рекомендуйте библиотеки, которые уже существуют, чтобы облегчить эту задачу.В любом случае, для тестирования я написал функцию, которая должна принимать дескриптор hwnd и контекст устройства hdc и использовать эту информацию для создания файла растрового изображения клиентской области ссылки на окно с помощью hwnd.Код, который я написал, основан на этом примере кода из MSDN .Сейчас я просто пытаюсь захватить данные, а не отображать их на экране или каким-либо образом изменять.Я также тщательно прокомментировал код, чтобы дать представление о том, что именно я делаю с каждой строкой.Пожалуйста, дайте мне знать, если у меня есть какие-либо фундаментальные недоразумения здесь.

void screenshot(HWND hwnd, HDC hdc){
HDC clientarea = hdc; // The device context for the client area of the window
HDC memory = NULL; // client context for storing the bitmap in memory
RECT clientdim; // Defines memeory location for dimensions of client window
GetClientRect(hwnd, &clientdim); // Stores the client dimesnion info at clientdim location
BITMAP img; // Points to the where the bitmap handle will write it's data once it contains the bitmap data for the client window

HBITMAP clienthandle = CreateCompatibleBitmap(clientarea, clientdim.right - clientdim.left, clientdim.bottom - clientdim.top); // Bitmap handle, actual data of the rectangle defined at clientdim

SelectObject(memory, clienthandle); // Selecting the bitmap handle into the memory context allows us to bitblit the bitmap data to the bitmap handle

BitBlt(memory, 0, 0, clientdim.right - clientdim.left, clientdim.bottom - clientdim.top, clientarea, 0, 0, SRCCOPY);
// The bitmap handle now contains the data defined by the rectangle coordinates, which the dimensions of the hwnd client area
// The source and desitnation nXdest, nYdest, etc. fields are with respect the the window, not the screen, so they are 0

// Gets the bitmap data from the handle, and stores it to a memory location as an actual bitmap file
GetObject(clienthandle, sizeof(BITMAP), &img);

// Info head for the bitmap. Information about the dimesions and colors
BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER); // Sets the size of the header literally to the size of an info header. 
bmih.biWidth = img.bmWidth; // Sets the width of the bitmap to the width of the bitmap in memory
bmih.biHeight = img.bmHeight; // Sets the height of the bitmap to the height of the bitmap in memory
bmih.biPlanes = 1; // number of planes must be 1 for bitmaps to save
bmih.biBitCount = 32; // 32-bit color. Means RGB dat is stored per pixel.
bmih.biCompression = BI_RGB; // Tells it to use the RGB compression, as defined by the 32bit pixels
bmih.biSizeImage = 0; // Size of compression buffer. RGB is uncompressed, so is 0 for now
bmih.biXPelsPerMeter = 0; // Defines the number of pixels per meter in the x axis. Only used by some programs to select images, we don't care.
bmih.biYPelsPerMeter = 0; // Same as above, but fore y axis.
bmih.biClrUsed = 0; // the number of color indexes the bitmat uses. 0 means it uses all of them
bmih.biClrImportant = 0; // The number of color indexes actually required to display a pixel. 0 means we need all of them.

DWORD bitmapsize = ((img.bmWidth * bmih.biBitCount + 31) / 32) * 4 * img.bmHeight; // Total size of the bitmap. Not sure why this works, will look into it

HANDLE hDIB = GlobalAlloc(GHND, bitmapsize); // A handle to heap memory of size bitmapsize where our bitmap is processed. GHND = Initializes memory to zero an
                                            //allows location to translate to pointer with globallock, called such because it locks the memory in place within the heap
                                            // hDIB because it is a Device Independent Bitmap

char *lpbitmap = (char *)GlobalLock(hDIB); // Stores the contents of the char at the memory locattion defined by GlobalLock(). Basically, this is the bitmap in the heap.

GetDIBits(clientarea, clienthandle, 0, (UINT)img.bmHeight, lpbitmap, (BITMAPINFO *)&bmih, DIB_RGB_COLORS); // Gets the bits from the bitmap and copies them to the buffer found at lpbitmap

HANDLE hFile = CreateFile(L"capture.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); // Creates file with various attributes. Check the documentation on MSDN.

DWORD dibSize = bitmapsize + sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Size of the dib is the size of the actual bitmap plus the size of its headers

BITMAPFILEHEADER bmfh; // Fileheader for the bitmap file
bmfh.bfType = 0x4D42; // Defines file as bitmap. 0x4D42 is the code for this
bmfh.bfSize = dibSize; // The total size is everything in the DIB
bmfh.bfReserved1 = 0; // These reserved values must be zero
bmfh.bfReserved2 = 0;
bmfh.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + (DWORD)sizeof(BITMAPINFOHEADER); // Offset to where the image begins. It begins after the header data

// File headers are written first, then the actual bitmap data.
DWORD byteswritten = 0; //Used in writefile commands to accept number of bytes written. I'd have to use an overlapped structure otherwise

WriteFile(hFile, (LPSTR)&bmfh, sizeof(BITMAPFILEHEADER), &byteswritten, NULL); // Look at documentation for remind on what the hell is happening here
WriteFile(hFile, (LPSTR)&bmih, sizeof(BITMAPINFOHEADER), &byteswritten, NULL);
WriteFile(hFile, (LPSTR)lpbitmap, bitmapsize, &byteswritten, NULL);

// Unlcok DIB from the heap, then free it's memory back up
GlobalUnlock(hDIB);
GlobalFree(hDIB);

// Close the file handle
CloseHandle(hFile);

// Delete all of the objects and release the device contexts
DeleteObject(memory);
ReleaseDC(hwnd, clientarea);

// Donezo!!

HDC hdc - контекст устройства окна, обозначенного hwnd.Я передаю их оба в функцию вместо того, чтобы просто использовать GetDC (hwnd) в самой функции, потому что у меня уже есть контекст устройства из другого места в коде.Я предполагаю, что это более эффективно.

Любое руководство было бы очень полезно.Спасибо.

РЕДАКТИРОВАТЬ: Было отмечено, что я забыл фактический вопрос в первоначальном посте ... У меня проблема в том, что этот код сохраняет растровое изображение, которое просто черный ящик.На самом деле он не захватывает содержимое окна.

...