1

I'm trying to execute an action when a pixel changes in a window by using SetWindowsHookEx. I can successfully recieve Windows messages, but most messages are called while no screen updates occur, and some messages are called more than once on one pixel.

// WH_GETMESSAGE doesn't call the callback for some reason...
SetWindowsHookEx(WH_CALLWNDPROC, hhookSysMsg, hinstDLL, GetWindowThreadProcessId(hwnd, NULL));

I tried listening for WM_PAINT, WM_NCPAINT, and WM_ERASEBKGND, but for some reason they don't fire every time - for example, in Notepad, it does not fire when the scrollbar colors change (for example when hovering over them with the cursor) or changing the text itself.

switch (msg->message)
    {
    // doesn't catch all screen updates!
    case WM_PAINT:
    case WM_NCPAINT:
    case WM_ERASEBKGND:
        // Bit-blit the screen to a file/process the screen/etc.
        ...
    default:
        break;
    }

Can someone help me out with this? If there's no concrete event that runs when a pixel is changed within a window, is there a list of events that I can do a switch-case expression on?

boooba
  • 149
  • 2
  • 12
  • Notepad uses more than one window. The interesting stuff happens in an EDIT control, a child of the outer frame window. Use the Spy++ utility to see this. – Hans Passant Sep 11 '21 at 13:17
  • @HansPassant Thanks, I didn't know that utility existed! I attached my callback to all the child HWNDs while listening for `WM_PAINT` and `WM_COMMAND` messages and it did the job for my use case. – boooba Sep 11 '21 at 14:59

1 Answers1

2

There is no message that notifies a client about the change of a pixel's color. This wouldn't really be useful either: Clients are in charge of drawing to the window's (client) area. If they need to know when a pixel changes color, it can monitor the state itself.

If you need to monitor the change of a pixel's color in a foreign process, the system won't help you with that. You'd be left with hooking all API calls that potentially change the color of a pixel, and keep state information around to determine a change in state.

IInspectable
  • 46,945
  • 8
  • 85
  • 181
  • Alright, while I haven't found an event that would monitor for these changes, I found something close: a combination of `WM_PAINT` and `WM_COMMAND` - it did the job pretty well, informing my code when the screen has been updated. Thanks for pointing me in the right direction! – boooba Sep 11 '21 at 14:57
  • 2
    Painting is at the discretion of any given application. While common, performing all rendering in response to a `WM_PAINT` message is not contractual. Notably, applications that don't use the GDI for rendering are likely to employ different schemes. – IInspectable Sep 11 '21 at 15:10