在 windows 中关闭显示器

Posted

技术标签:

【中文标题】在 windows 中关闭显示器【英文标题】:Turn off the monitor in windows 【发布时间】:2021-10-26 23:18:03 【问题描述】:

我需要在代码中关闭我的显示器。我用谷歌搜索并找到了一些应该这样做的代码,但是当我运行它时,什么都没有发生,我只得到一个 0 WinAPI 结果。我做错了什么?

class Program

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

    [DllImport("user32.dll")]
    private static extern IntPtr GetDesktopWindow();

    const int SC_MONITORPOWER = 0xF170;
    const int WM_SYSCOMMAND = 0x0112;
    const int MONITOR_OFF = 2;

    static void Main(string[] args)
    
        Console.WriteLine(
            SendMessage( 
                GetDesktopWindow(), 
                WM_SYSCOMMAND, 
                (IntPtr) SC_MONITORPOWER, 
                (IntPtr) MONITOR_OFF));
        Console.WriteLine("Hello World!");
    

【问题讨论】:

如果你发送MONITOR_STANBY = 1而不是MONITOR_OFF = 2,你有同样的问题吗?用HWND_BROADCAST = 0xFFFF 代替GetDesktopWindow() 怎么样? 广播在这里很可怕而且是错误的。 尝试 GetShellWindow 而不是 GetDesktopWindow docs.microsoft.com/en-us/windows/win32/api/winuser/… @SimonMourier Explorer 可能没有运行 @Anders - 当然。 【参考方案1】:

来自Fumbling around in the dark and stumbling across the wrong solution:

the desktop window is a very special window 和 通常应该避免,因为它的行为不像应用程序创建的窗口。特别是,作者试图将消息发布到桌面窗口。这曾经在 historically open world of the window manager 中工作,但安全性和稳健性问题已经优先于兼容性。

真正的解决方案是创建自己的窗口并将消息发送给它,其他任何东西都是 hack。

如果你不介意黑客攻击,至少尝试找到一个合适的窗口:

[DllImport("user32.dll", SetLastError = false)]
public static extern IntPtr GetForegroundWindow();

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

const int SC_MONITORPOWER = 0xF170;
const int WM_SYSCOMMAND = 0x0112;
const int MONITOR_OFF = 2;

static void Main(string[] args)

    IntPtr w;
    for (; IntPtr.Zero == (w = GetForegroundWindow());) System.Threading.Thread.Sleep(1000);
    PostMessage(w, WM_SYSCOMMAND, (IntPtr) SC_MONITORPOWER, (IntPtr) MONITOR_OFF);

而且因为它是一种 hack,所以有时它可能不起作用。您借用的窗口可能会在您发布消息之前被破坏。您可能无权向其发送消息 (UAC)。或者它可能决定不将此消息传递给DefWindowProc

另一个更好的技巧是创建一个临时窗口:

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

[DllImport("user32.dll")]
static extern int DestroyWindow(IntPtr hWnd);

[DllImport("user32.dll", SetLastError=true)]
public static extern IntPtr CreateWindowEx(uint dwExStyle, string lpClassName, IntPtr cap, uint dwStyle, int x, int y, int nWidth, int nHeight, IntPtr hWndParent, IntPtr hMenu, IntPtr hInstance, IntPtr lpParam);

const int SC_MONITORPOWER = 0xF170;
const int WM_SYSCOMMAND = 0x0112;
const int MONITOR_OFF = 2;

static void Main(string[] args)

    IntPtr w = CreateWindowEx(0, "Button", IntPtr.Zero, 0, 0, 0, 0, 0, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero, IntPtr.Zero);
    if (w != IntPtr.Zero)
    
        SendMessage(w, WM_SYSCOMMAND, (IntPtr) SC_MONITORPOWER, (IntPtr) MONITOR_OFF);
        DestroyWindow(w);
    

这仍然有点像 hack,因为它实际上从未泵送消息。

【讨论】:

实际上 - 效果很好 - 但 (-1) 上的监视器没有:( @DarrenOakey "Monitor on" 在最新版本的 Windows 上不起作用,您必须使用 SendInput/mouse_event 来伪造鼠标移动。在 *** 上搜索这个,我相信你会找到一些关于它的问题。 非常古老而简单的mouse_event 在 Windows 10 中运行良好。带有(IntPtr)(-1) 的 SendMessage 在 Windows 7 中运行。 -- 由于您使用的是 C#,因此您可以构建一个 NativeWindow,创建为,例如,class MonitorWindow : NativeWindow public MonitorWindow() var cp = new CreateParams(); CreateHandle(cp); ,而不是调用CreateWindowEx() 并添加ShutOff()WakeUp() 方法(这样您就可以将所有PInvoke 内容放在一个地方)。不再需要时调用其DestroyHandle() 方法。 是的 - 鼠标事件触发对我有用 - 谢谢大家!

以上是关于在 windows 中关闭显示器的主要内容,如果未能解决你的问题,请参考以下文章

如何在 VS 2013 中关闭 Razor 突出显示?

在 Visual C++ 中关闭突出显示“事件”关键字

在 Swift 中关闭键盘时,UIToolbar 不再显示在视图中

在 iOS 13 中关闭 UIScrollView 指示器清理

在 xamarin 表单中关闭应用程序时无法显示通知

如果在系统设置中关闭隐藏式字幕,则不会显示字幕