0

So, I'm testing the following function FindPixel with the following app. The HWND and COLORREF are constants that I've determined with Spy++ and Color Cop for debugging; the final version of the program will find these automatically.

I've confirmed that the part of this algorithm which determines whether the color exists works (ie: if the color exists anywhere in the window, the if statement for that is true eventually, and if it doesn't the if statement is never true), however, I cannot figure out how to isolate which pixel this occurs on. The line SetCursorPos(rect.left+i, rect.top+i2); does not move the mouse anywhere near the correct location.

The window I'm debugging this with is entirely white save for the one pixel with the value 16776960. The function can tell that it's there, but the values of (i, i2) are not the (x, y) coordinates of where it occurs.

Is there something I'm missing here?

#include <Windows.h>
void FindPixel(HWND hWnd, COLORREF target)
{
        HDC hDC = GetDC(hWnd);
        HDC memDC = CreateCompatibleDC (hDC);
        BYTE *ScreenData = NULL;
        HBITMAP hBitmap;
        BITMAPINFOHEADER bmHeader = {0};
        RECT rect;
        int width, height;
        int i, i2;
        GetWindowRect(hWnd, &rect);
        width = rect.right-rect.left;
        height = rect.bottom-rect.top;
        ScreenData = (BYTE*)malloc(4*width*height);
        hBitmap = CreateCompatibleBitmap(hDC, width, height);
        bmHeader.biSize = sizeof(BITMAPINFOHEADER);
        bmHeader.biPlanes = 1;
        bmHeader.biBitCount = 24;
        bmHeader.biWidth = width;
        bmHeader.biHeight = -height;
        bmHeader.biCompression = BI_RGB;
        SelectObject(memDC, hBitmap);
        BitBlt(memDC, 0, 0, width, height, hDC, 0, 0, SRCCOPY);

        GetDIBits(hDC, hBitmap, 0, height, ScreenData, (BITMAPINFO*)&bmHeader, DIB_RGB_COLORS);
        //      i=0;
        for(i = 0; i < width; i++)
        {
                for(i2 = 0; i2 < height; i2++)
                {
                        if(RGB((ScreenData[3*((i2*width)+i)+2]),(ScreenData[3*((i2*width)+i)+1]), ScreenData[3*((i2*width)+i)])==target)
                        {
                                SetCursorPos(rect.left+i, rect.top+i2);
                                DeleteObject(hBitmap);
                                DeleteDC(memDC);
                                free(ScreenData);
                                ReleaseDC(hWnd, hDC);
                                return;
                        }
                }
        }
        DeleteObject(hBitmap);
        DeleteDC(memDC);
        free(ScreenData);
        ReleaseDC(hWnd, hDC);
}

int APIENTRY WinMain(HINSTANCE hi, HINSTANCE hpi, LPSTR lpcl, int nsc)
{
        const COLORREF px = 16776960;
        const HWND hWnd = (HWND)0x000C04BC;
        Sleep(1000);
        FindPixel(hWnd, px);
        return 0;
}
Govind Parmar
  • 20,656
  • 7
  • 53
  • 85
  • 3
    Does the window have a standard border? You are working with non-client coordinates when you call `GetWindowRect`, but `GetDC` will return a DC for the client area, meaning your x/y coordinates will be off by the top/left non-client frame size when you call `SetCursorPos`. – Jonathan Potter Mar 06 '13 at 02:23
  • 1
    You also have to take the stride into account. There can be padding at the end of each row of pixels. The stride is computed by `((width * bits_per_pixel) + 7) / 8` – Jim Mischel Mar 06 '13 at 03:37
  • 1
    See http://stackoverflow.com/a/3688558/56778, and the other responses to that question. – Jim Mischel Mar 06 '13 at 10:56
  • Yeah, turns once I took the stride into account the function finds it correctly :) Thanks @JimMischel – Govind Parmar Mar 06 '13 at 18:19

1 Answers1

0

The problem was indeed that I was not taking the stride into account. Here is the working loop:

stride = ((((width * 24) + 31) & ~31) >> 3);

totalpx = stride*height;
for(i = 0; i < totalpx; i++)
{
    //int x = i % width;
    //int y = ((i-x)/width);
    if(RGB(
        (ScreenData[(3*i)+2]),
        (ScreenData[(3*i)+1]),
        (ScreenData[(3*i)+0]))==target)
    {       
        int x = i % stride;
        int y = ((i-x)/width);
        SetCursorPos(rect.left+x,rect.top+y);
        DeleteObject(hBitmap);
        DeleteDC(memDC);
        free(ScreenData);
        ReleaseDC(hWnd, hDC);
        return;
    }

}
Govind Parmar
  • 20,656
  • 7
  • 53
  • 85