namespace RadeonResetBugFixService.ThirdParty.MonitorChanger { // Code taken from https://github.com/Grunge/setDisplayRes using System; using System.Collections.Generic; using System.Runtime.InteropServices; // Encapsulates access to the PInvoke functions public class Display { public static List GetDisplayList(bool RetrieveMonitorname = false) { //todo: EDD_GET_DEVICE_INTERFACE_NAME //const int EDD_GET_DEVICE_INTERFACE_NAME = 0x1; List displays = new List(); DISPLAY_DEVICE d = new DISPLAY_DEVICE(); d.cb = Marshal.SizeOf(d); try { for (uint id = 0; NativeMethods.EnumDisplayDevices(null, id, ref d, 0); id++) { if (d.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop)) { //call again to get the monitor name (not only the graka name). DISPLAY_DEVICE devWithName = new DISPLAY_DEVICE(); devWithName.cb = Marshal.SizeOf(devWithName); NativeMethods.EnumDisplayDevices(d.DeviceName, 0, ref devWithName, 0); //overwrite device string and id, keep the rest! d.DeviceString = devWithName.DeviceString; d.DeviceID = devWithName.DeviceID; displays.Add(d); }//if is display }//for } catch (Exception ex) { Console.WriteLine(String.Format("{0}", ex.ToString())); } return displays; } // Return a list of all possible display types for this computer public static List GetDisplaySettings(string strDevName) { List modes = new List(); DevMode devmode = DevMode; int counter = 0; int returnValue = 1; // A return value of zero indicates that no more settings are available while (returnValue != 0) { returnValue = GetSettings(strDevName, ref devmode, counter++); modes.Add(devmode); } return modes; } // Return the current display setting public int GetCurrentSettings(string strDevName, ref DevMode devmode) { return GetSettings(strDevName, ref devmode, NativeMethods.ENUM_CURRENT_SETTINGS); } //todo: CDS_UPDATEREGISTRY // Change the settings to the values of the DEVMODE passed public static string ChangeSettings(DISPLAY_DEVICE a_dev, DevMode devmode, bool bSetPrimary) { string errorMessage = ""; ChangeDisplaySettingsFlags flags = new ChangeDisplaySettingsFlags(); flags = ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_GLOBAL; ReturnCodes iRet = NativeMethods.ChangeDisplaySettingsEx(a_dev.DeviceName, ref devmode, IntPtr.Zero, flags, IntPtr.Zero); //same again, but with PRIMARY if (bSetPrimary && iRet == ReturnCodes.DISP_CHANGE_SUCCESSFUL) { SetAsPrimaryMonitor(a_dev); }//if primary switch (iRet) { case ReturnCodes.DISP_CHANGE_SUCCESSFUL: break; case ReturnCodes.DISP_CHANGE_RESTART: errorMessage = "Please restart your system"; break; case ReturnCodes.DISP_CHANGE_FAILED: errorMessage = "ChangeDisplaySettigns API failed"; break; case ReturnCodes.DISP_CHANGE_BADDUALVIEW: errorMessage = "The settings change was unsuccessful because system is DualView capable."; break; case ReturnCodes.DISP_CHANGE_BADFLAGS: errorMessage = "An invalid set of flags was passed in."; break; case ReturnCodes.DISP_CHANGE_BADPARAM: errorMessage = "An invalid parameter was passed in. This can include an invalid flag or combination of flags."; break; case ReturnCodes.DISP_CHANGE_NOTUPDATED: errorMessage = "Unable to write settings to the registry."; break; default: errorMessage = "Unknown return value from ChangeDisplaySettings API"; break; } return errorMessage; } public static void SetAsPrimaryMonitor(DISPLAY_DEVICE a_dev) { var deviceMode = new DevMode(); NativeMethods.EnumDisplaySettings(a_dev.DeviceName, -1, ref deviceMode); var offsetx = deviceMode.dmPositionX; var offsety = deviceMode.dmPositionY; deviceMode.dmPositionX = 0; deviceMode.dmPositionY = 0; NativeMethods.ChangeDisplaySettingsEx( a_dev.DeviceName, ref deviceMode, (IntPtr)null, (ChangeDisplaySettingsFlags.CDS_SET_PRIMARY | ChangeDisplaySettingsFlags.CDS_UPDATEREGISTRY | ChangeDisplaySettingsFlags.CDS_NORESET), IntPtr.Zero); var device = new DISPLAY_DEVICE(); device.cb = Marshal.SizeOf(device); // Update other devices for (uint otherid = 0; NativeMethods.EnumDisplayDevices(null, otherid, ref device, 0); otherid++) { if (device.StateFlags.HasFlag(DisplayDeviceStateFlags.AttachedToDesktop) && device.DeviceID != a_dev.DeviceID) { device.cb = Marshal.SizeOf(device); var otherDeviceMode = new DevMode(); NativeMethods.EnumDisplaySettings(device.DeviceName, -1, ref otherDeviceMode); otherDeviceMode.dmPositionX -= offsetx; otherDeviceMode.dmPositionY -= 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); }//set as primary() // Return a properly configured DEVMODE public static DevMode DevMode { get { DevMode devmode = new DevMode(); devmode.dmDeviceName = new String(new char[32]); devmode.dmFormName = new String(new char[32]); devmode.dmSize = (short)Marshal.SizeOf(devmode); return devmode; } } // call the external function inthe Win32 API private static int GetSettings(string strDevName, ref DevMode devmode, int iModeNum) { // helper to wrap EnumDisplaySettings Win32 API return NativeMethods.EnumDisplaySettings(strDevName, iModeNum, ref devmode); } } // Encapsulate the magic numbers for the return value in an enumeration public enum ReturnCodes : int { DISP_CHANGE_SUCCESSFUL = 0, DISP_CHANGE_BADDUALVIEW = -6, DISP_CHANGE_BADFLAGS = -4, DISP_CHANGE_BADMODE = -2, DISP_CHANGE_BADPARAM = -5, DISP_CHANGE_FAILED = -1, DISP_CHANGE_NOTUPDATED = -3, DISP_CHANGE_RESTART = 1 } // To see how the DEVMODE struct was translated from the unmanaged to the managed see the Task 2 Declarations section // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/prntspol_8nle.asp [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] public struct DevMode { // The MarshallAs attribute is covered in the Background section of the article [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string dmDeviceName; public short dmSpecVersion; public short dmDriverVersion; public short dmSize; public short dmDriverExtra; public int dmFields; public int dmPositionX; public int dmPositionY; public int dmDisplayOrientation; public int dmDisplayFixedOutput; public short dmColor; public short dmDuplex; public short dmYResolution; public short dmTTOption; public short dmCollate; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string dmFormName; public short dmLogPixels; public short dmBitsPerPel; public int dmPelsWidth; public int dmPelsHeight; public int dmDisplayFlags; public int dmDisplayFrequency; public int dmICMMethod; public int dmICMIntent; public int dmMediaType; public int dmDitherType; public int dmReserved1; public int dmReserved2; public int dmPanningWidth; public int dmPanningHeight; public override string ToString() { return dmPelsWidth.ToString() + " x " + dmPelsHeight.ToString(); } public string[] GetInfoArray() { string[] items = new string[5]; items[0] = dmDeviceName; items[1] = dmPelsWidth.ToString(); items[2] = dmPelsHeight.ToString(); items[3] = dmDisplayFrequency.ToString(); items[4] = dmBitsPerPel.ToString(); return items; } } //Display Listening [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 DEVMODE_Flags : int { DM_BITSPERPEL = 0x40000, DM_DISPLAYFLAGS = 0x200000, DM_DISPLAYFREQUENCY = 0x400000, DM_PELSHEIGHT = 0x100000, DM_PELSWIDTH = 0x80000, DM_POSITION = 0x20 } [Flags()] public enum DisplayDeviceStateFlags : int { /// The device is part of the desktop. AttachedToDesktop = 0x1, MultiDriver = 0x2, /// The device is part of the desktop. PrimaryDevice = 0x4, /// Represents a pseudo device used to mirror application drawing for remoting or other purposes. MirroringDriver = 0x8, /// The device is VGA compatible. VGACompatible = 0x10, /// The device is removable; it cannot be the primary display. Removable = 0x20, /// The device has more display modes than its output devices support. 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 } [Flags()] public enum ChangeDisplayConfigFlags : uint { SDC_TOPOLOGY_INTERNAL = 0x00000001, SDC_TOPOLOGY_CLONE = 0x00000002, SDC_TOPOLOGY_EXTEND = 0x00000004, SDC_TOPOLOGY_EXTERNAL = 0x00000008, SDC_APPLY = 0x00000080, } class NativeMethods { // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_84oj.asp [DllImport("user32.dll", CharSet = CharSet.Ansi)] public static extern int EnumDisplaySettings(string lpszDeviceName, int iModeNum, ref DevMode lpDevMode); // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/gdi/devcons_7gz7.asp [DllImport("user32.dll", CharSet = CharSet.Ansi)] //CallingConvention = CallingConvention.Cdecl public static extern ReturnCodes ChangeDisplaySettingsEx(string lpszDeviceName, ref DevMode lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwFlags, IntPtr lParam); [DllImport("user32.dll")] public static extern int ChangeDisplaySettingsEx(int lpszDeviceName, int lpDevMode, int hwnd, int dwFlags, int 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 int ChangeDisplaySettingsEx(string lpszDeviceName, IntPtr lpDevMode, IntPtr hwnd, ChangeDisplaySettingsFlags dwflags, IntPtr lParam); [DllImport("user32.dll", CharSet = CharSet.Ansi)] public static extern ReturnCodes ChangeDisplaySettings(ref DevMode lpDevMode, int dwFlags); [DllImport("user32.dll")] public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags); [DllImport("user32.dll", CharSet = CharSet.Unicode)] public static extern long SetDisplayConfig(uint numPathArrayElements, IntPtr pathArray, uint numModeArrayElements, IntPtr modeArray, ChangeDisplayConfigFlags flags); public const int ENUM_CURRENT_SETTINGS = -1; } }