How can I detect whether the user is logging off?

There may be cases where you want to know whether the user is logging off. For example, your program might be responding to external events by (say) launching a helper program, but you don't want to do that if a logoff is in progress.

The way to find out is hidden in the Get­System­Metrics function, which is admittedly a rather non-obvious place to put it.

if (GetSystemMetrics(SM_SHUTTINGDOWN)) {
 // user is logging off, don't start anything new

Compounding the confusion is that the flag is called "shutting down", but in fact it reports whether the user is logging off (which in today's parlance is called signing out). The logout may be part of a shutdown, or it might not.

Comments (20)
  1. Brian_EE says:

    >Compounding the confusion is that the flag is called “shutting down”, but in fact it reports whether the user is logging off

    But the flag is for “session shutting down”, not “computer shutting down”. It’s only confusing if you’re wearing the wrong colored glasses.

    1. morlamweb says:

      The function is called GetSystemMetrics, and the flag is “SM_SHUTTINGDOWN”. The implication is that the metric reported is whether or not the system is shutting down given the names. It’s made clear in MSDN that the flag reports on the session state, not the system state, but you’d have know that GetSystemMetrics is the right function to call in the first place in order to look up the documentation.

  2. Daniel White says:

    is `WM_ENDSESSION` the right message form of this?

    1. Erik F says:

      A program that doesn’t have a message queue (or one that just got executed) wouldn’t have received that message.

  3. Damien says:

    And of course there’s the issue of the raciness of such a check. It may be true, at the time that GetSystemMetrics was called, the session was not shutting down. But by the time you act on this information, the user may have started the log off process.

    So I’d usually recommend skipping this check and just making other parts more robust in the face of sudden logoffs.

    1. DWalker07 says:

      That’s true for almost any check you make, such as whether a file exists; whether a file does not exist; whether there is a monitor attached; the resolution of the monitor (which can change any time the user wants to change it); etc.

  4. Koro says:

    Funny how there’s both GetSystemMetrics and SystemParametersInfo, with both having roughly the same purpose.

    1. Antonio Rodríguez says:

      In fact, they have different purposes. As its name implies, GetSystemMetrics returns mainly graphical and user interface values (or “metrics”), such as default font sizes and pixel pitches, system colors and user interface settings (right- or left-handed mouse, double click delay, drag start tolerance…). SM_SHUTTINGDOWN is one of the exceptions.

  5. D.R. says:

    Isn’t there a way to be proactively notified to know whether a user is logging off?

    1. MarcK4096 says:

      WM_ENDSESSION will tell you when the session is ending.

      When your process starts up, use SetProcessShutdownParameters to set the shutdown priority to an application last shutdown value to minimize the risk of having your process closed and then having another application block the logoff. This can occur when an application has an unsaved file and the user opts to abort the logoff to save the file.

  6. IanBoyd says:

    I recently wrote a program that runs in the background and plays the user preference sounds when various events happen:

    – they logoff
    – they lock their session
    – they unlock their session
    – the system is shutting down

    You can use **WTSRegisterSessionNotification** to register to receive notifications through **WM_WTSSESSION_CHANGE** for the first 3:

    – WTS_SESSION_LOGOFF (play “WindowsLogoff”)
    – WTS_SESSION_LOCK (play “WindowsLogoff”)
    – WTS_SESSION_UNLOCK (play “WindowsUnlock”)

    And then your standard way to detect if the system is shutting down:

    – WM_ENDSESSION (play “SystemExit”)

    1. DWalker07 says:

      It’s interesting that people’s preferences can be SO different. The first thing I do when I create a new user on any of my computers, is to set the Windows sound scheme to “No sounds”. I hate, hate it when I am helping other people on their computer, and every time I do anything there’s an audible “click” sound coming from the speaker, and an “orchestra blast” plays along with error message dialog boxes. It freaks me out.

      Give me silence! And I might be listening to music anyway; sounds interfere with that. :-)

  7. skSdnW says:

    SM_SHUTTINGDOWN is 0x2000, why was there a huge jump for a couple of these values? The “normal” metrics are still < 100.

    1. Chris B says:

      This is pure conjecture, but I’d guess that whoever coded it originally said something along the lines of “SM_SHUTTINGDOWN will be the last message in this lifecycle, so i’d like for it to have the highest value. If I assign it a high enough value, we have room for other messages in between and it’ll still be last in the list. I don’t want to use the highest possible 32 bit value because more actions could appear in the future that should come after this, so I’ll put an arbitrary line in the sand. 2000 sounds good.”

    2. Simon Kissane says:

      Why the jump in metric numbers? Some wild, possibly entirely inaccurate guesses based on zero actual information (maybe Raymond can tell me how accurate my guesses are):

      Hypothesis 1: Even though SM_SHUTTINGDOWN is exposed through GetSystemMetrics, maybe it takes a very different internal code path from all the other metrics. Maybe using a different number range might trigger the different code path. If the boundary between the two ranges is high enough (0x1000 or 0x2000 or whatever), then new metrics can be added to the original range without having to change the code which decides which code path to take.

      Hypothesis 2: Maybe SM_SHUTTINGDOWN was added by a different team than that which normally adds metrics to GetSystemMetrics, and they wanted a different number range to avoid any chance of conflicts between the two teams.

      1. Brian_EE says:

        >Why the jump in metric numbers?

        Because that’s how most of the world rolls. However, in the US, we’re still stuck using imperial numbers.


        1. Brian says:

          Not quite “imperial”. The US uses a unit system that is subtly different than Britain’s traditional “imperial” system in a small number of regards, most notably volume. In the UK (and it’s former dependencies), there are 40 fluid ounces in a quart (somewhat larger than a litre) (and 160 in a gallon). In the US, it’s 32 in a quart (smaller than a litre) and 128 in a gallon. But, that’s not all, the fluid ounces are different sizes. In the US, there are 29.573 ml in an fluid ounce. In the UK, it’s 28.413 ml. You’d think that a US quart (or gallon) would be four-fifths of an Imperial quart (/gallon) – i.e. 32/40. Instead, it’s five-sixths. Go figure.

          I grew up in Canada, with grade school in the Imperial system and then I spent most of high school through to the end of university during the transition to the metric system. However, it was only during a fluid mechanics exam in engineering school that I figured out that wacky 4/5 or 5/6 ratio weirdness.

    3. Joshua says:

      Read: introduced in NT3.1-NT4.

  8. Tihiy says:

    But how to detect if shutdown is cancelled (unless polling)?

    1. By the time this metric reports that shutdown is occurring, it can no longer be cancelled.

Comments are closed.

Skip to main content