What does LockWindowUpdate do?


Poor misunderstood LockWindowUpdate.

This is the first in a series on LockWindowUpdate, what it does, what it's for and (perhaps most important) what it's not for.

What LockWindowUpdate does is pretty simple. When a window is locked, all attempt to draw into it or its children fail. Instead of drawing, the window manager remembers which parts of the window the application tried to draw into, and when the window is unlocked, those areas are invalidated so that the application gets another WM_PAINT message, thereby bringing the screen contents back in sync with what the application believed to be on the screen.

This "keep track of what the application tried to draw while Condition X was in effect, and invalidate it when Condition X no longer hold" behavior you've seen already in another guise: CS_SAVEBITS. In this sense, LockWindowUpdate does the same bookkeeping that would occur if you had covered the locked window with a CS_SAVEBITS window, except that it doesn't save any bits.

The documentation explicitly calls out that only one window (per desktop, of course) can be locked at a time, but this is implied by the function prototype. If two windows could be locked at once, it would be impossible to use LockWindowUpdate reliably. What would happen if you did this:

LockWindowUpdate(hwndA); // locks window A
LockWindowUpdate(hwndB); // also locks window B
LockWindowUpdate(NULL); // ???

What does that third call to LockWindowUpdate do? Does it unlock all the windows? Or just window A? Or just window B? Whatever your answer, it would make it impossible for the following code to use LockWindowUpdate reliably:

void BeginOperationA()
{
 LockWindowUpdate(hwndA);
 ...
}

void EndOperationA()
{
 ...
 LockWindowUpdate(NULL);
}

void BeginOperationB()
{
 LockWindowUpdate(hwndB);
 ...
}

void EndOperationB()
{
 ...
 LockWindowUpdate(NULL);
}

Imagine that the BeginOperation functions started some operation that was triggered by asynchronous activity. For example, suppose operation A is drawing drag/drop feedback, so it begins when the mouse goes down and ends when the mouse is released.

Now suppose operation B finishes while a drag/drop is still in progress. Then EndOperationB will clean up operation B and call LockWindowUpdate(NULL). If you propose that that should unlock all windows, then you've just ruined operation A, which expects that hwndA still be locked. Similarly, if you argue that it should unlock only hwndA, then only only is operation A ruined, but so too is operation B (since hwndB is still locked even though the operation is complete). On the other hand, if you propose that LockWindowUpdate(NULL) should unlock hwndB, then consider the case where operation A completes first.

If LockWindowUpdate were able to lock more than one window at a time, then the function prototype would have to have been changed so that the unlock operation knows which window is being unlocked. There are many ways this could have been done. For example, a new parameter could have been added or a separate function created.

// Method A - new parameter
// fLock = TRUE to lock, FALSE to unlock
BOOL LockWindowUpdate(HWND hwnd, BOOL fLock);

// Method B - separate function
BOOL LockWindowUpdate(HWND hwnd);
BOOL UnlockWindowUpdate(HWND hwnd);

But neither of these is the case. The LockWindowUpdate function locks only one window at a time. And the reason for this will become more clear as we learn what LockWindowUpdate is for.

Comments (28)
  1. Tolbert says:

    This post might not be needed now had someone at Microsoft updated the LockWindowUpdate docs a year and a half ago when you wrote about it.

    If they’d only added something to the effect of “this function should only to be called to disable drawing in the window beneath the cursor during a drag and drop operation?”

    [I thought I already discussed this, on the tension between “descriptive” and “prescriptive” documentation. -Raymond]
  2. sergio says:

    Raymond, thank you a lot for starting that subject. I can admit that I tried to use that function once and I didn’t get the results I expected. I almost jumped from joy as I saw what you write about. I can’t wait for the rest of the series. (Yes I now it sounds geeeeky, but I can’t help it).

  3. Xavi says:

    "all attempt to draw into it or its children fail"

    Does it realy fail or is it just deferred.

    Fail would mean to me I get an error or something similiar.

    Well, we will see.

  4. andy says:

    Before I’ve read your other posts about what it really is useful for, it struck me that it would be simpler if you introduced transactions here? (e.g., with help of the new Kernel Transaction Manager).

    So, applications can do whatever they want with the window and some poor component should take care of merging everything together when it is commited :)

    Would at least be interesting to see if a prototype based on this works. Or perhaps this isn’t necessary anymore now with the Desktop Window Manager?

    Look forward to the rest of this serie :)

  5. kb says:

    Can I call LockWindowUpdate() in .NET?

  6. Mark Sowul says:

    "Can I call LockWindowUpdate() in .NET?"

    Yes, you can use P/Invoke.

    http://pinvoke.net/default.aspx/user32.LockWindowUpdate

  7. Mr Echo says:

    > The documentation explicitly calls out that only one window (per desktop, of course) can be locked at a time, but this is implied by the function prototype.

    If this is only one per-desktop, how would different applications synchronize the use of this call?  Or is it one per thread?

    [This is a non-issue when used as intended. Stay tuned. -Raymond]
  8. Anony Moose says:

    An error message for drawing "failure" would be really amazingly silly.

    Everything from "you’re drawing into the hiden part of a window that’s a little bit off the edge of the monitor" to "you’re drawing into the hiden part of a window that’s partly covered by another window" would technically result in no change to the display, but it’s not an error condition worth handling – and there’s no need for every application to duplicate code that ought to be (and in fact actually is) handled efficiently and intelligently by the operating system.

    Instead, the Win32 system just tells your application what to repaint and when to repaint it, and thus ensures that updates occur when necessary and appropriate.

    Nothing is "deferred" – after calling LockWindowUpdate(), any drawing oeprations on the affected window fail, get ignored, result in no change, and are not queued up for later execution. And this is perfectly sensible and reasonable behaviour.

  9. Tolbert says:

    >I thought I already discussed this, on the tension between “descriptive” and “prescriptive” documentation. -Raymond

    I don’t remember that one but will look for it.  At this point I don’t see how anything could possibly apply though.  This was a function that, according to you, was added for and had one and only one purpose/use, yet the documentation never mentions it.  Is there no wonder it’s misunderstood and misused?  How does one use a function as intended when its one intended use isn’t documented?

    [And the criminal code doesn’t tell you the intent of a law. -Raymond]
  10. Stefan Kuhr says:

    Wouldn’t it have been possible to give LockWindowUpdate sort of a per-thread or per-process affinity? So it can only lock or unlock its own windows, and if some program does something wrong, it is this process that has to pay? Otherwise any program can sabotage others on the same desktop, right? But most probably this is again a backwards compatibility issue, I guess, though I don’t remember if LWU was available on Win16. I am curious as to the rest of this series on LWU…

    [If you want to mess up another program, you can do it much easier than LockWindowUpdate. -Raymond]
  11. GregL says:

    When I tried using this function on windows 95 for some reason the desktop icons would refresh themselves. It was bizarre. Needless to say I stopped using it.

  12. Peter says:

    Ahem:

    RCW 9A.04.020

    Purposes — Principles of construction.

    (1) The general purposes of the provisions governing the definition of offenses are:

        (a) To forbid and prevent conduct that inflicts or threatens substantial harm to individual or public interests;

        (b) To safeguard conduct that is without culpability from condemnation as criminal;

        (c) To give fair warning of the nature of the conduct declared to constitute an offense;

        (d) To differentiate on reasonable grounds between serious and minor offenses, and to prescribe proportionate penalties for each.

        (2) The provisions of this title shall be construed according to the fair import of their terms but when the language is susceptible of differing constructions it shall be interpreted to further the general purposes stated in this title.

    Revised Washington Code — RCW section 9A.04.020

    [Sigh. Do I have to write “of course there may be exceptions but I’m just making a point” after every sentence? -Raymond]
  13. Miral says:

    This is why I use WM_SETREDRAW liberally, and LockWindowUpdate never.  But I’m interested in seeing the rest of the series to work out what it’s actually for :)

  14. Tim says:

    ‘Do I have to write “of course there may be exceptions but I’m just making a point” after every sentence?’

    That’s why Scott Adams (of Dilbert fame) uses the abbreviation BOCTAOE in his blog a lot.  (‘But Of Course There Are Obvious Exceptions’)

    [Yeah, but the fact that you even have to say BOCTAOE means that you’re operating at a level of discourse where nitpicking is the norm. -Raymond]
  15. hexatron says:

    I made a test case of a windows app that called WM_SETREDRAW FALSE on itself for 5 seconds, and tried dragging across it.

    It’s pretty funny. The WM_MOUSEMOVEs get sent to the window UNDER the now-undrawable window and scribbling on the undrawable (and undraggable) window. The crap stays there when the window comes back to life, of course–WM_SETREDRAW does no invalidation.

  16. Dean Harding says:

    Peter: I can’t seriously believe you thought that was actually helpful in any way…

  17. David Candy says:

    I’ll generously assume some criminal quoted that construction thing of a law I’ve never heard of and that such an action disproves Raymond’s assertion.

    In the humanities one has to be precise as one deal with very complex systems – groups of people. People think in schemas. So we are already predisposed to generalise anything into an absolute rule.

    I find the more deterministic arts and sciences, like API programming (not just of OSs but all from MS), so imprecide. I can’t be bothered to write code anymore as it always involves setting up experiments to get the real rules of many things.

    So my take is if one talks in absolutes then one should be nitpitted as one has shown a lack of rigerous thinking. Though if one does this in social situations then one is thought wierd.

  18. Rosyna says:

    Raymond, can you link to the function’s documentation on MSDN the first time you mention a function? Pretty please with a seared salmon cube on top?

    Like http://msdn2.microsoft.com/en-us/library/ms534869.aspx (at least I think that’s the right link to it)

  19. PavelS says:

    Maybe it’s intended for window moving.

    Users can move exactly one window at a time. (One mouse = one window)

    So if you don’t want to bother the user with updating window while moving it, the easiest way is to put LockWindowUpdate at the start and end of the moving process.

    You don’t need to program some "background buffer". All is done by OS itself.

  20. Xavi says:

    Thanks Anony Moose

    Fully agreed.

    A LockWindowUpdate unaware, non native english nitpicker now would state that it probaply would be clearer to write:

    "When a window is locked, all attempt to draw into it or its children result in no effect" BOCTAOE

    Just good I’m not such one, instead silently wait for the next post on this promising topic.

  21. PavelS says:

    Ha, here it is:

    http://msdn2.microsoft.com/en-us/library/ms534872.aspx

    So it helps to protect your window from being overdrawn but still being able to draw your valuable content to the DC with help of DCX_LOCKWINDOWUPDATE when moving/resizing.

    It’s funny.

    It seems that OS uses it very often, right in front of our eyes, but developers don’t now how to use it, nor they even know what it is good for.

  22. For temporarily drawing into somebody else’s window.

  23. Peter says:

    (This is regarding Raymond’s comment "And the criminal code doesn’t tell you the intent of a law.")

    Looking at the little bits of paper in my little home office here, I can come up with the following alternate phrases for everyone to use:

    "Telephones don’t tell you why to call people"

    "Menus don’t tell you why you should eat"

    "Printer manuals don’t tell you why you should print"

    "The internet doesn’t tell you why to surf"

    Food wrappers, on the other hand, are a fount of suggestions — this marshamllow bag has a pretty tasty looking ‘crispy rice bars’ recipe.

    :-) of course.

    (personally I’d love for all API documentation to give ‘serving suggestions’)

  24. Peter Ritchie says:

    "When a window is locked, all attempt to draw into it or its children result in no effect".

    I don’t think that generalization is correct.  It does have an effect, just not the same as if the window were not locked–it caches the bounds of any updates and forces a WM_PAINT of that boundary when the window becomes not locked.  (for clarity, if no updates occured, no WM_PAINT results).

  25. Norman Diamond says:

    > If LockWindowUpdate were able to lock more

    > than one window at a time, then the function

    > prototype would have to have been changed so

    > that the unlock operation knows which window

    > is being unlocked.

    Does MSDN agree?

    Pavel S., thank you for posting this link:

    http://msdn2.microsoft.com/en-us/library/ms534872.aspx

    *  While a window update lock is set, the system

    *  creates an accumulated bounding rectangle for

    *****  each locked window.

    *  When the lock is cleared, the system uses

    *  this bounding rectangle to set the update

    *  region for the window and its child windows

    There are also other situations where multiple somethings can be moved in one mouse dragging operation.  You can’t hold the control key and select multiple ordinary windows, but you can select multiple icons on the desktop to move their locations, or you can select multiple icons for files in Windows Explorer and drag them to another Windows Explorer (to move or copy) or to a desktop icon (to print or unpack or whatever).

  26. Dean Harding says:

    Norman: But it also says this, in the documentation for LockWindowUpdate itself (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/pantdraw_4i5h.asp):

    > Return Values

    > If the function succeeds, the return value is nonzero.

    >

    > If the function fails, the return value is zero,  indicating that an error

    > occurred or another window was already locked.

    I think Raymond is correct. The way to read that "each locked window" bit is to remember the fact that you lock the window you pass in *and its children*.

Comments are closed.