Search code examples
c#wpfwinapiwindows-7shutdown

Delay shutdown and lockscreen


Project:

I currently devellop an application to warn the user if he leaves (lockscreen or shutdown) his workplace and has left his smartcard in the reader.

I was able to detect through the use of the WinAPI (WinSCard.dll) if the smarcard is currently in the reader.

Problem:

I read (correct me if this is wrong) it is not possible for an application to delay the lockscreen so I currently focus on delaying the shutdown.

The problem I am having now is that I need to delay the ongoing shutdown to warn the user that he left his smartcard.

I try to use ShutdownBlockReasonCreate to delay the shutdown for at least the 5 seconds Windows so generously lets me. The idea was that if the user removes his smartcard my application calls ShutdownBlockReasonDestroy to continue the shutdown.

I implemented the two methods like so:

[DllImport("User32.dll", EntryPoint = "ShutdownBlockReasonCreate", 
           CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool ShutdownBlockReasonCreate(
    [In()]IntPtr wndHandle,
    [In()]string reason);

[DllImport("User32.dll", EntryPoint = "ShutdownBlockReasonDestroy", 
           CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern bool ShutdownBlockReasonDestroy(
    [In()]IntPtr wndHandle);

furthermore I use GetLastError to check for errors which I implemented this way:

[DllImport("Kernel32.dll", EntryPoint = "GetLastError", 
           CharSet = CharSet.Unicode, SetLastError = true)]
internal static extern int GetLastError();

Now the strange thing is that if I create the reason

WinAPIMethoden.ShutdownBlockReasonCreate(
      new WindowInteropHelper(Application.Current.MainWindow).Handle, 
                              "Smartcard still in reader!");

and then display the error

MessageBox.Show(WinAPIMethoden.GetLastError().ToString("X"));

it shows 0 which stands for ERROR_SUCCESS.

So far everything seems great. Now if I try to shut the PC down there is no sign whatsoever that my application has requested that the PC should not be shut down right now.

Question:

What am I doing wrong so that ShutdownBlockReasonCreate does not work as intended?

Or is there maybe a better way to prevent the user from shutting the PC down if his smartcard is still in like preventing him from initiating the shutdown while his card is in or something like that?

tl;dr:

I try to prevent shutdown while user has his smartcard in the reader. I use ShutdownBlockReasonCreate but it doesnt seem to work although there is no error.

Solution:

The accepted answer lead me to the solution of the problem.

You have to create the cancle reason AND subscribe a handler to SystemEvents.SessionEnding. This handler then has to set e.Cancel to true

void SystemEvents_SessionEnding(object sender, SessionEndingEventArgs e)
{
    if (mgr.state == SmartcardState.Inserted)
    {
        e.Cancel = true;
    }
}

To execute the programm on shutdown I addet it to the shutdown scripts using gpendit.msc. The programm then gets executed AFTER all programs have been terminated. Looks really weird but does the job.


Solution

  • Please take a look at these posts that could help you with your situation:

    How to abort shutdown in Windows (XP|Vista) programatically?

    Aborting computer shutdown from windows service

    Prevent windows Shutdown with CANCEL option C#

    Is there a way in c# to detect a Windows shutdown/logoff and cancel that action (after asking the user)