How to extract a part of HBITMAP without using BitBlt - c++

I have a HBITMAP object. Without using BitBlt I would like to divide it into parts and obtain either the bits or new bitmaps of these parts
I can do it with BitBlt, but it is slow. It takes ~50 ms for extracting the part.
I have considered extracting regions of the byte array obtained from the bitmap, but this seems difficult. Is there any other way?
Thanks!

BitBlt is very fast. If you are copying from another dc it takes a little too long. There is no way to get around that.
To word directly with pixels you need GetDIBits(HDC hdc, HBITMAP hbitmap...) but you still need BitBlt in order to setup the hbitmap
You can create a second memory dc, copy from first memory dc to second memory dc, this will be much faster. Using memory device context is like accessing bits directly.
#include <iostream>
#include <windows.h>
using namespace std;
long long milliseconds()
{
LARGE_INTEGER fq, t;
QueryPerformanceFrequency(&fq);
QueryPerformanceCounter(&t);
return 1000 * t.QuadPart / fq.QuadPart;
}
int main()
{
HWND hwnd = GetDesktopWindow();
HDC hdc = GetDC(hwnd);
HDC memdc = CreateCompatibleDC(hdc);
RECT rc;
GetWindowRect(hwnd, &rc);
int width = rc.right - rc.left;
int height = rc.bottom - rc.top;
int xPos = 100;
int yPos = 100;
int cropWidth = 500;
int cropHeight = 500;
HBITMAP hbitmap = CreateCompatibleBitmap(hdc, width, height);
SelectObject(memdc, hbitmap);
long long start;
start = milliseconds();
BitBlt(memdc, 0, 0, cropWidth, cropHeight, hdc, xPos, yPos, SRCCOPY);
//this will take about 50 ms, or much less
cout << milliseconds() - start << "\n";
{
//create a second memory dc:
start = milliseconds();
HDC memdc2 = CreateCompatibleDC(hdc);
HBITMAP hbitmap2 = CreateCompatibleBitmap(memdc2, 500, 500);
SelectObject(memdc2, hbitmap2);
BitBlt(memdc2, 0, 0, 500, 500, memdc, 0, 0, SRCCOPY);
//this will take about 1 ms:
cout << "time: " << milliseconds() - start << "\n";
DeleteObject(hbitmap2);
DeleteDC(memdc2);
}
DeleteDC(memdc);
DeleteObject(hbitmap);
ReleaseDC(hwnd, hdc);
return 0;
}
For the small you have shown it shouldn't be necessary to either access bits directly, or to use a second memory dc. You can copy any portion of the screen directly, it will only need 1 BitBlt operation.

Related

Capturing a specific window using C++ returns old data

I'm currently working on a project that requires to take a screenshot a specific window.
That's what I got so far:
Main function
int main() {
LPCSTR windowname = "Calculator";
HWND handle = FindWindowA(NULL, windowname);
while (!handle) {
std::cout << "Process not found..." << std::endl;
handle = FindWindowA(NULL, windowname);
Sleep(100);
}
Mat img = captureScreenMat(handle);
resetMat();
imwrite("test2.jpg", img);
showInMovedWindow("IMG", img);
waitKey(0);
destroyAllWindows();
return 0;
}
winCapture
Mat src;
void showInMovedWindow(string winname, Mat img) {
namedWindow(winname);
moveWindow(winname, 40, 30);
imshow(winname, img);
}
BITMAPINFOHEADER createBitmapHeader(int width, int height)
{
BITMAPINFOHEADER bi;
bi.biSize = sizeof(BITMAPINFOHEADER);
bi.biWidth = width;
bi.biHeight = -height;
bi.biPlanes = 1;
bi.biBitCount = 32;
bi.biCompression = BI_RGB;
bi.biSizeImage = 0;
bi.biXPelsPerMeter = 0;
bi.biYPelsPerMeter = 0;
bi.biClrUsed = 0;
bi.biClrImportant = 0;
return bi;
}
int getHeight(HWND hwnd) {
RECT rect;
GetWindowRect(hwnd, &rect);
int height = rect.bottom - rect.top;
return height;
}
int getWidth(HWND hwnd) {
RECT rect;
GetWindowRect(hwnd, &rect);
int width = rect.right - rect.left;
return width;
}
Mat captureScreenMat(HWND hwnd)
{
HDC hwindowDC = GetDC(hwnd);
HDC hwindowCompatibleDC = CreateCompatibleDC(hwindowDC);
SetStretchBltMode(hwindowCompatibleDC, COLORONCOLOR);
int screenx = GetSystemMetrics(SM_XVIRTUALSCREEN);
int screeny = GetSystemMetrics(SM_YVIRTUALSCREEN);
int width = getWidth(hwnd);
int height = getHeight(hwnd);
src.create(height, width, CV_8UC4);
HBITMAP hbwindow = CreateCompatibleBitmap(hwindowDC, width, height);
BITMAPINFOHEADER bi = createBitmapHeader(width, height);
//DEBUG
cout << hbwindow << endl;
cout << hwindowCompatibleDC << endl;
cout << hwindowDC << endl;
SelectObject(hwindowCompatibleDC, hbwindow);
StretchBlt(hwindowCompatibleDC, 0, 0, width, height, hwindowDC, screenx, screeny, width, height, SRCCOPY);
GetDIBits(hwindowCompatibleDC, hbwindow, 0, height, src.data, (BITMAPINFO*)&bi, DIB_RGB_COLORS);
DeleteObject(hbwindow);
DeleteDC(hwindowCompatibleDC);
DeleteDC(hwindowDC);
ReleaseDC(NULL, hwindowDC);
return src;
}
void resetMat() {
src.release();
}
Most windows work really well with this approach, but there are some windows that are working the first time, I try to take a img of them, but every time I try to take another screenshot of the same process, it just gives me the first screenshot I took of it. It only works again after a restart of the process and even then It just works again for one screenshot and all after are the same.
I thought it would be some kind of memory leak, but I'm deleting all the objects and releasing the handle.
I think that something is wrong with the handle, but I couldn't figure out what.
I'm not familiar with working with the windowsAPI and hope someone knowns more than me.
Fixed: Process blocked creating handle.
When you call SelectObject you must save the previous-selected handle (available from the return value) and you MUST select it back before deleting or releasing the device context.
Right now you are breaking a bunch of rules.
Deleting a bitmap which is selected into a device context.
Deleting a DC gotten from GetDC.
Calling both DeleteDC and ReleaseDC on the same handle.
Passing NULL as the first parameter of ReleaseDC, which should be the same HWND passed to GetDC.
Deleting a DC without selecting the original bitmap back into it.
These bugs royally mess up the window DC. If it was a transient DC, the system probably cleans up your mess immediately. But if the window class has the CS_OWNDC or CS_CLASSDC flags, you do permanent damage to the window. That's why your method appears to work with some windows and not others.

Capture pixel data from only a specified window

I want the code below to take a screenshot of a specified window only, becuse this way BitBlt is faster.
The code below takes a screenshot of a window, specified by the name of window, loads the pixel data in a buffer and then re-draws the picture on your screen just to prove the copying worked.
I'd like to take screenshots of browser windows like Google Chrome, but it doesn't seem to work. It draws a black rectangle on my screen with the correct dimensions of the window.
Seems to be working all the time with the window of Minecraft.
Also worked with the Tor Browser.
I noticed that after querying window info, minecraft's window had no child-windows, but when it didn't work with the others, all of them had multiple child-windows.
#include<iostream>
#include<Windows.h>
#include<vector>
using namespace std;
int main() {
HWND wnd = FindWindow(NULL, "Minecraft 1.15.1");//Name of window to be screenshoted
if (!wnd) {
std::cout << "e1\n";
std::cin.get();
return 0;
}
WINDOWINFO wi = { 0 };
wi.cbSize = sizeof(WINDOWINFO);
GetWindowInfo(wnd, &wi);
RECT rect;
GetWindowRect(wnd, &rect);
int width = wi.rcClient.right - wi.rcClient.left;
int height = wi.rcClient.bottom - wi.rcClient.top;
cout << width << height;
/////Fetch window info^^^^^^^^
BYTE* ScreenData = new BYTE[4 * width*height];
// copy screen to bitmap
HDC hScreen = GetWindowDC(wnd);
HDC hDC = CreateCompatibleDC(hScreen);
HBITMAP hBitmap = CreateCompatibleBitmap(hScreen, width, height);
HGDIOBJ old_obj = SelectObject(hDC, hBitmap);
BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);
SelectObject(hDC, old_obj);
BITMAPINFO bmi = { 0 };
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
std::cout << GetDIBits(hDC, hBitmap, 0, 0, NULL, &bmi, DIB_RGB_COLORS)<<endl;
//std::cout << bmi.bmiHeader.biHeight<< " "<< bmi.bmiHeader.biWidth<<endl;
BYTE*buffer = new BYTE[4* bmi.bmiHeader.biHeight*bmi.bmiHeader.biWidth];
bmi.bmiHeader.biHeight *= -1;
std::cout<<GetDIBits(hDC, hBitmap, 0, bmi.bmiHeader.biHeight, buffer, &bmi, DIB_RGB_COLORS)<<endl;//DIB_PAL_COLORS
/////Load window pixels into a buffer^^^^^^^^
POINT p;
int r = 0;
int g = 0;
int b = 0;
int x = 0;
int y = 0;
HDC sc = GetDC(NULL);
COLORREF color;
while (true) {
if ((y*-1) == bmi.bmiHeader.biHeight+1 && x == bmi.bmiHeader.biWidth-1) { break; }
r = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x)+2];
g = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x)+1];
b = (int)buffer[4 * ((y*bmi.bmiHeader.biWidth) + x) ];
color = RGB(r, g, b);
SetPixel(sc, x, y, color);
x++;
if (x == bmi.bmiHeader.biWidth) {
y++;
x = 0;
}
}
/////Prove that the copying was successful and buffer is full^^^^^^^^
Sleep(5000);
std::cout << "fin\n";
std::cin.get();
return 0;
}
I think the problem is the order you're doing things.
Before you put the bitmap on the clipboard, you should select it out of your memory device context.
Once you put the bitmaps on the clipboard, you no longer own it, so you shouldn't try to delete it.
The best way to do that is probably to move your // clean up section before the // save bitmap to clipboard section and to eliminate your DelectObject(hBitmap) statement. So the tail end of your code should probably be:
BitBlt(hDC, 0, 0, width, height, hScreen, 0, 0, SRCCOPY);
// clean up
SelectObject(hDC, old_obj); // selects hBitmap out of hDC
DeleteDC(hDC);
ReleaseDC(NULL, hScreen);
// save bitmap to clipboard
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hBitmap); // clipboard now owns the bitmap
CloseClipboard();
If you still have a problem after those changes, I would check the return value of the SetClipboardData call. If that's failing, GetLastError may give a clue.

How to store multiple bitmaps in a class?

I want to create a class that generates some bitmaps at runtime and then draws them in the context of the target device on request.
I try this:
myBitmaps.h
#include <windows.h>
class myBitmaps
{
public:
void myBitmaps(HDC hDC);
const int size = 16;
HDC firstDC;
HBITMAP firstBuff;
HDC secondDC;
HBITMAP secondBuff;
void drawBitmap(HDC hDC, int xPos, int yPos, bool first);
}
myBitmaps.cpp
#include "myBitmaps.h"
void myBitmaps(HDC hDC)
{
firstDC = CreateCompatibleDC(hDC);
firstBuff = CreateCompatibleBitmap(hDC, size, size);
SelectObject(firstDC, firstBuff);
...draw some lines...
secondDC = CreateCompatibleDC(hDC);
secondBuff = CreateCompatibleBitmap(hDC, size, size);
SelectObject(secondDC, secondBuff);
...draw some lines...
}
void drawBitmap(HDC hDC, int xPos, int yPos, bool first)
{
if(first) {
BitBlt(hDC, xPos, yPos, size, size, firstDC , 0, 0, SRCCOPY);
}
else {
BitBlt(hDC, xPos, yPos, size, size, secondDC , 0, 0, SRCCOPY);
}
}
But this code causes a runtime error.
How can I store multiple bitmaps in my class?
There can be only one type of each GDI object selected into any type
of DC at a time. The memory DC is unique, because it is the only type
of DC that is possible to use an HBITMAP with a call to
::SelectObject. Unlike other GDI object types, the HBITMAP can only be
selected into one DC at a time. Therefore, if you are using the same
bitmap with multiple memory DCs, be sure to save the original HGDIOBJ
pushed-out from the memory DC when you select your bitmap into the DC.
Otherwise, your attempt to select the bitmap into a second memory DC
will fail.
For more details, please refer to the link below.
Guide to Win32 Memory DC
The link lists a lot of things you should pay attention to when using CompatibleDC in the link. Please read them carefully.

4K screen capturing in Windows and directly save into a buffer

I know there are many posts across the web to do screen capturing in Windows either using GDI or DirectX approaches. However, all I found save the captured image to a bitmap, whereas I want to save it into a buffer instead. Here is my code to do so in GDi way:
HWND hwind = GetDesktopWindow();
HDC hdc = GetDC(hwind);
uint32_t resx = GetSystemMetrics(SM_CXSCREEN);
uint32_t resy = GetSystemMetrics(SM_CYSCREEN);
uint32_t BitsPerPixel = GetDeviceCaps(hdc, BITSPIXEL);
HDC hdc2 = CreateCompatibleDC(hdc);
BITMAPINFO info;
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biWidth = resx;
info.bmiHeader.biHeight = resy;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biBitCount = BitsPerPixel;
info.bmiHeader.biCompression = BI_RGB;
void *data;
static HBITMAP hbitmap = CreateDIBSection(hdc2, &info, DIB_RGB_COLORS,
(void**)&data, 0, 0);
SelectObject(hdc2, hbitmap);
BitBlt(hdc2, 0, 0, resx, resy, hdc, 0, 0, SRCCOPY);
uint8_t *ptr = new uint8_t[4 * resx * resy];
uint32_t lineSizeSrc = 4 * resx; // not always correct
uint32_t linesizeDst = 4 * resx;
for (uint32_t y = 0; y < resy; y++)
memcpy(ptr + y * lineSizeDst,
(uint8_t*) data + y * lineSizeSrc,
lineSizeDst);
DeleteObject(hbitmap);
ReleaseDC(hwind, hdc);
if (hdc2) {
DeleteDC(hdc2);
}
First, as far as I know, the value of lineSizeSrc in this code is not always correct since depending on the screen resolution, some zeros may be added to each line of data. Can anyone please explain when the zeros are added and how to get the correct value for lineSizeSrc?
Second, is it possible to get the captured image in 4K resolution regardless of the resolution of the monitor, for instance by forcing the graphics card to output in 4K resolution?
First, as far as I know, the value of lineSizeSrc in this code is not always correct since depending on the screen resolution, some zeros may be added to each line of data. Can anyone please explain when the zeros are added and how to get the correct value for lineSizeSrc?
The bitmap format requires that each line begin at an address that's a multiple of 4 bytes. Often, this just works out because common image widths are multiples of 4 or because the size of an individual pixel is 32-bits (which is 4 bytes).
But if you're representing an image with an unusual width (e.g., 31 pixels wide) and using something like 24 bits (3 bytes) per pixel then you'll need to pad the end of each line so that the next line starts on a multiple of 4.
A common way to do this is to round up the "stride":
lineSizeSrc = (resx * BitsPerPixel + 31) / 8;
resx * BitsPerPixel tells us the number of bits needed to represent the line. Dividing by 8 converts bits to bytes--sort of. Integer division truncates any remainder. By adding 31 first we ensures that the truncation gives us the smallest multiple of 32 bits (4 bytes) that's equal to or larger than the number of bits we need. So lineSizeSrc is the number of bytes needed for each row.
You should use lineSizeSrc instead of resx in the calculation of how many bytes you need.
Second, is it possible to get the captured image in 4K resolution regardless of the resolution of the monitor, for instance by forcing the graphics card to output in 4K resolution?
There's not a simple, works-in-all-cases method. Your best bet is probably to ask the program to render to a window that's 4K, even if the graphics card isn't in that mode. Some programs will support this, but others might now. Look at the documentation for the WM_PRINT and WM_PRINTCLIENT messages.
Most modern monitors support 32bit color which is relatively simple as it doesn't require palettes. Example in C++:
void capture(char* &buffer)
{
HWND hwnd = GetDesktopWindow();
HDC hdc = GetDC(hwnd);
int w = GetSystemMetrics(SM_CXSCREEN);
int h = GetSystemMetrics(SM_CYSCREEN);
int BitsPerPixel = GetDeviceCaps(hdc, BITSPIXEL);
if (BitsPerPixel = 32)
{
HDC memdc = CreateCompatibleDC(hdc);
HBITMAP bmp = CreateCompatibleBitmap(hdc, w, h);
HGDIOBJ oldbitmap = SelectObject(memdc, bmp);
BitBlt(memdc, 0, 0, w, h, hdc, 0, 0, CAPTUREBLT | SRCCOPY);
SelectObject(memdc, oldbitmap);
DWORD bitsize = w * h * 4;
char *bits = new char[bitsize];
DWORD szInfoHdr = sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER bmpInfoHeader =
{ szInfoHdr, w, h, 1, (WORD)BitsPerPixel, BI_RGB, 0, 0, 0, 0, 0 };
GetDIBits(hdc, bmp, 0, h, bits, (BITMAPINFO*)&bmpInfoHeader, DIB_RGB_COLORS);
buffer = new char[bitsize + szInfoHdr];
memcpy(buffer, &bmpInfoHeader, szInfoHdr);
memcpy(buffer + szInfoHdr, bits, bitsize);
delete[]bits;
DeleteObject(bmp);
DeleteObject(memdc);
}
ReleaseDC(hwnd, hdc);
}
You can pass buffer through a function. The following code can be used for testing:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
char *buffer = 0;
//capture the screen and save to buffer
capture(buffer);
if (buffer)
{
//paint the buffer for testing:
BITMAPINFO* bmpinfo = (BITMAPINFO*)buffer;
if (bmpinfo->bmiHeader.biBitCount == 32)
{
int w = bmpinfo->bmiHeader.biWidth;
int h = bmpinfo->bmiHeader.biHeight;
char *bits = buffer + sizeof(BITMAPINFOHEADER);
HBITMAP hbitmap = CreateDIBitmap(hdc,
&bmpinfo->bmiHeader, CBM_INIT, bits, bmpinfo, DIB_RGB_COLORS);
HDC memdc = CreateCompatibleDC(hdc);
SelectObject(memdc, hbitmap);
BitBlt(hdc, 0, 0, w, h, memdc, 0, 0, SRCCOPY);
}
delete[]buffer;
}
EndPaint(hWnd, &ps);
}
Note however, GetSystemMetrics(SM_CXSCREEN) returns the width of the primary monitor only.
You may want SM_CXVIRTUALSCREEN and SM_CYVIRTUALSCREEN to get the width/height of multi-monitor. Use SM_(X/Y)VIRTUALSCREEN to get top-left corner.

c++ read pixels with GetDIBits()

I'm trying to create a function which is equivalent to the windows API GetPixel() function, but I want to create a bitmap of my screen and then read that buffer.
This is what I've got (Mostly copy pasted from google searches), when I run it it only prints out 0's. I think I've got most of it right, and that my issue is that I don't know how to read the BYTE variable.
So my question is, what do I need to do in order to get it to print out some random colors (R,G or B) with my for loop?
#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
int main() {
HDC hdc,hdcMem;
hdc = GetDC(NULL);
hdcMem = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdcMem, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
MyBMInfo.bmiHeader.biBitCount = 32;
MyBMInfo.bmiHeader.biCompression = BI_RGB;
MyBMInfo.bmiHeader.biHeight = abs(MyBMInfo.bmiHeader.biHeight);
// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}
for(int i = 0; i < 100; i++) {
cout << (int)lpPixels[i] << endl;
}
return 0;
}
Windows 7
C::B 13.12 (Console Application)
Compiler: mingw32-gcc
Library gdi32 linked
As agreed, I'm adding a new answer with the working code snippet (I added the missing cleanup of lpPixels). See the discussions in my previous answer and the one made by #enhzflep.
#include <Windows.h>
#include <iostream>
#include <math.h>
#include <stdio.h>
using namespace std;
HBITMAP GetScreenBmp( HDC hdc) {
// Get screen dimensions
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
// Create compatible DC, create a compatible bitmap and copy the screen using BitBlt()
HDC hCaptureDC = CreateCompatibleDC(hdc);
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, nScreenWidth, nScreenHeight);
HGDIOBJ hOld = SelectObject(hCaptureDC, hBitmap);
BOOL bOK = BitBlt(hCaptureDC,0,0,nScreenWidth, nScreenHeight, hdc,0,0,SRCCOPY|CAPTUREBLT);
SelectObject(hCaptureDC, hOld); // always select the previously selected object once done
DeleteDC(hCaptureDC);
return hBitmap;
}
int main() {
HDC hdc = GetDC(0);
HBITMAP hBitmap = GetScreenBmp(hdc);
BITMAPINFO MyBMInfo = {0};
MyBMInfo.bmiHeader.biSize = sizeof(MyBMInfo.bmiHeader);
// Get the BITMAPINFO structure from the bitmap
if(0 == GetDIBits(hdc, hBitmap, 0, 0, NULL, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error" << endl;
}
// create the bitmap buffer
BYTE* lpPixels = new BYTE[MyBMInfo.bmiHeader.biSizeImage];
// Better do this here - the original bitmap might have BI_BITFILEDS, which makes it
// necessary to read the color table - you might not want this.
MyBMInfo.bmiHeader.biCompression = BI_RGB;
// get the actual bitmap buffer
if(0 == GetDIBits(hdc, hBitmap, 0, MyBMInfo.bmiHeader.biHeight, (LPVOID)lpPixels, &MyBMInfo, DIB_RGB_COLORS)) {
cout << "error2" << endl;
}
for(int i = 0; i < 100; i++) {
cout << (int)lpPixels[i];
}
DeleteObject(hBitmap);
ReleaseDC(NULL, hdc);
delete[] lpPixels;
return 0;
}
Basically, you need to have drawn some pixels in order to get back a result other than 0.
At present, the 4th line of code in your main creates an empty (blank, 0-initialized) image. You then get information about the size of this image with your first call to GetDIBits. You then get the actual (blank) pixels with your second call to GetDIBits.
To fix, just load a bitmap file from disk into your hBitmap and select this bitmap into your hdcMem.
I.e, change
HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 1680, 1050);
to something like this.
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, "xpButton.bmp", IMAGE_BITMAP, 0,0, LR_LOADFROMFILE);
HBITMAP old = (HBITMAP) SelectObject(hdcMem, hBitmap);
(make sure you use a valid bmp file name. Mine exists in the same folder as the .cpp file, since this is the 'current' directory when you run via the IDE. If you wish to run via explorer, place another copy of the bmp in the same folder as your exe)
Here's the bmp I've used (which has been converted to a png after upload to SO):
And here's the first 10 iterations through the loop.
255
5
253
0
255
5
253
0
255
5
Note that the pixel at 0,0 has the colour of: rgb(253,5,255) and it's an 8bit image, so there's no alpha channel, hence it has the value 0. The pixels are stored as [BGRA], [BGRA], [BGRA], etc, etc.
I'll leave it to you to fix the (non-existant) clean-up section of your program. Windows will de-allocate the memory you've used here, but you absolutely should not get into the habit of not freeing any memory you've allocated. :)
Your code seems a bit confused. Too many snippets I guess :).
Still, you're quite close:
The first GetDIBits() call is in order to get the properties of the bitmap filled in, as the comment in your code suggests.
You are using an unnecessary MemDC for this - which is probably from a snippet that wants to do a BitBlt with the screen.
You then can use the filled in structure to get the actual bitmap pixels with the second GetDIBits() call, but what you're doing is replacing the properties with hard coded values again, making the first GetDIBits() call useless.
So: Drop the MemDC - you don't need it - and replace hdcMem with hdc in the first call to GetDIBits(), then remove all the statements that overwrite bmiHeader members after the first GetDIBits call and you should get your pixels.
Oh, and of course don't forget to call ReleaseDC()/DeleteObject() on the dc and bitmap and delete[] the buffer :)