Date: | February 22, 2007 / year-entry #64 |
Tags: | code |
Orig Link: | https://blogs.msdn.microsoft.com/oldnewthing/20070222-01/?p=27913 |
Comments: | 28 |
Summary: | Okay, now that we know what operations LockWindowUpdate is meant to be used with, we can look at various ways people misuse the function for things unrelated to dragging. People see the "the window you lock won't be able to redraw itself" behavior of LockWindowUpdate and use it as a sort of lazy version of... |
Okay, now that we know what operations People see the "the window you lock won't be able to redraw itself" behavior of
As we noted earlier, only one window in the system can be locked for update at a time. If your intention for calling First off, if some other program is misusing Second, if you have locked your window for update and the user switches to another program and tries to drag an item (or even just tries to move the window!), that attempt to Conversely, if you decide to call This is just a specific example of the more general programming mistake of using global state to manage a local condition. When you want to disable redrawing in one of your windows, you don't want this to affect other windows in the system; it's a local condition. But you're using a global state (the window locked for update) to keep track of it. I can already anticipate people saying, "Well, the window manager shouldn't let somebody lock a window for update if they're not doing a drag/drop operation." But how does the window manager know? It knows what is happening, but it doesn't know why. Is that program calling Next time, a final remark on |
Comments (28)
Comments are closed. |
Lazy? I resent that assertion.
The Win32 API is extremely large. The easiest way to find something is to look in the function reference. LockWindowUpdate is right there, SetWindowRedraw is not. There is not one line in LockWindowUpdate that says that does not say “hey, use this only for dragging” or “this functionality exists in WM_SETREDRAW”.
It’s one thing for you to point out common pitfalls, it’s quite another to assume that those mistakes are the result of laziness on the part of the programmer. I would hazard a guess that 90% of people using LockWindowUpdate are doing so because they simply don’t know about WM_SETREDRAW. And they would use the SetWindowRedraw macro if it exists.
It’s the difference between saying “Many people use LockWindowUpdate, but that’s a common pitfall, and SetWindowRedraw should be used instead” and “Many people use LockWindowUpdate because they’re too lazy to use SetWindowRedraw.”
Wouldn’t much the redrawing issues in a D&D implementation simplified by creating a temporary transparent window on top of the desktop and drawing there instead?
If something below redraws, it would cause a redraw on the overlayed window. This is how I implement splitter bar feedback in my application. Personally, I can’t recall ever using using LockWindowUpdate or even SetDraw(FALSE).
You said that the blocking happens in the functions that acquire a DC (BeginPaint etc.) (and the docs say they return an empty visible region). So what happens if the program already has a DC and is currently painting?
Is it suspended? Is the DC altered? Or perhaps the LockWindowUpdate would wait? It all sounds hard to implement.
Nice table, Raymond :)
(Hope this feedback gives you encouragement to continue writing, despite Jack Matthew’s comment above!)
It seems to me that maybe MSDN could benefit from user comments in the documentation. The PHP documentation has this and anyone can comment on any function or page in the entire documentation. They also bundle up the comments into the downloadable documentation.
Even if they you don’t want to allow user comments, what about comments from Microsoft employees? A little note from Raymond Chen appended to the bottom of the page could go a long way.
I might be wrong, but after reviewing Raymond’s post, he was glib with the first commenter because Raymond never once called programmers lazy.
He said: "LockWindowUpdate and use it as a sort of lazy version of the WM_SETREDRAW message"
and: "it’s too lazy to use the WM_SETREDRAW message"
You can argue there’s an implication there about the person who wrote the code, but even if that’s so, I think we should cut Raymond a little slack. He’s sharing information with us in part because he sees developers making mistakes. If he does get exasperated sometimes, remember how much he’s dealt with developers behaving badly. Don’t always take something personally.
Yes, there are issues with documentation that need addressing. It’s sadly an imperfect world as anyone who works on software realizes. I also imagine Raymond knows and has seen enough that he could write many more books. Be thankful he’s sharing what he knows so we at least have this knowledge published somewhere!
I’ve tried to replace LockWindowUpdate in my application with SetWindowRedraw but it certainly does not have the same behavior. I’ve even added a call to `InvalidateRect’.
The difference is that my algorithm to resize child windows is broken by using SetWindowRedraw but works just fine with LockWindowUpdate. Any idea?
For info, I only call LockWindowUpdate on top level windows.
Oh-ho! Finally, I get it. I do – randomly – have the "I can’t drag anything" problem. I’ve never been able to understand why until now. Thanks – it makes sense now, even if I can’t find the misbehaving application.
And for the people that are too lazy to read through the docs? Yeah, there’s a lot of stuff there. Odds are, if you’re trying to do something to a window, there’s a message for it. Do a little digging; it’s what you’re paid for.
In this particular case, the docs clearly say "Only one window can be locked at a time.", which should be a pretty big warning that this may not be the thing you’re looking for, if you’re trying to disable drawing to a portion of your application.
Raymond, it’s clear that you aren’t the master of MSDN, nor would you want to be. However, perhaps you have advice for how we developers could exert pressure on Microsoft to produce/maintain better documentation? Many of us really appreciate your posts and simply feel they would be that much more valuable if their content could be somehow integrated with MS documentation. It’s frustrating that there is so much good material scattered about the web that can be quite hard to find.
The MSDN wiki idea is OK, but I’m not sure it’s really optimal: there is no way to annotate Microsoft portions of the documentation, which means in order to take advantage of user-generated content, I must scan through all of it even if I’m only interested in, say, the exceptions a class throws. Moreover, it really doesn’t support a good method for talking about content in multiple pages simultaneously (e.g. using class X with class Y). I think it would be incredibly useful to be able to look up some class/function/whatever and find all the relevant, verified-[mostly-]correct material related to it. Yes, I know that Google (err, Live Search) exists, but it has no method for eliminating duplication and misinformation other than popularity.
What do you think the biggest obstacles are with respect to getting [formal] documentation published more quickly? I was going to suggest that MS devs responsible for feature X review documentation generated by non-MS devs or MS devs not responsible for X. I should think this would benefit everyone: MS gets documentation written for it and the contributors get to be MVPs or simply get verification/correction of their understanding of whatever they documented. It seems that many of the troubles you encounter (or at least write about) have to do with people misusing MS APIs. Is it not in your (and MS’s) best interest to try to improve the situation? I hope you’re not saying that there simply is no way the formal documentation can appreciably improve.
I can’t believe how I ever got anything done at all before the internet came along. If I am tasked with writing some new functionality that I’ve never implemented before, the name of some random function ("I know, LockWindowUpdate!") doesn’t pop into my, I don’t visit ONE MSDN page and NOTHING ELSE. No. I search the internet to see if someone else has done what I am doing before (chances are good that LOTS of people have!)
MSDN isn’t perfect. But that’s why people like Raymond have blogs. It’s about a million times easier for Raymond to write a couple of posts about this function that it would be to get all of this info included into MSDN.
And there’s nothing wrong with that! Perhaps when the "Community Content" section makes its way to the LockWindowUpdate documentation, someone will stick a link to this blog in there. But until then, I’m going to stick with Google, because what Raymond is writing has been written many times before, I’m sure.
I thought I’d pipe up at this point (I’m one of your silent readers who rarely comments): your blog is a great read and I’ve learned a lot from it. (I even placed an order for your book a few days ago.) Please don’t feel discouraged, there are a lot of people who value your blog highly.
Also, don’t mistake developers who feel frustrated at the documentation for developers feeling frustrated at you – I think it’s a shoot-the-messenger reaction on their part. And you’re quite right about the articles – I almost never read them, and rely solely on the API references. I think it’s because they’re usually longer (or another click away) and I just want to find something as quickly as possible. Maybe I should start reading them more…
Likely so. I did not even know that they where there.
I am used to Javadoc, where warnings and usage information is at the top of the page.
This, and MSDN2 loads so horrifically slowly, I really am discouraged from exploring it more. Every time I go to a new page, there is this huge redraw lag.
Honestly, blogs like yours are of greater resource than MSDN. :)
Raymond, I think your response to the first poster is a little glib, to be honest (although I can understand the frustration).
And this leads me to ask something that I’ve been wondering about since you moved onto LockWindowUpdate recently. It’s because I had exactly the same problem as the poster – I’m a Windows programmer of many years experience, but I read the MSDN entry on LockWindowUpdate once, and it seemed to be what I was looking for. It wasn’t, of course.
So, bearing in mind that I am aware of the following:
* Raymond does not run Microsoft.
* Raymond does not run MSDN.
* Raymond can’t force random people at Microsoft to do things he wants.
Let me ask this: as it is clear (I hope), that there is a problem with the documentation for LockWindowUpdate, what can be done to fix this? Do you forward suggestions to MSDN for documentation correction? Is there a system in place at Microsoft to do this? Does MSDN allow 3rd party developers to do this easily (and I don’t mean email blackholeforallfeedback@microsoft.com or whatever).
It’s just that a fair number of your blog entries are about people using APIs incorrectly (and then the compatibility problems this can cause). So, ignoring the inertia of existing Windows apps, wouldn’t it be nice to let developers know how to miss these potholes? I can’t imagine this LockWindowUpdate thing is a new problem (I first encountered it a few years ago, and iirc only learned the correct solution from your blog), yet the MSDN docs I just looked up on the MSDN site still just say “Only one window can be locked at a time.”
No mention of SetWindowRedraw etc, or “Here’s a hint. This probably isn’t the function you want unless you just want to do flicker-free dragging.” Just still the same description that has misled countless developers already.
I remember in DDJ, they used to do a regular feature of ‘Help file annotations’ (back in the days when Windows help files supported annotations). They were basically notes/caveats about certain pages in the help that you could add to your system, and then you’d always see them. This was actually really useful (and good that a competent source like DDJ provided ones you might not know about). Of course, sites like php.net have democratised this, so you can see anyone’s tips on each page (sometimes good; sometimes an example of really poor code).
I guess I’m really saying: documentation needs to be improved. Some of this stuff (incorrect API usage) is really affecting some Windows (i.e. MS) devs quite significantly, so do/can they push for documentation revisions?
I’m aware it’s probably quite hard for MS devs to get MSDN changed – a friend of mine once waited a year for MSDN to approve a short tech article he wrote, and in the end he gave up waiting and published it on another site. He works for MS, btw.
But maybe that’s the problem. I don’t care if you think it should be ‘obvious’ by using extensive logic and deduction on the documentation to divine what is being said. Most developers don’t have time to learn absolutely everything about absolutely every API they use. Developer time is *expensive* – we always go on about this wrt programming languages and frameworks, but no-one ever seems to think this applies to having decent documentation.
The ‘just apply logic’ argument is weak, because if it were true, then we wouldn’t bother to write comments in our code either.
If an API has consistently been misunderstood and misused, then the documentation is at fault, not the developer. I would rarely blame the ‘stupid users’ if a program I wrote regularly baffled users and let them do the wrong things, or things they didn’t expect – I would assume that the UI was poorly designed. I’d just like to see a similar approach for API documentation.
Sorry to rant, it’s a bugbear of mine.
So: if you find an API that is being abused, and it’s affecting you (or another MS dev) a lot, do you feel you have sufficient mechanisms in place to do something to address this at MS, and get the documentation changed?
Or is that mechanism your blog? :-)
I agree with Jack Mathews and a few others. If you’d said "findable" instead of "lazy" then it would be accurate and inoffensive. People do indeed SEE LockWindowUpdate; it’s easy to find.
A few months ago I wanted some effect that might resemble either WM_SETREDRAW or some of the APIs mentioned in the comments, but didn’t guess that a window message might be the way to do it and couldn’t find an API that really looked suitable. I sort-of solved it by ShowWindow, hide before manipulations and show afterwards. I wasn’t happy but the results looked OK and the testers approved.
OK, time for comic relief.
Oh, that’s easy to fix! Anyone who wants to abuse LockWindowUpdate should just abuse LockWindowUpdate(NULL) before abusing LockWindowUpdate on their own window.
Thursday, February 22, 2007 1:46 PM by Herb
You’re right… now come to think of it, one window per process? one per window station? one per terminal services session? one per computer?
Dean, you hit the nail on the head. I search for the way to accomplish tasks all the time. I have never stopped at finding one solution. Ever. Rarely is there only one solution to a problem, therefore I keep searching until I find a consensus.
Also, if any documentation contained every possible nugget of information it would be too verbose to get anything useful out of it.
On top of that, as Raymond pointed out, this function is old, and maybe at that time it was very evident that it was only used for dragging operations. I’m new to programming (relatively — meaning only 8 years or so) so I don’t know anything, just offering up a solution.
Sheesh, people! If you want to bitch about MS, join any one of a million forums out there. They abound.
However, if you want to learn and enjoy Raymond’s unique contributions (comp related or cycling or cooking or languages — he’s a pretty interesting and varied guy) then leave the petty whining at home.
Thanks for the heads-up. It’s become a habit for me to read this blog, and then do a full search of my code for the subject API to make sure i’m actually using it correctly. In this case, i’d done exactly what you described (and then fixed it a few years ago, after encountering some of the problems you predict).
FWIW: MSDN sucks, in so SO many ways… but this isn’t the place for that rant. Thanks again for the work you do to make Windows development a tad less of a crap-shoot. :)
“There’s more to documentation than just the function description page. The function documentation focuses on ‘What does this function do? Just the facts ma’am.’, and the overviews/articles focus on ‘How should the functions be used as intended?’ It seems people look only at the former and totally miss out on the fact that they link to the latter. I get the impression that MSDN could delete all the overviews and articles and nobody would even notice. -Raymond”
I must take issue with this, as it seems similar to those who claim their code does not need comments. While it’s good to know what a function does, is it not also invaluable to know what it was *meant* to do? Such a purpose statement does not need to be very long; the articles you mention can pick up on the nuances. Some function names don’t need an explanation — .NET’s System.IO.File.Delete(string) is quite obvious. Some function names, such as LockWindowUpdate, are most definitely not clear in this respect, which you yourself have noted.
Thank you for discussing the WM_SETREDRAW message. The documentation it isn’t clear about what the WM_SETREDRAW message does, making it look like a message specific to list boxes and other controls that might implement it. It seems that SendMessage(WM_SETREDRAW, FALSE) actually just clears the WS_VISIBLE style bit for any window, which has a similar effect as calling
SetWindowLongPtr(GWL_STYLE, * & ~WS_VISIBLE)
or
SetWindowPos(SWP_NOxxx | SWP_HIDEWINDOW),
namely hiding the window without repainting the parent.
on using SetWindowRedraw to speed up adding items to a combobox or listbox:
http://blogs.msdn.com/oldnewthing/archive/2004/06/10/152612.aspx
"This is just a specific example of the more general programming mistake of using global state to manage a local condition."
"…function documentation says what, overviews and articles say why."
Bingo. Raymond offers an excellent parallelism.
In a system so large, complex, baroque, and overburdened with legacy as Windows, it is essential to get a handle on the big picture. Yes, the detail reference material could try to accommodate those in the habit of bottom-up (or bottom only) research by including more explanation of intent and integration. Perhaps in some instances it should. But the point of diminishing returns is reached very quickly because these are not bottom-up considerations.
If I may offer a silly analogy: Reading a dictionary is not going to tell you how to construct meaningful sentences and paragraphs. It would be impossibly impractical to cover that topic in any depth within each definition.
[quote user=Tim]
Is there a system in place at Microsoft to do this? Does MSDN allow 3rd party developers to do this easily (and I don’t mean email blackholeforallfeedback@microsoft.com or whatever).
[/quote]
I sent one suggestion to netfwsdk@microsoft.com 2 years before for .NET SDK documentation improvement, and they quickly respond to me that the change would be made in version 1.1.1 of SDK Doc.
So let me reassure you that the blackhole isn’t there. :)
It’s anecdotal but I’ve found the MSDN feedback link at least got me a response, and a quick one as well. It’s apparently not the black hole that one might assume it is.
(I found two pages in MSDN which contradicted each other over something like the meaning of a boolean argument. It was easy to write a test program to work out which was correct. I then wrote to MSDN to let them know, in case someone only found the incorrect page, and I soon got a reply from someone saying thanks and that they would look into it. Unfortunately I can’t remember what the thing actually was so I can’t verify that the documentation is now correct, but a human being certainly looked at the issue and replied in good time so there’s a good chance it was fixed.)
Sure the MSDN feedback link isn’t a black hole, it gets me responses too.
The last time I reported a few bugs about one page, Microsoft politely extended the discussion long enough so that Microsoft repeated its assertions twice in one discussion: I had acquired web site http://msdn.microsoft.com outside of North America, therefore it differed vastly from North American version of http://msdn.microsoft.com, therefore I should pay a support fee to Microsoft Japan to report bugs in the page.
After that it became a black hole.
This has been a timely series – just one problem:
I latched onto the series eagerly, as I was aware of a number of uses of LockWindowUpdate in a particular project, and was keen to find out a) why this was bad (I had a feeling I knew – the indiscriminate nature of LockWindowUpdate(0) is a BIG clue) and more importantly b) what was the right way to do what LockWindowUpdate() does.
Unfortunately, One of the cases where LockWindowUpdate() is used in this project cannot seemingly be replaced by WM_SETREDRAW – at least not as simply as suggested.
The scenario is:
I’m about to create a MDI child window. This is a Delphi app, and the VCL for reasons best known to itself always creates MDI children at CW_USEDEFAULT X and Y. But our app re-positions these windows to the place the user last left them.
It can’t do this until after the window has been created, and the result is a very ugly flicker.
Guess what LockWindowUpdate() was being used for? :D
Previously, the creation of the MDI child was wrapped in a par of LockWindowUpdate() calls that locked and unlocked the MDI window itself, and this worked like a charm.
Replacing these calls to LockWindowUpdate() with appropriate WM_SETREDRAW not only doesn’t work, but actually results in an ugly mess.
The flicker is eliminated, but the MDI child form doesn’t repaint in full (all sorts of invalidate/redraw/update incantations have been thrown at it no to avail).
We have tried using the handle of the MDICLIENT window of the MDI window, as well as the handle of the window itself, also to no avail.
Help?
Thanks for the reply Raymond.
Sadly in the particular Delphi app in question this isn’t possible because of some very messy code in the inherited implementations of the MDI window wrappers (not just VCL code, but also some very untidy legacy code in the project itself that implements the window placement info persistence at runtime).
I appreciate that the finer points of Delphi VCL overrides etc goes waaaay beyond the scope of this blog, but was just curious why WM_SETREDRAW is not an adequate replacement for LockWindowUpdate() in this particular case.
I haven’t got time to take apart the low level MDI wrappers (not to mention the risk that doing so would have ancillary consequences in the 200+ forms in the project that derive from these base classes!), so will have to leave LockWindowUpdate() in place for now.
From the content of this series, I think it’s use in this particular case is “safe enough”, even if ultimately undesirable.
Thanks again.
Very nice site! Good work.
就像我们在前面所说的,同一时间系统中只能有一个窗口的更新被锁定。如果你调用LockWindowUpdate的目的仅仅是防止窗口重绘,比如因为你在更新这个窗口,在你的更新完成前,不希望它不停的刷新,那么请直接禁止窗口的重绘。如果你使用了LockWindowUpdate,将引来无数下面的问题。
PingBack from http://www.aaronlerch.com/blog/2007/02/24/lock-updates-for-a-control/