当从锁定屏幕中选择“切换用户”时,C#GUI启动服务不起作用

问题描述:

我正在为我工​​作的公司编写一个帮助台。它提供的许多功能之一是使用“始终可用”的GUI来重置Windows密码的简单方法 - 当用户锁定其帐户(win + l),注销或仅在任何用户登录之前(在Windows启动到登录屏幕后)。当从锁定屏幕中选择“切换用户”时,C#GUI启动服务不起作用

由于采用了ISenseLogon接口和我从LogonLauncher Open Source project获得的一些代码,因此大部分功能都能按预期工作。 GUI是由注册到ISenseLogon事件(登录,注销,显示锁定,显示锁定,ShellStart)的服务启动的简单Windows窗体。

的问题我面对的是以下内容:后一个帐户是锁定和另一个用户按下锁定屏幕上切换用户按钮时,GUI被关闭并且按下Ctrl + Alt +删除继续提示符出现,但GUI不会重新打开。由于代码在所有其他情况下工作(引导,注销,显示锁定,所有生成GUI),其他一些事件必须导致GUI关闭(以编程方式它只能被用户登录,解锁显示或服务关闭)。

服务类:

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类),我会很乐意附加它,但是因为一切都在切换用户案例,我怀疑它是需要的。 干杯;并且对于这篇长文章感到抱歉,这个问题有点出乎我的意料!

+0

在任何人对此提出异议之前,微软没有“通缉”,或潜在的安全隐患:我知道这一切,谢谢。除了我们的技术支持为被阻止的用户分配临时密码之外,这是使密码重置随时可用的唯一方法。 – Praetorian

找到解决方法:使用标准

CanHandleSessionChangeEvent = true 

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

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