How to shut down the system correctly
   
By development of the software for the computer management frequently there is a necessity
for a code which shuts down the operation system without user participation. It seemed,
that it can be done easy: there is ExitWindowsEx API function, doing it, however so simple
decision works not always. The thing is that each application started on the computer, has
the right to cancel system shutdown or to suspend it, by showing a pop-up window. Basically,
it is possible to avoid it by a call of ExitWindowsEx with EWX_FORCE flag, but in this case
all applications are terminated by a method of "rough force", which may result in data loss.
Some applications react to such method of terminating inadequately, for example, WinPopup
shows a pop-up window, and if at the moment of a ExitWindowsEx call there were already any
pop-up windows on the screen, the system may crash.

The decision of the task arises with itself: it is necessary to close all working
applications before the ExitWindowsEx call, and so correct, as far as it is possible.

What may be considered as "correct closing of the application"? It is possible to discuss
very long on this question, and the decision will be specific for each application.
Therefore we shall not look throw a question of data preservation in the open documents
here (it's necessity, on my sight, is rather disputed), but we shall try to find a sequence
of commands, common for all applications, and, as a rule, resulting to their closing
without of "rough force" of TerminateProcess function.

So, action first: we are closing all pop-up windows, visible on the screen, sending them
WM_CLOSE message. We are waiting some time, while the applications will process the message.

Action second: we are sending to all top-level applications' windows WM_CLOSE message. It is
equivalent to pressing on cross in a right top corner of a window. The different
applications react to it differently: the first may close itself obediently, second will show
a pop-up window, third will move itself to tray, fourth can simply ignore this message. Again
we are waiting some time.

Action third: again we are closing emerged pop-up windows (it would be possible to press the
default button on these windows, but, on my sight, it can cause undesirable consequences, for
example, the file will be saved without user permission while he/she was not going to save it
by the security reason) and again we are waiting slightly. 

Action fourth: we are notifying remaining applications about the system shutdown by sending
to their top-level windows WM_QUERYENDSESSION message. This message returns a value, and if
it is not equal to zero, the application permits system shutdown. In this case we are sending
the message WM_ENDSESSION to it. After that the application should close itself. We are
waiting. 

Action fifth: again we are closing emerged pop-up windows. We are waiting.

Action sixth: we are destroying the remaining applications using TerminateProcess API.
We warned them! Here it is necessary to mean, that some top-level windows can belong to one
process, and consequently it is necessary to make provision for the TerminateProcess function
was not applied repeatedly to such processes. Once again we are waiting. 

Action seventh: here now, at last, it is possible to call ExitWimdowsEx function. 

In the above-stated sequence of actions the applications which have no visible windows, up
to ExitWimdowsEx call are not closed. As a rule, such applications are specially developed
for work without user intervention, and are normally closing together with operation system. 

It is more preferable to some applications, that they were closed only together with OS: for
example, Windows Explorer and Internet Explorer in this case keep windows structure and
arrangement. This group includes also Program Manager and WinPopup. The classes of their
windows make the list of exceptions when messages are sending. 

There are features of all stated above application in Windows NT/2000. Firstly,
ExitWindowsEx will work correctly only if the process is started under account with
sufficient rights (it should belong to Administrators or Server Operators group), but it
is not enough: the process must obtain the "SeShutdownPrivilege" privilege. How to do it -
see the source code and the Knowledge Base article. Secondly, all this is meaningful only
when the program, shutting down the system, works on an interactive desktop. If this
program is started as a service or by Task Scheduler, it can "not see" the user
applications' windows, and can not close them. However, in Windows NT/2000 there is a
InitiateSystemShutdown function, which practically always shuts down the system. 

See also:

Microsoft Knowledge Base Q161136, Q168796.
 
 2000 Sergey Merzlikin
http://smsoft.chat.ru
smsoft@chat.ru 
