How is LockWindowUpdate meant to be used?
Now that we know how
LockWindowUpdate works, we can look at what it is for.
Actually, the intended purpose of
LockWindowUpdate can be captured in one word: dragging. But we’ll get to that a little later.
The purpose of
LockWindowUpdate is to allow a program to temporarily take over the responsibility of drawing a window. Of course, in order to do this, you have to prevent the window procedure (or anybody else) from doing their normal drawing activities; otherwise, the two pieces of code (the code that normally draws the window and the code that’s trying to take over) fight for control of the window and you get an ugly mess since neither knows what the other is doing.
But if you’ve locked the window for updating, how do you draw to it? You use the
DCX_LOCKWINDOWUPDATE flag to the
GetDCEx function. This flag means, “Let me draw to the window even though it is locked for update.” Only the code that locked the window for update should pass this flag, of course, since it would otherwise create the conflict that
LockWindowUpdate was intended to avoid in the first place.
Since people like tables so much, I’ve made one that summarizes what changes when a window is locked for update:
|Normal behavior||Window locked for update|
||Drawing operations paint the window||Drawing operations paint nothing, but the affected area is remembered for future invalidation|
||(do not use)||Drawing operations paint the window|
In other words, when a window is locked for update, the ability to draw to the window is taken away from the normal DC-acquisition functions (
BeginPaint and friends) and given to
GetDC(DCX_LOCKWINDOWUPDATE). Note that if no window is locked for update, you should not pass the
DCX_LOCKWINDOWUPDATE flag; the purpose of that flag is to indicate “I’m the guy who called
LockWindowUpdate. Let me in!”
It’s sort of the window manager equivalent of the old comedy routine where you tell the guard, “Nobody is allowed into this room.” And then you come back an hour later and the guard won’t let you in.
“I’m sorry, sir, but I’m not allowed to let anyone into this room.”
“But I’m the one who told you not to let anyone into the room.”
“That’s right sir, and I’m following your orders. Nobody is allowed into the room.”
The mistake was in the initial order to the guard. You should have said, “Nobody except me is allowed into this room.” And
DCX_LOCKWINDOWUPDATE is how you tell the window manager, “It’s me. Let me in.”
If you go back and look at the way the
LockWindowUpdate function works, you’ll see that if the window that was locked doesn’t try to draw, then when the window is unlocked, nothing is invalidated. Whereas the
CS_SAVEBITS class style automatically saves the original pixels and restores them when the window is removed from the screen, the
LockWindowUpdate doesn’t do any such thing. It is your responsibility to ensure that any pixels you changed while the window was locked for update have been restored to their original values when you call
LockWindowUpdate(NULL). This is typically done by saving the original pixels into an off-screen bitmap before you do your custom painting and putting them back when you’re done.
Okay, so here’s the intended usage pattern:
- When you want to take over drawing from another window, call
LockWindowUpdateon that window.
- Save the pixels from that window that you’re going to overwrite.
- Draw your new pixels. (These pixels are often a modification of the original pixels. For example, you might add the image of an object that is being dragged over that window.)
- Repeat as necessary as long as your operation is still in progress. (Doing so may require you to “back up” more pixels of the screen if the region of the screen you’re modifying is different from the region you modified originally. You can do this backup/restore incrementally. For example, instead of accumulating the set of pixels you need to restore, you can restore all the original pixels, compute the new position of the drag image, save those new pixels, and draw the new image. That way, you have only one set of “backup pixels” to deal with.)
- When the operation is complete, restore the original pixels and call
Next time, we’ll look more at that one word “dragging” and how it is closely tied to the whole concept of
Even though we’ve only started talking about
LockWindowUpdate, you should already know enough to answer this question.
(Note: The purpose of this series is to describe the way the
LockWindowUpdate was intended to be used, not to discuss whether it was a good design in the first place.)