2008-10-12 19 views
6

Tôi đang cố sử dụng API Windows để đặt màn hình chính. Nó dường như không hoạt động - màn hình của tôi chỉ flicks và không có gì xảy ra.Sử dụng API Windows từ C# để đặt màn hình chính

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

tôi gọi là phương pháp như thế này:

SetPrimary(Screen.AllScreens[1]) 

Bất kỳ ý tưởng?

Trả lời

3

tôi có thể không thực sự giúp bạn với WINAPI-thứ nhưng nếu bạn đang sử dụng một card Nvidia bạn có thể có một cái nhìn tại NVcontrolPanel Api Documentation Sau đó, bạn có thể làm cho đầu ra thứ cấp chính của bạn sử dụng rundll32.exe NvCpl.dll,dtcfg primary 2 Hy vọng rằng sẽ giúp bạn .

3

Theo số documentation for ChangeDisplaySettingsEx, "thành viên dmSize phải được khởi tạo thành kích thước tính theo byte, của cấu trúc DEVMODE." Hơn nữa, các trạng thái the EnumDisplaySettings documentation, "Trước khi gọi EnumDisplaySettings, hãy đặt thành viên dmSize thành sizeof (DEVMODE) và đặt thành viên dmDriverExtra để cho biết kích thước, tính bằng byte, dung lượng bổ sung có sẵn để nhận dữ liệu trình điều khiển riêng". Tôi không thấy điều này xảy ra trong mẫu mã được đưa ra trong câu hỏi; đó là một lý do tại sao nó có thể thất bại.

Ngoài ra, bạn có thể gặp lỗi trong các định nghĩa về cấu trúc DEVMODE và DISPLAY_DEVICE không được bao gồm trong câu hỏi. Roger Lipscombe's suggestion để làm cho nó hoạt động từ C/C++ trước tiên là một cách tuyệt vời để loại trừ loại vấn đề này.

Cuối cùng, hãy kiểm tra giá trị trả lại từ ChangeDisplaySettingsEx và xem liệu có cung cấp một đầu mối về lý do tại sao nó có thể không thành công.

4

Tôi gặp chính xác cùng một vấn đề, cả từ C# và sau khi làm theo lời khuyên ở đây để dùng thử trong C++. Cuối cùng tôi phát hiện ra rằng tài liệu của Microsoft không rõ ràng là yêu cầu đặt màn hình chính sẽ bị bỏ qua (nhưng với thao tác được báo cáo thành công!) Trừ khi bạn cũng đặt vị trí của màn hình thành (0, 0) trên cấu trúc DEVMODE. Tất nhiên, điều này có nghĩa rằng bạn cũng cần phải thay đổi vị trí của các màn hình khác để chúng ở cùng một vị trí tương đối với màn hình chính mới. Mỗi tài liệu (http://msdn.microsoft.com/en-us/library/windows/desktop/dd183413%28v=vs.85%29.aspx), gọi ChangeDisplaySettingsEx cho mỗi màn hình với cờ CDS_NORESET và sau đó thực hiện cuộc gọi cuối cùng với mọi thứ null.

Các mã sau đây làm việc cho tôi:

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

Lưu ý rằng một chữ ký cho ChangeDisplaySettingsEx với một struct devmode như tham số thứ hai rõ ràng là sẽ không cho phép bạn vượt qua trong IntPtr.Zero. Tạo cho mình hai chữ ký khác nhau cho các cuộc gọi extern cùng, tức là

[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

Tôi về để thử mã này ra và thử nghiệm, nhưng có thể bạn bình luận một chút về những gì các chiến lược để chuyển vị trí của các màn hình khác nên được? Tôi đã không tìm thấy nhiều tài liệu về MSDN về ý nghĩa của vị trí và cách chúng cần liên quan với nhau, cho dù chúng là tiêu cực hay tích cực, v.v. Ví dụ của bạn di chuyển tất cả các màn hình khác về phía trước và lên trên bởi vị trí trước đó của màn hình chính mới - lý do cơ bản để thực hiện điều này là gì? Không hoàn toàn nhìn thấy nó. – user1454265

+0

Tôi đoán để làm cho một phỏng đoán - Tôi giả định toàn bộ máy bay 2D là trò chơi công bằng, tích cực hay tiêu cực, và vị trí tương đối chỉ là vấn đề cho bọc chuột? – user1454265

+0

Tôi không có cơ hội để thử nó tại thời điểm @ user1454265 (vì vậy hy vọng bạn sẽ xác minh những gì tôi đang nói khi bạn làm), nhưng hồi ức của tôi là góc trên bên trái của màn hình chính luôn luôn là (0 , 0), vì vậy tôi đã viết ở trên theo cách mà các màn hình giữ lại vị trí tương đối của chúng khi bạn thay đổi vị trí chính (rất quan trọng đối với tôi đặc biệt vì tôi có ba màn hình có kích thước khác nhau ở những nơi lẻ). – ADBailey

5

Đây là mã đầy đủ dựa trên ADBailey của giải pháp:

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

Cảm ơn bạn rất nhiều ADBaley và Vladimir. Tôi có thể sử dụng để cài đặt trường học của chúng tôi (Giáo viên PC + Scaler-> Beamer) đây là mã cho tất cả mọi người: https://github.com/Grunge/setDisplayRes Lời chào và Cảm ơn – grunge

Các vấn đề liên quan