diff --git a/ScreenRotateForWin10/APIWrapper.cs b/ScreenRotateForWin10/APIWrapper.cs new file mode 100644 index 0000000..4aa6013 --- /dev/null +++ b/ScreenRotateForWin10/APIWrapper.cs @@ -0,0 +1,216 @@ +using System; +using System.Runtime.InteropServices; + +namespace ScreenRotateForWin10 +{ + // See: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183565(v=vs.85).aspx + [StructLayout(LayoutKind.Explicit, CharSet = CharSet.Ansi)] + internal 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 DM 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; + [System.Runtime.InteropServices.FieldOffset(62)] + public short dmDuplex; + [System.Runtime.InteropServices.FieldOffset(64)] + public short dmYResolution; + [System.Runtime.InteropServices.FieldOffset(66)] + public short dmTTOption; + [System.Runtime.InteropServices.FieldOffset(68)] + public short dmCollate; + [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; + } + + // See: https://msdn.microsoft.com/en-us/library/windows/desktop/dd183569(v=vs.85).aspx + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)] + internal 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; + } + + // See: https://msdn.microsoft.com/de-de/library/windows/desktop/dd162807(v=vs.85).aspx + [StructLayout(LayoutKind.Sequential)] + internal struct POINTL + { + long x; + long y; + } + + internal enum DISP_CHANGE : int + { + Successful = 0, + Restart = 1, + Failed = -1, + BadMode = -2, + NotUpdated = -3, + BadFlags = -4, + BadParam = -5, + BadDualView = -6 + } + + // http://www.pinvoke.net/default.aspx/Enums/DisplayDeviceStateFlags.html + [Flags()] + internal 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 + } + + // http://www.pinvoke.net/default.aspx/user32/ChangeDisplaySettingsFlags.html + [Flags()] + internal enum DisplaySettingsFlags : int + { + 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()] + internal enum DM : int + { + Orientation = 0x00000001, + PaperSize = 0x00000002, + PaperLength = 0x00000004, + PaperWidth = 0x00000008, + Scale = 0x00000010, + Position = 0x00000020, + NUP = 0x00000040, + DisplayOrientation = 0x00000080, + Copies = 0x00000100, + DefaultSource = 0x00000200, + PrintQuality = 0x00000400, + Color = 0x00000800, + Duplex = 0x00001000, + YResolution = 0x00002000, + TTOption = 0x00004000, + Collate = 0x00008000, + FormName = 0x00010000, + LogPixels = 0x00020000, + BitsPerPixel = 0x00040000, + PelsWidth = 0x00080000, + PelsHeight = 0x00100000, + DisplayFlags = 0x00200000, + DisplayFrequency = 0x00400000, + ICMMethod = 0x00800000, + ICMIntent = 0x01000000, + MediaType = 0x02000000, + DitherType = 0x04000000, + PanningWidth = 0x08000000, + PanningHeight = 0x10000000, + DisplayFixedOutput = 0x20000000 + } + + internal class APIWrapper + { + [DllImport("user32.dll")] + internal static extern DISP_CHANGE ChangeDisplaySettingsEx( + string lpszDeviceName, ref DEVMODE lpDevMode, IntPtr hwnd, + DisplaySettingsFlags dwflags, IntPtr lParam); + + [DllImport("user32.dll")] + internal static extern bool EnumDisplayDevices( + string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, + uint dwFlags); + + [DllImport("user32.dll", CharSet = CharSet.Ansi)] + internal static extern int EnumDisplaySettings( + string lpszDeviceName, int iModeNum, ref DEVMODE lpDevMode); + + public const int DMDO_DEFAULT = 0; + public const int DMDO_90 = 1; + public const int DMDO_180 = 2; + public const int DMDO_270 = 3; + + public const int ENUM_CURRENT_SETTINGS = -1; + + } +} diff --git a/ScreenRotateForWin10/App.config b/ScreenRotateForWin10/App.config index 8324aa6..0380cf0 100644 --- a/ScreenRotateForWin10/App.config +++ b/ScreenRotateForWin10/App.config @@ -1,6 +1,9 @@  - - - + + + + + + \ No newline at end of file diff --git a/ScreenRotateForWin10/Display.cs b/ScreenRotateForWin10/Display.cs new file mode 100644 index 0000000..8c89a4d --- /dev/null +++ b/ScreenRotateForWin10/Display.cs @@ -0,0 +1,107 @@ +using System; +using System.Runtime.InteropServices; + +namespace ScreenRotateForWin10 +{ + public class Display + { + /// + /// Angles for Orient + /// + public enum Orientations + { + DEGREES_CW_0 = 0, + DEGREES_CW_90 = 3, + DEGREES_CW_180 = 2, + DEGREES_CW_270 = 1 + } + + /// + /// Rotate the screen + /// + /// The number of display, starts from 1, same in Setting + /// Degrees + /// + public static bool Rotate(uint DisplayNumber, Orientations Orientation) + { + if (DisplayNumber == 0) + throw new ArgumentOutOfRangeException("DisplayNumber", DisplayNumber, "First display is 1."); + + bool result = false; + DISPLAY_DEVICE d = new DISPLAY_DEVICE(); + DEVMODE dm = new DEVMODE(); + d.cb = Marshal.SizeOf(d); + + if (!APIWrapper.EnumDisplayDevices(null, DisplayNumber - 1, ref d, 0)) + throw new ArgumentOutOfRangeException("DisplayNumber", DisplayNumber, "Number is greater than connected displays."); + + if (0 != APIWrapper.EnumDisplaySettings( + d.DeviceName, APIWrapper.ENUM_CURRENT_SETTINGS, ref dm)) + { + if ((dm.dmDisplayOrientation + (int)Orientation) % 2 == 1) // Need to swap height and width? + { + int temp = dm.dmPelsHeight; + dm.dmPelsHeight = dm.dmPelsWidth; + dm.dmPelsWidth = temp; + } + + switch (Orientation) + { + case Orientations.DEGREES_CW_90: + dm.dmDisplayOrientation = APIWrapper.DMDO_270; + break; + case Orientations.DEGREES_CW_180: + dm.dmDisplayOrientation = APIWrapper.DMDO_180; + break; + case Orientations.DEGREES_CW_270: + dm.dmDisplayOrientation = APIWrapper.DMDO_90; + break; + case Orientations.DEGREES_CW_0: + dm.dmDisplayOrientation = APIWrapper.DMDO_DEFAULT; + break; + default: + break; + } + + DISP_CHANGE ret = APIWrapper.ChangeDisplaySettingsEx( + d.DeviceName, ref dm, IntPtr.Zero, + DisplaySettingsFlags.CDS_UPDATEREGISTRY, IntPtr.Zero); + + result = ret == 0; + } + + return result; + } + + public static void ResetAllRotations() + { + try + { + uint i = 0; + while (++i <= GetScreenCount()) // make exception less + { + Rotate(i, Orientations.DEGREES_CW_0); + } + } + catch (ArgumentOutOfRangeException) + { + // Everything is fine, just reached the last display + } + } + + /// + /// Get the number of screens + /// + /// screen count + public static uint GetScreenCount() + { + DISPLAY_DEVICE d = new DISPLAY_DEVICE(); + d.cb = Marshal.SizeOf(d); + + uint result = 0; + while (!APIWrapper.EnumDisplayDevices(null, ++result - 1, ref d, 0)) { } + return result; + } + } + +} diff --git a/ScreenRotateForWin10/MainWindow.xaml b/ScreenRotateForWin10/MainWindow.xaml index 14edad9..386ebbb 100644 --- a/ScreenRotateForWin10/MainWindow.xaml +++ b/ScreenRotateForWin10/MainWindow.xaml @@ -5,8 +5,32 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:ScreenRotateForWin10" mc:Ignorable="d" - Title="MainWindow" Height="450" Width="800"> - - + Title="屏幕转向控制程序" Height="410" Width="360" ResizeMode="CanMinimize"> + + + + + + +