0

I have a question about strangely originating WM_PAINT messages sent to my window. It happens on Windows 7 and doesn’t happen on Windows XP.

Details

In my program, I have a timer that triggers GUI updates, the timer is based on this API call:

CreateTimerQueueTimer

In the thread provided my the system to process timer expiration, I do some GUI updates, namely, drawing a line in the window (0,0)->(57,50):

HDC hdc = GetDC (hwnd);
MoveToEx (hdc, 0, 0, NULL);
LineTo (hdc, 57, 50);
ReleaseDC(hwnd,hdc);

In works as I would expect on Windows XP, but on Windows7 this makes a system to send WM_PAINT message to this window with update region: (0,0,58,51). Notice that rectangle is by one pixel wider than the square area affected by the line.

This WM_PAINT arriving because of this drawing is something that I don’t understand. The window is not touched/overlapped/resized or whatever. Apparently, this line is recognized by the system as invalidation of the rectangle.

And this only happens when in Windows 7 (as opposed to Windows XP).

Question

Is it something new about WDM or windows handling in W7? Any way to avoid this?

It maybe a bug in my program or the graphic toolkit I’m using (or both). But why it only manifests on Windows 7 then?

Thanks for any clue!

Denny

Denny
  • 11
  • 3

1 Answers1

2

Psychic debugging time (in other words, I'm totally guessing)...

Remember that you can only update the content of a window from the thread which created the window. If you're calling GetDC()..ReleaseDC() from a thread other than the thread which created the window, I'm not suprised it's causing problems.

The timer APIs for Vista/Win7 have a totally different implementation from the timer APIs in XP, it's entirely possible that your timer might be running on a different thread.

Instead of drawing in the timer, why not post a message to the window indicating that the timer fired. Then in the message handler, invalidate the region for the window. Then handle drawing the line in the WM_PAINT handler.

In general Windows is much happier if you paint on a window in the WM_PAINT handler instead of painting during other window messages.

Larry Osterman
  • 16,086
  • 32
  • 60
  • Thanks. Yes, I definitelly do update GUI from arbitrary thread supplied by the system, which can well be not the one that created the window. Coud you point out where it's stated that it's forbidden to do like this? This page about GetDC http://msdn.microsoft.com/en-us/library/dd144871%28VS.85%29.aspx only states that only **one** thread should operate on the context, once it's obtained. – Denny Apr 16 '11 at 22:19
  • some quotations from the page referenced above: "Note that the handle to the DC can only be used by a single thread at any one time... ReleaseDC must be called from the same thread that called GetDC" – Denny Apr 16 '11 at 22:20
  • Windows are tied to the thread which created the window. You might be able to get away with interacting with the window from another thread, but there's no guarantee. Have you tried my suggestion (dispatching the timer back to the window thread) to see if it helps? – Larry Osterman Apr 17 '11 at 02:21
  • Hi Larry, I'll try to crate some minimalistic app to see if it happens or not. BTW, what exactly do you suggest: use SetTimer and draw in its callback OR invalidating window region in some another thread and handling WM_PAINT normally, in WindowProc? – Denny Apr 17 '11 at 06:13
  • Either one works. And as I said, I don't know if this is the problem - it's a random guess (I've never tried painting on a window from outside the window's thread). – Larry Osterman Apr 17 '11 at 17:06