2008-10-12 8 views
6

J'essaie d'utiliser l'API Windows pour définir le moniteur principal. Cela ne semble pas fonctionner - mon écran tourne et rien ne se passe.Utilisation de l'API Windows à partir de C# pour définir le moniteur principal

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); 
} 

J'appelle la méthode comme ceci:

SetPrimary(Screen.AllScreens[1]) 

Toutes les idées?

Répondre

3

Je ne peux pas vraiment vous aider à winapi-choses, mais si vous utilisez une carte Nvidia vous pouvez avoir un coup d'oeil à la NVcontrolPanel Api Documentation Ensuite, vous pouvez faire la sortie secondaire primaire à l'aide de votre rundll32.exe NvCpl.dll,dtcfg primary 2 Espoir qui vous aidera à .

3

Selon le documentation for ChangeDisplaySettingsEx, "le membre dmSize doit être initialisé à la taille, en octets, de la structure DEVMODE." En outre, the EnumDisplaySettings documentation indique: «Avant d'appeler EnumDisplaySettings, définissez le membre dmSize sur sizeof (DEVMODE) et définissez le membre dmDriverExtra pour indiquer la taille, en octets, de l'espace supplémentaire disponible pour recevoir les données du pilote privé». Je ne vois pas cela se produire dans l'exemple de code donné dans la question; c'est une des raisons pour lesquelles cela peut échouer. En outre, vous pouvez avoir des erreurs dans les définitions des structures DEVMODE et DISPLAY_DEVICE, qui n'ont pas été incluses dans la question. Roger Lipscombe's suggestion pour le faire fonctionner à partir de C/C++ est d'abord un excellent moyen d'exclure ce type de problème. Enfin, vérifiez la valeur de retour à partir de ChangeDisplaySettingsEx et voyez si cela donne une idée de la raison pour laquelle il pourrait échouer.

4

J'ai rencontré exactement le même problème, à la fois de C# et après avoir suivi les conseils ici pour l'essayer en C++. J'ai finalement découvert que ce que la documentation de Microsoft ne précise pas, c'est que la demande de configuration du moniteur principal sera ignorée (mais avec l'opération signalée comme réussie!) Sauf si vous définissez également la position du moniteur sur (0, 0) sur la structure DEVMODE. Bien sûr, cela signifie que vous devez également déplacer les positions de vos autres moniteurs afin qu'ils restent au même endroit par rapport au nouveau moniteur principal. Par la documentation (http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx), appelez ChangeDisplaySettingsEx pour chaque moniteur avec l'indicateur CDS_NORESET, puis effectuez un appel final avec tout null.

Le code suivant a fonctionné pour moi:

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); 
    } 

Notez qu'une signature pour ChangeDisplaySettingsEx avec une struct DEVMODE comme second paramètre évidemment ne vous permettra pas de passer dans IntPtr.Zero. Créez vous-même deux signatures différentes pour le même appel extern, à savoir

[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); 
+0

Je suis sur le point d'essayer ce code sortir et expérience, mais pouvez-vous commenter un peu sur ce que la stratégie pour déplacer les positions des autres moniteurs devrait être? Je n'ai pas trouvé beaucoup de documentation sur MSDN sur ce que signifient les positions et comment elles doivent se relier, qu'elles soient négatives ou positives, etc. Votre exemple déplace tous les autres moniteurs vers la gauche et vers le haut par la position précédente du nouveau moniteur principal - quelle est la raison d'agir ainsi? Pas tout à fait le voir. – user1454265

+0

Je suppose pour faire une conjecture - je suppose que tout le plan 2D est juste jeu, positif ou négatif, et le positionnement relatif importe juste pour boucler la souris? – user1454265

+0

Je n'ai pas la chance de l'essayer en ce moment @ user1454265 (donc j'espère que vous vérifierez ce que je dis quand vous faites), mais je me souviens que le coin supérieur gauche du moniteur principal est toujours (0 , 0), donc j'ai écrit ce qui précède de telle sorte que les moniteurs conservent leur positionnement relatif lorsque vous changez le primaire (crucial pour moi d'autant plus que j'ai trois moniteurs de tailles différentes dans des endroits impairs). – ADBailey

5

Voici le code complet basé sur la solution de ADBailey:

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; 
} 
+0

Merci beaucoup ADBaley et Vladimir. Je pourrais l'utiliser pour nos installations scolaires (Teacher PC + Scaler-> Beamer) voici le code pour tout le monde: https://github.com/Grunge/setDisplayRes Salutations et Merci – grunge

Questions connexes