使用 C# 中的 Windows API 设置主监视器

Use Windows API from C# to set primary monitor(使用 C# 中的 Windows API 设置主监视器)
本文介绍了使用 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);
}

我这样调用方法:

SetPrimary(Screen.AllScreens[1])

有什么想法吗?

推荐答案

下面是基于ADBailey解决方案的完整代码:

Here is the full code based on ADBailey's solution:

public class MonitorChanger
{
    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);
    }
}

[StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)]
public struct DEVMODE
{
    public const int CCHDEVICENAME = 32;
    public const int CCHFORMNAME = 32;

    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHDEVICENAME)]
    [System.Runtime.InteropServices.FieldOffset(0)]
    public string dmDeviceName;
    [System.Runtime.InteropServices.FieldOffset(32)]
    public Int16 dmSpecVersion;
    [System.Runtime.InteropServices.FieldOffset(34)]
    public Int16 dmDriverVersion;
    [System.Runtime.InteropServices.FieldOffset(36)]
    public Int16 dmSize;
    [System.Runtime.InteropServices.FieldOffset(38)]
    public Int16 dmDriverExtra;
    [System.Runtime.InteropServices.FieldOffset(40)]
    public UInt32 dmFields;

    [System.Runtime.InteropServices.FieldOffset(44)]
    Int16 dmOrientation;
    [System.Runtime.InteropServices.FieldOffset(46)]
    Int16 dmPaperSize;
    [System.Runtime.InteropServices.FieldOffset(48)]
    Int16 dmPaperLength;
    [System.Runtime.InteropServices.FieldOffset(50)]
    Int16 dmPaperWidth;
    [System.Runtime.InteropServices.FieldOffset(52)]
    Int16 dmScale;
    [System.Runtime.InteropServices.FieldOffset(54)]
    Int16 dmCopies;
    [System.Runtime.InteropServices.FieldOffset(56)]
    Int16 dmDefaultSource;
    [System.Runtime.InteropServices.FieldOffset(58)]
    Int16 dmPrintQuality;

    [System.Runtime.InteropServices.FieldOffset(44)]
    public POINTL dmPosition;
    [System.Runtime.InteropServices.FieldOffset(52)]
    public Int32 dmDisplayOrientation;
    [System.Runtime.InteropServices.FieldOffset(56)]
    public Int32 dmDisplayFixedOutput;

    [System.Runtime.InteropServices.FieldOffset(60)]
    public short dmColor; // See note below!
    [System.Runtime.InteropServices.FieldOffset(62)]
    public short dmDuplex; // See note below!
    [System.Runtime.InteropServices.FieldOffset(64)]
    public short dmYResolution;
    [System.Runtime.InteropServices.FieldOffset(66)]
    public short dmTTOption;
    [System.Runtime.InteropServices.FieldOffset(68)]
    public short dmCollate; // See note below!
    [System.Runtime.InteropServices.FieldOffset(72)]
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCHFORMNAME)]
    public string dmFormName;
    [System.Runtime.InteropServices.FieldOffset(102)]
    public Int16 dmLogPixels;
    [System.Runtime.InteropServices.FieldOffset(104)]
    public Int32 dmBitsPerPel;
    [System.Runtime.InteropServices.FieldOffset(108)]
    public Int32 dmPelsWidth;
    [System.Runtime.InteropServices.FieldOffset(112)]
    public Int32 dmPelsHeight;
    [System.Runtime.InteropServices.FieldOffset(116)]
    public Int32 dmDisplayFlags;
    [System.Runtime.InteropServices.FieldOffset(116)]
    public Int32 dmNup;
    [System.Runtime.InteropServices.FieldOffset(120)]
    public Int32 dmDisplayFrequency;
}

public enum DISP_CHANGE : int
{
    Successful = 0,
    Restart = 1,
    Failed = -1,
    BadMode = -2,
    NotUpdated = -3,
    BadFlags = -4,
    BadParam = -5,
    BadDualView = -6
}

[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public struct DISPLAY_DEVICE
{
    [MarshalAs(UnmanagedType.U4)]
    public int cb;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
    public string DeviceName;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string DeviceString;
    [MarshalAs(UnmanagedType.U4)]
    public DisplayDeviceStateFlags StateFlags;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string DeviceID;
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
    public string DeviceKey;
}

[Flags()]
public enum DisplayDeviceStateFlags : int
{
    /// <summary>The device is part of the desktop.</summary>
    AttachedToDesktop = 0x1,
    MultiDriver = 0x2,
    /// <summary>The device is part of the desktop.</summary>
    PrimaryDevice = 0x4,
    /// <summary>Represents a pseudo device used to mirror application drawing for remoting or other purposes.</summary>
    MirroringDriver = 0x8,
    /// <summary>The device is VGA compatible.</summary>
    VGACompatible = 0x10,
    /// <summary>The device is removable; it cannot be the primary display.</summary>
    Removable = 0x20,
    /// <summary>The device has more display modes than its output devices support.</summary>
    ModesPruned = 0x8000000,
    Remote = 0x4000000,
    Disconnect = 0x2000000,
}

[Flags()]
public enum ChangeDisplaySettingsFlags : uint
{
    CDS_NONE = 0,
    CDS_UPDATEREGISTRY = 0x00000001,
    CDS_TEST = 0x00000002,
    CDS_FULLSCREEN = 0x00000004,
    CDS_GLOBAL = 0x00000008,
    CDS_SET_PRIMARY = 0x00000010,
    CDS_VIDEOPARAMETERS = 0x00000020,
    CDS_ENABLE_UNSAFE_MODES = 0x00000100,
    CDS_DISABLE_UNSAFE_MODES = 0x00000200,
    CDS_RESET = 0x40000000,
    CDS_RESET_EX = 0x20000000,
    CDS_NORESET = 0x10000000
}

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

    [DllImport("user32.dll")]
    // A signature for ChangeDisplaySettingsEx with a DEVMODE struct as the second parameter won't allow you to pass in IntPtr.Zero, so create an overload
    public static extern DISP_CHANGE ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam);

    [DllImport("user32.dll")]
    public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);

    [DllImport("user32.dll")]
    public static extern bool EnumDisplaySettings(string deviceName, int modeNum, ref DEVMODE devMode);
}

[StructLayout(LayoutKind.Sequential)]
public struct POINTL
{
    public int x;
    public int y;
}

这篇关于使用 C# 中的 Windows API 设置主监视器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!

本站部分内容来源互联网,如果有图片或者内容侵犯了您的权益,请联系我们,我们会在确认后第一时间进行删除!

相关文档推荐

MSBuild cannot find a reference(MSBuild 找不到参考)
The reference assemblies for framework .NETCore, Version=v5.0 were not found(未找到框架 .NETCore,Version=v5.0 的参考程序集)
quot;File has a different computed hash than specified in manifestquot; error when signing the EXE(“文件的计算哈希值与清单中指定的不同签署EXE时出错)
MS-Build BeforeBuild not firing(MS-Build BeforeBuild 未触发)
Using C# 7.1 with MSBuild(将 C# 7.1 与 MSBuild 结合使用)
Build project with Microsoft.Build API(使用 Microsoft.Build API 构建项目)