Fumbling around in the dark and stumbling across the wrong solution


I don't mean to pick on this series of entries, but it illustrates an interesting pattern of stumbling across the wrong "solution".

The series begins by attempting to trigger the system's monitor blank timeout by posting a message to the desktop window. As we saw earlier, the desktop window is a very special window and as a rule should be avoided, since it won't behave like windows created by applications. In particular, the author tried to post a message to the desktop window. This used to work in the historically open world of the window manager, but security and robustness concerns have come to take priority over compatibility. In Windows XP SP2, the desktop window resists being disabled because programs were doing it inadvertently, and it appears that the desktop also resists having messages posted to it. My guess is that this was done as a way to strengthen protection against shatter attacks. This did improve robustness and stability, but it also broke the article's dubious PostMessage hack.

Enter round three, wherein the author fumbled around for other windows the monitor blank timeout message could be posted to, and eventually the author found that posting the message to the mysterious window HWND_TOPMOST = -1 seemed to do the trick.

I knew in the back of my mind that people developed software this way, but the hopeful part of my brain continued to wish that it was merely taking place in a fantasy world. Making up intentionally invalid parameters and seeing what happens falls into the category of malicious goofing around, not in the realm of software engineering and design. Even if you find something that seems to work, you certainly wouldn't design a product around it!

(Similarly, I've seen people ask questions like "What does message 49251 mean?" This is the reverse case: Seeing a made-up number and attempting to assign meaning to it. Message numbers starting at 0xC000 (decimal 49152) are messages registered via RegisterWindowMessage. The numerical value of the message associated with a registered window message is unpredictable and varies from desktop to desktop. The only guarantee is that it will remain consistent within a single desktop.)

If you look more carefully at what the author stumbled across, you'll see that the "solution" is actually another bug. It so happens that the numerical value -1 for a window handle is suspiciously close to the value of HWND_BROADCAST:

#define HWND_BROADCAST  ((HWND)0xffff)

It so happens that internally, the window manager supports (HWND)-1 as an alternative value for HWND_BROADCAST. (I leave you to speculate why.) As a result, what the author actually is doing is broadcasting the monitor power-off message to all top-level windows! As we saw before, broadcasting messages is a very dangerous business, and in this case, the author is just lucky that all the windows on the desktop interpret the message the same way, that it is safe to process the message multiple times, and none of the windows perform any special filtering for that message. (Another author stumbled across the same incorrect "solution" but didn't provide any insight into the process by which the result was arrived at. Yet another author sort of found some issues but didn't quite put them all together.)

For example, a presentation program might want to suppress monitor power-off when it is the foreground window by trapping the message and turning the monitor back on. If such a program happens to be running, broadcasting the power-off message to all top-level windows would turn off the monitor for all the windows that deferred to system default behavior, but when that presentation program received the message, it would turn the monitor back on. Now you're at the mercy of the order in which the windows process that broadcast message. When the presentation program processes the message, the monitor will turn back on, and if that program happens to be the last one to process the message (say, it got paged out and was slow to page back in), then the monitor will merely blink off and back on.

The correct solution is not to post messages to random windows. If you want the message to go through window message default processing, create a window and process it yourself. Don't try to trick some other window (or in this case, hundreds of other windows simultaneously) into doing it for you.

Comments (68)
  1. Re HWND_TOPMOST vs. HWND_BROADCAST issue… I searched MSDN for HWND_TOPMOST and found a handful of items where it’s described as a valid (or even required) target to send/post messages to:

    About Messages and Message Queues

    http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/aboutmessagesandmessagequeues.asp

    "If the window handle is HWND_TOPMOST, DispatchMessage sends the message to the window procedures of all top-level windows in the system."

    Using Messages and Message Queues

    http://msdn.microsoft.com/library/en-us/winui/winui/windowsuserinterface/windowing/messagesandmessagequeues/usingmessagesandmessagequeues.asp

    "If the handle is HWND_TOPMOST, the system posts the message to the thread message queues of all top-level windows."

    WM_TIMECHANGE

    http://msdn.microsoft.com/library/en-us/sysinfo/base/wm_timechange.asp

    "Windows Me/98/95:  An application should send this message to all top-level windows after changing the system time using the SendMessageTimeout function with HWND_TOPMOST. Do not send this message by calling SendMessage with HWND_BROADCAST."

    I only ever used it with SetWindowPos to make a window topmost…

  2. Anonymous says:

    Don’t leave us hanging…what is the correct method of powering down the monitor? A quick search on MSDN reveals ‘SetActivePwrScheme’ as a good start anyways.

    Another dangerous habit I noticed looking at the examples is misusing special parameters such as HWND_BROADCAST and HWND_TOPMOST. These values are only valid in certain functions, PostMessage/SendMessage and SetWindowPos in this case. You cannot expect any function that takes an HWND to properly handle these values. It seems obvious but its one of those mistakes I made when starting Windows programming.

  3. Anonymous says:

    So, what is the correct way of turning off the monitor?

  4. Anonymous says:

    Ok now I think I may have badly interpreted your last paragraph, and that sending a message is not the correct solution! (And I am reassured!)

    Still, why does the posted solution work? Is it because of the defwndproc or is a window intercepting the notification and doing the correct API call? (That would still leave me wondering why)

  5. Anonymous says:

    Your article started by saying the user was trying to “trigger the
    system’s monitor blank timeout”.  He said he was trying to power
    off the monitor.  Are those the same things?

    [Picky, picky. If you trigger the monitor blank timeout, then the monitor turns off. Do you also nitpick the difference between “Triggering the screen saver timeout” and “starting the screen saver”? -Raymond]
  6. Anonymous says:

    "Making up intentionally invalid parameters and seeing what happens falls into the category of malicious goofing around, not in the realm of software engineering and design."

    Some would describe it as hacking, which isn’t always malicious, or goofing around.  We owe a good many of the world’s inventions to people who were just "seeing what happens."

  7. Anonymous says:

    The correct way is to make your own window and once it’s up and running to SendMessage or PostMessage to it. If your window procedure is correctly written, the messages which are not handled by your code will be handled by the system, and that’s what you want.

  8. Anonymous says:

    From the MSDN articles Aaron dug up I see there’s even a little internal confusion between HWND_TOPMOST and HWND_BROADCAST. Perhaps this is partly the reason why the window manager accepts an alternate value of -1 for HWND_BROADCAST.

    Another thing I’m wondering about, hasn’t HWND always been an unsigned value? If so, isn’t

    #define HWND_TOPMOST    ((HWND)-1)

    a bad idea?

  9. Anonymous says:

    If Windows was open source we wouldn’t have to “fumble around in the
    dark”.  Us poor non-Microsoft developers often have to reverse
    engineer Windows to get our job done; please don’t demean us because of
    it.  We don’t really want to use Windows — its just forced on us
    by the marketplace.

    [I would argue the reverse. With the source code, people would be more likely to break the rules, because they can see which rules they can get away with breaking. “Oh, sure it’s documented as ‘must be zero’, but I can pass garbage since I checked the source code and nobody uses it.” Yeah, nobody uses it yet. And then Vista starts using the parameter and you crash. -Raymond]
  10. Anonymous says:

    I’m going to be ruthless and defend the developers actions. Power management in windows is pretty minimally documented except in the driver pages, and support in .NET is particularly sparse. And of course, there is no source code for all of us to look at.

    Raymond: you have the advantages of (a) the source and (b) the ability to email someone who will know someone who knows the answer. The rest of us have to make do with experiments. Just be glad this isnt shipping software that you have to support in future.

  11. Anonymous says:

    Please tell us:

    1. How to power off the monitor in the right way and

    2. How to prevent the monitor from turning off, if you are writing eg. a presentation program.

    Are these two things even possible?

  12. Anonymous says:

    So, is the correct method to power-off a monitor to:

    hwnd = CreateWindow(WC_MYCLASS, WS_POPUP..);

    PostMessage(hwnd, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);

    [pump messages]

    Where WC_MYCLASS has a WndProc like:

    LRESULT MyWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)

    {

     // TODO: Close after processing?

     if (message == WM_DESTROY) PostQuitMessage(0);

     return DefWindowProc(hWnd, message, wParam, lParam);

    }

    As an aside, is there a built-in Windows class that has a virtually-empty procedure body, save calling DefWindowProc and handles WM_DESTROY by calling PostQuitMessage? Or, is it easier to create a top-level hidden STATIC window (or something similiar) to perform that processing?

  13. Anonymous says:

    Huh, I didn’t think it would work but indeed posting a SC_MONITORPOWER message to an existing window does in fact turn the monitor off. For example, from a MFC application:

    ::PostMessage(SomeCWnd.m_hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, 2);

    I’m still wondering how you’d do it if you don’t have a window handle, such as a console application, without creating a temporary window.

  14. Anonymous says:

    “With the source code, people would be more likely to break the rules, because they can see which rules they can get away with breaking.” –Raymond

    If I have neither the source code nor reliable documentation, I can only find (by experiment) what works right now.  I can’t even determine if I am really breaking any rules.  With either source code access or correct documentation, I can discover the correct thing to do, and then decide whether to take chances.

    I posit that I am much more likely to track changes in released source code or in reliable documentation than I am to repeat my entire series of experiments whenever I suspect that something may have changed.

    -Wang-Lo.

    [How does having the source code tell you what the rules are? The source code tells you what something does, not how something was meant to be used. There’s nothing in the source code to a wrench that says “Do not use to hammer nails.” -Raymond]
  15. Anonymous says:

    Exactly! To power off the monitor you just

    SendMessage(MyhWnd, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF)

    where MyhWnd is the handle to a window you created yourself. The message is then passed to DefWindowProc which does the dirty deed for you.

  16. To put Raymond’s comments re open source another way – having the source code will make developers MORE likely to rely on the side effects of internal implementation details than they already do.  That’s fine as long as the internal implementation details NEVER change, but that is rarely true of any product that lives beyond version 1.0.  Believe me, I feel your pain – I live with it too.  But open source is the wrong medicine for that pain.

  17. Anonymous says:

    Well, yes and no.  They’re rhetorical in that the answer is obvious.  They’re not rhetorical in that they still deserve an answer.

    MSDNWiki covers "Visual Studio 2005 and .NET Framework 2.0."  Yes, .NET is great and all, but an awfully large percentage of software isn’t written in it, and an awfully large percentage of software probably never will be.  You’re not going to see any drop in questions about Win32 until you have the documentation about it posted there and available for edit and discussion.

  18. Sean, your claim was that a Wiki would generate correct and complete documentation.

    Raymond’s effectively using the VS 2005 and CLR V2 Wiki as a test harness.  If, after 6 months the CLR V2 Wiki has better documentation than MSDN, clearly you were right.  If, on the other hand, it doesn’t, then a wiki isn’t the right solution.

    [Telling me that won’t accomplish anything. Why not tell the MSDN Wiki team? -Raymond]
  19. Anonymous says:

    I must disagree with your (Raymond’s) argument that open source APIs are more prone to misuse.  Your argument boils down to “people can see the guts of the thing, so they’re more likely to rely on implementation choices; when the implementation changes, their app will be broken.”

    APIs are contracts; the API promises to provide such-and-such functionality if called in such-and-such fashion.

    If the correct calling procedure is documented in an easy-to-find way, there is no excuse for the developer to break the contract by calling it in a way other-than-specified.

    So much is true of both open and closed source software.

    The problem is that documentation tends to quickly fall out of sync.

    Open source has the advantage that the contract can be specified right in the code.  This obviates (to a certain extent) the need to consult and maintain outside documentation.

    So open source has the advantage when it comes to maintaining and exploring APIs (for any given development team.)

    [So if you got the source code to hundreds of undocumented APIs, that would discourage you from calling them? -Raymond]
  20. Anonymous says:

    So Raymond, who pissed in your cornflakes today?  Seriously, either the documentation needs to be improved or you should stop bitching about how we try to call the under documented items.  Actually noting how to call the function (or answering any of the 4 or 5 comments asking may have helped as well).

    [Even if the documentation is bad, does that justify basing a solution on passing intentionally invalid parameters? Is it justifiable to break the law because you can’t find any legal alternative to what you’re trying to do? -Raymond]
  21. Anonymous says:

    if you got the source code to hundreds of undocumented APIs, that would discourage you from calling them

    I want to underline too… :'(

    Well, it’s your blog :)

    Anyway… why are they undocumented?

    Quality of documentation is important.  “No documentation” is just another form of bad documentation.

    “Legacy – do not use in new code” is perfectly acceptable documentation.

    [“Implementation detail – not part of the interface contract; may change at any time.” -Raymond]
  22. Anonymous says:

    “Implementation detail – not part of the interface contract; may change at any time.”

    Yeah, like that.

    Or to avoid developer fatigue, something like:

    “All these APIs are subject to change except the ones marked OK TO USE”

    TMTOWTDI

    [So you’re saying there should be a section in MSDN called, “Undocumented functionality” that reads, “Functions, structures, flags, etc. not documented here are reserved for the implementation and are not part of the interface contract. They are subject to change at any time and are not supported”? I can ask them to write up that one-paragraph documentation section if it’ll make you happy. -Raymond]
  23. Anonymous says:

    http://msdnwiki.microsoft.com/ –>
    “We are not able to support editing in Firefox for this release. Check back soon for an updated release that will provide better Firefox support.”
    Will this be fixed in 6 month?

    [Why are you asking me? I have nothing to do with the MSDN Wiki. -Raymond]
  24. Anonymous says:

    I would’ve thought that by now people would’ve stopped requesting "the right way" to stop the monitor from turning off.

    The "right way" is to get the user to go into his power settings and choose presentation mode or always on or something to that effect.

    To understand why he’s responded to a few other posts and not to the ones requesting this information, perhaps you should read this: http://blogs.msdn.com/oldnewthing/archive/2005/06/07/426294.aspx

    which is his post entitled "What if two programs did this?" and think about what would happen if one program tried to turn the monitor off while another tried to keep it on.

  25. Anonymous says:

    Hmm… Raymond, do you mean that in order to put the monitor into blank timeout, one has to post a message to ITS window?

    How is that logical?

    And besides, I hope the message in question is not the one tried in the linked blog, because he is sending (WM_SYSCOMMAND, SC_MONITORPOWER), which is described as a notification (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardaccelerators/keyboardacceleratorreference/keyboardacceleratormessages/wm_syscommand.asp)

    and not as being able to result as an order to the ‘system’! I am not a GUI programmer, so maybe I don’t understand the windowing "model", but I would expect that this  WM_SYSCOMMAND notification only have an impact on the defwndproc for the maximize&co notifications, the monitor&screensavers being simple "notifications" on which the window/app shall not have any influence (other than saying "hey i’m using the display, please don’t do that") and certainly I wouldn’t expect *my* defwndproc to handle the screensaver start by itself.

    I can see why many people thought that the desktop window was "responsible" for the screensaver and monitor shutdown, but granted they should have checked in the doc! :)

  26. Anonymous says:

    I have often wanted my 2 monitors (on separate computers) to come *out* of power-save mode (power off mode?) at about 8:00 AM each weekday, just before I arrive at work.

    Not crucial in the scheme of things, but one can always hope…

  27. Anonymous says:

    How man!

    My previous MSDN link says (in the remarks) that the defwndproc, when passed the WM_SYSCOMMAND, *does* the action corresponding to the notification. Well as I said before, I can understand for the maximize, close & co but not for the screensaver & monitor power…

    This GUI stuff is confusing for me…

  28. Anonymous says:

    Functions, structures, flags, etc. not documented here are reserved for the implementation and are not part of the interface contract

    I think that’s implicit… not necessary to make another section.

    > what would happen if one program tried to turn the monitor off while another tried to keep it on

    Irresistible force vs. immovable object :)

    [Now I’m confused. First you said that some documentation to the effect of “Implementation detail, subject to change” is needed, now you say it’s implicit… -Raymond]
  29. Anonymous says:

    Guillaume: so the right way to put the monitor in standby is to pop a message box asking the user to make it ‘always-on’? ;-)

    Maybe you meant "pop-up a message box to ask the user to shut down his monitor" ;)

    The "what if two programs did this" doesn’t apply here, what if two programs wanted to shut down the monitor? Hmm I don’t know… maybe… shut down the monitor!!

    Anyway, I guess the correct solution is the defwndproc one. Still, I don’t understand what is the idea behind it…

  30. Anonymous says:

    Guillaume:

    So you’re seriously saying that the user should toggle the power settings himself every time he wants to watch a DVD? Blech.

    Nektar:

    Add a handler for WM_SYSCOMMAND. If wParam is SC_MONITORPOWER and lParam is 1 or 2, return 0. All other wParam and lParam values, if not already handled by your code, should be forwarded to DefWindowProc. A similar approach exists for SC_SCREENSAVE.

  31. Anonymous says:

    To turn the power off, I have used this
    #include “stdafx.h”
    #include <windows.h>

    int _tmain(int argc, _TCHAR* argv[])
    {
    SendMessage(GetForegroundWindow(),WM_SYSCOMMAND, SC_MONITORPOWER, 1);
    return 0;
    }

    and it seems to work.
    Of course, that doesnt account for if there is a foreground window that actually processes SC_MONITORPOWER instead of passing it to DefWindowProc.

    [And it assumes that there is a foreground window at all and that you have permission to send a message to it. Just create your own window already. -Raymond]
  32. Anonymous says:

    >Even if the documentation is bad, does that justify basing a solution on passing intentionally invalid parameters? Is it justifiable to break the law because you can’t find any legal alternative to what you’re trying to do? -Raymond <<

    I don’t know, ask Rosa Parks.  Breaking bad laws is one of the cornerstones of civil disobedience…

    [So passing intentionally invalid parameters is a form of civil disobedience. Remember that another cornerstone of civil disobedience is the expectation of being arrested. Do you expect Windows to block your program when you do these things? -Raymond]
  33. Anonymous says:

    Monitor Blank vs Power Off

    At first I was thinking along the lines of the vertical blank on CRT devices – which iirc was the period of time it took for the CRT guns to reset from the end of the final line on the display to the beginning of the first line.

    Terminology exists for a reason – mixing up terms, even if the context seems to make it obvious what is meant.  In this case I can’t even see a reason for having changed the terminology at all.

    The “screensaver defense” is a little disingenuous.

    Screensaver = screensaver = screensaver.

    But blanking the monitor doesn’t necessarily involve turning it off, and the term “blank” has other, very precise meanings for display devices.

    Also I find it a little odd to criticise a consumer of an API for naively making a call that the API itself seems to be mis-interpreting – for whatever reason – and then lambasting the consumer code for the API’s idiosynchracies.

    This blog is usually interesting, often informative, but every now and again it seems to miss the point a little.

    Had the tone of the piece been different it wound’t have mattered, but it seemed to be just a little condescending and critical, rather than a factual critique of an innocent mistake.

    <shrug>

    Keep it up though.

    :)

    [So much for blogs being an informal means of communication. Do I need to hire an editor now? My point was “I can’t believe people actually develop software this way – randomly doing stuff to see what happens instead of thinking about what they are actually doing.” But from the feedback it appears that it’s unfair of me to suggest that people try to understand what they’re doing. So go ahead, pass random parameters. We’ll make more. -Raymond]
  34. Anonymous says:

    Is it justifiable to break the law because you can’t find any legal alternative to what you’re trying to do? -Raymond

    Yes, depending on what you want to do. Of course, that’s a philosophy debate.

  35. Anonymous says:

    So if open source is the wrong medicine for the pain of underdocumentation, then what is the right medicine — given that the average developer cannot contact people inside Microsoft to ask them either (A) how it’s supposed to work or (B) to fix the documentation?

    Microsoft, for years, has had a very opaque corporate structure to the outside world; I’ll place bets the majority of readers of this blog (myself included) don’t even know which team *Raymond* is on, much less how to contact members of the right team.  That dearth of information has started to change over the last few years, but the net effect is that Microsoft has gone from an opaque wall to an opaque wall with a few pinholes of knowledge poked through it — far from transparent.

    Here’s a proposal:  Convert a large portion of the Windows API documentation over to a Wiki, so that anybody can post, comment, and edit, with a suitable history log and rollbacks in case of abuse.  My guess is that less than six months after converting it, the complaints about the confusing parts of the API would vanish almost entirely.  Of course, this would mean embracing open communication, and I get the feeling there are a lot of folks inside Microsoft who really don’t want to do that.

    [You mean like this? We’ll see if your six month prediction comes true. -Raymond]
  36. Anonymous says:

    So you’re seriously saying that the user should toggle the power settings himself every time he wants to watch a DVD? Blech.  – Bob

    Any program that went and automatically changed the power scheme or monitor setting goes straight into the recycle bin on my machine. Keep your filthy mits off my personal user settings!

  37. Anonymous says:

    http://msdnwiki.microsoft.com/wikiedit/search.aspx?query=createwindow

    >  MSDN Wiki
    >
    >     CreateWindow    [Search]
    >
    >  There are no search results to display.

    Um, exactly what is this site supposed to be documenting, anyway?  It seems a little lacking on Win32, which is where most of the Windows-related questions seem to be.  I’d say the six months starts when the content is actually *posted* the first time around, and it sure doesn’t seem to be yet.

    *sigh*  Wish it didn’t take upwards of 30 seconds to load a single page there, either.  Traceroute gets as far as a few servers on msn.net before reaching ungodly ping times.  :-(

    [I’ll assume your questions were rhetorical since there’s an FAQ right on the site. -Raymond]
  38. Anonymous says:

    Win32 API documentation is poor. Until the documentation is as good as
    i want it to be, my life would be easier if i had the source code.

    Let’s pull out a random example, since AJAX is the new cool thing: IXMLHttpRequest.Send()

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/xmlsdk/html/52aaf5ff-e302-4490-821a-cb3a085fe5ee.asp

    If i do a synchronous request, will OnReadyStateChange get called? If so, how many times?

    i already know the answer, i’m not asking for technical support.
    i’m pointing out one example were the “contract” between the API
    writers and the developers is not fully spelled out.

    Yes, there is a contract that we want to adhere to, but you have to tell us what the contract is.

    [I don’t doubt that the documentation is lacking in many places. But if you were going to fill in the gaps, would you really consider intentionally passing invalid parameters as part of the missing documentation? -Raymond]
  39. Anonymous says:

    > Is it justifiable to break the law because you can’t find any legal alternative to what you’re trying to do?

    It depends on:

    * the consequences of breaking the law (why the law is there)

    * the consequences of not being able to do what you’re trying to do

    * how hard you tried to find a legal alternative

    * what else is on your list of things to do

    Finding a "correct" way of doing things is a halting problem… it’s hard to tell if the answer is just one more search away, or doesn’t exist.

  40. Anonymous says:

    Dear god, (some)people!  If it’s not documented, it’s logical to assume absolutely nothing about it.  Doc writers will never think to write down every way to NOT use something — only the proper ways *to* use it (think about how long the documentation would be for SendMessage!) and perhaps some common mistakes.  I’m shocked people think this is some new revelation — this is simply the way documentation has always worked for every toolkit ever made.

  41. Anonymous says:

    > First you said that some documentation to the effect of "Implementation detail, subject to change" is needed

    Yes… *in the source code.*  That comment fell under the scope of your "if you got the source code to hundreds of undocumented APIs" scenario.

    To save copy/paste time, it would suffice to have a rule that "everything in source code is subject to change unless it specifically says otherwise," and then just tag certain chunks of code as /* public */

    > now you say it’s implicit…

    In a /library of external documentation/ it’s implicit.

    *poor-man’s bold*

    /poor-man’s italic/

    /* just a comment */

  42. Anonymous says:

    Larry says, “Raymond’s effectively using the VS 2005 and CLR V2 Wiki as a test harness.  If, after 6 months the CLR V2 Wiki has better documentation than MSDN, clearly you were right.  If, on the other hand, it doesn’t, then a wiki isn’t the right solution.”

    I understand that.  The principle behind a Wiki is that you should get the best results with the most eyeballs.  Lots of folks are interested in .NET, sure, but not anywhere near as many as are interested in accurate documentation of Win32.  So wouldn’t it make sense to populate the Wiki initially with the most desired information, which in this case would be the Win32 API?

    Raymond says, “My point was ‘I can’t believe people actually develop software this way – randomly doing stuff to see what happens instead of thinking about what they are actually doing.’ But from the feedback it appears that it’s unfair of me to suggest that people try to understand what they’re doing.”

    Ray, I think you’re right on both counts.  It’s pretty insane that people try to develop that way, and I doubt anybody here would disagree with that.  To quote MST3K:  “Randomly blowing up things is not a good battle strategy in a spaceship.”

    But, that said, the only reason folks resort to the software equivalent of guerrila warfare is because the known documentation is either misleading, hard to find, or just plain wrong.  It’s fair to suggest people know what they’re doing, but unfair to *require* it.  You and I may have degrees in computer science or software engineering, but the majority of people coding for Windows don’t, so it behooves you to provide the best documentation for them that you can.  I would think that by this point, having heard a thousand people complaining that the Win32 documentation has significant problems and almost nobody claiming it’s good the way it is, and that with thousands of people getting the API calls wrong, that you’d at least consider that maybe, just maybe, there’s a problem with it.  This poor guy sounds to me like an exasperated programmer who tried everything he could to do it right and finally just gave up and tried anything he could think of until he found something that worked (and yes, we’ve all been at the “just work already!” stage; don’t claim you haven’t!).  Had the docs been more precise and easier to find, he might never have resorted to the crazy solutions.

    [How could the SendMessage documentation have been improved to solve this problem? “When sending a message to a window, make sure it’s really a window”? -Raymond]
  43. Anonymous says:

    This does suggest that perhaps a Win32 API Wiki might be appropriate. Then all these people suggesting API doc improvements could, well, improve the API docs.

  44. Anonymous says:

    Bloody hell. There IS an msdn wiki. Who knew? Not I for certain. I sense a certain .NET focus however.

  45. Anonymous says:

    "I’m still wondering how you’d do it if you don’t have a window handle, such as a console application, without creating a temporary window."

    Lookup GetConsoleWindow()

  46. Anonymous says:

    So, how do we avoid fumbling around in the dark in the first place? For instance, I’d like to emulate the effect of pressing Alt+Esc. (I do know you can’t use WM_SYSCOMMAND in this case because it starts a modal event loop looking for the release of the Alt key).

  47. Anonymous says:

    It is possible to just do this without creating a temporary window:

    DefWindowProc(0, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);

    [Another example: “Hey, NULL is an invalid parameter to DefWindowProc. Let’s pass it and see what happens!” -Raymond]
  48. Anonymous says:

    paul2: Any program that went and automatically changed the power scheme or monitor setting goes straight into the recycle bin on my machine. Keep your filthy mits off my personal user settings!



    The approach given DOES keep its mitts off your profile. Do you complain that games change your "personal user settings" when they open a fullscreen window?

  49. Dean Harding says:

    [How could the SendMessage documentation have been improved to solve this problem? "When sending a message to a window, make sure it’s really a window"? -Raymond]

    There’s nothing wrong with the SendMessage documentation. the problem is with the WM_SYSCOMMAND documentation. For reference:

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/keyboardaccelerators/keyboardacceleratorreference/keyboardacceleratormessages/wm_syscommand.asp

    First of all, the title of the page is "WM_SYSCOMMAND Notification" which implies that the message is a *notification* and not something you’d generate yourself.

    Then, the first paragraph says:

    "A window receives this message when the user chooses a command from the Window menu (formerly known as the system or control menu) or when the user chooses the maximize button, minimize button, restore button, or close button."

    Which is totally wrong in this case. Now further down the page it says this:

    "An application can carry out any system command at any time by passing a WM_SYSCOMMAND message to DefWindowProc."

    Which is probably what the original person was wanting. This suggests that the functionality of WM_SYSCOMMAND has probably evolved over time, while the documentation has not evolved as well.

    I’ll not suggest that what the original person did was right, and thinking about what is written in the documentation should have come up with the "correct" solution. But you can’t deny the documentation for WM_SYSCOMMAND probably needs some work.

    Should I post a comment on the documentation page asking them to clarify it? Probably. But I’m a busy person, and if I wanted to submit corrections every time I spotted them, I’d be using open source software :p~

  50. Anonymous says:

    <quote>But if you were going to fill in the gaps, would you really consider intentionally passing invalid parameters as part of the missing documentation?</quote>

    i would have thought so, yes. But when i actually read the guys posts for myself, i see that he wasn’t randomly passing garbage and hoping it would work. He did what we all do, read through differect sections of the SDK documentation, trying to cobble together the idea of how it’s supposed to work.  The fact that code iteration #1 and #2 didn’t work obviously means that the documentation wasn’t clear enough and he did something wrong. So we keep trying things that are along the same line until it does work. The fact that it works by accident isn’t something that we’re supposed to just divine.

    If you look at the documentation for SC_MONITORPOWER there is no indication that you are allowed to send the message anywhere. If fact, looking at the documentation for WM_SYSCOMMAND there is no indication that you’re supposed to be allowed to send any WM_SYSCOMMAND messages anywhere. The contract doesn’t specify it being allowed, so it must be forbidden – and therefore "hacking."  Yet i find no shortage of people sending fake SC_MINIMIZE and SC_CLOSE messages.

    So maybe it’s not so bad after all – just poorly documented.

    Next, i receive a SC_MONITORPOWER notification when the monitor is powering down. It is a chance for me to know this is happening, and i can react accordinly (e.g. make my program do less graphical stuff.) Windows will know i’ve seen the message when i call DefWindowProc. Fair enough. But now someone is suggesting that if i simply generate a SC_MONITORPOWER notification message, and pass it to the DefWindowProc, and that will magically shut down the monitor is crazy. That is not only counter-intuitiave, but not mentioned in the documentation (even taking into account the line "The DefWindowProc function carries out the window menu request for the predefined actions specified in the previous table."). And as we’ve seen before

    http://blogs.msdn.com/oldnewthing/archive/2006/05/12/596113.aspx

    simply mimicing the thing doesn’t make it so. Just because you decide to generate a SC_MONITORPOWER message doesn’t mean that the monitor was in the process of turning off, or that the process will suddenly startup – at least the documentation provides no indication of that. And yet other people used to do it and it worked. So either it was a bug in Windows that it didn’t react as documentation, or it was an undocumented feature – subject to change in future versions of Windows, or it was a poorly documented feature. Yet i find no shortage of people sending fake SC_MONITORPOWER messages.

    So maybe it’s not so bad after all – just poorly documented

    Finally, he didn’t broadcast a message, he sent a message to WM_TOPMOST. Apparently if i fake the symptoms of a monitor in the process of shutting down, then it shuts down. So one gets the idea that if i send a SC_MONITORPOWER message, the monitor will start to power down. Well obviously i can’t send it to myself, because i have no ability to initiate a monitor shutdown. i need to send it to some central "windows" authority who will then initiate the monitor shutdown procedure, and in turn broadcast a message to every window on the system, letting them know the monitor is about to turn off, as part of the normal preparation for monitor shutdown. Sounds perfectly reasonable and logical. But how shall we tell Windows the monitor should be shut off? Well, who starts the process in the first place? Windows of course. What is our way in to talk to "the sytem"?

    SendMessage(0, …

    SendMessage(-1, …

    SendMessage(GetDesktopWindow(), …

    One of those outta work. No? Dammit, wish this stuff was documented. Any other Windowsy hWnd’s we can find?

    SendMessage(HWND_TOPMOST, …

    Documentation doesn’t say to can send WM_SYSCOMMANDS, but you can. Documentation doesn’t say you can initiate a monitor shutdown by calling yourself, but you can.

    If i generate a WM_POWER message and pass it to DefWindowProc will the computer turn off? Documentation doesn’t really say. It says "Notifies applications that the system is about to enter a suspended mode."  Still ambigious.  

    So, in the absense of documentation as good as i want it to be, couse code please. Perhaps you could just redo windows in CLR, so we would decompile it ourselves into readable source code.

  51. Anonymous says:

    >It is possible to just do this without creating a temporary window:

    DefWindowProc(0, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);

    <<

    That does not work, at least not on XP SP2.  

  52. Anonymous says:

    I agree that the guy with the crazy solution is wrong. But I can’t help to sympathize.

    As Sean W mentioned: How many times when you want to do something and you don’t know how? Documentations doesn’t help. You can spend hours on MSDN unless you have the right keywords. So you google it or ask your friends how – but this likely leads to a buggy solution from the last guy who experienced the same problem.

    And this is mainly the fault of Microsoft for being so big. When you have millions of developers, you’re bound to get many wrong solutions for the same problem – especially when the "right" solution isn’t obvious.

    The only way to improve this situation is for Microsoft to address the needs for all these developers. Have a database for how-to-do-stuff that’s easy to find. **Advertise it**. 3rd parties websites have already done it (only with possibly buggy solutions).

    Either this, or put up with sketchy code and compatibility problems from now until windows become obsolete.

  53. Anonymous says:

    @OldNewThing,

    As the author of the ‘offending’ articles, it seems only logical to respond to this. Let me state that this is oooold code and medio 2004 it was a pain in the ass to find code or a hint about powering down a monitor.

    First of all, some background. I needed the monitor power off/on functionality for a TFT monitor in a painting frame on the wall at home. This monitor displays photos I shoot during holidays, cats etc, but also serves another role. The monitor is touch enabled and shows me a TV guide, photo browsing, movies at the local movie theatre and – important – trafic jam info (as I live near Amsterdam).

    The monitor power off occurs at 11:30PM and the monitor is switched on again at 6:30AM. At least the living room is not lit up anymore during the night.

    As soon as I published the code, Raymond Chen (you!?) notified me that this was not the ‘best’ way to do this. Unfortunately, Chen’s comments on my blog did not survive upgrade to Community Server…

    <EDIT>

    Googling for Raymond Chen leads me to OldNewThing, so you HAVE been helping me in 2004! <large grin>

    </EDIT>

    Enfin, on Chen’s comments, I modified the code to NOT use HWND_TOPMOST anymore, but just post the message to the handle of the .NET form, as Chen indicated. Unfortunately, I did not conclude the article series with the proper version (because it was already in the comments) and thus serves a happy bashing session two years later.

    This is the code I use after Chen’s suggestion:

    PostMessage((int)this.Handle, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);

    The ‘this.Handle’ is the handle of the WinForm showing the photos and has been working splendidly for two years. And this is also what you and others are suggesting.

    Actual code is (after refactor sessions):

    User32.NativeMethods.PostMessage((int)this.Handle, User32.Constants.WM_SYSCOMMAND, User32.Constants.SC_MONITORPOWER, User32.Constants.MONITOR_OFF);

    And yes, I was ‘fumbling’ to find a solution. Documentation about the messages was not usable, no code existed on blogs or article sites like Codeproject. And thus you experiment until a ‘solution’ appears and publish your findings. By publishing, Chen educated me and helped me refine the solution. The more eyes look at code, the better.

    My published search for a better impersonation (in SharePoint) also yielded better versions of de solution.

    The least you could have done in this blog post, is provide some code of a correct solution, instead of letting the readers guess for it. This also helps any other developer in finding the best solution for powering down a monitor.

    I hope you will be as helpful as in 2004 next time I have a hardcore windows problem. ;-)

  54. Anonymous says:

    "Making up intentionally invalid parameters and seeing what happens falls into the category of malicious goofing around, not in the realm of software engineering and design."

    I’d argue that this *is* part of software engineering. It’s reverse engineering and

    you’ve touched on it before (http://blogs.msdn.com/oldnewthing/archive/2006/03/31/565878.aspx and other compatibility posts).

    Someone must have said this before, but if not, I claim it: "Reverse engineering, the 2nd oldest [software] profession".

    [BTW I like the inline comments better than replies to your own posts. I wonder sometimes why you persevere, though. I hope the good outweighs the bad].

  55. Anonymous says:

    @Victor — the correct solution was posted in the last paragraph of the post.  Granted, it’s not code, but it also shouldn’t be hard to translate "make a window and post the message there" into workable code.

  56. Anonymous says:

    Re: [Picky, picky.]

    Raymond, I was honsetly asking if those were the same things.  I didn’t know.   (I thought maybe the monitor would BLANK instead of power off.  I *know* that blanking a screen and powering it off aren’t the same.)

    Now that you have yelled at me, I now know.  Sorry for questioning it, because it’s not obvious that those are the same things.

  57. Anonymous says:

    So passing intentionally invalid parameters is a form of civil
    disobedience. Remember that another cornerstone of civil disobedience
    is the expectation of being arrested. Do you expect Windows to block
    your program when you do these things? -Raymond

    Yes. In fact, that would have stopped the original code you
    complain about. If Windows would have thrown a BadParam exception, the
    original user would never have posted it. The first test run would have
    made it clear it was illegal.

    I’m not sure if this would require a special developers build of
    XP, but even if, Microsoft could also sell that as a ‘hardened’ version
    just like Sun created hardened Solaris.

    [There is already a special developer build of Windows for this. It’s called the checked build. -Raymond]
  58. Anonymous says:

    Just wanted to point out that code IS documentatoin (code by contract anyone? http://www.artima.com/cppsource/deepspace3.html)
    so yes, in this way open source is better (a little promo: ReactOS
    0.3.0 RC1 just came out, so try it out if you want an open source
    windows :) ).

    Also when you are complaining about people adressing you questions
    which are not your responsibility:  Microsoft is for us a big
    opaque thing, it’s not like on the bottom of every page there is a
    link: if you want to provide feedback, click here! For example you say
    that we should address our complaints regarding the blog software to
    the “makers of the software”. But who are they? In every open source
    forum / blog software you would have found the link to the author at
    the bottom of the page, but not here. IMHO a more suitable response
    would be: it’s not my responsability / area of expertise, contact X
    (with a mail address or a link to the contact page) for it. Remember,
    you are not just yourself, you represent the entire company, like it or
    not.

    (Just in a sidedone, although I’m sure I’ll start a flame war: if
    open source isn’t better, how is it possible that in 4 years we have
    built a browser which is more secure, and the IE team still couldn’t
    plug all the holes and almost every month they come out with a remote
    code execution attack? I know that rewriting software from scratch is
    bad, but this is embarrasing)

    [If code is documentation, then how can you safely change the code? Somebody may have been relying on the code you changed, and it was “documented” as such. The blog software used to put a link to the software author at the bottom of the page; it looks like they’ve removed it. There has always been a link to the blog software author on the Suggestion Box page. And I can’t say “You should contact X with your problem” if I don’t know who X is. And I don’t want people just throwing random questions at me because “Oh, even though it’s not Raymond’s area, he’ll tell me who X is”. I don’t want to become an “X finder”. As for IE: Can you open your My Computer folder from your favorite non-IE browser? How about an FTP site in icon mode so you can drag/drop files to upload/download? Or view a PDF file inside the browser window instead of using an external plug-in? IE has a much larger surface area than most other browsers. -Raymond]
  59. BryanK says:

    Regarding IE:

    > Can you open your My Computer folder from your favorite non-IE browser?

    No, but on the other hand, I don’t see the point of being able to
    do this, either.  That’s what Windows Explorer is for.  (No
    matter how much Microsoft marketing wanted us to believe that the
    Internet was no different from the local machine 5 years ago, it wasn’t
    true then, and it’s even less true now.  The local machine can be
    trusted much more than the Internet can be.)

    (Note that I can do it (or its equivalent, view the root directory)
    in Konqueror.  It’s just that Konqueror isn’t my *favorite* non-IE
    browser.)

    > How about an FTP site in icon mode so you can drag/drop files to upload/download?

    What’s the point of this?  It makes it slightly easier for new
    users, or something?  If you have a browser, why would you expect
    to be able to drag-and-drop to download a file?  Wouldn’t users
    expect to click a file to download it, just like when you’re browsing
    via HTTP?  Except, oh, that’s right, marketing says that the
    Internet is no different from the local filesystem again.

    OTOH, most third-party FTP programs have a drag-and-drop mode (and
    it’s possible that some of them will accept drops from Windows Explorer
    too, I don’t know).  Not sure how many of them are free, though.
     And when you’re using a different program for FTP, it’s a little
    more obvious that a different action may be required to download a
    file, so the interface “cost” of going fully DnD isn’t as high.

    (Actually, Konqueror may be able to do this also, but I’ve never
    tried it so I don’t know for sure.  Certainly the infrastructure
    is there; someone would just need to write an FTP kioslave.)

    > Or view a PDF file inside the browser window instead of using an external plug-in?

    “External plug-in” like the one from Adobe that’s required for IE
    too (at least IE6SP1)?  No, I can’t view PDFs without that.
     But with it, I can view them “inside the browser window”.

    (But I doubt that Adobe has a plug-in for Konqueror.  However,
    KDE does have a PDF viewer (named, appropriately enough, kpdf), and
    it’s possible that kpdf can be invoked inside the Konqueror window.
     Never tried that either, though, so I don’t know for sure.)

    [I’m not saying that any of these were necessarily good ideas, but once you’ve shipped a feature you’re committed to supporting it. Even the bad features. Companies have built line of business processes around these features. -Raymond]
  60. Anonymous says:

    Originally posted by Raymond:

    [Or view a PDF file inside the browser window instead of using an external plug-in?]

    That reminds me of an interesting thing my PC does…

    I have several toolbars set up as a sidebar on the desktop, including a "My Computer" bar which lets me browse my filesystem via drop-down menus. One interesting side-effect of this method is that when I open a PDF from this menu, it opens in IE!

    I’m guessing this is because the ability to make toolbars out of folders came with IE4, which was the first version of IE to be integrated into Windows, and that somehow they’re treated as being part of the "IE side" of Explorer, which naturally opens PDFs inline?

    … Will this be bugfixed in Vista? ;)

  61. BryanK says:

    [I’m not saying that any of these were necessarily good ideas, but once you’ve shipped a feature you’re committed to supporting it.]

    Ah, I get it.  So it sounds like the problem with IE is Microsoft’s marketing department way back in 1995-96-ish, perhaps along with a lack of clairvoyance about future threats.  :-P

    (However, if Konqueror can indeed do all those things — and it’s been 4-5 years since I last used it — then the fact that it’s not coming out with a new patch every month should imply something too.)

    Revenant — You turn that toolbar on from the taskbar’s context menu, right?  (Right-click the taskbar, Toolbars, New Toolbar, select My Computer, hit OK.)  That toolbar shows PDFs in Acrobat for me, not IE.  This is 2K Pro SP4, though, so maybe that has something to do with it?  (Also, IE is no longer my default browser, so that might be part of the difference too.)

  62. Anonymous says:

    BryanK — Yes, that’s the toolbar. (I was quite gratified when they started making it one of the default toolbars, since I’ve been using this particular feature since Win98.)

    I’m running XP Pro SP2, and IE is not my default browser either. In fact, I told Windows never to use it – yeah, I know, like that ever made a difference…

    Specifically, my PC is opening PDFs with the Acrobat plugin in an IE window. If I open then via a normal Explorer window, my application preferences are honoured.

    Just out of interest: was your "My Computer" toolbar part of the taskbar when you tested, or part of a separate toolbar? If it was part of the taskbar, you might want to give it a go as part of a sidebar and see what happens. You’ll need another (blank or otherwise) toolbar on the same screen edge to make it use the menu function.

  63. BryanK says:

    Oh, you’re right, it was part of the taskbar.  But I put it on the right side of the screen (well, I put the Address toolbar on the right side of the screen, then added My Computer to it), and it didn’t open up IE, just Acrobat.  I also tried a file located on a mapped network drive (so it’s from a different zone), and that didn’t seem to make any difference.

    What happens if you open the PDF from the Start->Run box?  (Are ShellExecute and ShellExecuteEx working, in other words?)

  64. Anonymous says:

    I wish to duplicate this followup in this thread because it follows up to this thread and there’s no way to do newsgroup-style crossposts.

    > It so happens that the numerical value -1

    > for a window handle is suspiciously close to

    > the value of HWND_BROADCAST:

    > #define HWND_BROADCAST  ((HWND)0xffff)

    > It so happens that internally, the window

    > manager supports (HWND)-1 as an alternative

    > value for HWND_BROADCAST. (I leave you to

    > speculate why.)

    We can leave it to MSDN to say why.

    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/dataexchange/dynamicdataexchange/usingdynamicdataexchange.asp

    *  Usually, the client broadcasts this message

    *  by calling SendMessage, with –1 as the

    *  first parameter.

  65. Anonymous says:

    The reason why -1 still can be used as a substute for 0xFFFF is because, in 16-bit Windows, -1 = 0xFFFF because the message value was 16-bit. It no longer equals 0xFFFF because the message value is increased to 32-bit in Win32.

Comments are closed.