No, really, you need to pass all unhandled messages to DefWindowProc

Earlier I had discussed that you have to return the special value BROADCAST_QUERY_DENY if you want to deny a device removal query because too many programs thought that they had covered "all" the Windows messages and just returned zero for the others. Since then, there have been lots of other window messages added to the system, many of which contain nontrivial processing in DefWindowProc. Yet, every so often, I run into another program that assumed that "Microsoft will never enhance the window manager" and simply returned zero for all the messages they didn't handle.

Indeed, often these programs don't even cover all the existing messages! One program had a helper window that handled just a few messages and returned zero for the rest. As a result, you couldn't shut down the computer because returning zero in response to the WM_QUERYENDSESSION message means, "No, don't shut down." I guess the people who wrote that program assumed you would shut down their program manually. (Programs are not supposed to fail a shutdown unless the decision came from the user, typically by clicking "Cancel" in response to a "Do you want to exit without saving?") Custom keyboard buttons like the volume control buttons didn't work either (if focus was on this helper window), because it neglected to pass the WM_APPCOMMAND message to the DefWindowProc function.

Therefore, once again, I implore you: If you don't handle a message in your window procedure, pass it to the DefWindowProc function. Your customer base thanks you.

(Note for people who take what I say too literally: If you are using a framework, then follow that framework's protocol for indicating that you want default message processing to occur. For example, dialog procedures do not pass unhandled messages to the DefWindowProc function; they merely return FALSE to indicate that default processing should take place.)

Yes, ofcourse (I do that). But using DefWindowProc is always a little bit creepy because so much things that I don’t know about, so I implement more WM handlers then I’d actually need, just to ensure a proper state and nice handling instead of ignoring it and let Windows figure it out by itself, which cannot possibly know how my program would best handle it so just does a "safety measure" to ensure nothing breaks.

100% true, but seeing it in this context an idea has popped up. To programmers who are less skilled, and/or who copy sample code without noticing that the source and destination contexts differ in this way, it might not be obvious that dialog procs and window procs differ in this way. Also is there some possibility that the documentation of dialog procs might have been less clear in the past than it is now? Or maybe wizards generated bad code, somewhat like Visual Studio 2005 still generating bad code for winmain functions? If it’s not always the programmer’s fault then I wish something could be done to help, though in this situation it seems pretty difficult to help.

1) Have a dummy message, WM_QUERYPROPERHANDLING for instance and make it clear in the docs that *only* DefWindowProc can properly handle this message. For added reliability, you could just use a random unassigned message ID.

2) Have DefWindowProc return a pseudo-random magic value for this message. The value should be as unpredictable as possible and the algorithm to generate it should change in every single version and edition of Windows.

Then, periodically send the dummy message to all applications. See which ones respond correctly. For applications that do not, ignore their responses to WM_QUERYENDSESSION and other messages where returning 0 can be bad for the user.

I like the ideas of Stu and Luc Rooijakkeers. In fact it would be nice for any debug version of a program (with or without a debug version of Windows) to get killed on an Assert when it misbehaves this way. This assert won’t fix old programs but it will help fix new ones.

My previous comment has a bug. I asked if the documentation of dialog procs used to be less clear in the past, but the correct question would be if the documentation of window procs used to be less clear in the past. If anyone copied code from a dialog proc into a window proc, they could be in bad shape, same as if they used window proc code generated by some automated wizards.

Stu: What you suggest would be possible I guess, but the problem is compounded by the fact that a program may have multiple message-handling loops (think modal dialogs, for example).

Personally, I’d feel safer if every such "bad if not handled properly" message would be *immediately* preceded by such a "test default handling" message. It’s not like they are that frequent (i.e. many times per second) anyway…

Reserving a certain range for the random message id would be best, I think, to discourage developers from just adding a single case WM_QUERYPROPERHANDLING: to their message handling code. And of course this *would* need to be documented properly and added to message tracing code etc. Perhaps using a pseudo-registered window message would work for this?

Is it actually even possible to look up the name of a registered window message?

Finally, to make this probing message really work for developers, the debug version of windows (or even better, any program being debugged?) should complain when the message ISN’T being handled properly, preferably with a "never bother me again about this particular version of this particular executable" option (where "particular version" should include version numbers and file date/time to account for continuing development).

"It’s not just old applications that continue to report failiure in response to WM_QUERYENDSESSION"

Wow! It’s almost funny that Rowland Shaw’s link points to a product feedback on the brand-spanking-new SQL Server 2005, which aborts a shutdown request before the user even answers the "save or abandon" dialog box.

So if DefWindowProc is so important, and this issue is common, then why not have a compatability flag to change the behavior around calling the Window with specific messages. Basically, when you call the WndProc, and it returns that it didn’t handle the message, check if the DefWindowProc was called. This is simply a matter of having something like so:

// The app didn’t process the message and didn’t care to ask Windows to process the message

result = DefWindowProc( … );

}

How evil is a solution like this? How likely would it be to break existing functionality? Would adding an app compatability flag for this be a bad solution? My guess is that this kind of problem/solution has huge testing problems. I wonder if tools like App Verifier check these kinds of problems.

I like the idea to help debuggers to check for this, but IMHO a lazy programmer will always wreak havoc. You can plug a few critical holes (is this one?), but no amount of code can plug laziness. And by trying you just create a mess for the OS maintainer and a pain for other developers.

all laptop users must hate apps that dont let you suspend or shutdown, its a mistaken attempt by the app to stop you doing something they feel is misguided or wrong. Office 2000, for example wont let you suspend if you are reading a network file, even if that is one in a folder you’ve marked as ‘available offline’. There’s nothing like pulling a laptop out of a bag to find it overhot, battery down to 7% and a dialog saying "you cannot suspend" to make you feel ill will to developers and general.

Windows vista will take the veto of suspend (WM_POWER) out of apps, but not drivers, which peeves me. IMO unsigned drivers shouldnt have the right either, as it means they havent been through WHQL yet. WM_QUERYENDSESSION is the same: system shutdown is too important to let an app veto.

If an app can only save its state on a clean close, then the app is broken. they should go read up on "crash only software" and rethink what they are doing

Any way to find out what window is doing this? My laptop will occasionally refuse to shutdown. Never a message telling me why. I typically kill every process I can and it’ll shut down.

I suppose one of these days when I’m not in a hurry to leave I’ll have to kill a process and try a shutdown, kill another and shutdown, etc. It’d be a pain but at least I might find the misbehaving program that way.

Your entry just got me thinking that maybe I could write a little console program to send that message to every window and tell me which one refused the shutdown.

Neil: I guess I don’t understand how this proposed "certification requirement" document would be any different from just a list of "common mistakes and how to avoid them" that applies to all programs, not just programs submitted to certification.

I think Neil’s idea was that a listing in the requirements wouldn’t only inform (or hide as the case may be) the requirement to developers, but would also have an effect on testing. That is, to get the logo, programs would have to pass a test that would include testing for this case.

I do wonder how some programs get logos that they pretty obviously aren’t qualified for. Some such programs aren’t even made by the company that issues the logos.