如何在 C# 中立即强制显示器进入省电模式?

Posted

技术标签:

【中文标题】如何在 C# 中立即强制显示器进入省电模式?【英文标题】:How can I force the monitor into power saving mode immediately in C#? 【发布时间】:2016-06-22 23:35:51 【问题描述】:

我有两台显示器 (HP EliteDisplay E190i),都连接到两台计算机 (2x VGA + DP)。 这些显示器还支持 DVI,所以每次我想在计算机之间切换时,我都必须浏览显示器的菜单,而不是使用愚蠢的切换按钮。我以前的显示器比较笨,而且切换真的很容易,但我就是不习惯整个导航——它经常让人困惑……

这就是交易 - 我希望能够通过执行命令在计算机之间快速切换。显然这不能直接完成(计算机没有以任何方式相互连接),但是当显示器进入省电模式(或操作系统关闭它们时)时,显示器开始扫描可用输入。这样他们就可以锁定到另一台计算机并解决问题。

足够的介绍,我已经尝试过this solution,效果很好,但并不完美:

它有一个淡出动画,需要几秒钟才能真正关闭显示器 在上述淡出动画期间,我必须不要触摸鼠标/键盘,否则会被取消

我尝试在让显示器进入睡眠状态之前根据this answer 禁用输入,然后在 5 秒后重新启用它,但这也不起作用,因为:

它要求我以管理员权限运行应用程序,否则输入不会被阻止 即使在以管理员权限运行时输入被阻止,我仍然可以在淡出动画期间移动鼠标或按键盘上的某些键来取消它(即使指针没有移动,或者键盘输入是忽略)。

这是我的代码:

[DllImport("user32.dll")]
private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);

[DllImport("user32.dll")]
private static extern int BlockInput(int fBlockIt);

static void Main()

    SendMessage(0xFFFF, 0x112, 0xF170, 2);
    try
    
        int result = BlockInput(1);
        Console.WriteLine(result);
        Thread.Sleep(5000);
    
    finally
    
        BlockInput(0);
    

我在两台计算机上都使用 Windows 7 Enterprise x64。

有什么办法可以让整个仪式顺利进行吗?

【问题讨论】:

那么第二个解决方案的问题是您无法以管理员权限运行它? 不,当我以管理员权限运行时输入被阻止,正如预期的那样。然而,即使输入被阻止,移动鼠标或按下我的键盘上的一个键(物理上)取消了淡出动画 - 即使 pointer 没有移动并且键盘输入被忽略(键被按下,但没有在记事本中输入文本)。 在发送睡眠命令之前阻塞输入怎么样 @RomanCoo 也没有用。 考虑过购买硬件 KVM 切换器吗? 【参考方案1】:

我不得不编辑我的答案,因为愚蠢地我没有完整阅读您的问题。

我建议创建一个应用程序,它位于两台计算机上,通过一个简单的 TCP 服务器/客户端套接字相互发送请求。

这将允许您,例如,按下 PC 1 上的按钮,使其进入睡眠状态并对显示器执行相同操作,并向 PC 2 发送消息以唤醒并窃取显示器输入。就这个速度而言,我想这取决于几个变量,但这可以在以后处理。

TCP 客户端/服务器:

using System;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;

namespace ClientSocket_System
  
   class tcpClientSocket
   

    #region Global Variables

    TcpClient tcpService;
    IPEndPoint serverEndPoint;
    NetworkStream netStream;

    #endregion


    public void commToServer()
    
        tcpService = new TcpClient();
        serverEndPoint = new IPEndPoint(IPAddress.Parse("xxx.xxx.xxx.xx"), xxxx); //Enter IP address of computer here along with a port number if needed
        try
        
            tcpService.Connect(serverEndPoint);
            netStream = tcpService.GetStream();
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes("SwitchComputers");
            netStream.Write(buffer, 0, buffer.Length);
            netStream.Flush();
            tcpService.Close();
        
        catch(Exception ex)
        
        
    
   

还有服务器:

using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.IO;

namespace ClientSocket_System

    class tcpServerTerminal
    



        private TcpListener tcpListener;
        private Thread listenThread;
        private TcpClient tcpService;
        string msgFromClient;



        public void ServerStart()
        
            tcpListener = new TcpListener(IPAddress.Any, 5565);
            listenThread = new Thread(new ThreadStart(ListenForClients));
            listenThread.Start();
        

        public void ListenForClients()
        
            tcpListener.Start();

            while (true)
            
                //blocks until a client has connected to the server
                TcpClient client = this.tcpListener.AcceptTcpClient();

                //create a thread to handle communication 
                //with connected client
                Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                clientThread.Start(client);
            
        

        public void HandleClientComm(object client)
        
            tcpService = (TcpClient)client;

            NetworkStream netStream = tcpService.GetStream();

            byte[] message = new byte[4096];
            int bytesRead;

            while (true)
            
                bytesRead = 0;

                try
                
                    //blocks until a client sends a message
                    bytesRead = netStream.Read(message, 0, 4096);
                
                catch
                
                    //a socket error has occured
                    break;
                

                if (bytesRead == 0)
                
                    //the client has disconnected from the server
                    break;
                

                //message has successfully been received
                ASCIIEncoding encoder = new ASCIIEncoding();

                msgFromClient = encoder.GetString(message, 0, bytesRead);

                if (msgFromClient == "SwitchComputers")
                

                    //RUN CODE HERE TO ACTION PC SLEEP AND MONITOR SLEEP

                    msgFromClient = null;
                
            
        

        public void SocketSend()
        
            NetworkStream streamToClient = tcpService.GetStream();
            ASCIIEncoding encoder = new ASCIIEncoding();
            byte[] buffer = encoder.GetBytes("SwitchComputers");

            streamToClient.Write(buffer, 0, buffer.Length);
            streamToClient.Flush();
        

    

也许是这样,至少值得研究一下,上面的代码并没有完全完善,但它允许您通过家庭网络控制两台计算机的操作,从而允许同时执行特定命令:睡眠/唤醒等。

希望这能给你一个新的调查方向。

另外,我认为将阻止输入的代码格式化为最佳做法:

[return: MarshalAs(UnmanagedType.Bool)]
[DllImport("user32.dll", CharSet=CharSet.Auto, ExactSpelling=true)]
public static extern bool BlockInput([In, MarshalAs(UnmanagedType.Bool)] bool fBlockIt);

【讨论】:

这不行。计算机没有以任何方式相互连接(在我的问题中也提到过)。此外,我主要是RUN CODE HERE TO ACTION PC SLEEP AND MONITOR SLEEP部分遇到问题,而不是计算机之间的通信。 抱歉,我假设它们至少都连接到屋内的路由器或调制解调器。我建议这样做的原因主要是因为当一台计算机处于睡眠状态而另一台计算机唤醒时,它会自动将数据推送到可视引脚,这是窃取显示的内容,因此这将是解决您的问题的一种有趣方式。话虽这么说,但是当我回到家时,我将提交一些代码,用于阻止来自计算机的视觉信号到我的显示器,我们可以看看它是否比您当前的解决方案更好。

以上是关于如何在 C# 中立即强制显示器进入省电模式?的主要内容,如果未能解决你的问题,请参考以下文章

Deepin电源管理和开机自动执行指令进入省电模式(CPUPOWER)

我们怎样才能让 iPhone 屏幕保持活跃,而不是进入省电模式?

如何强制我的 C# 应用程序立即确认 TCP 数据报?

如何用cmd命令强制删除文件夹?

如何检查我的分机是不是处于省电模式?

如何强制 iOS 应用以纵向模式启动