打开/关闭显示器

61

通过代码(C#)可以编程地开关显示器吗?


4
在你的问题中加上“以编程方式”,可能会避免被点踩。这是我的个人意见 :-) - Newtopian
5
每个人都认为自己比 OP 更聪明,知道他/她的问题。Vinoth 没有问如何使用按钮来完成,他/她问的是是否可以使用代码实现...... - Inisheer
3
@Binary,我不同意你的观点。这并不是恶意灌水,你应该回答问题而不是试图给这个简单的问题投反对票。 - Tom Smykowski
安东尼,我明白了,但是我是编辑这个问题的人。 - Inisheer
添加交叉引用:https://dev59.com/HUzSa4cB1Zd3GeqPrPuH - Marc Gravell
显示剩余6条评论
9个回答

25

你有没有试过谷歌一下?

第一个结果是:http://www.codeproject.com/KB/cs/Monitor_management_guide.aspx

我不意外你需要使用一些由Windows提供的DLL文件。

(我猜你需要C#的解决方案,因为这是你唯一添加的标签)。

编辑于2013年2月8日:

有人提到该解决方案在Windows 7和8下不再适用。那么这里是一个可以在Windows 7下很好地工作的解决方案,尚未尝试过Windows 8。

http://cocoa.ninja/posts/Turn-off-your-monitor-in-Csharp.html

namespace MonitorOff {

    public enum MonitorState {
        MonitorStateOn = -1,
        MonitorStateOff = 2,
        MonitorStateStandBy = 1
    }

    public partial class Form1 : Form {
        [DllImport("user32.dll")]
        private static extern int SendMessage(int hWnd, int hMsg, int wParam, int lParam);

        public Form1() {
            InitializeComponent();
            SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
        }

        void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e) {
            SetMonitorInState(MonitorState.MonitorStateOff);
        }

        private void button1_Click(object sender, EventArgs e) {
            SetMonitorInState(MonitorState.MonitorStateOff);
        }

        private void SetMonitorInState(MonitorState state) {
            SendMessage(0xFFFF, 0x112, 0xF170, (int)state);
        }
    }
}

你知道这个答案是在2009年给出的吗? - Wim Haanstra
34
我明白,但由于这个答案在2013年仍然在谷歌排名靠前,我想其他像我一样的人将会看到它并下载并尝试该项目,只有发现它不适用于2009年之后的Windows操作系统。 我试图为他们节省那10多分钟的时间。我绝不会削弱你的答案所提供的价值,我相信它帮助了成千上万的人,我只是想让人们知道情况已经改变了。 - Quinxy von Besiex
第二个链接现在已经失效。 - Pieter Geerkens
请查看此类似答案:http://stackoverflow.com/a/42393472/1468842 - Opmet
1
在 Windows 10 中,这会将所有显示器都置于“睡眠”状态,直到我移动鼠标。 - t0b4cc0
显示剩余2条评论

20

按下开关按钮


如果你想在代码中实现,Win32 API似乎可以达成这个目的:

SendMessage hWnd, WM_SYSCOMMAND, SC_MONITORPOWER, param

其中 WM_SYSCOMMAND = 0x112,SC_MONITORPOWER = 0xF170,param表示将显示器置于的模式: -1:打开 2:关闭 1:能源节省模式

hWnd可以是任何窗口的句柄 - 所以如果你有一个表单,类似这样的东西应该可以工作。

int WM_SYSCOMMAND = 0x112;
int SC_MONITORPOWER = 0xF170;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

public static void Main(string[] args)
{
    Form f = new Form();
    bool turnOff = true;   //set true if you want to turn off, false if on
    SendMessage(f.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)(turnOff ? 2 : -1));
}

注意,我实际上没有尝试过这个...


3
如果停电了,灯光可能太暗无法看到开关键,因此您可能需要准备手电筒以应对这种情况。 - S.Lott
1
我非常想回答这个问题,+1 :-) - Newtopian
3
关闭显示器的功能很好用,但是我似乎无法将其打开。 - Quinxy von Besiex
3
在Windows 10中关闭显示器是可行的,但尝试重新打开它会导致它短暂地亮起(约一秒钟),然后再次变黑。 - Albert MN.
1
如果连接了两个显示器,是否可以打开/关闭第一个和第二个显示器? - Ωmega
请看我对顶部答案的评论 - 这种技术是一种hack,不应该使用,因为它发送了一个被记录为只能由系统发送的消息。唯一值得注意的是,至少这个答案没有尝试将消息广播到所有窗口。 - zhuman - MSFT

19

上面的回答https://dev59.com/hnRB5IYBdhLWcg3wH0SW#713504非常适用于关闭Windows 7/8的显示器,但不适用于唤醒它。在这些系统上,您需要执行类似于这样的hackish操作(如发现的https://dev59.com/GGcs5IYBdhLWcg3wynDD#14171736):

[DllImport("user32.dll")]
static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);

private const int MOUSEEVENTF_MOVE = 0x0001;

private void Wake(){
mouse_event(MOUSEEVENTF_MOVE, 0, 1, 0, UIntPtr.Zero);
Sleep(40);
mouse_event(MOUSEEVENTF_MOVE, 0, -1, 0, UIntPtr.Zero);
}

这个解决方案在 Windows Vista 上使用两个显示器非常有效。 - Doug Null
只是个人意见,mouse_event无法使MS Office Communicator保持“活动”状态,只有鼠标点击和keybd_event才能实现,因此最好实际使用这些方法或者移动鼠标超过一个像素,以防止有人认为“当有人碰到桌子时我们应该停止打开显示器”。 - Motomotes
3
上面的被接受的答案在Windows 10上对我没用。那个被接受的答案会让屏幕短暂地亮起,但然后它就会再次关闭。这是在Surface Pro上发生的。一旦我采用了这个解决方案,它就非常好用。有点取巧,但它能工作,对于我约会的女孩来说已经足够了! - jaredbaszler
1
如果你在寻找一个在 .bat 文件或任务计划程序中实现此功能的方法(比如说),而不是从 C# 中实现,那么这个回答:https://superuser.com/a/1371383 提供了一种方法。你可以使用以下代码触发一个水平鼠标移动 40px 的操作,如果显示器由于长时间闲置而关闭,则会重新打开:powershell (Add-Type '[DllImport(\"user32.dll\")]^public static extern void mouse_event(uint dwFlags, int dx, int dy, uint dwData, int dwExtraInfo);' -Name user32 -PassThru)::mouse_event(1,40,0,0,0) - Doin

18

对于希望在控制台应用上实现此功能的用户:

using System;
using System.Runtime.InteropServices;
using System.Timers;

namespace TurnScreenOFF
{
    class Program
    {
        private static int WM_SYSCOMMAND = 0x0112;
        private static uint SC_MONITORPOWER = 0xF170;

        public static void Main(string[] args)
        {
            SendMessage(GetConsoleWindow(), WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)2);
        }

        [DllImport("kernel32.dll")]
        static extern IntPtr GetConsoleWindow();

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);
    }
}

已适配并测试。在Windows 8上百分之百工作。


4
在非控制台应用程序中,不需要调用GetConsoleWindow或获取GUI hwnd,只需使用HWND_BROADCAST消息(SendMessage(New IntPtr(0xFFFF)...)即可。请注意,此翻译仅供参考,如有歧义,请以原文为准。 - ElektroStudios
1
适用于Windows 10 Home,使用HWND_BROADCASTPostMessage() - CrazyIvan1974
1
HWND_BROADCAST在Windows 10上对我起了作用,但同时也锁死了,不知道为什么,可能是我使用了多个显示器。然而,GetConsoleWindow()顺利运行。 - GrandMasterFlush
不要使用HWND_BROADCAST,否则会导致每个接收应用程序依次尝试挂起。 - Mark

12

这段代码可以用于开启和关闭操作。它在Windows 7上也能正常工作。

   private int SC_MONITORPOWER = 0xF170;

    private uint WM_SYSCOMMAND = 0x0112;

    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);



    enum MonitorState
    {
        ON = -1,
        OFF = 2,
        STANDBY = 1
    }
    private void SetMonitorState(MonitorState state)
    {
        Form frm = new Form();

        SendMessage(frm.Handle, WM_SYSCOMMAND, (IntPtr)SC_MONITORPOWER, (IntPtr)state);

    }

要调用该函数,您必须像这样执行:

SetMonitorState(MonitorState.ON);
SetMonitorState(MonitorState.OFF);

注意:此代码在WPF应用程序中进行了测试。使用以下命名空间:

using System.Runtime.InteropServices;
using System.Windows.Forms;

7

我没有找到复制粘贴的例子,所以自己创建了一个,请不要忘记添加对System.Windows.Forms的引用。

using System;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;


namespace monitor_on_off
{
    class Program
    {
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
        [DllImport("user32.dll")]
        static extern void mouse_event(Int32 dwFlags, Int32 dx, Int32 dy, Int32 dwData, UIntPtr dwExtraInfo);

        private const int WmSyscommand = 0x0112;
        private const int ScMonitorpower = 0xF170;
        private const int MonitorShutoff = 2;
        private const int MouseeventfMove = 0x0001;

        public static void MonitorOff(IntPtr handle)
        {
            SendMessage(handle, WmSyscommand, (IntPtr)ScMonitorpower, (IntPtr)MonitorShutoff);
        }

        private static void MonitorOn()
        {
            mouse_event(MouseeventfMove, 0, 1, 0, UIntPtr.Zero);
            Thread.Sleep(40);
            mouse_event(MouseeventfMove, 0, -1, 0, UIntPtr.Zero);
        }

        static void Main()
        {
            var form = new Form();

            while (true)
            {
                MonitorOff(form.Handle);
                Thread.Sleep(5000);
                MonitorOn();
                Thread.Sleep(5000);
            }
        }
    }
}

1
在我的 Windows 10 64 位系统上运行良好。我甚至创建了一个使用它的小型 Node.js 服务器,现在我可以通过手机关闭屏幕。非常感谢。顺便说一句,打开命令也起作用了,但如果我第二次运行关闭命令,即使已经关闭,它也会重新打开。这对我来说并不重要。 - Natan Rubinstein

3
我已经研究过所有人发布的将显示器置于睡眠状态并在其他时间唤醒它的方法。尽管SendMessage()在Windows XP上确实有效,但是它无法在显示器休眠一段时间后唤醒显示器。我已经尝试使用C#、DOS、脚本来处理电源配置文件以及Powershell。最终我放弃了,并回到最初的想法证明是正确的。你需要在显示器关闭后使用PostMessage(),最好总是使用PostMessage()。因此,之前的所有代码都是正确的,只需使用以下代码即可:
using System.Runtime.InteropServices;
[DllImport("user32.dll")]
static extern IntPtr PostMessage(int hWnd, int msg, int wParam, int lParam);
PostMessage(-1, WM_SYSCOMMAND, SC_MONITORPOWER, MONITOR_OFF);

在执行过程中并正常工作(2015年5月11日),我正在运行:

  • Windows 7专业版版本6.1.7601服务包1 Build 7601
  • Visual Studio专业版2013版本12.0.31101.00升级4
  • .NET Framework 4.5.51209
  • C#

我的系统完全是最新的。


嗨@Mike,我尝试了你的解决方案,我的显示器变黑了,但大约1秒后它们又亮了起来。使用PostMessage和SendMessage尝试过。(Windows 7 6.1.7601 x64) 有什么想法吗? - ZeroDotNet

2

代码行最少的答案:

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

static class Program
{
    [DllImport("user32.dll")]
    static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, int lParam);

    [STAThread]
    static void Main()
    {
        SendMessage(new Form().Handle, 0x0112, 0xF170, 2);
    }
}

3
在我看来,它不比2011年klaasjan69的答案更好。虽然更短,但可读性较差。它只回答了“关闭”情况,而没有回答“打开”情况。我不认为“最少代码行数”是一个优点。 - I liked the old Stack Overflow

0

对于Windows 10(已在Pro 64位上进行测试),我能够使用此页面中提到的SendMessage()技术关闭显示器。

然而,我无法将显示器打开: “鼠标移动” 技巧不起作用,SendMessage()技术会使屏幕重新打开一秒钟然后再关掉,并且使用PostMessage()没有改变任何东西。

但是这个技巧实际上非常简单,我所要做的就是使用SendKeys()模拟一个按键操作。我在这里使用ALT因为它本身对系统没有影响,但它也可以是其他键。

SendKeys.SendWait("%");

如果您没有使用Windows.Forms,使用SendInput()发送“ALT”也可以工作,但实现起来更加繁琐。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接