2008-10-12 12 views
6

Próbuję użyć interfejsu API systemu Windows do ustawienia monitora głównego. To nie działa - mój ekran po prostu kręci i nic się nie dzieje.Użyj interfejsu Windows API z C#, aby ustawić monitor główny

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 wywołać metodę tak:

SetPrimary(Screen.AllScreens[1]) 

jakieś pomysły?

Odpowiedz

3

nie mogę pomóc w WinAPI-stuff, ale jeśli używasz karty Nvidia może trzeba spojrzeć na NVcontrolPanel Api Documentation Następnie można dokonać wyjścia pomocniczego swój podstawowy korzystając rundll32.exe NvCpl.dll,dtcfg primary 2 nadzieję, że pomoże .

3

Zgodnie z documentation for ChangeDisplaySettingsEx, "element dmSize musi być zainicjalizowany do rozmiaru, w bajtach, struktury DEVMODE." Ponadto, the EnumDisplaySettings documentation stwierdza: "Przed wywołaniem EnumDisplaySettings, ustaw członka dmSize na sizeof (DEVMODE) i ustaw członka dmDriverExtra, aby wskazał rozmiar (w bajtach) dodatkowej przestrzeni dostępnej do odbioru prywatnych danych sterownika". Nie widzę tego w przykładowym kodzie podanym w pytaniu; to jeden z powodów, dla których może się nie udać.

Ponadto mogą występować błędy w definicjach struktur DEVMODE i DISPLAY_DEVICE, które nie zostały uwzględnione w pytaniu. Roger Lipscombe's suggestion, aby najpierw działało z C/C++, jest doskonałym sposobem na wykluczenie tego typu problemów.

Na koniec sprawdź wartość zwracaną z ChangeDisplaySettingsEx i zobacz, czy to daje wskazówkę, dlaczego może się nie udać.

4

Wpadłem na dokładnie ten sam problem, zarówno z C#, jak i po zastosowaniu się tutaj, aby wypróbować to w C++. W końcu odkryłem, że rzeczy, których dokumentacja Microsoft nie wyjaśnia, jest to, że żądanie ustawienia głównego monitora zostanie zignorowane (ale z operacją zgłoszoną jako pomyślna!), Chyba że ustawisz także pozycję monitora na (0, 0) w strukturze DEVMODE. Oczywiście oznacza to również, że musisz przesunąć pozycje innych monitorów, aby pozostały w tym samym miejscu w stosunku do nowego głównego monitora. Zgodnie z dokumentacją (http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx) należy wywołać ChangeDisplaySettingsEx dla każdego monitora z flagą CDS_NORESET, a następnie wykonać ostateczne połączenie ze wszystkimi wartościami NULL.

Poniższy kod pracował dla mnie:

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

Należy pamiętać, że podpis na ChangeDisplaySettingsEx z struct DEVMODE jako drugi parametr oczywiście nie będzie można przejść w IntPtr.Zero. Załóż sobie dwa różne podpisów pod tym samym extern wezwania, tj

[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

mam zamiar wypróbować ten kod na zewnątrz i eksperyment, ale można skomentować nieco, jaka powinna być strategia zmiany pozycji innych monitorów? Nie znalazłem wiele dokumentacji na temat MSDN o tym, co oznaczają pozycje i jak muszą się ze sobą nawzajem odnosić, czy powinny być ujemne czy pozytywne, itd. Twój przykład przenosi wszystkie inne monitory w lewo i w górę o poprzednie położenie nowy główny monitor - jakie są tego powody? Nie całkiem to widzę. – user1454265

+0

Domyślam się przypuszczać - zakładam, że cały samolot 2D jest uczciwą grą, pozytywną lub negatywną, a względne pozycjonowanie ma znaczenie tylko dla zawijania myszy? – user1454265

+0

Nie mam okazji wypróbować go w tej chwili @ user1454265 (więc mam nadzieję, że weryfikujesz to, co mówię, kiedy to robisz), ale moim wspomnieniem jest to, że lewy górny róg głównego monitora jest zawsze (0 , 0), więc napisałem powyższe w taki sposób, że monitory zachowują swoje względne położenie podczas zmiany podstawowego (kluczowe dla mnie szczególnie, ponieważ mam trzy monitory o różnych rozmiarach w dziwnych miejscach). – ADBailey

5

Oto pełny kod na podstawie ADBailey w roztworze:

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

Dziękuję bardzo ADBaley i Vladimir. Mogę użyć tego do naszych szkolnych instalacji (Teacher PC + Scaler-> Beamer) tutaj jest kod dla wszystkich: https://github.com/Grunge/setDisplayRes Pozdrowienia i Podziękowania – grunge

Powiązane problemy