当从锁定屏幕中选择 "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.
我希望有人觉得这有帮助,我花了几个小时试图让上面的代码工作!
我目前正在为我工作的公司编写帮助台。它提供的众多功能之一是使用“始终可用”的 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.
我希望有人觉得这有帮助,我花了几个小时试图让上面的代码工作!