从C#使用Windows API设置为主显示器 [英] Use Windows API from C# to set primary monitor

查看:398
本文介绍了从C#使用Windows API设置为主显示器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用Windows API来设置主显示器。它似乎并没有工作 - 我的屏幕只是笔触并没有任何反应。

I'm trying to use the Windows API to set the primary monitor. It doesn't seem to work - my screen just flicks and nothing happens.

    public const int DM_ORIENTATION = 0x00000001;
public const int DM_PAPERSIZE = 0x00000002;
public const int DM_PAPERLENGTH = 0x00000004;
public const int DM_PAPERWIDTH = 0x00000008;
public const int DM_SCALE = 0x00000010;
public const int DM_POSITION = 0x00000020;
public const int DM_NUP = 0x00000040;
public const int DM_DISPLAYORIENTATION = 0x00000080;
public const int DM_COPIES = 0x00000100;
public const int DM_DEFAULTSOURCE = 0x00000200;
public const int DM_PRINTQUALITY = 0x00000400;
public const int DM_COLOR = 0x00000800;
public const int DM_DUPLEX = 0x00001000;
public const int DM_YRESOLUTION = 0x00002000;
public const int DM_TTOPTION = 0x00004000;
public const int DM_COLLATE = 0x00008000;
public const int DM_FORMNAME = 0x00010000;
public const int DM_LOGPIXELS = 0x00020000;
public const int DM_BITSPERPEL = 0x00040000;
public const int DM_PELSWIDTH = 0x00080000;
public const int DM_PELSHEIGHT = 0x00100000;
public const int DM_DISPLAYFLAGS = 0x00200000;
public const int DM_DISPLAYFREQUENCY = 0x00400000;
public const int DM_ICMMETHOD = 0x00800000;
public const int DM_ICMINTENT = 0x01000000;
public const int DM_MEDIATYPE = 0x02000000;
public const int DM_DITHERTYPE = 0x04000000;
public const int DM_PANNINGWIDTH = 0x08000000;
public const int DM_PANNINGHEIGHT = 0x10000000;
public const int DM_DISPLAYFIXEDOUTPUT = 0x20000000;

public const int ENUM_CURRENT_SETTINGS = -1;
public const int CDS_UPDATEREGISTRY = 0x01;
public const int CDS_TEST = 0x02;
public const int CDS_SET_PRIMARY = 0x00000010;

public const long DISP_CHANGE_SUCCESSFUL = 0;
public const long DISP_CHANGE_RESTART = 1;
public const long DISP_CHANGE_FAILED = -1;
public const long DISP_CHANGE_BADMODE = -2;
public const long DISP_CHANGE_NOTUPDATED = -3;
public const long DISP_CHANGE_BADFLAGS = -4;
public const long DISP_CHANGE_BADPARAM = -5;
public const long DISP_CHANGE_BADDUALVIEW = -6;

    public static void SetPrimary(Screen screen)
{
  DISPLAY_DEVICE d = new DISPLAY_DEVICE();
  DEVMODE dm = new DEVMODE();
  d.cb = Marshal.SizeOf(d);
  uint deviceID = 1;
  User_32.EnumDisplayDevices(null, deviceID, ref  d, 0); // 
  User_32.EnumDisplaySettings(d.DeviceName, 0, ref dm);
  dm.dmPelsWidth = 2560;
  dm.dmPelsHeight = 1600;
  dm.dmPositionX = screen.Bounds.Right;
  dm.dmFields = DM_POSITION | DM_PELSWIDTH | DM_PELSHEIGHT;
  User_32.ChangeDisplaySettingsEx(d.DeviceName, ref dm, IntPtr.Zero, CDS_SET_PRIMARY, IntPtr.Zero);
}



我把类似这样的方法:

I call the method like this:

SetPrimary(Screen.AllScreens[1])

任何想法?

推荐答案

我遇到了一模一样的问题,无论是从C#和这里下面的建议去尝试后,在C ++。我最终发现,微软的文档没有说清楚的事情是,设置在主显示器的请求将被忽略(但与操作报告为成功!),除非你还显示器的位置设置为(0,0 )上在DEVMODE结构。当然,这意味着你还需要使他们保持相对于新的主显示器的相同位置,改变你的其他显示器的位置。每文档(的http:/ /msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx ),调用ChangeDisplaySettingsEx用于与CDS_NORESET标志每台显示器,然后作出一个最后的电话。一切都空

I ran into exactly the same problem, both from C# and after following the advice here to try it in C++. I eventually discovered that the thing the Microsoft documentation doesn't make clear is that the request to set the primary monitor will be ignored (but with the operation reported as successful!) unless you also set the position of the monitor to (0, 0) on the DEVMODE struct. Of course, this means that you also need to shift the positions of your other monitors so that they stay in the same place relative to the new primary monitor. Per the documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx), call ChangeDisplaySettingsEx for each monitor with the CDS_NORESET flag and then make a final call with everything null.

下面的代码为我工作:

    public static void SetAsPrimaryMonitor(uint id)
    {
        var device = new DISPLAY_DEVICE();
        var deviceMode = new DEVMODE();
        device.cb = Marshal.SizeOf(device);

        NativeMethods.EnumDisplayDevices(null, id, ref device, 0);
        NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref deviceMode);
        var offsetx = deviceMode.dmPosition.x;
        var offsety = deviceMode.dmPosition.y;
        deviceMode.dmPosition.x = 0;
        deviceMode.dmPosition.y = 0;

        NativeMethods.ChangeDisplaySettingsEx(
            device.DeviceName, 
            ref deviceMode, 
            (IntPtr)null, 
            (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), 
            IntPtr.Zero);

        device = new DISPLAY_DEVICE();
        device.cb = Marshal.SizeOf(device);

        // Update remaining devices
        for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++)
        {
            if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && otherid != id)
            {
                device.cb = Marshal.SizeOf(device);
                var otherDeviceMode = new DEVMODE();

                NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode);

                otherDeviceMode.dmPosition.x -= offsetx;
                otherDeviceMode.dmPosition.y -= offsety;

                NativeMethods.ChangeDisplaySettingsEx(
                    device.DeviceName,
                    ref otherDeviceMode,
                    (IntPtr)null,
                    (ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET),
                    IntPtr.Zero);

            }

            device.cb = Marshal.SizeOf(device);
        }

        // Apply settings
        NativeMethods.ChangeDisplaySettingsEx(null, IntPtr.Zero, (IntPtr)null, ChangeDisplaySettingsFlags.CDS_NONE, (IntPtr)null);
    }

请注意,对于ChangeDisplaySettingsEx与DEVMODE结构作为第二个参数的签名显然深得'T让你在IntPtr.Zero通过。创建你自己的相同的extern通话,即

Note that a signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter obviously won't allow you to pass in IntPtr.Zero. Create yourself two different signatures for the same extern call, i.e.

    [DllImport("user32.dll")]
    public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);

这篇关于从C#使用Windows API设置为主显示器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆