Frequently in development of the software for computer
management there is a necessity for a
code which shuts down 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 call of ExitWindowsEx
with EWX_FORCE flag, but in this case all applications
are terminating 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 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 ExitWindowsEx
call, and so correct, as far as it is possible.
What may be considered as "correct closing of application"?
It is possible to discuss this
question very long, and the decision will be specific for
each application. Therefore we shall not look
throw a question of data preservation in open
documents here (it's necessity, on my sight, is
rather disputable), 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, by sending them WM_CLOSE message.
We are waiting some time,
while applications are processing the message.
Action second:
we are sending to all top-level applications'
windows WM_CLOSE message. It is equivalent to clicking
the cross in a right top corner of a window. Different applications react on 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
is 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 security reason),
and again we are waiting slightly.
Action fourth:
we are notifying remaining applications of
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 WM_ENDSESSION message to it. After that the application
must close itself. We are waiting.
Action fifth:
again we are closing emerged pop-up windows. We
are waiting.
Action sixth:
we are destroying 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 TerminateProcess
function is not applying 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, are not closing before ExitWimdowsEx call.
As a rule, such applications are specially developed for work
without user intervention, and are normally
closing with operation system.
It is more preferable to some applications, that they are closing only together
with OS: for example, Windows Explorer and
Internet Explorer in this case keep windows
set 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 using of all stated above 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 "SeShutdownPrivilege"
privilege. How to do it - see source code and
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.
|