当从锁定屏幕中选择 "Switch User" 时,C# GUI 启动服务不起作用

C# GUI starting service not working when "Switch User" is selected from Lock Screen

我目前正在为我工​​作的公司编写帮助台。它提供的众多功能之一是使用“始终可用”的 GUI 重置 Windows 密码的简单方法 - 当用户锁定他们的帐户 (win+l)、注销或只是在任何之前用户已登录(在 Windows 启动到登录屏幕后立即)。

由于 ISenseLogon 接口和我从 LogonLauncher Open Source project 获得的一些代码,大部分功能都按预期工作。 GUI 是一个简单的 Windows 表单,由注册到 ISenseLogon 事件(登录、注销、DisplayLock、DisplayUnlock、ShellStart)的服务启动。

我面临的问题如下:在一个帐户被 锁定后 并且另一个用户按下锁定屏幕上的 切换用户 按钮, GUI 关闭并出现 Press ctrl + alt + delete to continue 提示,但 GUI 没有重新打开。

由于代码在所有其他情况下都有效(启动、注销、显示锁定都会生成 GUI),一定是其他一些事件导致 GUI 关闭(以编程方式,它只会被用户登录、解锁显示或服务关闭)。

服务Class:

public partial class Service1:ServiceBase {
    private const string LpDesktop = @"WinSta0\Winlogon";
    private const string appName = "C:\LoginAgent.exe";

    public Service1() {
        InitializeComponent();
        Environment.CurrentDirectory = AppDomain.CurrentDomain.BaseDirectory;
        SensLogon.DisplayLock += SensLogon_DisplayLock;
        SensLogon.DisplayUnlock += SensLogon_DisplayUnlock;
        SensLogon.Logon += SensLogon_Logon;
        SensLogon.Logoff += SensLogon_Logoff;
        SensLogon.ShellStart += SensLogon_ShellStart;
    }

    #region Cases
    protected override void OnStart(string[] args) {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("ServiceStart");
    }

    private void SensLogon_Logoff(string userName) {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("Logoff");
    }

    private void SensLogon_Logon(string userName) {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("Logon");
    }

    private void SensLogon_DisplayUnlock(string userName) {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("DisplayUnlock");
    }

    private void SensLogon_DisplayLock(string userName) {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("DisplayLock");
    }

    protected void SensLogon_ShellStart(string userName) {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("ShellStart");
    }

    protected override void OnStop() {
        var processEventThread = new Thread(ProcessSensEvent);
        processEventThread.Start("ServiceStop");
    }
    #endregion

    //Starts instance of the InjectProcess class, which starts or kills the LoginAgent process.
    private void ProcessSensEvent(object e) {
        var ip = new InjectProcess();

        if(e.ToString().Equals("Logoff") || e.ToString().Equals("ServiceStart") || e.ToString().Equals("DisplayLock") || e.ToString().Equals("ShellStart")) {
            ip.Inject(LpDesktop, appName);
            
        }
        else if(e.ToString().Equals("Logon") || e.ToString().Equals("DisplayUnlock") || e.ToString().Equals("ServiceStop"))
            ip.TerminateSystemProcess(appName);
    }
}

SensLogon:

class SensLogon {
    private static SensLogonInterop _eventCatcher;

    static SensLogon() {}

    #region Event Registers
    private static int _registerCount = 0;
    private static bool IsRegistered {
        get {
            return (_registerCount > 0);
        }
    }

    private static SensLogonEventHandler RegisterEvent(SensLogonEventHandler original, SensLogonEventHandler newDel) {
        bool shouldRegister = (original == null);
        original = original + newDel;

        if(shouldRegister) {
            if(_registerCount <= 0) {
                if(_eventCatcher == null)
                    _eventCatcher = new SensLogonInterop();
                _registerCount = 1;
            }
            else
                _registerCount++;
        }
        return original;
    }

    private static SensLogonEventHandler UnregisterEvent(SensLogonEventHandler original, SensLogonEventHandler oldDel) {
        original = original - oldDel;

        if(original == null) {
            _registerCount--;

            if(_registerCount == 0) {
                _eventCatcher.Dispose();
                _eventCatcher = null;
            }
        }
        return original;
    }
    #endregion

    #region ISensLogon Event creation
    public static void OnDisplayLock(string bstrUserName) {
        if(displayLock != null)
            displayLock(bstrUserName);
    }
    public static void OnDisplayUnlock(string bstrUserName) {
        if(displayUnlock != null)
            displayUnlock(bstrUserName);
    }
    public static void OnLogon(string bstrUserName) {
        if(logon != null)
            logon(bstrUserName);
    }
    public static void OnLogoff(string bstrUserName) {
        if(logoff != null)
            logoff(bstrUserName);
    }
    public static void OnShellStart(string bstrUserName) {
        if(shellStart != null)
            OnShellStart(bstrUserName);
    }
    #endregion

    #region Event declarations
    private static SensLogonEventHandler displayLock = null;
    private static SensLogonEventHandler displayUnlock = null;
    private static SensLogonEventHandler logon = null;
    private static SensLogonEventHandler logoff = null;
    private static SensLogonEventHandler shellStart = null;

    public static event SensLogonEventHandler DisplayLock {
        add {
            displayLock = RegisterEvent(displayLock, value);
        }
        remove {
            displayLock = UnregisterEvent(displayLock, value);
        }
    }

    public static event SensLogonEventHandler DisplayUnlock {
        add {
            displayUnlock = RegisterEvent(displayUnlock, value);
        }
        remove {
            displayUnlock = UnregisterEvent(displayUnlock, value);
        }
    }

    public static event SensLogonEventHandler Logon {
        add {
            logon = RegisterEvent(logon, value);
        }
        remove {
            logon = UnregisterEvent(logon, value);
        }
    }

    public static event SensLogonEventHandler Logoff {
        add {
            logoff = RegisterEvent(logoff, value);
        }
        remove {
            logoff = UnregisterEvent(logoff, value);
        }
    }

    public static event SensLogonEventHandler ShellStart {
        add {
            shellStart = RegisterEvent(logoff, value);
        }
        remove {
            shellStart = UnregisterEvent(logoff, value);
        }
    }
    #endregion
}

关于如何防止 GUI 关闭或在单击 切换用户 按钮后重新打开它的任何想法?

如果需要更多代码(EventSystemRegistrar、SensLogonInterop 类),我很乐意附上它,但由于一切都在为切换用户案例而努力,我怀疑是否需要它。 干杯;很抱歉 post,这个问题有点超出我的能力范围!

找到了解决方法,使用标准

CanHandleSessionChangeEvent = true

并覆盖默认的会话事件处理函数。我建议使用这些而不是 ISensLogon 接口,因为它们需要的代码少得多。 一个很好的例子可以在微软官方文档中找到:SessionChangeDescription Structure.

我希望有人觉得这有帮助,我花了几个小时试图让上面的代码工作!