Hello,

I have a HWND for a window. I have double checked that it is a 100% valid window by using SetActiveWindow(), SetFocus(), and SetForegroundWindow() on it, successfully bringing it to the frontmost window. However whenever I try to use GetPixel on it it returns -1 (0xFFFFFFFF). What am I doing wrong? Here is a sample of what I am talking about:

HWND myWindow=FindWindow(NULL,"Test Window");
if (!myWindow)return;
SetActiveWindow(myWindow);
SetFocus(myWindow);
SetForegroundWindow(myWindow);
//now the window with title text "Test Window" is active, focussed and in the foreground
uint32_t pxl=GetPixel(GetDC(myWindow),500,500);
//pxl ALWAYS equals 0xFFFFFFFF here... why?!

I have used pretty much identical code before without this problem, why am I getting it now?

The only difference I can see is that this time the x and y coordinates are stored in a global variable for ease of use with my multi-threaded functions (threaded with CreateThread). Can anybody tell me why I can't seem to access the pixels of my window?

According to MSDN GetPixel returns the error value 0xFFFFFFFF / CLR_INVALID under 3 very specific conditions.

  1. The pixel is outside the boundaries of the current clipping area
  2. The device does not support GetPixel
  3. There is no bitmap selected within the device context

Best bet is to take a look at the MSDN page and see whether any of those conditions apply to your application and update it accordingly.

Also, a community comment on the page states that GetPixel is not thread-safe. So if your program is threaded, that could also be part of the problem!

If nothing there helps, then I don't know what else to suggest offhand!

I checked against all of those conditions and here is what I found:

  1. I am not sure how to check the clipping area, but my window is definitely larger than the pixel I am checking (by at least 200 pixels according to photoshop).

  2. How can I tell if a device supports GetPixel? Anyway I have an older version of the same code that works fine on the same exact window...

  3. I read about that issue elsewhere as well, so I added:

    HDC myDC=CreateCompatibleDC(GetDC(myWindow));
    SelectObject(myDC,CreateCompatibleBitmap(GetDC(myWindow),1,1));

And used the new DC handle with the bitmap selected. This still did not work.

As for the multithreading, I am using it so that my program can run while it is in the background (as it will always be since it constantly forces myWindow to be in the foreground). I tested it with that code commented out and calling the thread as a normal function, but GetPixel is still returning CLR_INVALID.

The only differences between the code that works and the code I am using now are:

1) The old code only used <iostream> whereas the new code uses SDL
2) The old code checked a bunch of pixels whereas the new code only checks one (thus the reason I rewrote the code - optimization)
3) The old code also used SendInput to send inputs to the monitored window whereas the new code merely monitors it.

Basically here is the description of what I want my program to do:

  1. Create a GUI window, ready for drawing, that is 100x100 pixels smaller than the desktop window.
  2. Attempt to locate a window given its title bar contents, while it cannot be found cause the window to blink between red and black.
  3. While the window is found check a specific pixel. Display its colour to the window. Also check if the window still exists and if it exists ensure that it is the topmost window (SetActive,SetFocus,SetForeground)
  4. Once the window is lost return to step 2.
  5. If the user 'X's out the window during any of the above steps the program should close gracefully. (achieved by handling inputs at all times)

Here is a simplified version of my program that, I would expect, would do exactly that (Sorry about the SDL 1, I am still learning SDL 2):

//WindowObserver.h:
#ifndef WINDOW_OBSERVER_H
#define WINDOW_OBSERVER_H

#define _WIN32_WINNT 0x0500
#include <windows.h>
#include <cstdint>
#include <iostream>

class WindowObserver
{// private:
    HWND myWindow;
    HDC myDC;
    public:
    WindowObserver()
    {
        myWindow=NULL;
        myDC=NULL;
    }
    //Loads myWindow (and myDC), returns true on success
    bool load(const char *title)
    {
        //check if we already have the window
        if (myWindow)
            return false;//you can't load 2 windows with this class
        myWindow=FindWindow(NULL,title);
        if (myWindow)
        {
            myDC=CreateCompatibleDC(GetDC(myWindow));
            SelectObject(myDC,CreateCompatibleBitmap(GetDC(myWindow),1,1));
            return true;
        }
        return false;
    }
    //Checks if myWindow is valid
    bool operator!()
    {
        return IsWindow(myWindow);//so that if(!wnd){x} does x only if myWindow is bad
    }
    //Also checks if myWindow is valid
    operator bool()
    {
        return IsWindow(myWindow);//so that if(wnd){x} does x only if myWindow is good
    }
    //Checks if myWindow is in the foreground
    bool isActive()
    {
        return GetForegroundWindow()==myWindow;
    }
    //tries to force myWindow to the foreground.
    void activate()
    {
        SetActiveWindow(myWindow);
        SetFocus(myWindow);
        SetForegroundWindow(myWindow);
    }
    //returns the pixel colour at x,y
    uint32_t getPixel(int x, int y)
    {
        return GetPixel(myDC,x,y);
    }
};

#endif // WINDOW_OBSERVER_H





//test.cpp
#include "WindowObserver.h"
#include "SDL\SDL.h"
#include <cstdlib>//for atoi

#define RED_COLOUR 0xFFFF0000
#define BLACK_COLOUR 0xFF000000

//Globals, later contained in a struct to be passed to the thread
SDL_Surface *screen;
bool quit;
const char *title;
int x,y;
SDL_Event event;
void loadGUI(int w, int h)
{
    if (SDL_Init(SDL_INIT_EVERYTHING))
        std::cout<<"Error initializing SDL..."<<std::endl;
    screen=SDL_SetVideoMode(w,h,32,SDL_SWSURFACE);
}
void drawGUI(uint32_t col)
{
    SDL_FillRect(screen,NULL,col);
    SDL_Flip(screen);
}
void quitGUI(){SDL_Quit();}
void checkInput()
{
    while (SDL_PollEvent(&event))
        quit|=(event.type==SDL_QUIT);
}
DWORD WINAPI UpdateScreen(WindowObserver &wnd)
{
    while (!quit)
    {
        checkInput();//I don't want to go non-responding, so I check input often
        if (!wnd&&!wnd.load(title))//ensure the window is valid
        {
            //if it isn't blink red and black
            drawGUI(RED_COLOUR);
            Sleep(1000);
            drawGUI(BLACK_COLOUR);
            Sleep(1000);
            return 1;
        }
        if (!wnd.isActive())//ensure the window is active
            wnd.activate();
        drawGUI(wnd.getPixel(x,y));
        checkInput();
    }
}

void showHelp()
{
    std::cout<<
"Usage: test.exe <title> <x> <y>\n\
\t<title> - The title of the window we are trying to find.\n\
\t<x>     - The x coordinate of the pixel you wish to observe.\n\
\t<y>     - The y coordinate of the pixel you wish to observe."<<std::endl;
}
//test.exe <title>
int main(int argc, char *argv[])
{
    if (argc!=4)
    {
        showHelp();
        return 1;
    }
    title=argv[1];
    x=atoi(argv[2]);
    y=atoi(argv[3]);

    //find out what dimensions we want the window to have
    RECT resolution;
    GetWindowRect(GetDesktopWindow(), &resolution);
    //create the window
    loadGUI(resolution.right-100,resolution.bottom-100);
    //create the observer
    WindowObserver wnd;
    quit=false;
    HANDLE thread;
    DWORD exitCode;
    while (!quit)
    {
        checkInput();
        if (!thread)//check if the thread exists
            thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)UpdateScreen,(PVOID)&wnd,0,NULL);
        else
        {
            GetExitCodeThread(thread,&exitCode);//check if the thread is done execution
            if (exitCode!=STILL_ACTIVE)
                thread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)UpdateScreen,(PVOID)&wnd,0,NULL);
        }
    }
    quitGUI();
    return 0;
}

It occurs to me that the only reason I am using threads instead of a sequential programming is that I was under the impression that that was the only way to get code to continue running when its host window was not active. However, from a quick google search most people claim this is not the case.

As such I tried writing a simple program that just switched from red to black. When I tested this program it worked right up until I selected another window, at which point it effectively 'paused' until I selected it again. Is there any way to make this not happen?

When I tested this program it worked right up until I selected another window, at which point it effectively 'paused' until I selected it again. Is there any way to make this not happen?

Maybe the following starter code can be of some assistance to you..

#pragma comment(lib,"user32.lib")
#pragma comment(lib, "gdi32.lib")

#include <Windows.h>

const int ID_TIMER = 1;

HWND window1;
HWND myWindow;
char title[] = {"MyWindow"};

int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd);
LRESULT CALLBACK WinProc1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);


int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nShowCmd)
{
    //Firts: we need to declarate wndclassex we want to use
    WNDCLASSEX wClass1;
    //Clear them
    memset(&wClass1,0,sizeof(WNDCLASSEX));
    wClass1.cbSize=sizeof(WNDCLASSEX);
    wClass1.style=CS_HREDRAW|CS_VREDRAW;
    wClass1.lpfnWndProc=(WNDPROC)WinProc1;
    wClass1.cbClsExtra=NULL;
    wClass1.cbWndExtra=NULL;
    wClass1.hInstance=hInst;
    wClass1.hIcon=NULL;
    wClass1.hCursor=LoadCursor(NULL,IDC_ARROW);
    wClass1.hbrBackground=(HBRUSH)COLOR_WINDOW;
    wClass1.lpszMenuName=NULL;
    wClass1.lpszClassName="Window Class1";
    wClass1.hIconSm=NULL;

    if(!RegisterClassEx(&wClass1)) {
        MessageBox(NULL,"Could not register class1","Window Class Failed",MB_ICONERROR);
    }
    window1=CreateWindowEx(NULL,"Window Class1","Window 1",WS_OVERLAPPEDWINDOW,200,400,200,200,NULL,NULL,hInst,NULL);
    if(!window1) {
        MessageBox(NULL,"Could not create window1","Window Creation Failed",MB_ICONERROR);
    }
    ShowWindow(window1,SW_SHOW);

    MSG msg;
    memset(&msg,0,sizeof(MSG));
    while(GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
}

LRESULT CALLBACK WinProc1(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    int ret;
    HDC hDC;
    PAINTSTRUCT Ps;
    HPEN        hPen;
    RECT rect;
    HBRUSH brush;
    static bool bColorChange = false;
    int CX, CY;
    switch(msg)
    {
    case WM_CREATE:
    {
        CX = GetSystemMetrics(SM_CXFULLSCREEN);
        CY = GetSystemMetrics(SM_CYFULLSCREEN)
             + GetSystemMetrics(SM_CYCAPTION);

        MoveWindow(hWnd, 100, 100, CX-200, CY-200, TRUE);

        ret = SetTimer(hWnd, ID_TIMER, 1000, NULL);
        if(ret == 0)
            MessageBox(hWnd, "Could not SetTimer()!", "Error", MB_OK | MB_ICONEXCLAMATION);
    }
    break;

    case WM_PAINT:
    {
        hDC = BeginPaint(hWnd, &Ps);
        if(bColorChange == false )
        {
            bColorChange = true;
            //BLACK
            brush = CreateSolidBrush(RGB(0, 0, 0));
         }
        else
        {
            bColorChange = false;
            //RED
            brush = CreateSolidBrush(RGB(255, 0, 0));
        }
        SetClassLongPtr(hWnd, GCLP_HBRBACKGROUND, (LONG)brush);
        EndPaint(hWnd, &Ps);
    }
    break;

     case WM_TIMER:
    {

      // Find your window here
     //    myWindow=FindWindow(NULL,title);

        GetClientRect(hWnd, &rect);
        InvalidateRect(hWnd, &rect,true);
    }
    break;

     case WM_CLOSE:
        DestroyWindow(hWnd);
        break;

    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    }
     return DefWindowProc(hWnd,msg,wParam,lParam);
}

Sorry about the late post, it took me forever to test your code with my modifications due to a few sneaky bugs (a dropped compiler and missing breaks were the two big ones). However it seems to work perfectly.

Thank you very much.

whenever I try to use GetPixel on it it returns -1 (0xFFFFFFFF). What am I doing wrong?

Have you also resolved the GetPixel issue?

This question has already been answered. Start a new discussion instead.