当从锁定屏幕中选择“切换用户”时,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类),我会很乐意附加它,但是因为一切都在切换用户案例,我怀疑它是需要的。 干杯;并且对于这篇长文章感到抱歉,这个问题有点出乎我的意料!
找到解决方法:使用标准
CanHandleSessionChangeEvent = true
,并覆盖默认会话事件处理函数。我建议使用这些而不是ISensLogon
接口,因为它们需要的代码少得多。 一个很好的例子可以在Microsoft官方文档中找到:SessionChangeDescription Structure。
我希望有人认为这有帮助,我花了几个小时试图让上面的代码工作!
在任何人对此提出异议之前,微软没有“通缉”,或潜在的安全隐患:我知道这一切,谢谢。除了我们的技术支持为被阻止的用户分配临时密码之外,这是使密码重置随时可用的唯一方法。 – Praetorian