Win32 GDI: AlphaBlend() not using constant alpha value correctly - c++

The code provided at the end draws a grid of red 3x3px rectangles with a random constant alpha value using AlphaBlend(). The output however, turns out not "quite" random:
Notice runs of constant alpha along x-axis.
What might be causing this?
P.S. Stepping though the debugger produces the expected output.
Code to produce output:
void draw_mark(HDC hdc, int x, int y,
COLORREF mark_clr, int mark_w, int mark_h, BYTE alpha);
void produce_output(HWND hWnd) {
InvalidateRect(hWnd, NULL, TRUE);
UpdateWindow(hWnd);
const int grid_w = 64, grid_h = 64;
const int mark_sz = 3;
HDC hdc = GetDC(hWnd);
for(int y = 0; y < grid_h; ++y) {
for(int x = 0; x < grid_w; ++x) {
BYTE rnd_alpha = rand(); // use random alpha for each mark
draw_mark(hdc, x * mark_sz, y * mark_sz,
RGB(255,0,0), mark_sz, mark_sz, rnd_alpha);
}
}
// clean-up
ReleaseDC(hWnd, hdc);
}
// draws a [mark_w x mark_h] rectangle at (x,y) with alpha
void draw_mark(HDC hdc, int x, int y,
COLORREF mark_clr, int mark_w, int mark_h, BYTE alpha)
{
HDC hdcMem = CreateCompatibleDC(NULL);
HBITMAP hbm = CreateCompatibleBitmap(hdc, mark_w, mark_h);
HGDIOBJ hOldBmp = SelectObject(hdcMem, hbm);
for(int x = 0; x < mark_w; ++x) {
for(int y = 0; y < mark_h; ++y) {
SetPixel(hdcMem, x, y, mark_clr);
}
}
POINT marker_center{mark_w / 2, mark_h / 2};
SetPixel(hdcMem, marker_center.x, marker_center.y, RGB(255, 255, 255));
BLENDFUNCTION bf{};
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.AlphaFormat = 0; // ignore source per-pixel alpha and...
bf.SourceConstantAlpha = alpha; // ...use constant alpha provided instead
AlphaBlend(hdc,
x - marker_center.x, y - marker_center.y,
mark_w, mark_h,
hdcMem, 0, 0, mark_w, mark_h, bf);
// clean-up
SelectObject(hdcMem, hOldBmp);
DeleteObject(hbm);
DeleteDC(hdcMem);
};
EDIT - As I look more into it, here are the additional issues I have noticed:
1- Output is normal when AlphaBlend() destination is a memory DC, but not when a window DC. So the issue has to do with bliting directly to screen.
2- Corrupt output is unrelated to use of rand() function. Replacing BYTE rnd_alpha = rand(); with ++alpha also produces somewhat similar corrupt outputs.
3- More interestingly, suspending the thread in the inner loop such as Sleep(some_duration) seems to reduce the corruption. Higher the some_duration, less the corruption. Here is a sample output:
First output is generated by first blitting to a memory DC, then to window. The rest is directly to the window. Notice how corruption increases(i.e. output becomes less random) as thread suspension time decreases.

Related

Why is drawing to a hidden HDC giving different results than when drawing to the HDC returned by GetDC(HWND)

I have two methods, paintDoubleBuffered and paint. They are both supposed to draw this image on the screen:
The image is made up of approximately 12 smaller images each sized 256x256 tiled together.
My standard painting method works as expected. Here it is:
void MainWindow::paint(HWND hwnd) {
HDC hdc{GetDC(hwnd)};
paint(hwnd, hdc);
ReleaseDC(hwnd, hdc);
}
void MainWindow::paint(HWND hwnd, HDC hdc) {
constexpr INT img_width{ MDNR_Map::pannel_width };
constexpr INT img_height{ MDNR_Map::pannel_height };
const INT width{ GetDeviceCaps(hdc, HORZRES) };
const INT height{ GetDeviceCaps(hdc, VERTRES) };
const INT num_width_pannels{ (width / img_width) + 1 };
const INT num_height_pannels{ (height / img_height) + 1 };
Gdiplus::Graphics g(hdc);
g.SetCompositingMode(CompositingMode::CompositingModeSourceCopy);
g.SetInterpolationMode(InterpolationMode::InterpolationModeNearestNeighbor);
for (INT y = 0; y < num_height_pannels; y++) {
for (INT x = 0; x < num_width_pannels; x++) {
Location_t get_loaction(x + map_location.x, y + map_location.y, map_location.layer);
const IMG_t v{ mdnr_map.get(get_loaction) };
const Point drawPoint((INT)(img_width * x), (INT)(img_height * y));
Status stat{ g.DrawImage(v, drawPoint) };
if (stat != Status::Ok)
{
throw std::runtime_error(":(");
}
}
}
}
The issue with that paint method is that mdnr_map.get is an io bound call and may take several micro seconds. Because I need to call it about 12 times, it can lead to flickering.
To solve this, I attempted to write a double-buffered paint method, which is as follows:
void MainWindow::paintDoubleBuffered(HWND hwnd) {
// Get DC for window
HDC hdc{ GetDC(hwnd) };
const INT win_width{ GetDeviceCaps(hdc, HORZRES) };
const INT win_height{ GetDeviceCaps(hdc, VERTRES) };
// Create an off-screen DC for double-buffering
HDC hdcMem{ CreateCompatibleDC(hdc) };
HBITMAP hbmMem{ CreateCompatibleBitmap(hdc, win_width, win_height) };
HANDLE hOld{ SelectObject(hdcMem, hbmMem) };
// Draw into hdcMem here
paint(hwnd, hdcMem);
// Transfer the off-screen DC to the screen
BitBlt(hdc, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY);
// Free-up the off-screen DC
SelectObject(hdcMem, hOld);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
}
However, this does not work and instead produces this abombination of an image:
With a little poking and proding, I was able to discover that if I changed my double buffered paint method by multiplying the image size by 1.5, the image was no longer so garbled, but was now zoomed in by a factor of 1.5
void MainWindow::paintDoubleBuffered(HWND hwnd) {
// Get DC for window
HDC hdc{ GetDC(hwnd) };
const INT win_width{ GetDeviceCaps(hdc, HORZRES) };
const INT win_height{ GetDeviceCaps(hdc, VERTRES) };
// Create an off-screen DC for double-buffering
HDC hdcMem{ CreateCompatibleDC(hdc) };
HBITMAP hbmMem{ CreateCompatibleBitmap(hdc, win_width, win_height) };
HANDLE hOld{ SelectObject(hdcMem, hbmMem) };
// Draw into hdcMem here
constexpr INT img_width{ MDNR_Map::pannel_width + 128 }; // MDNR_Map::pannel_width is 256
constexpr INT img_height{ MDNR_Map::pannel_height + 128}; // MDNR_Map::pannel_height is 256
const INT num_width_pannels{ (win_width / img_width) + 1 };
const INT num_height_pannels{ (win_height / img_height) + 1 };
Gdiplus::Graphics g(hdcMem);
g.SetCompositingMode(CompositingMode::CompositingModeSourceCopy);
g.SetInterpolationMode(InterpolationMode::InterpolationModeNearestNeighbor);
for (INT y = 0; y < num_height_pannels; y++) {
for (INT x = 0; x < num_width_pannels; x++) {
Location_t get_loaction(x + map_location.x, y + map_location.y, map_location.layer);
Gdiplus::Bitmap* pannel{ mdnr_map.get(get_loaction) };
const Point drawPoint((INT)(img_width * x), (INT)(img_height * y));
Status stat{ g.DrawImage(pannel, drawPoint) };
if (stat != Status::Ok)
{
throw std::runtime_error(":(");
}
}
}
// Transfer the off-screen DC to the screen
BitBlt(hdc, 0, 0, win_width, win_height, hdcMem, 0, 0, SRCCOPY);
// Free-up the off-screen DC
SelectObject(hdcMem, hOld);
DeleteObject(hbmMem);
DeleteDC(hdcMem);
}
My question is why does drawing to the HDC returned by CreateCompatibleBitmap produce a different result than drawing to the HDC returned by GetDC?
I have tried:
All raster-operation codes for BltBlt.
I have checked that the temporary HDC is the same size as the window.
I have tried replacing the code snippet
const INT win_width{ GetDeviceCaps(hdc, HORZRES) };
const INT win_height{ GetDeviceCaps(hdc, VERTRES) };
with
RECT rect;
GetWindowRect(hwnd, &rect);
const INT win_width{ rect.right - rect.left };
const INT win_height{ rect.bottom - rect.top };
I have also called SetProcessDPIAware() before drawing.
Upon feedback from #Paul Sanders, I rewrote my paintDoubleBuffered method as follows, NOTE, I have called BufferedPaintInit in the object constructor:
void MainWindow::paintDoubleBuffered(HWND hwnd) {
PAINTSTRUCT ps;
HDC hdc{ BeginPaint(hwnd, &ps)};
RECT sz;
GetWindowRect(hwnd, &sz);
BP_PAINTPARAMS paintParams = { 0 };
paintParams.cbSize = sizeof(paintParams);
paintParams.dwFlags = BPPF_ERASE;
paintParams.pBlendFunction = NULL;
paintParams.prcExclude = NULL;
HDC hdcBuffer;
HPAINTBUFFER hBufferedPaint = BeginBufferedPaint(hdc, &sz, BPBF_COMPATIBLEBITMAP, &paintParams, &hdcBuffer);
if (hBufferedPaint && this->bufferedInitResult == Ok) {
// Application specific painting code
paint(hwnd, hdcBuffer);
EndBufferedPaint(hBufferedPaint, TRUE);
}
else{
paint(hwnd, hdc);
}
ReleaseDC(hwnd, hdc);
}
Unfortunately, this did not work and the resultant screen looks like this:
The issue ended up being not in the approach to double buffering, but in the call to Graphics::DrawImage(Image*, Gdiplus::Point) in my paint method. Changing to DrawImage(Image* image, INT x, INT y, INT width, INT height) fixed the scaling issue.

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.

GetPixel() not working correctly Windows API C++

I'm writing a program that reads each pixel of a window and store it in an array of bytes as black and white, each bit of the bytes is a black/white value.
But GetPixel() doesn't seem to work the way I expected. Here's the part of the code for reading pixels and storing them:
byte *colors = new byte[250000 / 8 + 1];
ZeroMemory(colors, 250000 / 8 + 1);
HDC hdc = GetDC(hwnd);
HDC memDC = CreateCompatibleDC(hdc);
HBITMAP memBitmap = CreateCompatibleBitmap(hdc, 500, 500);
SelectObject(memDC, memBitmap);
BitBlt(memDC, 0, 0, 500, 500, hdc, 0, 0, SRCCOPY);
for (int y = 0; y < 500; y++) {
for (int x = 0; x < 500; x++) {
COLORREF pxcolor = GetPixel(memDC, x, y);
if (pxcolor == CLR_INVALID) {
MessageBox(hwnd, _T("Oops..."), NULL, NULL);
}
int r = GetRValue(pxcolor);
int g = GetGValue(pxcolor);
int b = GetBValue(pxcolor);
int average = (r + g + b) / 3;
bool colorBW = average >= 128;
int currentIndex = y * 500 + x;
if (colorBW) {
SetBit(colors, currentIndex);
}
}
}
ReleaseDC(hwnd, hdc);
DeleteDC(memDC);
DeleteObject(memBitmap);
delete[] colors;
SetBit():
inline VOID SetBit(byte *bytes, int index, bool state = true) {
byte byteToSet = bytes[index / 8];
int bitNumber = index % 8;
bytes[index / 8] = state ? (byteToSet | (0b1000'0000 >> bitNumber)) : (byteToSet & ((0b1111'1111 >> (bitNumber + 1)) | (0b1111'1111 << (8 - bitNumber - 1))));
}
Every pixel read in by GetPixel() seems to give me 0x000000, or pure black.
My code used to call GetPixel() with the first parameter being hdc, without all the bitmap and memory DC stuff, but that way every pixel returns CLR_INVALID. I came across this question, and the above code is after I have changed it into using memory DCs and bitmaps. But it just went from returning CLR_INVALID to 0x000000 for each pixel.
If I add this line before I use GetPixel():
SetPixel(memDC, x, y, RGB(255, 255, 255));
GetPixel() returns the correct result. Why is it functioning this way?

How to extract bitmap from spritesheet in Win32 C++?

I'm trying to load individual cards from a spritesheet of cards based on suit and rank but I'm unsure of how to construct a new Bitmap object from cutting out Rectangle coordinates in the source image. I'm using <windows.h> currently and trying to find a simple way to accomplish this. I'm looking for something like this:
HBITMAP* twoOfHearts = CutOutFromImage(sourceImage, new Rectangle(0, 0, 76, 116));
From source: http://i.stack.imgur.com/WZ9Od.gif
Here's a function I played with the other week for more-or-less this same task. In my case, I wanted to return a HBRUSH that could be used with FillRect. In that instance, we still need to create a bitmap of the area of interest, before then going on to create a brush from it.
In your case, just return the dstBmp instead. spriteSheet is a global that has had a 256x256 spritesheet loaded. I've hardcoded the size of my sprites to 16x16, you'd need to change that to something like 81x117.
Here's some code that grabs a copy of the required area and some more that uses these 'stamps' to draw a level map. That said - there are all kinds of problems with this approach. Speed is one, excessive work is another one that impacts on the first. Finally, scrolling a window drawn like this produces artefacts.
// grabs a 16x16px section from the spriteSheet HBITMAP
HBRUSH getSpriteBrush(int col, int row)
{
HDC memDC, dstDC, curDC;
HBITMAP oldMemBmp, oldDstBmp, dstBmp;
curDC = GetDC(HWND_DESKTOP);
memDC = CreateCompatibleDC(NULL);
dstDC = CreateCompatibleDC(NULL);
dstBmp = CreateCompatibleBitmap(curDC, 16, 16);
int xOfs, yOfs;
xOfs = 16 * col;
yOfs = 16 * row;
oldMemBmp = (HBITMAP)SelectObject(memDC, spriteSheet);
oldDstBmp = (HBITMAP)SelectObject(dstDC, dstBmp);
BitBlt(dstDC,0,0,16,16, memDC, xOfs,yOfs, SRCCOPY);
SelectObject(memDC, oldMemBmp);
SelectObject(dstDC, oldDstBmp);
ReleaseDC(HWND_DESKTOP, curDC);
DeleteDC(memDC);
DeleteDC(dstDC);
HBRUSH result;
result = CreatePatternBrush(dstBmp);
DeleteObject(dstBmp);
return result;
}
void drawCompoundSprite(int x, int y, HDC paintDC, char *tileIndexes, int numCols, int numRows)
{
int mapCol, mapRow;
HBRUSH curSprite;
RECT curDstRect;
for (mapRow=0; mapRow<numRows; mapRow++)
{
for (mapCol=0; mapCol<numCols; mapCol++)
{
int curSpriteIndex = tileIndexes[mapRow*numCols + mapCol];
int spriteX, spriteY;
spriteX = curSpriteIndex % 16;
spriteY = curSpriteIndex / 16;
curDstRect.left = x + 16*mapCol;
curDstRect.top = y + 16 * mapRow;
curDstRect.right = curDstRect.left + 16;
curDstRect.bottom = curDstRect.top + 16;
curSprite = getSpriteBrush(spriteX, spriteY);
FillRect(paintDC, &curDstRect, curSprite);
DeleteObject(curSprite);
}
}
}
The latter function has since been replaced with the following:
void drawCompoundSpriteFast(int x, int y, HDC paintDC, unsigned char *tileIndexes, int numCols, int numRows, pMapInternalData mData)
{
int mapCol, mapRow;
HBRUSH curSprite;
RECT curDstRect;
HDC memDC;
HBITMAP oldBmp;
memDC = CreateCompatibleDC(NULL);
oldBmp = (HBITMAP)SelectObject(memDC, mData->spriteSheet);
for (mapRow=0; mapRow<numRows; mapRow++)
{
for (mapCol=0; mapCol<numCols; mapCol++)
{
int curSpriteIndex = tileIndexes[mapRow*numCols + mapCol];
int spriteX, spriteY;
spriteX = curSpriteIndex % mData->tileWidth;
spriteY = curSpriteIndex / mData->tileHeight
// Draw sprite as-is
// BitBlt(paintDC, x+16*mapCol, y+16*mapRow,
// mData->tileWidth, mData->tileHeight,
// memDC,
// spriteX * 16, spriteY*16,
// SRCCOPY);
// Draw sprite with magenta rgb(255,0,255) areas treated as transparent (empty)
TransparentBlt(
paintDC,
x+mData->tileWidth*mapCol, y+mData->tileHeight*mapRow,
mData->tileWidth, mData->tileHeight,
memDC,
spriteX * mData->tileWidth, spriteY*mData->tileHeight,
mData->tileWidth, mData->tileHeight,
RGB(255,0,255)
);
}
}
SelectObject(memDC, oldBmp);
DeleteObject(memDC);
}

How to read the screen pixels?

I want to read a rectangular area, or whole screen pixels. As if screenshot button was pressed.
How i do this?
Edit: Working code:
void CaptureScreen(char *filename)
{
int nScreenWidth = GetSystemMetrics(SM_CXSCREEN);
int nScreenHeight = GetSystemMetrics(SM_CYSCREEN);
HWND hDesktopWnd = GetDesktopWindow();
HDC hDesktopDC = GetDC(hDesktopWnd);
HDC hCaptureDC = CreateCompatibleDC(hDesktopDC);
HBITMAP hCaptureBitmap = CreateCompatibleBitmap(hDesktopDC, nScreenWidth, nScreenHeight);
SelectObject(hCaptureDC, hCaptureBitmap);
BitBlt(hCaptureDC, 0, 0, nScreenWidth, nScreenHeight, hDesktopDC, 0,0, SRCCOPY|CAPTUREBLT);
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = nScreenWidth;
bmi.bmiHeader.biHeight = nScreenHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight];
GetDIBits(
hCaptureDC,
hCaptureBitmap,
0,
nScreenHeight,
pPixels,
&bmi,
DIB_RGB_COLORS
);
// write:
int p;
int x, y;
FILE *fp = fopen(filename, "wb");
for(y = 0; y < nScreenHeight; y++){
for(x = 0; x < nScreenWidth; x++){
p = (nScreenHeight-y-1)*nScreenWidth+x; // upside down
unsigned char r = pPixels[p].rgbRed;
unsigned char g = pPixels[p].rgbGreen;
unsigned char b = pPixels[p].rgbBlue;
fwrite(fp, &r, 1);
fwrite(fp, &g, 1);
fwrite(fp, &b, 1);
}
}
fclose(fp);
delete [] pPixels;
ReleaseDC(hDesktopWnd, hDesktopDC);
DeleteDC(hCaptureDC);
DeleteObject(hCaptureBitmap);
}
Starting with your code and omitting error checking ...
// Create a BITMAPINFO specifying the format you want the pixels in.
// To keep this simple, we'll use 32-bits per pixel (the high byte isn't
// used).
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = nScreenWidth;
bmi.bmiHeader.biHeight = nScreenHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
bmi.bmiHeader.biCompression = BI_RGB;
// Allocate a buffer to receive the pixel data.
RGBQUAD *pPixels = new RGBQUAD[nScreenWidth * nScreenHeight];
// Call GetDIBits to copy the bits from the device dependent bitmap
// into the buffer allocated above, using the pixel format you
// chose in the BITMAPINFO.
::GetDIBits(hCaptureDC,
hCaptureBitmap,
0, // starting scanline
nScreenHeight, // scanlines to copy
pPixels, // buffer for your copy of the pixels
&bmi, // format you want the data in
DIB_RGB_COLORS); // actual pixels, not palette references
// You can now access the raw pixel data in pPixels. Note that they are
// stored from the bottom scanline to the top, so pPixels[0] is the lower
// left pixel, pPixels[1] is the next pixel to the right,
// pPixels[nScreenWidth] is the first pixel on the second row from the
// bottom, etc.
// Don't forget to free the pixel buffer.
delete [] pPixels;
Rereading your question, it sounds like we may have gotten off on a tangent with the screen capture. If you just want to check some pixels on the screen, you can use GetPixel.
HDC hdcScreen = ::GetDC(NULL);
COLORREF pixel = ::GetPixel(hdcScreen, x, y);
ReleaseDC(NULL, hdcScreen);
if (pixel != CLR_INVALID) {
int red = GetRValue(pixel);
int green = GetGValue(pixel);
int blue = GetBValue(pixel);
...
} else {
// Error, x and y were outside the clipping region.
}
If you're going to read a lot of pixels, then you're better off with a screen capture and then using GetDIBits. Calling GetPixel zillions of times will be slow.
You make a screenshot with BitBlt(). The size of the shot is set with the nWidth and nHeight arguments. The upper left corner is set with the nXSrc and nYSrc arguments.
You can use the code below to read the screen pixels:
HWND desktop = GetDesktopWindow();
HDC desktopHdc = GetDC(desktop);
COLORREF color = GetPixel(desktopHdc, x, y);
HBITMAP is not a pointer or an array, it is a handle that is managed by Windows and has meaning only to Windows. You must ask Windows to copy the pixels somewhere for use.
To get an individual pixel value, you can use GetPixel without even needing a bitmap. This will be slow if you need to access many pixels.
To copy a bitmap to memory you can access, use the GetDIBits function.