系统事件 (SessionEnding) 未按预期工作
System Events (SessionEnding) not working as expected
我制作了一个简单的 windows 应用程序(虽然没有任何表单)并且在其中我使用 SessionEnding 在 OS 关闭之前根据 C# Cookbook 中的 recipe19.1 做一些事情(我已修改,因为 Debug 无论如何都不起作用)
应用程序在启动时创建一个文本文件(它确实如此),然后当任何事件发生时应该创建另一个空白文本文件。
代码在下面,它没有按预期工作。事件发生时不会创建任何内容。谁能告诉我这有什么问题吗?
作为旁注,这次我尝试了其他示例,使用 the documentation 中所述的 WndProc 覆盖,它似乎有效,但我不确定如何将其应用于没有表单的应用程序
代码
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Threading;
namespace NoConsoleApp2
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
RegisterForSystemEvents();
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Onstart.txt");
bool keepRunning = true;
Debug.WriteLine("Start");
for (int i = 0; i < 100 && keepRunning; i++)
{
Thread.Sleep(1000);
}
Debug.WriteLine("End");
}
public static void RegisterForSystemEvents()
{
//Always get the final notification when the event thread is shutting down
//so we can unregister.
SystemEvents.EventsThreadShutdown += new EventHandler(OnEventsThreadShutdown);
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(OnPowerModeChanged);
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(OnSessionSwitch);
SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
SystemEvents.SessionEnded += new SessionEndedEventHandler(OnSessionEnded);
}
private static void UnregisterFromSystemEvents()
{
SystemEvents.EventsThreadShutdown -= new EventHandler(OnEventsThreadShutdown);
SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(OnPowerModeChanged);
SystemEvents.SessionSwitch -= new SessionSwitchEventHandler(OnSessionSwitch);
SystemEvents.SessionEnding -= new SessionEndingEventHandler(OnSessionEnding);
SystemEvents.SessionEnded -= new SessionEndedEventHandler(OnSessionEnded);
}
/* Notifies you when the thread that is distributing the events from the SystemEvents class is
* shutting down so that we can unregister events on the SystemEvents class
*/
private static void OnEventsThreadShutdown(object sender, EventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "END.txt");
Debug.WriteLine("System event thread is shutting down, no more notifications");
//Unregister all our events as the notification thread is goin away
UnregisterFromSystemEvents();
}
/* Triggers when the user suspends or resumes the system from a suspended state
*/
private static void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "power.txt");
switch (e.Mode)
{
case PowerModes.Resume:
Debug.WriteLine("PowerMode: OS is resuming from suspended state");
break;
case PowerModes.StatusChange:
Debug.WriteLine("PowerMode: There was a change relating to the power supply (weak battery, unplug, etc...)");
break;
case PowerModes.Suspend:
Debug.WriteLine("PowerMode: OS is about to be suspended");
break;
}
}
/* Triggered by a change in the logged-on user
*/
private static void OnSessionSwitch(object sender, SessionSwitchEventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "sessionswitch.txt");
switch (e.Reason)
{
case SessionSwitchReason.ConsoleConnect:
Debug.WriteLine("Session connected from the console");
break;
case SessionSwitchReason.ConsoleDisconnect:
Debug.WriteLine("Session disconnected from the console");
break;
case SessionSwitchReason.RemoteConnect:
Debug.WriteLine("Remote Session connected");
break;
case SessionSwitchReason.RemoteDisconnect:
Debug.WriteLine("Remote Session disconnected");
break;
case SessionSwitchReason.SessionLock:
Debug.WriteLine("Session has been locked");
break;
case SessionSwitchReason.SessionLogoff:
Debug.WriteLine("User was logged off from a session");
break;
case SessionSwitchReason.SessionLogon:
Debug.WriteLine("User has logged on to a session");
break;
case SessionSwitchReason.SessionRemoteControl:
Debug.WriteLine("Session changed to or from remote status");
break;
case SessionSwitchReason.SessionUnlock:
Debug.WriteLine("Session has been unlocked");
break;
}
}
/* Triggered when the user is trying to log off or shut down the system
*/
private static void OnSessionEnding(object sender, SessionEndingEventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "sessionend.txt");
//True to cancel the user request to end the session, false otherwise
e.Cancel = false;
switch(e.Reason)
{
case SessionEndReasons.Logoff:
Debug.WriteLine("Session ending as the user is logging off");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Logoff.txt");
break;
case SessionEndReasons.SystemShutdown:
Debug.WriteLine("Session ending as the OS is shutting down");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Shutdown.txt");
break;
}
}
/* Triggered when the user is actually logging off or shutting down the system
*/
private static void OnSessionEnded(object sender, SessionEndedEventArgs e )
{
switch(e.Reason)
{
case SessionEndReasons.Logoff:
Debug.WriteLine("Session ended as the user is logging off");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Loggedoff.txt");
break;
case SessionEndReasons.SystemShutdown:
Debug.WriteLine("Session ended as the OS is shutting down");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Shutted.txt");
break;
}
}
}
}
编辑:
我被告知我应该使用 Application.Run 并且事件正在响应。但是我假设 运行 形成一个循环,所以我想知道在哪里放置我自己的逻辑(在这个例子中是 for 循环)
static void Main()
{
RegisterForSystemEvents();
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Onstart.txt");
bool keepRunning = true;
Debug.WriteLine("Start");
Application.Run(); //this activates the events
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "GoFOrloop.txt");
for (int i = 0; i < 100 && keepRunning; i++)
{
Thread.Sleep(1000);
}
Debug.WriteLine("End");
}
在这种情况下,文件 GoForLoop.txt 永远不会创建(意味着循环本身永远不会执行)
编辑2:
我已经在 EDIT 中尝试了解决方案并且它有效(事件被触发)但是主要逻辑(在这种情况下是循环)不起作用所以我尝试了第二个建议使用应用程序上下文。遗憾的是这次虽然循环有效,但事件不再触发:(
class Context : ApplicationContext
{
public Context()
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "GoFOrLoop.txt");
for (int i = 0; i < 60; i++)
{
// Console.WriteLine("Number: " + i);
Thread.Sleep(1000);
}
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "end.txt");
Debug.WriteLine("End");
// Environment.Exit(1);
ExitThread();
}
}
主要
[STAThread]
static void Main()
{
/* Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
*/
RegisterForSystemEvents();
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Onstart.txt");
// bool keepRunning = true;
Debug.WriteLine("Start");
// Application.Run(); //this works
Application.Run(new Context()); //this DOES NOT work
}
Windows 处理事件的应用程序使用消息循环。
在您的代码中,您没有 运行 消息循环。
添加到Main
方法:
Application.Run();
This 为您的应用启动消息循环。
我制作了一个简单的 windows 应用程序(虽然没有任何表单)并且在其中我使用 SessionEnding 在 OS 关闭之前根据 C# Cookbook 中的 recipe19.1 做一些事情(我已修改,因为 Debug 无论如何都不起作用)
应用程序在启动时创建一个文本文件(它确实如此),然后当任何事件发生时应该创建另一个空白文本文件。 代码在下面,它没有按预期工作。事件发生时不会创建任何内容。谁能告诉我这有什么问题吗?
作为旁注,这次我尝试了其他示例,使用 the documentation 中所述的 WndProc 覆盖,它似乎有效,但我不确定如何将其应用于没有表单的应用程序
代码
using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.Threading;
namespace NoConsoleApp2
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
RegisterForSystemEvents();
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Onstart.txt");
bool keepRunning = true;
Debug.WriteLine("Start");
for (int i = 0; i < 100 && keepRunning; i++)
{
Thread.Sleep(1000);
}
Debug.WriteLine("End");
}
public static void RegisterForSystemEvents()
{
//Always get the final notification when the event thread is shutting down
//so we can unregister.
SystemEvents.EventsThreadShutdown += new EventHandler(OnEventsThreadShutdown);
SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(OnPowerModeChanged);
SystemEvents.SessionSwitch += new SessionSwitchEventHandler(OnSessionSwitch);
SystemEvents.SessionEnding += new SessionEndingEventHandler(OnSessionEnding);
SystemEvents.SessionEnded += new SessionEndedEventHandler(OnSessionEnded);
}
private static void UnregisterFromSystemEvents()
{
SystemEvents.EventsThreadShutdown -= new EventHandler(OnEventsThreadShutdown);
SystemEvents.PowerModeChanged -= new PowerModeChangedEventHandler(OnPowerModeChanged);
SystemEvents.SessionSwitch -= new SessionSwitchEventHandler(OnSessionSwitch);
SystemEvents.SessionEnding -= new SessionEndingEventHandler(OnSessionEnding);
SystemEvents.SessionEnded -= new SessionEndedEventHandler(OnSessionEnded);
}
/* Notifies you when the thread that is distributing the events from the SystemEvents class is
* shutting down so that we can unregister events on the SystemEvents class
*/
private static void OnEventsThreadShutdown(object sender, EventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "END.txt");
Debug.WriteLine("System event thread is shutting down, no more notifications");
//Unregister all our events as the notification thread is goin away
UnregisterFromSystemEvents();
}
/* Triggers when the user suspends or resumes the system from a suspended state
*/
private static void OnPowerModeChanged(object sender, PowerModeChangedEventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "power.txt");
switch (e.Mode)
{
case PowerModes.Resume:
Debug.WriteLine("PowerMode: OS is resuming from suspended state");
break;
case PowerModes.StatusChange:
Debug.WriteLine("PowerMode: There was a change relating to the power supply (weak battery, unplug, etc...)");
break;
case PowerModes.Suspend:
Debug.WriteLine("PowerMode: OS is about to be suspended");
break;
}
}
/* Triggered by a change in the logged-on user
*/
private static void OnSessionSwitch(object sender, SessionSwitchEventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "sessionswitch.txt");
switch (e.Reason)
{
case SessionSwitchReason.ConsoleConnect:
Debug.WriteLine("Session connected from the console");
break;
case SessionSwitchReason.ConsoleDisconnect:
Debug.WriteLine("Session disconnected from the console");
break;
case SessionSwitchReason.RemoteConnect:
Debug.WriteLine("Remote Session connected");
break;
case SessionSwitchReason.RemoteDisconnect:
Debug.WriteLine("Remote Session disconnected");
break;
case SessionSwitchReason.SessionLock:
Debug.WriteLine("Session has been locked");
break;
case SessionSwitchReason.SessionLogoff:
Debug.WriteLine("User was logged off from a session");
break;
case SessionSwitchReason.SessionLogon:
Debug.WriteLine("User has logged on to a session");
break;
case SessionSwitchReason.SessionRemoteControl:
Debug.WriteLine("Session changed to or from remote status");
break;
case SessionSwitchReason.SessionUnlock:
Debug.WriteLine("Session has been unlocked");
break;
}
}
/* Triggered when the user is trying to log off or shut down the system
*/
private static void OnSessionEnding(object sender, SessionEndingEventArgs e)
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "sessionend.txt");
//True to cancel the user request to end the session, false otherwise
e.Cancel = false;
switch(e.Reason)
{
case SessionEndReasons.Logoff:
Debug.WriteLine("Session ending as the user is logging off");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Logoff.txt");
break;
case SessionEndReasons.SystemShutdown:
Debug.WriteLine("Session ending as the OS is shutting down");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Shutdown.txt");
break;
}
}
/* Triggered when the user is actually logging off or shutting down the system
*/
private static void OnSessionEnded(object sender, SessionEndedEventArgs e )
{
switch(e.Reason)
{
case SessionEndReasons.Logoff:
Debug.WriteLine("Session ended as the user is logging off");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Loggedoff.txt");
break;
case SessionEndReasons.SystemShutdown:
Debug.WriteLine("Session ended as the OS is shutting down");
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Shutted.txt");
break;
}
}
}
}
编辑:
我被告知我应该使用 Application.Run 并且事件正在响应。但是我假设 运行 形成一个循环,所以我想知道在哪里放置我自己的逻辑(在这个例子中是 for 循环)
static void Main()
{
RegisterForSystemEvents();
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Onstart.txt");
bool keepRunning = true;
Debug.WriteLine("Start");
Application.Run(); //this activates the events
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "GoFOrloop.txt");
for (int i = 0; i < 100 && keepRunning; i++)
{
Thread.Sleep(1000);
}
Debug.WriteLine("End");
}
在这种情况下,文件 GoForLoop.txt 永远不会创建(意味着循环本身永远不会执行)
编辑2: 我已经在 EDIT 中尝试了解决方案并且它有效(事件被触发)但是主要逻辑(在这种情况下是循环)不起作用所以我尝试了第二个建议使用应用程序上下文。遗憾的是这次虽然循环有效,但事件不再触发:(
class Context : ApplicationContext
{
public Context()
{
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "GoFOrLoop.txt");
for (int i = 0; i < 60; i++)
{
// Console.WriteLine("Number: " + i);
Thread.Sleep(1000);
}
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "end.txt");
Debug.WriteLine("End");
// Environment.Exit(1);
ExitThread();
}
}
主要
[STAThread]
static void Main()
{
/* Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
*/
RegisterForSystemEvents();
System.IO.File.Create(AppDomain.CurrentDomain.BaseDirectory + "Onstart.txt");
// bool keepRunning = true;
Debug.WriteLine("Start");
// Application.Run(); //this works
Application.Run(new Context()); //this DOES NOT work
}
Windows 处理事件的应用程序使用消息循环。 在您的代码中,您没有 运行 消息循环。
添加到Main
方法:
Application.Run();
This 为您的应用启动消息循环。