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">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ScreenRotateForWin10/MainWindow.xaml.cs b/ScreenRotateForWin10/MainWindow.xaml.cs
index fb5aaa3..92d91d3 100644
--- a/ScreenRotateForWin10/MainWindow.xaml.cs
+++ b/ScreenRotateForWin10/MainWindow.xaml.cs
@@ -1,17 +1,6 @@
-using System;
-using System.Collections.Generic;
+using System.Collections.Generic;
using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
namespace ScreenRotateForWin10
{
@@ -23,6 +12,64 @@ public partial class MainWindow : Window
public MainWindow()
{
InitializeComponent();
+ DataContext = this;
+ Init();
+ }
+
+ private List screenList = new List();
+ private int screenCount = 0;
+
+ private void Init()
+ {
+ var result = new List();
+ result.AddRange(
+ Enumerable.Range(1, (int)(Display.GetScreenCount()))
+ .Select(x => $"{x}号屏幕") // $"NO.{x} Screen"
+ );
+ result.Add("所有"); // All
+ screenList = result;
+ choiceComboBox.ItemsSource = screenList;
+ screenCount = (int)Display.GetScreenCount();
+ }
+
+ private void RotateChoice(int choice, Display.Orientations degree)
+ {
+ if (choice == screenCount) // choose "All"
+ {
+ for (int i = 1; i <= screenCount; ++i)
+ Display.Rotate((uint)i, degree);
+ }
+ else
+ {
+ Display.Rotate((uint)choice + 1, degree);
+ }
+ }
+
+ private void DefaultButton_Click(object sender, RoutedEventArgs e) => Display.ResetAllRotations();
+
+ private void Button_Click(object sender, RoutedEventArgs e)
+ {
+ RotateChoice(choiceComboBox.SelectedIndex, Display.Orientations.DEGREES_CW_0);
+ }
+
+ private void Button_Click_1(object sender, RoutedEventArgs e)
+ {
+ RotateChoice(choiceComboBox.SelectedIndex, Display.Orientations.DEGREES_CW_270);
+ }
+
+ private void Button_Click_2(object sender, RoutedEventArgs e)
+ {
+ RotateChoice(choiceComboBox.SelectedIndex, Display.Orientations.DEGREES_CW_180);
+ }
+
+ private void Button_Click_3(object sender, RoutedEventArgs e)
+ {
+ RotateChoice(choiceComboBox.SelectedIndex, Display.Orientations.DEGREES_CW_90);
+ }
+
+ private void Button_Click_4(object sender, RoutedEventArgs e)
+ {
+ RotateChoice(choiceComboBox.SelectedIndex, Display.Orientations.DEGREES_CW_0);
}
}
}
diff --git a/ScreenRotateForWin10/ScreenRotateForWin10.csproj b/ScreenRotateForWin10/ScreenRotateForWin10.csproj
index 365090a..91ccc68 100644
--- a/ScreenRotateForWin10/ScreenRotateForWin10.csproj
+++ b/ScreenRotateForWin10/ScreenRotateForWin10.csproj
@@ -34,6 +34,13 @@
prompt
4
+
+ app.manifest
+
+
+
+
+
@@ -55,6 +62,8 @@
MSBuild:Compile
Designer
+
+
MSBuild:Compile
Designer
@@ -86,6 +95,7 @@
ResXFileCodeGenerator
Resources.Designer.cs
+
SettingsSingleFileGenerator
Settings.Designer.cs
@@ -94,5 +104,8 @@
+
+
+
\ No newline at end of file
diff --git a/ScreenRotateForWin10/app.manifest b/ScreenRotateForWin10/app.manifest
new file mode 100644
index 0000000..9ea09f0
--- /dev/null
+++ b/ScreenRotateForWin10/app.manifest
@@ -0,0 +1,74 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PerMonitorV2
+ True/PM
+
+
+
+
+
+
+