好的。这是一个有点虚荣的应用程序,但我今天在工作中遇到了一种情况,我在培训班上,机器设置为每 10 分钟锁定一次。好吧,如果培训师对谈话感到兴奋——而不是更换幻灯片——机器就会锁定。
我想写一个很小的应用程序,它只有一个任务栏图标,除了每 4 分钟将鼠标移动 1 个像素之外什么都不做。
我可以用 Delphi(我的强语言)以 3 种方式做到这一点,但我正在转向 C# 工作,我想知道那里阻力最小的路径。
对于 C# 3.5
没有 notifyicon 因此您需要在任务管理器中手动终止此应用程序
using System;
using System.Drawing;
using System.Windows.Forms;
static class Program
{
static void Main()
{
Timer timer = new Timer();
// timer.Interval = 4 minutes
timer.Interval = (int)(TimeSpan.TicksPerMinute * 4 / TimeSpan.TicksPerMillisecond);
timer.Tick += (sender, args) => { Cursor.Position = new Point(Cursor.Position.X + 1, Cursor.Position.Y + 1); };
timer.Start();
Application.Run();
}
}
执行此操作的“正确”方法是响应 WM_SYSCOMMAND 消息。在 C# 中,这看起来像这样:
protected override void WndProc(ref Message m)
{
// Abort screensaver and monitor power-down
const int WM_SYSCOMMAND = 0x0112;
const int SC_MONITOR_POWER = 0xF170;
const int SC_SCREENSAVE = 0xF140;
int WParam = (m.WParam.ToInt32() & 0xFFF0);
if (m.Msg == WM_SYSCOMMAND &&
(WParam == SC_MONITOR_POWER || WParam == SC_SCREENSAVE)) return;
base.WndProc(ref m);
}
根据MSDN,如果在 Vista 或更高版本上的策略启用了屏幕保护程序密码,这将不起作用。大概以编程方式移动鼠标也被忽略了,尽管我没有对此进行测试。
当我在家工作时,我将鼠标线系在一个左右摆动的桌面风扇上。它使鼠标保持移动并防止工作站进入睡眠状态。
像这样的东西应该可以工作(不过,你会想要改变间隔)。
public Form1()
{
InitializeComponent();
Timer Every4Minutes = new Timer();
Every4Minutes.Interval = 10;
Every4Minutes.Tick += new EventHandler(MoveNow);
Every4Minutes.Start();
}
void MoveNow(object sender, EventArgs e)
{
Cursor.Position = new Point(Cursor.Position.X - 1, Cursor.Position.Y - 1);
}
(Windows 10 / .Net 5 / C# 9.0)
而不是假装活动,你可以
通知系统它正在使用,从而防止系统在应用程序运行时进入睡眠或关闭显示器
使用SetThreadExecutionState,如PInvoke.net上所述:
using System;
using System.Runtime.InteropServices;
using System.Threading;
namespace VanityApp
{
internal static class Program
{
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern ExecutionState SetThreadExecutionState(ExecutionState esFlags);
[Flags]
private enum ExecutionState : uint
{
ES_AWAYMODE_REQUIRED = 0x00000040,
ES_CONTINUOUS = 0x80000000,
ES_DISPLAY_REQUIRED = 0x00000002,
ES_SYSTEM_REQUIRED = 0x00000001
}
private static void Main()
{
using AutoResetEvent autoResetEvent = new AutoResetEvent(false);
using Timer timer = new Timer(state => SetThreadExecutionState(ExecutionState.ES_AWAYMODE_REQUIRED | ExecutionState.ES_CONTINUOUS | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_SYSTEM_REQUIRED), autoResetEvent, 0, -1);
autoResetEvent.WaitOne();
}
}
}
Timer 是一个System.Threading.Timer,具有方便的构造函数,它使用AutoResetEvent.WaitOne()来避免立即退出。
Raf 为 Win10 世界的问题提供了一个优雅的答案,但不幸的是,他的 autoResetEvent.WaitOne() 指令阻塞了线程,因此它必须在自己的单独线程中。
对我有用的东西实际上可以在主线程中运行,代码不必放在 Main() 方法中,您实际上可以有一个按钮来启用此功能,一个按钮来禁用它。
首先,您当然需要定义执行状态标志:
[Flags]
private enum ExecutionState : uint // options to control monitor behavior
{
ES_AWAYMODE_REQUIRED = 0x00000040, // prevent idle-to-sleep
ES_CONTINUOUS = 0x80000000, // allow monitor power down
ES_DISPLAY_REQUIRED = 0x00000002, // prevent monitor power down
ES_SYSTEM_REQUIRED = 0x00000001 // keep system awake
}
现在,每当您想保持系统唤醒并阻止显示器关闭或空闲到睡眠时,您需要做的就是执行一个命令:
SetThreadExecutionState(ExecutionState.ES_AWAYMODE_REQUIRED | ExecutionState.ES_CONTINUOUS | ExecutionState.ES_DISPLAY_REQUIRED | ExecutionState.ES_SYSTEM_REQUIRED);
然后,如果您想撤消此操作并将系统返回到其原始执行状态,只需发出以下命令:
SetThreadExecutionState(ExecutionState.ES_CONTINUOUS);
请记住,每个命令都会返回之前的执行状态,这意味着,当您第一次更改此状态时,您可以在本地缓存返回的值,并在您想要恢复之前的状态时使用它。