├── .github
└── FUNDING.yml
├── icon.png
├── icon-128.png
├── icon-256.png
├── Binaries
├── sr.exe
└── SetResolution.exe
├── SetResolution
├── install-localpackage.ps1
├── signtool.exe
├── Properties
│ ├── launchsettings.json
│ ├── Resources.resx
│ └── Resources.Designer.cs
├── build.ps1
├── publish-nuget.ps1
├── DisplayProfile.cs
├── Westwind.SetResolution.csprojExperimental
├── SetResolutionCommandLineParser.cs
├── AppConfiguration.cs
├── Westwind.SetResolution.csproj
├── Program.cs
├── CommandLine
│ ├── CommandLineParser.cs
│ └── ColorConsole.cs
├── SetResolutionProcessor.cs
├── DisplayManagerNative.cs
├── Utilities
│ └── SerializationUtils.cs
└── DisplayManager.cs
├── Assets
├── HelpScreen.png
├── ListDisplay.png
└── SetResolutionMain.png
├── LICENSE.MD
├── SetResolution.sln
├── .gitattributes
├── .editorconfig
├── .gitignore
└── README.md
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | github: [RickStrahl]
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/icon.png
--------------------------------------------------------------------------------
/icon-128.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/icon-128.png
--------------------------------------------------------------------------------
/icon-256.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/icon-256.png
--------------------------------------------------------------------------------
/Binaries/sr.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/Binaries/sr.exe
--------------------------------------------------------------------------------
/SetResolution/install-localpackage.ps1:
--------------------------------------------------------------------------------
1 | dotnet tool update -g SetResolution --add-source ./nupkg
--------------------------------------------------------------------------------
/Assets/HelpScreen.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/Assets/HelpScreen.png
--------------------------------------------------------------------------------
/Assets/ListDisplay.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/Assets/ListDisplay.png
--------------------------------------------------------------------------------
/Binaries/SetResolution.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/Binaries/SetResolution.exe
--------------------------------------------------------------------------------
/SetResolution/signtool.exe:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/SetResolution/signtool.exe
--------------------------------------------------------------------------------
/Assets/SetResolutionMain.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RickStrahl/SetResolution/HEAD/Assets/SetResolutionMain.png
--------------------------------------------------------------------------------
/SetResolution/Properties/launchsettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "SetResolution list": {
4 | "commandName": "Project",
5 | "commandLineArgs": "LIST"
6 | },
7 | "SetResolution Set": {
8 | "commandName": "Project",
9 | "commandLineArgs": "SET -h 1080 -w 1920 -o 0 -f 60"
10 | },
11 | "SetResolution 4k": {
12 | "commandName": "Project",
13 | "commandLineArgs": "4k"
14 | }
15 | }
16 | }
--------------------------------------------------------------------------------
/SetResolution/build.ps1:
--------------------------------------------------------------------------------
1 | # build exe (net472)
2 | dotnet build -c Release
3 |
4 | # build dotnet tool (net6.0)
5 | dotnet build -c Release /p:DefineConstants="BUILD_DOTNET_TOOL"
6 |
7 | copy .\bin\Release\net472\SetResolution.exe ..\Binaries
8 |
9 | & ".\signtool.exe" sign /v /n "West Wind Technologies" /tr "http://timestamp.digicert.com" /td SHA256 /fd SHA256 "..\Binaries\SetResolution.exe"
10 |
11 | # Shortcut name
12 | copy ..\binaries\SetResolution.exe ..\binaries\sr.exe
13 |
14 | # My Utilities folder
15 | if (Test-Path ~\DropBox\utl) {
16 | copy ..\binaries\SetResolution.exe ~\DropBox\utl\SetResolution.exe
17 | copy ..\binaries\SetResolution.exe ~\DropBox\utl\sr.exe
18 | }
19 |
20 |
--------------------------------------------------------------------------------
/SetResolution/publish-nuget.ps1:
--------------------------------------------------------------------------------
1 | # Dotnet Tool Publishing
2 | # ----------------------
3 | # Make sure to set project DefineConstant to BUILD_DOTNET_TOOL
4 | # before running this file
5 |
6 | if (test-path ./nupkg) {
7 | remove-item ./nupkg -Force -Recurse
8 | }
9 |
10 | dotnet build -c Release /p:DefineConstants="BUILD_DOTNET_TOOL"
11 |
12 | $filename = gci "./nupkg/*.nupkg" | sort LastWriteTime | select -last 1 | select -ExpandProperty "Name"
13 | Write-host $filename
14 | $len = $filename.length
15 |
16 | if ($len -gt 0) {
17 | Write-Host "signing... $filename"
18 | nuget sign ".\nupkg\$filename" -CertificateSubject "West Wind Technologies" -timestamper " http://timestamp.digicert.com"
19 | Write-Host "Pushing to NuGet..."
20 | nuget push ".\nupkg\$filename" -source "https://nuget.org"
21 | Write-Host "Done."
22 | }
--------------------------------------------------------------------------------
/SetResolution/DisplayProfile.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Westwind.SetResolution
8 | {
9 | public class DisplayProfile
10 | {
11 |
12 | public string Name { get; set; }
13 |
14 | public int Width { get; set; }
15 |
16 | public int Height { get; set; }
17 |
18 | public int Frequency { get; set; } = 60;
19 |
20 | public int BitSize { get; set; } = 32;
21 |
22 | public Orientation Orientation { get; set; } = 0;
23 |
24 | public void UpdateCommandLine(SetResolutionCommandLineParser cmd)
25 | {
26 | cmd.Width = Width;
27 | cmd.Height = Height;
28 | cmd.Frequency = Frequency;
29 | cmd.BitCount = BitSize;
30 | cmd.Orientation = Orientation;
31 | }
32 |
33 | public override string ToString()
34 | {
35 | return $"{Name}: {Width} x {Height}, {BitSize}, {Frequency}";
36 | }
37 |
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/LICENSE.MD:
--------------------------------------------------------------------------------
1 | West Wind Set Resolution
2 | =============================================
3 |
4 | MIT License
5 | -----------
6 |
7 | Copyright (c) 2019-2022 West Wind Technologies
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in all
17 | copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
--------------------------------------------------------------------------------
/SetResolution.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.4.33122.133
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Westwind.SetResolution", "SetResolution\Westwind.SetResolution.csproj", "{D5715759-1922-4203-961A-C10DE8EA36A0}"
7 | EndProject
8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Files", "Solution Files", "{15259836-2069-4908-922C-1B7714FB51A3}"
9 | ProjectSection(SolutionItems) = preProject
10 | .gitignore = .gitignore
11 | README.md = README.md
12 | EndProjectSection
13 | EndProject
14 | Global
15 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
16 | Debug|Any CPU = Debug|Any CPU
17 | Release|Any CPU = Release|Any CPU
18 | EndGlobalSection
19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
20 | {D5715759-1922-4203-961A-C10DE8EA36A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
21 | {D5715759-1922-4203-961A-C10DE8EA36A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
22 | {D5715759-1922-4203-961A-C10DE8EA36A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
23 | {D5715759-1922-4203-961A-C10DE8EA36A0}.Release|Any CPU.Build.0 = Release|Any CPU
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {B0C754ED-2A91-498E-8F4D-5B1FF806DCAA}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/SetResolution/Westwind.SetResolution.csprojExperimental:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net6.0;net472
5 | Exe
6 | 0.1.4
7 | SetResolution
8 | Westwind.SetResolution
9 | Set Windows Display Resolution
10 | SetResolution: Set Windows Display Resolution from Terminal
11 |
12 | Allows you set Windows display Resolution from the Terminal via simple commands.
13 |
14 | Using this tool you can:
15 |
16 | * Set a specific resolution, frequency, bitness and rotation
17 | * List all available display modes
18 | * Create and use profiles for easy access
19 | * Supports multiple Monitors
20 |
21 | Rick Strahl, West Wind Technologies
22 | West Wind Technologies, 2022-2023
23 |
24 |
25 |
26 |
27 |
28 | True
29 | True
30 | Resources.resx
31 |
32 |
33 |
34 | PublicResXFileCodeGenerator
35 | Resources.Designer.cs
36 |
37 |
38 |
39 |
40 | true
41 | setresolution
42 | setresolution
43 |
44 | ./nupkg
45 | true
46 |
47 |
48 |
--------------------------------------------------------------------------------
/SetResolution/SetResolutionCommandLineParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Runtime.CompilerServices;
3 | using System.Threading;
4 | using HtmlPackager.ConsoleApp;
5 |
6 | namespace Westwind.SetResolution
7 | {
8 | public class SetResolutionCommandLineParser : CommandLineParser
9 | {
10 |
11 | public int Width { get; set; }
12 |
13 | public int Height { get; set; }
14 |
15 | public int Frequency { get; set; } = 60;
16 |
17 | public int BitCount { get; set; } = 32;
18 |
19 | public Orientation Orientation { get; set; } = 0;
20 |
21 | public string Profile { get; set; }
22 |
23 |
24 | public bool Help { get; set; }
25 |
26 | public bool StartTray { get; set; }
27 |
28 | public bool CreateProfile { get; set; }
29 | public bool ShowResolutions { get; set; }
30 | public bool ListAll { get; set; }
31 |
32 | public int MonitorId { get; set; }
33 |
34 | ///
35 | /// Don't ask for confirmation
36 | ///
37 | public bool NoPrompt { get; set; }
38 |
39 | public bool NoPersist { get; set; }
40 |
41 |
42 | public SetResolutionCommandLineParser(string[] args = null, string cmdLine = null)
43 | : base(args, cmdLine)
44 | {
45 | }
46 |
47 | public override void Parse()
48 | {
49 | Width = ParseIntParameterSwitch("-w", 0);
50 | Height = ParseIntParameterSwitch("-h", 0);
51 | Frequency = ParseIntParameterSwitch("-f", 60);
52 | BitCount = ParseIntParameterSwitch("-b", 32);
53 | int or = ParseIntParameterSwitch("-o", 0);
54 | Orientation = (Orientation) or;
55 | ListAll = ParseParameterSwitch("-la");
56 |
57 | Profile = ParseStringParameterSwitch("-p");
58 | MonitorId = ParseIntParameterSwitch("-m");
59 |
60 | NoPrompt = ParseParameterSwitch("-noprompt");
61 | NoPersist = ParseParameterSwitch("-nopersist");
62 | Help = ParseParameterSwitch("-h");
63 | }
64 |
65 |
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/SetResolution/AppConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Xml.Serialization;
5 | using Westwind.Utilities;
6 |
7 | namespace Westwind.SetResolution
8 | {
9 | [XmlRoot(ElementName = "SetResolution")]
10 | public class AppConfiguration
11 | {
12 | public static AppConfiguration Current { get; set; }
13 |
14 | ///
15 | /// Display Profiles
16 | ///
17 | public List Profiles { get; set; } = new List();
18 |
19 | ///
20 | /// Minimum Resolution
21 | ///
22 | public int MinResolutionWidth { get; set; } = 1024;
23 |
24 | public static void Load()
25 | {
26 | var file = Path.Combine(Program.StartupPath, "SetResolution.xml");
27 |
28 | if (File.Exists(file))
29 | Current = SerializationUtils.DeSerializeObject(file, typeof(AppConfiguration), false) as AppConfiguration;
30 |
31 | if (Current == null)
32 | {
33 | Current = new AppConfiguration();
34 | Current.Profiles.Add(new DisplayProfile()
35 | {
36 | Name = "1080",
37 | Width= 1920,
38 | Height= 1080,
39 | Frequency = 60,
40 | BitSize= 32
41 | });
42 | Current.Profiles.Add(new DisplayProfile()
43 | {
44 | Name = "4k",
45 | Width = 3840 ,
46 | Height = 2160,
47 | Frequency = 60,
48 | BitSize = 32
49 | });
50 | Current.Profiles.Add(new DisplayProfile()
51 | {
52 | Name = "1440",
53 | Width = 2560,
54 | Height = 1440,
55 | Frequency = 60,
56 | BitSize = 32
57 | });
58 | Current.Profiles.Add(new DisplayProfile()
59 | {
60 | Name = "720",
61 | Width = 1280,
62 | Height = 720,
63 | Frequency = 60,
64 | BitSize = 32
65 | });
66 | }
67 | }
68 |
69 | public static bool Save()
70 | {
71 | var file = Path.Combine(Program.StartupPath, "SetResolution.xml");
72 | try
73 | {
74 | SerializationUtils.SerializeObject(Current, file);
75 | }
76 | catch
77 | {
78 | return false;
79 | }
80 | return true;
81 | }
82 |
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/SetResolution/Westwind.SetResolution.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
8 | Exe
9 | 0.3.2
10 | SetResolution
11 | Westwind.SetResolution
12 | Set Windows Display Resolution
13 | SetResolution: Set Windows Display Resolution from Terminal
14 |
15 | Allows you set Windows display Resolution from the Terminal via simple commands.
16 |
17 | This tool lets you:
18 |
19 | * Set a specific resolution, frequency, bitness and rotation
20 | * List all available display modes
21 | * Create and use profiles for quick mode switches
22 | * Support multiple Monitors
23 | * Prompts for confirmation to avoid possibly invalid display modes
24 |
25 | Rick Strahl, West Wind Technologies
26 | West Wind Technologies, 2022-2025
27 |
28 |
29 | icon.png
30 | LICENSE.MD
31 | README.md
32 | http://github.com/rickstrahl/SetResolution
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 | True
41 | True
42 | Resources.resx
43 |
44 |
45 |
46 | PublicResXFileCodeGenerator
47 | Resources.Designer.cs
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | net472
60 |
61 |
62 |
63 |
64 | net9.0
65 |
66 | true
67 | SetResolution
68 | setresolution
69 |
70 | ./nupkg
71 | true
72 |
73 |
74 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 | root = true
3 |
4 | # Don't use tabs for indentation.
5 | [*]
6 | indent_style = space
7 | trim_trailing_whitespace = false
8 |
9 | # Code files
10 | [*.{cs,csx,vb,vbx}]
11 | indent_size = 4
12 | insert_final_newline = true
13 | charset = utf-8-bom
14 | trim_trailing_whitespace = true
15 |
16 | [*.less]
17 | charset = utf-8
18 | end_of_line = lf
19 | indent_size = 2
20 | insert_final_newline = true
21 | trim_trailing_whitespace = true
22 |
23 | [**.cshtml]
24 | indent_size = 4
25 |
26 | # size matters when we render html emails
27 | [StackOverflow/Views/Email/**.Html.cshtml]
28 | indent_style = tab
29 | tab_width = 4
30 | trim_trailing_whitespace = true
31 |
32 | # Xml project files
33 | [*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}]
34 | indent_size = 2
35 |
36 | # Xml config files
37 | [*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}]
38 | indent_size = 2
39 |
40 | # JSON files
41 | [*.json]
42 | indent_size = 2
43 |
44 | # Dotnet code style settings:
45 | [*.{cs,vb}]
46 | # Sort using and Import directives with System.* appearing first
47 | dotnet_sort_system_directives_first = true
48 |
49 | # Avoid "this." and "Me." if not necessary
50 | dotnet_style_qualification_for_field = false:suggestion
51 | dotnet_style_qualification_for_property = false:suggestion
52 | dotnet_style_qualification_for_method = false:suggestion
53 | dotnet_style_qualification_for_event = false:suggestion
54 |
55 | # Use language keywords instead of framework type names for type references
56 | dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
57 | dotnet_style_predefined_type_for_member_access = true:suggestion
58 |
59 | # Suggest more modern language features when available
60 | dotnet_style_object_initializer = true:suggestion
61 | dotnet_style_collection_initializer = true:suggestion
62 | dotnet_style_coalesce_expression = true:suggestion
63 | dotnet_style_null_propagation = true:suggestion
64 | dotnet_style_explicit_tuple_names = true:suggestion
65 |
66 | # CSharp code style settings:
67 | [*.cs]
68 | # Prefer "var" everywhere
69 | #csharp_style_var_for_built_in_types = true:suggestion
70 | csharp_style_var_when_type_is_apparent = true:suggestion
71 | csharp_style_var_elsewhere = true:suggestion
72 |
73 | # Prefer method-like constructs to have a expression-body
74 | csharp_style_expression_bodied_methods = true:none
75 | csharp_style_expression_bodied_constructors = true:none
76 | csharp_style_expression_bodied_operators = true:none
77 |
78 | # Prefer property-like constructs to have an expression-body
79 | csharp_style_expression_bodied_properties = true:none
80 | csharp_style_expression_bodied_indexers = true:none
81 | csharp_style_expression_bodied_accessors = true:none
82 |
83 | # Suggest more modern language features when available
84 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
85 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
86 | csharp_style_inlined_variable_declaration = true:suggestion
87 | csharp_style_throw_expression = true:suggestion
88 | csharp_style_conditional_delegate_call = true:suggestion
89 |
90 | # Newline settings
91 | csharp_new_line_before_open_brace = all
92 | csharp_new_line_before_else = true
93 | csharp_new_line_before_catch = true
94 | csharp_new_line_before_finally = true
95 | csharp_new_line_before_members_in_object_initializers = true
96 | csharp_new_line_before_members_in_anonymous_types = true
97 |
98 | # Space settings
99 | csharp_space_after_keywords_in_control_flow_statements = true:suggestion
--------------------------------------------------------------------------------
/SetResolution/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Data;
3 | using System.IO;
4 | using System.Reflection;
5 | using System.Threading;
6 | using Westwind.SetResolution.CommandLine;
7 |
8 | namespace Westwind.SetResolution
9 | {
10 | public class Program
11 | {
12 | public static string StartupPath { get; set; }
13 |
14 | static void Main(string[] args)
15 | {
16 | StartupPath = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
17 | AppConfiguration.Load();
18 |
19 | var cmdLine = new SetResolutionCommandLineParser();
20 | cmdLine.Parse();
21 |
22 | var version = Assembly.GetExecutingAssembly().GetName().Version;
23 | var ver = version.Major + "." + version.Minor + (version.Build > 0 ? "." + version.Build : string.Empty);
24 |
25 | string text = $"Set Resolution v{ver}";
26 | ColorConsole.WriteLine(text, ConsoleColor.Yellow);
27 | ColorConsole.WriteLine(new string('-',text.Length), ConsoleColor.Yellow);
28 | ColorConsole.WriteLine($"(c) West Wind Technologies, 2022-{DateTime.Now.Year}", ConsoleColor.DarkGray);
29 |
30 | if (args == null || args.Length == 0 || args[0] == "HELP" || args[0] == "/?")
31 | {
32 |
33 | Console.WriteLine("\nSet Monitor Display Resolution to any available machine display mode.");
34 |
35 |
36 | string options = $@"
37 | [cyan]Syntax[/cyan]
38 | ------
39 | [yellow]SetResolution |SET|LIST|PROFILES|CREATEPROFILE
40 | -w 1920 -h 1080 -f 60 -b 32 -o 0 -p ProfileName[/yellow]
41 |
42 | [cyan]Commands[/cyan]
43 | --------
44 | HELP || /? This help display
45 | Apply Display settings from a named Profile
46 | SET Sets Display Settings -
47 | provide either a profile (-p) or display options -w/-h/-f/-b/-o
48 | LIST Lists all available display modes and monitors
49 | PROFILES Lists all saved profiles (stored in SetResolution.xml)
50 | CREATEPROFILE Creates a new profile by specifying name and display options
51 | - {Path.Combine(StartupPath,"SetResolution.xml")}
52 |
53 | [cyan]Display Settings[/cyan]
54 | ----------------
55 | -w Display Width
56 | -h Display Height
57 | -f Display Frequency in Hertz (60*)
58 | -o Orientation - 0 (default*), 1 (90deg), 2 (180deg), 3 (270deg)
59 | -p Profile name
60 | -noprompt Don't prompt for confirmation of new settings
61 | -nopersist Don't persist settings across Windows reboots (default persists)
62 |
63 | [cyan]Command Modifiers[/cyan]
64 | -----------------
65 | -m Monitor Id to apply command to (1,2,3 etc - use LIST to see Ids)
66 | applies to: LIST, SET. If not specified, Default monitor is used.
67 | -la List all Display modes (LIST command). Default only shows current matches
68 |
69 | [cyan]Examples[/cyan]
70 | --------
71 | SetResolution MyProfile
72 | SetResolution SET -p MyProfile -m2
73 | SetResolution SET -w 1920 -h 1080 -f 60 -m2 -noprompt
74 | SetResolution LIST -m2
75 | SetResolution PROFILES
76 | SetResolution CREATEPROFILE -p ""My Profile"" -w 1920 -h 1080 -f 60
77 | ";
78 | ColorConsole.WriteEmbeddedColorLine(options);
79 | }
80 | else
81 | {
82 | Console.WriteLine();
83 |
84 | var processor = new SetResolutionProcessor(cmdLine);
85 | processor.Process();
86 |
87 | Console.WriteLine();
88 | }
89 |
90 |
91 | AppConfiguration.Save();
92 | }
93 | }
94 | }
95 |
--------------------------------------------------------------------------------
/SetResolution/CommandLine/CommandLineParser.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace HtmlPackager.ConsoleApp
5 | {
6 | ///
7 | /// Basic Command Line Parser class that can deal with simple
8 | /// switch based command line arguments
9 | ///
10 | /// supports: FirstParm (first commandline argume
11 | /// -pString or -p"String"
12 | /// -f switch/flag parameters
13 | ///
14 | public abstract class CommandLineParser
15 | {
16 | ///
17 | /// The Command Line arguments string array.
18 | /// Note unlike Environment.GetCommandLineArguments() this
19 | /// holds only the arguments and not the executable
20 | ///
21 | public string[] Arguments { get; set; }
22 |
23 | ///
24 | /// The full command line including the executable
25 | ///
26 | public string CommandLine { get; set; }
27 |
28 | ///
29 | /// The first argument (if any). Useful for a
30 | /// command/action parameter
31 | ///
32 | public string FirstParameter { get; set; }
33 |
34 | public CommandLineParser(string[] args = null, string cmdLine = null)
35 | {
36 | if (string.IsNullOrEmpty(cmdLine))
37 | CommandLine = Environment.CommandLine;
38 | else
39 | CommandLine = cmdLine;
40 |
41 | if (args == null)
42 | args = Environment.GetCommandLineArgs();
43 |
44 | List argList = new List(args);
45 |
46 | if (argList.Count > 1)
47 | {
48 | FirstParameter = argList[1];
49 |
50 | // argument array contains startup exe - remove
51 | argList.RemoveAt(0);
52 | Arguments = argList.ToArray();
53 | }
54 | else
55 | {
56 | FirstParameter = string.Empty;
57 | // empty array - not null to match args array
58 | Arguments = new string[0];
59 | }
60 | }
61 |
62 | ///
63 | /// Override to provide parse switches\parameter
64 | /// into object structure
65 | ///
66 | public abstract void Parse();
67 |
68 |
69 | ///
70 | /// Parses a string Parameter switch in the format of:
71 | ///
72 | /// -p"c:\temp files\somefile.txt"
73 | /// -pc:\somefile.txt
74 | ///
75 | /// Note no spaces are allowed between swich and value.
76 | ///
77 | /// parameter switch key
78 | /// Value to return if no match is found
79 | /// Match or non-matching value
80 | protected string ParseStringParameterSwitch(string parm, string nonMatchingValue = null)
81 | {
82 | int at = CommandLine.IndexOf(parm, 0, StringComparison.OrdinalIgnoreCase);
83 |
84 | if (at > -1)
85 | {
86 | string rest = CommandLine.Substring(at + parm.Length).Trim();
87 |
88 | if (rest.StartsWith("\""))
89 | {
90 | // read to end quote
91 | at = rest.IndexOf('"', 2);
92 | if (at == -1)
93 | return CommandLine;
94 |
95 | return rest.Substring(1, at - 1);
96 | }
97 | else if (rest == " ")
98 | {
99 | // no spaces after parameters
100 | return CommandLine;
101 | }
102 | else
103 | {
104 | // read to next space
105 | rest = rest.Trim();
106 | at = (rest + " ").IndexOf(' ');
107 | string stringParm = rest.Substring(0, at);
108 | if (!string.IsNullOrEmpty(stringParm))
109 | stringParm = stringParm.Trim('"', '\'');
110 |
111 | return stringParm;
112 | }
113 | }
114 |
115 | return nonMatchingValue;
116 | }
117 |
118 | protected int ParseIntParameterSwitch(string parm, int failedValue = -1)
119 | {
120 | string val = ParseStringParameterSwitch(parm);
121 | int res = failedValue;
122 | if (!int.TryParse(val, out res))
123 | res = failedValue;
124 |
125 | return res;
126 | }
127 |
128 | protected bool ParseParameterSwitch(string parm)
129 | {
130 | int at = CommandLine.IndexOf(parm, 0, StringComparison.OrdinalIgnoreCase);
131 |
132 | if (at > -1)
133 | return true;
134 |
135 | return false;
136 | }
137 | }
138 | }
139 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | #!SetResolution.exe
2 |
3 | ## Ignore Visual Studio temporary files, build results, and
4 | ## files generated by popular Visual Studio add-ons.
5 |
6 | # User-specific files
7 | *.suo
8 | *.user
9 | *.userosscache
10 | *.sln.docstates
11 |
12 | # User-specific files (MonoDevelop/Xamarin Studio)
13 | *.userprefs
14 |
15 | # Build results
16 | [Dd]ebug/
17 | [Dd]ebugPublic/
18 | [Rr]elease/
19 | [Rr]eleases/
20 | x64/
21 | x86/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 | [Ll]og/
26 |
27 | # Visual Studio 2015 cache/options directory
28 | .vs/
29 | # Uncomment if you have tasks that create the project's static files in wwwroot
30 | #wwwroot/
31 |
32 | # MSTest test Results
33 | [Tt]est[Rr]esult*/
34 | [Bb]uild[Ll]og.*
35 |
36 | # NUNIT
37 | *.VisualState.xml
38 | TestResult.xml
39 |
40 | # Build Results of an ATL Project
41 | [Dd]ebugPS/
42 | [Rr]eleasePS/
43 | dlldata.c
44 |
45 | # DNX
46 | project.lock.json
47 | project.fragment.lock.json
48 | artifacts/
49 |
50 | *_i.c
51 | *_p.c
52 | *_i.h
53 | *.ilk
54 | *.meta
55 | *.obj
56 | *.pch
57 | *.pdb
58 | *.pgc
59 | *.pgd
60 | *.rsp
61 | *.sbr
62 | *.tlb
63 | *.tli
64 | *.tlh
65 | *.tmp
66 | *.tmp_proj
67 | *.log
68 | *.vspscc
69 | *.vssscc
70 | .builds
71 | *.pidb
72 | *.svclog
73 | *.scc
74 |
75 | # Chutzpah Test files
76 | _Chutzpah*
77 |
78 | # Visual C++ cache files
79 | ipch/
80 | *.aps
81 | *.ncb
82 | *.opendb
83 | *.opensdf
84 | *.sdf
85 | *.cachefile
86 | *.VC.db
87 | *.VC.VC.opendb
88 |
89 | # Visual Studio profiler
90 | *.psess
91 | *.vsp
92 | *.vspx
93 | *.sap
94 |
95 | # TFS 2012 Local Workspace
96 | $tf/
97 |
98 | # Guidance Automation Toolkit
99 | *.gpState
100 |
101 | # ReSharper is a .NET coding add-in
102 | _ReSharper*/
103 | *.[Rr]e[Ss]harper
104 | *.DotSettings.user
105 |
106 | # JustCode is a .NET coding add-in
107 | .JustCode
108 |
109 | # TeamCity is a build add-in
110 | _TeamCity*
111 |
112 | # DotCover is a Code Coverage Tool
113 | *.dotCover
114 |
115 | # NCrunch
116 | _NCrunch_*
117 | .*crunch*.local.xml
118 | nCrunchTemp_*
119 |
120 | # MightyMoose
121 | *.mm.*
122 | AutoTest.Net/
123 |
124 | # Web workbench (sass)
125 | .sass-cache/
126 |
127 | # Installshield output folder
128 | [Ee]xpress/
129 |
130 | # DocProject is a documentation generator add-in
131 | DocProject/buildhelp/
132 | DocProject/Help/*.HxT
133 | DocProject/Help/*.HxC
134 | DocProject/Help/*.hhc
135 | DocProject/Help/*.hhk
136 | DocProject/Help/*.hhp
137 | DocProject/Help/Html2
138 | DocProject/Help/html
139 |
140 | # Click-Once directory
141 | publish/
142 |
143 | # Publish Web Output
144 | *.[Pp]ublish.xml
145 | *.azurePubxml
146 | # TODO: Comment the next line if you want to checkin your web deploy settings
147 | # but database connection strings (with potential passwords) will be unencrypted
148 | #*.pubxml
149 | *.publishproj
150 |
151 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
152 | # checkin your Azure Web App publish settings, but sensitive information contained
153 | # in these scripts will be unencrypted
154 | PublishScripts/
155 |
156 | # NuGet Packages
157 | *.nupkg
158 | # The packages folder can be ignored because of Package Restore
159 | **/packages/*
160 | # except build/, which is used as an MSBuild target.
161 | !**/packages/build/
162 | # Uncomment if necessary however generally it will be regenerated when needed
163 | #!**/packages/repositories.config
164 | # NuGet v3's project.json files produces more ignoreable files
165 | *.nuget.props
166 | *.nuget.targets
167 |
168 | # Microsoft Azure Build Output
169 | csx/
170 | *.build.csdef
171 |
172 | # Microsoft Azure Emulator
173 | ecf/
174 | rcf/
175 |
176 | # Windows Store app package directories and files
177 | AppPackages/
178 | BundleArtifacts/
179 | Package.StoreAssociation.xml
180 | _pkginfo.txt
181 |
182 | # Visual Studio cache files
183 | # files ending in .cache can be ignored
184 | *.[Cc]ache
185 | # but keep track of directories ending in .cache
186 | !*.[Cc]ache/
187 |
188 | # Others
189 | ClientBin/
190 | ~$*
191 | *~
192 | *.dbmdl
193 | *.dbproj.schemaview
194 | *.jfm
195 | *.pfx
196 | *.publishsettings
197 | node_modules/
198 | orleans.codegen.cs
199 |
200 | # Since there are multiple workflows, uncomment next line to ignore bower_components
201 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
202 | #bower_components/
203 |
204 | # RIA/Silverlight projects
205 | Generated_Code/
206 |
207 | # Backup & report files from converting an old project file
208 | # to a newer Visual Studio version. Backup files are not needed,
209 | # because we have git ;-)
210 | _UpgradeReport_Files/
211 | Backup*/
212 | UpgradeLog*.XML
213 | UpgradeLog*.htm
214 |
215 | # SQL Server files
216 | *.mdf
217 | *.ldf
218 |
219 | # Business Intelligence projects
220 | *.rdl.data
221 | *.bim.layout
222 | *.bim_*.settings
223 |
224 | # Microsoft Fakes
225 | FakesAssemblies/
226 |
227 | # GhostDoc plugin setting file
228 | *.GhostDoc.xml
229 |
230 | # Node.js Tools for Visual Studio
231 | .ntvs_analysis.dat
232 |
233 | # Visual Studio 6 build log
234 | *.plg
235 |
236 | # Visual Studio 6 workspace options file
237 | *.opt
238 |
239 | # Visual Studio LightSwitch build output
240 | **/*.HTMLClient/GeneratedArtifacts
241 | **/*.DesktopClient/GeneratedArtifacts
242 | **/*.DesktopClient/ModelManifest.xml
243 | **/*.Server/GeneratedArtifacts
244 | **/*.Server/ModelManifest.xml
245 | _Pvt_Extensions
246 |
247 | # Paket dependency manager
248 | .paket/paket.exe
249 | paket-files/
250 |
251 | # FAKE - F# Make
252 | .fake/
253 |
254 | # JetBrains Rider
255 | .idea/
256 | *.sln.iml
257 |
258 | # CodeRush
259 | .cr/
260 |
261 | # Python Tools for Visual Studio (PTVS)
262 | __pycache__/
263 | *.pyc
--------------------------------------------------------------------------------
/SetResolution/Properties/Resources.resx:
--------------------------------------------------------------------------------
1 |
2 |
3 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 | text/microsoft-resx
110 |
111 |
112 | 2.0
113 |
114 |
115 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
116 |
117 |
118 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
119 |
120 |
121 | The settings change was unsuccessful because system is DualView capable.
122 |
123 |
124 | An invalid set of flags was passed in.
125 |
126 |
127 | The graphics mode is not supported.
128 |
129 |
130 | An invalid parameter was passed in. This can include an invalid flag or combination of flags.
131 |
132 |
133 | The display driver failed the specified graphics mode.
134 |
135 |
136 | Unable to write settings to the registry.
137 |
138 |
139 | The computer must be restarted in order for the graphics mode to work.
140 |
141 |
142 | Fatal error.
143 |
144 |
145 | Your about to change display settings to
146 | {0}
147 | Are you sure you want to continue?
148 |
149 |
150 | You are about to close the application. Are you sure you want to change screen settings to its original state?
151 | {0}
152 |
153 |
154 | Are you sure you want to reset screen settings to its original state?
155 | {0}
156 |
157 |
158 | Are you sure you want to rotate the screen?
159 |
160 |
161 | The settings change was successful.
162 |
163 |
--------------------------------------------------------------------------------
/SetResolution/CommandLine/ColorConsole.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Text.RegularExpressions;
3 |
4 | namespace Westwind.SetResolution.CommandLine
5 | {
6 |
7 | ///
8 | /// Console Color Helper class that provides coloring to individual commands
9 | ///
10 | ///
11 | /// Console Color Helper class that provides coloring to individual commands
12 | ///
13 | public static class ColorConsole
14 | {
15 | ///
16 | /// WriteLine with color
17 | ///
18 | ///
19 | ///
20 | public static void WriteLine(string text, ConsoleColor? color = null)
21 | {
22 | if (color.HasValue)
23 | {
24 | var oldColor = System.Console.ForegroundColor;
25 | if (color == oldColor)
26 | Console.WriteLine(text);
27 | else
28 | {
29 | Console.ForegroundColor = color.Value;
30 | Console.WriteLine(text);
31 | Console.ForegroundColor = oldColor;
32 | }
33 | }
34 | else
35 | Console.WriteLine(text);
36 | }
37 |
38 | ///
39 | /// Writes out a line with a specific color as a string
40 | ///
41 | /// Text to write
42 | /// A console color. Must match ConsoleColors collection names (case insensitive)
43 | public static void WriteLine(string text, string color)
44 | {
45 | if (string.IsNullOrEmpty(color))
46 | {
47 | WriteLine(text);
48 | return;
49 | }
50 |
51 | if (!Enum.TryParse(color, true, out ConsoleColor col))
52 | {
53 | WriteLine(text);
54 | }
55 | else
56 | {
57 | WriteLine(text, col);
58 | }
59 | }
60 |
61 | ///
62 | /// Write with color
63 | ///
64 | ///
65 | ///
66 | public static void Write(string text, ConsoleColor? color = null)
67 | {
68 | if (color.HasValue)
69 | {
70 | var oldColor = System.Console.ForegroundColor;
71 | if (color == oldColor)
72 | Console.Write(text);
73 | else
74 | {
75 | Console.ForegroundColor = color.Value;
76 | Console.Write(text);
77 | Console.ForegroundColor = oldColor;
78 | }
79 | }
80 | else
81 | Console.Write(text);
82 | }
83 |
84 | ///
85 | /// Writes out a line with color specified as a string
86 | ///
87 | /// Text to write
88 | /// A console color. Must match ConsoleColors collection names (case insensitive)
89 | public static void Write(string text, string color)
90 | {
91 | if (string.IsNullOrEmpty(color))
92 | {
93 | Write(text);
94 | return;
95 | }
96 |
97 | if (!ConsoleColor.TryParse(color, true, out ConsoleColor col))
98 | {
99 | Write(text);
100 | }
101 | else
102 | {
103 | Write(text, col);
104 | }
105 | }
106 |
107 | #region Wrappers and Templates
108 |
109 |
110 | ///
111 | /// Writes a line of header text wrapped in a in a pair of lines of dashes:
112 | /// -----------
113 | /// Header Text
114 | /// -----------
115 | /// and allows you to specify a color for the header. The dashes are colored
116 | ///
117 | /// Header text to display
118 | /// wrapper character (-)
119 | /// Color for header text (yellow)
120 | /// Color for dashes (gray)
121 | public static void WriteWrappedHeader(string headerText,
122 | char wrapperChar = '-',
123 | ConsoleColor headerColor = ConsoleColor.Yellow,
124 | ConsoleColor dashColor = ConsoleColor.DarkGray)
125 | {
126 | if (string.IsNullOrEmpty(headerText))
127 | return;
128 |
129 | string line = new string(wrapperChar, headerText.Length);
130 |
131 | WriteLine(line, dashColor);
132 | WriteLine(headerText, headerColor);
133 | WriteLine(line, dashColor);
134 | }
135 |
136 | private static Lazy colorBlockRegEx = new Lazy(
137 | () => new Regex("\\[(?.*?)\\](?[^[]*)\\[/\\k\\]", RegexOptions.IgnoreCase),
138 | isThreadSafe: true);
139 |
140 | ///
141 | /// Allows a string to be written with embedded color values using:
142 | /// This is [red]Red[/red] text and this is [cyan]Blue[/blue] text
143 | ///
144 | /// Text to display
145 | /// Base text color
146 | public static void WriteEmbeddedColorLine(string text, ConsoleColor? baseTextColor = null)
147 | {
148 | if (baseTextColor == null)
149 | baseTextColor = Console.ForegroundColor;
150 |
151 | if (string.IsNullOrEmpty(text))
152 | {
153 | WriteLine(string.Empty);
154 | return;
155 | }
156 |
157 | int at = text.IndexOf("[");
158 | int at2 = text.IndexOf("]");
159 | if (at == -1 || at2 <= at)
160 | {
161 | WriteLine(text, baseTextColor);
162 | return;
163 | }
164 |
165 | while (true)
166 | {
167 | var match = colorBlockRegEx.Value.Match(text);
168 | if (match.Length < 1)
169 | {
170 | Write(text, baseTextColor);
171 | break;
172 | }
173 |
174 | // write up to expression
175 | Write(text.Substring(0, match.Index), baseTextColor);
176 |
177 | // strip out the expression
178 | string highlightText = match.Groups["text"].Value;
179 | string colorVal = match.Groups["color"].Value;
180 |
181 | Write(highlightText, colorVal);
182 |
183 | // remainder of string
184 | text = text.Substring(match.Index + match.Value.Length);
185 | }
186 |
187 | Console.WriteLine();
188 | }
189 |
190 | #endregion
191 |
192 | #region Success, Error, Info, Warning Wrappers
193 |
194 | ///
195 | /// Write a Success Line - green
196 | ///
197 | /// Text to write out
198 | public static void WriteSuccess(string text)
199 | {
200 | WriteLine(text, ConsoleColor.Green);
201 | }
202 |
203 | ///
204 | /// Write a Error Line - Red
205 | ///
206 | /// Text to write out
207 | public static void WriteError(string text)
208 | {
209 | WriteLine(text, ConsoleColor.Red);
210 | }
211 |
212 | ///
213 | /// Write a Warning Line - Yellow
214 | ///
215 | /// Text to Write out
216 | public static void WriteWarning(string text)
217 | {
218 | WriteLine(text, ConsoleColor.DarkYellow);
219 | }
220 |
221 |
222 | ///
223 | /// Write a Info Line - dark cyan
224 | ///
225 | /// Text to write out
226 | public static void WriteInfo(string text)
227 | {
228 | WriteLine(text, ConsoleColor.DarkCyan);
229 | }
230 |
231 | #endregion
232 | }
233 |
234 | }
235 |
--------------------------------------------------------------------------------
/SetResolution/Properties/Resources.Designer.cs:
--------------------------------------------------------------------------------
1 | //------------------------------------------------------------------------------
2 | //
3 | // This code was generated by a tool.
4 | // Runtime Version:4.0.30319.42000
5 | //
6 | // Changes to this file may cause incorrect behavior and will be lost if
7 | // the code is regenerated.
8 | //
9 | //------------------------------------------------------------------------------
10 |
11 | namespace Westwind.SetResolution.Properties {
12 | using System;
13 |
14 |
15 | ///
16 | /// A strongly-typed resource class, for looking up localized strings, etc.
17 | ///
18 | // This class was auto-generated by the StronglyTypedResourceBuilder
19 | // class via a tool like ResGen or Visual Studio.
20 | // To add or remove a member, edit your .ResX file then rerun ResGen
21 | // with the /str option, or rebuild your VS project.
22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
25 | public class Resources {
26 |
27 | private static global::System.Resources.ResourceManager resourceMan;
28 |
29 | private static global::System.Globalization.CultureInfo resourceCulture;
30 |
31 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
32 | internal Resources() {
33 | }
34 |
35 | ///
36 | /// Returns the cached ResourceManager instance used by this class.
37 | ///
38 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
39 | public static global::System.Resources.ResourceManager ResourceManager {
40 | get {
41 | if (object.ReferenceEquals(resourceMan, null)) {
42 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Westwind.SetResolution.Properties.Resources", typeof(Resources).Assembly);
43 | resourceMan = temp;
44 | }
45 | return resourceMan;
46 | }
47 | }
48 |
49 | ///
50 | /// Overrides the current thread's CurrentUICulture property for all
51 | /// resource lookups using this strongly typed resource class.
52 | ///
53 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
54 | public static global::System.Globalization.CultureInfo Culture {
55 | get {
56 | return resourceCulture;
57 | }
58 | set {
59 | resourceCulture = value;
60 | }
61 | }
62 |
63 | ///
64 | /// Looks up a localized string similar to The settings change was unsuccessful because system is DualView capable..
65 | ///
66 | public static string InvalidOperation_Disp_Change_BadDualView {
67 | get {
68 | return ResourceManager.GetString("InvalidOperation_Disp_Change_BadDualView", resourceCulture);
69 | }
70 | }
71 |
72 | ///
73 | /// Looks up a localized string similar to An invalid set of flags was passed in..
74 | ///
75 | public static string InvalidOperation_Disp_Change_BadFlags {
76 | get {
77 | return ResourceManager.GetString("InvalidOperation_Disp_Change_BadFlags", resourceCulture);
78 | }
79 | }
80 |
81 | ///
82 | /// Looks up a localized string similar to The graphics mode is not supported..
83 | ///
84 | public static string InvalidOperation_Disp_Change_BadMode {
85 | get {
86 | return ResourceManager.GetString("InvalidOperation_Disp_Change_BadMode", resourceCulture);
87 | }
88 | }
89 |
90 | ///
91 | /// Looks up a localized string similar to An invalid parameter was passed in. This can include an invalid flag or combination of flags..
92 | ///
93 | public static string InvalidOperation_Disp_Change_BadParam {
94 | get {
95 | return ResourceManager.GetString("InvalidOperation_Disp_Change_BadParam", resourceCulture);
96 | }
97 | }
98 |
99 | ///
100 | /// Looks up a localized string similar to The display driver failed the specified graphics mode..
101 | ///
102 | public static string InvalidOperation_Disp_Change_Failed {
103 | get {
104 | return ResourceManager.GetString("InvalidOperation_Disp_Change_Failed", resourceCulture);
105 | }
106 | }
107 |
108 | ///
109 | /// Looks up a localized string similar to Unable to write settings to the registry..
110 | ///
111 | public static string InvalidOperation_Disp_Change_NotUpdated {
112 | get {
113 | return ResourceManager.GetString("InvalidOperation_Disp_Change_NotUpdated", resourceCulture);
114 | }
115 | }
116 |
117 | ///
118 | /// Looks up a localized string similar to The computer must be restarted in order for the graphics mode to work..
119 | ///
120 | public static string InvalidOperation_Disp_Change_Restart {
121 | get {
122 | return ResourceManager.GetString("InvalidOperation_Disp_Change_Restart", resourceCulture);
123 | }
124 | }
125 |
126 | ///
127 | /// Looks up a localized string similar to Fatal error..
128 | ///
129 | public static string InvalidOperation_FatalError {
130 | get {
131 | return ResourceManager.GetString("InvalidOperation_FatalError", resourceCulture);
132 | }
133 | }
134 |
135 | ///
136 | /// Looks up a localized string similar to Your about to change display settings to
137 | ///{0}
138 | ///Are you sure you want to continue?.
139 | ///
140 | public static string Msg_Disp_Change {
141 | get {
142 | return ResourceManager.GetString("Msg_Disp_Change", resourceCulture);
143 | }
144 | }
145 |
146 | ///
147 | /// Looks up a localized string similar to You are about to close the application. Are you sure you want to change screen settings to its original state?
148 | ///{0}.
149 | ///
150 | public static string Msg_Disp_Change_Original {
151 | get {
152 | return ResourceManager.GetString("Msg_Disp_Change_Original", resourceCulture);
153 | }
154 | }
155 |
156 | ///
157 | /// Looks up a localized string similar to Are you sure you want to reset screen settings to its original state?
158 | ///{0}.
159 | ///
160 | public static string Msg_Disp_Change_Reset {
161 | get {
162 | return ResourceManager.GetString("Msg_Disp_Change_Reset", resourceCulture);
163 | }
164 | }
165 |
166 | ///
167 | /// Looks up a localized string similar to Are you sure you want to rotate the screen?.
168 | ///
169 | public static string Msg_Disp_Change_Rotate {
170 | get {
171 | return ResourceManager.GetString("Msg_Disp_Change_Rotate", resourceCulture);
172 | }
173 | }
174 |
175 | ///
176 | /// Looks up a localized string similar to The settings change was successful..
177 | ///
178 | public static string Msg_Disp_Change_Successful {
179 | get {
180 | return ResourceManager.GetString("Msg_Disp_Change_Successful", resourceCulture);
181 | }
182 | }
183 | }
184 | }
185 |
--------------------------------------------------------------------------------
/SetResolution/SetResolutionProcessor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading;
5 | using Westwind.SetResolution.CommandLine;
6 |
7 | namespace Westwind.SetResolution
8 | {
9 | public class SetResolutionProcessor
10 | {
11 | private SetResolutionCommandLineParser CommandLine { get; }
12 |
13 | public SetResolutionProcessor(SetResolutionCommandLineParser commandLine)
14 | {
15 | CommandLine= commandLine;
16 | }
17 |
18 | public void Process()
19 | {
20 | if (CommandLine.FirstParameter.Equals("Set", StringComparison.OrdinalIgnoreCase))
21 | {
22 | SetResolution();
23 | }
24 |
25 | if (CommandLine.FirstParameter.Equals("List", StringComparison.OrdinalIgnoreCase))
26 | {
27 | ListDisplayModes(CommandLine.ListAll);
28 | }
29 |
30 | if (CommandLine.FirstParameter.Equals("Profiles", StringComparison.OrdinalIgnoreCase))
31 | {
32 | ListProfiles();
33 | }
34 |
35 | if (CommandLine.FirstParameter.Equals("CreateProfile", StringComparison.OrdinalIgnoreCase))
36 | {
37 | CreateProfile();
38 | }
39 |
40 | // No Action command (help is handled on startup)
41 | if (CommandLine.FirstParameter.StartsWith("-"))
42 | {
43 | // assume we're using SetResolution with parameters
44 | SetResolution();
45 | }
46 |
47 | // Launch Profile by name
48 | if (AppConfiguration.Current.Profiles.Any(pro => pro.Name.Equals(CommandLine.FirstParameter, StringComparison.OrdinalIgnoreCase)))
49 | {
50 | CommandLine.Profile = CommandLine.FirstParameter;
51 | SetResolution();
52 | }
53 | }
54 |
55 | private void CreateProfile()
56 | {
57 | if (string.IsNullOrEmpty(CommandLine.Profile))
58 | {
59 | ColorConsole.WriteError("You have to specify a profile to create.");
60 | return;
61 | }
62 |
63 | if (CommandLine.Width == 0 || CommandLine.Height == 0)
64 | {
65 | ColorConsole.WriteError("Please specify at minimum a Width and Height for the profile.");
66 | return;
67 | }
68 |
69 | var profile = new DisplayProfile()
70 | {
71 | Name = CommandLine.Profile,
72 | Width = CommandLine.Width,
73 | Height = CommandLine.Height,
74 | Frequency = CommandLine.Frequency,
75 | BitSize = CommandLine.BitCount,
76 | Orientation = CommandLine.Orientation,
77 | };
78 |
79 | var set = AppConfiguration.Current.Profiles.FirstOrDefault(p =>
80 | p.Name.Equals(profile.Name, StringComparison.OrdinalIgnoreCase));
81 | if (set != null)
82 | AppConfiguration.Current.Profiles.Remove(set);
83 |
84 | AppConfiguration.Current.Profiles.Add(profile);
85 | AppConfiguration.Save();
86 |
87 | ColorConsole.WriteSuccess($"Created new Profile: {profile.Name}. {profile}");
88 |
89 | ListProfiles();
90 | }
91 |
92 | private void SetResolution()
93 | {
94 | var devices = DisplayManager.GetAllDisplayDevices();
95 | var monitor = devices.FirstOrDefault(d => d.IsSelected); // main monitor
96 | var currentSettings = DisplayManager.GetCurrentDisplaySetting();
97 |
98 | if (CommandLine.MonitorId > 0)
99 | {
100 | monitor = devices.FirstOrDefault(d => d.Index == CommandLine.MonitorId);
101 | devices.ForEach(d=> d.IsSelected = false);
102 | monitor.IsSelected = true;
103 | }
104 |
105 |
106 | if (!string.IsNullOrEmpty(CommandLine.Profile))
107 | {
108 | var profile = AppConfiguration.Current.Profiles.FirstOrDefault(p=> p.Name.Equals(CommandLine.Profile, StringComparison.OrdinalIgnoreCase));
109 | if (profile == null)
110 | {
111 | ColorConsole.WriteError($"Couldn't find Display Profile {CommandLine.Profile}");
112 | Console.WriteLine();
113 | ListProfiles();
114 | return;
115 | }
116 |
117 | profile.UpdateCommandLine(CommandLine);
118 | }
119 |
120 | if (CommandLine.Width == 0 || CommandLine.Height == 0)
121 | {
122 | ColorConsole.WriteError("Please specify at minimum Width and Height parameters.");
123 | return;
124 | }
125 |
126 | if (CommandLine.Frequency == 0)
127 | {
128 | CommandLine.Frequency = 60;
129 | }
130 |
131 | var list = DisplayManager.GetAllDisplaySettings(monitor.DriverDeviceName);
132 |
133 | var set = list.FirstOrDefault(d=> d.Width == CommandLine.Width &&
134 | d.Height == CommandLine.Height &&
135 | d.Frequency == CommandLine.Frequency &&
136 | d.BitCount == CommandLine.BitCount &&
137 | d.Orientation == (Orientation) CommandLine.Orientation );
138 |
139 | if (set == null)
140 | {
141 | ColorConsole.WriteError($"Couldn't find a matching Display Mode.");
142 | Console.WriteLine();
143 | ListDisplayModes();
144 | return;
145 | }
146 |
147 | set.NoPersist = CommandLine.NoPersist;
148 |
149 | try
150 | {
151 | DisplayManager.SetDisplaySettings(set, monitor.DriverDeviceName);
152 | ColorConsole.WriteEmbeddedColorLine($"Switched Display Mode on Monitor [green]{monitor.DisplayName}[/green] to:\n[green]{set.ToString()}[/green]");
153 | }
154 | catch(Exception ex)
155 | {
156 | ColorConsole.WriteError("Unable to set Display Mode to " + set.ToString() + "\nError: " + ex.Message);
157 | return;
158 | }
159 |
160 | if (!CommandLine.NoPrompt)
161 | {
162 | ColorConsole.WriteLine("\npress any key to confirm new resolution within 5 seconds.",ConsoleColor.Yellow);
163 | bool keyPressed = false;
164 | for (int i = 0; i < 55; i++)
165 | {
166 | Thread.Sleep(100);
167 | if (Console.KeyAvailable)
168 | {
169 | Console.ReadKey(true);
170 | keyPressed = true;
171 | break;
172 | }
173 | }
174 |
175 | if (!keyPressed)
176 | {
177 | ColorConsole.WriteWarning("No key pressed: Resetting Display Mode to previous settings.");
178 | DisplayManager.SetDisplaySettings(currentSettings, deviceName: monitor.DriverDeviceName);
179 | }
180 | else
181 | {
182 | ColorConsole.WriteSuccess("Successfully changed resolution.");
183 | }
184 | }
185 | }
186 |
187 | private void ListDisplayModes(bool showAll = false)
188 | {
189 | string text;
190 | var devices = DisplayManager.GetAllDisplayDevices();
191 | var monitor = devices.FirstOrDefault(d => d.IsSelected); // main monitor
192 | if (CommandLine.MonitorId > 0)
193 | {
194 | monitor = devices.FirstOrDefault(d => d.Index == CommandLine.MonitorId);
195 | devices.ForEach(d => d.IsSelected = false);
196 | monitor.IsSelected = true;
197 | }
198 |
199 | var displayModes = DisplayManager.GetAllDisplaySettings(monitor.DriverDeviceName);
200 | var current = DisplayManager.GetCurrentDisplaySetting(monitor.DriverDeviceName);
201 |
202 | ColorConsole.WriteLine("Available Monitors", ConsoleColor.Yellow);
203 | ColorConsole.WriteLine("------------------", ConsoleColor.Yellow);
204 | foreach (var device in devices)
205 | {
206 | if (device.IsSelected)
207 | ColorConsole.WriteLine(device.ToString(), ConsoleColor.Green);
208 | else
209 | Console.WriteLine(device);
210 | }
211 | Console.WriteLine();
212 |
213 |
214 | IList filtered = displayModes;
215 | if (!CommandLine.ListAll)
216 | {
217 | filtered = displayModes.Where(d =>
218 | d.Width >= AppConfiguration.Current.MinResolutionWidth &&
219 | d.Frequency == current.Frequency &&
220 | d.Orientation == current.Orientation)
221 | .OrderByDescending(d=> d.Width)
222 | // unique
223 | .GroupBy(d => new {d.Width, d.Height, d.Frequency, d.Orientation})
224 | .Select(g => g.First())
225 | .ToList();
226 | }
227 | else
228 | {
229 | filtered = filtered.OrderByDescending(d => d.Width).ToList();
230 | }
231 |
232 | text = $"Available Display Modes ({filtered.Count})" ;
233 | ColorConsole.WriteLine(text, ConsoleColor.Yellow);
234 | ColorConsole.WriteLine(new string('-', text.Length), ConsoleColor.Yellow);
235 |
236 |
237 | foreach (var set in filtered)
238 | {
239 | if (set.Equals(current))
240 | ColorConsole.WriteLine(set.ToString(!CommandLine.ListAll) + " *", ConsoleColor.Green);
241 | else
242 | Console.WriteLine(set.ToString(!CommandLine.ListAll));
243 | }
244 | }
245 |
246 | private void ListProfiles()
247 | {
248 | var list = DisplayManager.GetAllDisplaySettings();
249 |
250 | ColorConsole.WriteLine("Available Profiles", ConsoleColor.Yellow);
251 | ColorConsole.WriteLine("-----------------------", ConsoleColor.Yellow);
252 |
253 |
254 | foreach (var profile in AppConfiguration.Current.Profiles)
255 | {
256 | Console.WriteLine(profile.ToString());
257 | }
258 | }
259 | }
260 | }
261 |
--------------------------------------------------------------------------------
/SetResolution/DisplayManagerNative.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Based on original code from:
3 | *
4 | * (c) Mohammad Elsheimy
5 | * Changing Display Settings Programmatically
6 | *
7 | * https://www.c-sharpcorner.com/uploadfile/GemingLeader/changing-display-settings-programmatically/
8 | *
9 | * Added support for:
10 | *
11 | * * Listing Monitors and Monitor specific display modes
12 | * * Set display mode for a specific monitor/driver
13 | *
14 | */
15 |
16 | using System;
17 | using System.Runtime.InteropServices;
18 |
19 | namespace Westwind.SetResolution
20 | {
21 | static class DisplayManagerNative
22 | {
23 | #region Enum Display Settings
24 |
25 | [DllImport("User32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
26 | [return: MarshalAs(UnmanagedType.Bool)]
27 | public static extern bool EnumDisplaySettings(
28 | //[param: MarshalAs(UnmanagedType.LPTStr)]
29 | //string lpszDeviceName, //display device
30 | byte[] lpszDeviceName, // display device ToLPTStr
31 | [param: MarshalAs(UnmanagedType.U4)]
32 | int iModeNum, // graphics mode
33 | [In, Out]
34 | ref DEVMODE lpDevMode // graphics mode settings
35 | );
36 |
37 | public const int ENUM_CURRENT_SETTINGS = -1;
38 | public const int DMDO_DEFAULT = 0;
39 | public const int DMDO_90 = 1;
40 | public const int DMDO_180 = 2;
41 | public const int DMDO_270 = 3;
42 |
43 | [Flags()]
44 | public enum DmFlags : int
45 | {
46 | DM_ORIENTATION = 0x00000001,
47 | DM_PAPERSIZE = 0x00000002,
48 | DM_PAPERLENGTH = 0x00000004,
49 | DM_PAPERWIDTH = 0x00000008,
50 | DM_SCALE = 0x00000010,
51 | DM_POSITION = 0x00000020,
52 | DM_NUP = 0x00000040,
53 | DM_DISPLAYORIENTATION = 0x00000080,
54 | DM_COPIES = 0x00000100,
55 | DM_DEFAULTSOURCE = 0x00000200,
56 | DM_PRINTQUALITY = 0x00000400,
57 | DM_COLOR = 0x00000800,
58 | DM_DUPLEX = 0x00001000,
59 | DM_YRESOLUTION = 0x00002000,
60 | DM_TTOPTION = 0x00004000,
61 | DM_COLLATE = 0x00008000,
62 | DM_FORMNAME = 0x00010000,
63 | DM_LOGPIXELS = 0x00020000,
64 | DM_BITSPERPEL = 0x00040000,
65 | DM_PELSWIDTH = 0x00080000,
66 | DM_PELSHEIGHT = 0x00100000,
67 | DM_DISPLAYFLAGS = 0x00200000,
68 | DM_DISPLAYFREQUENCY = 0x00400000,
69 | DM_ICMMETHOD = 0x00800000,
70 | DM_ICMINTENT = 0x01000000,
71 | DM_MEDIATYPE = 0x02000000,
72 | DM_DITHERTYPE = 0x04000000,
73 | DM_PANNINGWIDTH = 0x08000000,
74 | DM_PANNINGHEIGHT = 0x10000000,
75 | DM_DISPLAYFIXEDOUTPUT = 0x20000000
76 | }
77 |
78 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
79 | public struct DEVMODE
80 | {
81 | // You can define the following constant
82 | // but OUTSIDE the structure because you know
83 | // that size and layout of the structure is very important
84 | // CCHDEVICENAME = 32 = 0x50
85 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
86 | public string dmDeviceName;
87 | // In addition you can define the last character array
88 | // as following:
89 | //[MarshalAs(UnmanagedType.ByValArray, SizeConst = 32)]
90 | //public Char[] dmDeviceName;
91 |
92 | // After the 32-bytes array
93 | [MarshalAs(UnmanagedType.U2)]
94 | public ushort dmSpecVersion;
95 |
96 | [MarshalAs(UnmanagedType.U2)]
97 | public ushort dmDriverVersion;
98 |
99 | [MarshalAs(UnmanagedType.U2)]
100 | public ushort dmSize;
101 |
102 | [MarshalAs(UnmanagedType.U2)]
103 | public ushort dmDriverExtra;
104 |
105 | [MarshalAs(UnmanagedType.U4)]
106 | public DmFlags dmFields;
107 |
108 | public POINTL dmPosition;
109 |
110 | [MarshalAs(UnmanagedType.U4)]
111 | public uint dmDisplayOrientation;
112 |
113 | [MarshalAs(UnmanagedType.U4)]
114 | public uint dmDisplayFixedOutput;
115 |
116 | [MarshalAs(UnmanagedType.I2)]
117 | public short dmColor;
118 |
119 | [MarshalAs(UnmanagedType.I2)]
120 | public short dmDuplex;
121 |
122 | [MarshalAs(UnmanagedType.I2)]
123 | public short dmYResolution;
124 |
125 | [MarshalAs(UnmanagedType.I2)]
126 | public short dmTTOption;
127 |
128 | [MarshalAs(UnmanagedType.I2)]
129 | public short dmCollate;
130 |
131 | // CCHDEVICENAME = 32 = 0x50
132 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
133 | public string dmFormName;
134 | // Also can be defined as
135 | //[MarshalAs(UnmanagedType.ByValArray,
136 | // SizeConst = 32, ArraySubType = UnmanagedType.U1)]
137 | //public Byte[] dmFormName;
138 |
139 | [MarshalAs(UnmanagedType.U2)]
140 | public ushort dmLogPixels;
141 |
142 | [MarshalAs(UnmanagedType.U4)]
143 | public uint dmBitsPerPel;
144 |
145 | [MarshalAs(UnmanagedType.U4)]
146 | public uint dmPelsWidth;
147 |
148 | [MarshalAs(UnmanagedType.U4)]
149 | public uint dmPelsHeight;
150 |
151 | [MarshalAs(UnmanagedType.U4)]
152 | public uint dmDisplayFlags;
153 |
154 | [MarshalAs(UnmanagedType.U4)]
155 | public uint dmDisplayFrequency;
156 |
157 | [MarshalAs(UnmanagedType.U4)]
158 | public uint dmICMMethod;
159 |
160 | [MarshalAs(UnmanagedType.U4)]
161 | public uint dmICMIntent;
162 |
163 | [MarshalAs(UnmanagedType.U4)]
164 | public uint dmMediaType;
165 |
166 | [MarshalAs(UnmanagedType.U4)]
167 | public uint dmDitherType;
168 |
169 | [MarshalAs(UnmanagedType.U4)]
170 | public uint dmReserved1;
171 |
172 | [MarshalAs(UnmanagedType.U4)]
173 | public uint dmReserved2;
174 |
175 | [MarshalAs(UnmanagedType.U4)]
176 | public uint dmPanningWidth;
177 |
178 | [MarshalAs(UnmanagedType.U4)]
179 | public uint dmPanningHeight;
180 |
181 | ///
182 | /// Initializes the structure variables.
183 | ///
184 | public void Initialize()
185 | {
186 | this.dmDeviceName = new string(new char[32]);
187 | this.dmFormName = new string(new char[32]);
188 | this.dmSize = (ushort)Marshal.SizeOf(this);
189 | }
190 | }
191 |
192 |
193 | // 8-bytes structure
194 | [StructLayout(LayoutKind.Sequential)]
195 | public struct POINTL
196 | {
197 | public int x;
198 | public int y;
199 | }
200 |
201 | #endregion
202 |
203 |
204 | #region Enum DisplayDevices
205 |
206 | [DllImport("user32.dll")]
207 | public static extern bool EnumDisplayDevices(string lpDevice, uint iDevNum, ref DISPLAY_DEVICE lpDisplayDevice, uint dwFlags);
208 |
209 |
210 | [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
211 | public struct DISPLAY_DEVICE
212 | {
213 | [MarshalAs(UnmanagedType.U4)]
214 | public int cb;
215 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)]
216 | public string DeviceName;
217 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
218 | public string DeviceString;
219 | [MarshalAs(UnmanagedType.U4)]
220 | public DisplayDeviceStateFlags StateFlags;
221 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
222 | public string DeviceID;
223 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 128)]
224 | public string DeviceKey;
225 | }
226 |
227 | [Flags()]
228 | public enum DisplayDeviceStateFlags : int
229 | {
230 | /// The device is part of the desktop.
231 | AttachedToDesktop = 0x1,
232 | MultiDriver = 0x2,
233 | /// The device is part of the desktop.
234 | PrimaryDevice = 0x4,
235 | /// Represents a pseudo device used to mirror application drawing for remoting or other purposes.
236 | MirroringDriver = 0x8,
237 | /// The device is VGA compatible.
238 | VGACompatible = 0x10,
239 | /// The device is removable; it cannot be the primary display.
240 | Removable = 0x20,
241 | /// The device has more display modes than its output devices support.
242 | ModesPruned = 0x8000000,
243 | Remote = 0x4000000,
244 | Disconnect = 0x2000000
245 | }
246 | #endregion
247 |
248 |
249 | #region Errors
250 |
251 | [DllImport("User32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
252 | [return: MarshalAs(UnmanagedType.I4)]
253 | public static extern int ChangeDisplaySettings(
254 | [In, Out]
255 | ref DEVMODE lpDevMode,
256 | [param: MarshalAs(UnmanagedType.U4)]
257 | uint dwflags);
258 |
259 |
260 | [DllImport("user32.dll")]
261 | public static extern int ChangeDisplaySettingsEx(string lpszDeviceName,
262 | ref DEVMODE lpDevMode,
263 | IntPtr hwnd,
264 | uint dwflags,
265 | IntPtr lParam);
266 |
267 |
268 |
269 | [DllImport("kernel32.dll", SetLastError = true, BestFitMapping = false, ThrowOnUnmappableChar = true)]
270 | [return: MarshalAs(UnmanagedType.Bool)]
271 | public static extern uint FormatMessage(
272 | [param: MarshalAs(UnmanagedType.U4)]
273 | uint dwFlags,
274 | [param: MarshalAs(UnmanagedType.U4)]
275 | uint lpSource,
276 | [param: MarshalAs(UnmanagedType.U4)]
277 | uint dwMessageId,
278 | [param: MarshalAs(UnmanagedType.U4)]
279 | uint dwLanguageId,
280 | [param: MarshalAs(UnmanagedType.LPTStr)]
281 | out string lpBuffer,
282 | [param: MarshalAs(UnmanagedType.U4)]
283 | uint nSize,
284 | [param: MarshalAs(UnmanagedType.U4)]
285 | uint arguments);
286 |
287 | public const uint FORMAT_MESSAGE_FROM_HMODULE = 0x800;
288 |
289 | public const uint FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x100;
290 | public const uint FORMAT_MESSAGE_IGNORE_INSERTS = 0x200;
291 | public const uint FORMAT_MESSAGE_FROM_SYSTEM = 0x1000;
292 | public const uint FORMAT_MESSAGE_FLAGS = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM;
293 |
294 | #endregion
295 |
296 | #region Helpers
297 |
298 | public static byte[] ToLPTStr(string str)
299 | {
300 | if (str == null) return null;
301 |
302 | var lptArray = new byte[str.Length + 1];
303 |
304 | var index = 0;
305 | foreach (char c in str.ToCharArray())
306 | lptArray[index++] = Convert.ToByte(c);
307 |
308 | lptArray[index] = Convert.ToByte('\0');
309 |
310 | return lptArray;
311 | }
312 |
313 | #endregion
314 | }
315 |
316 | }
317 |
--------------------------------------------------------------------------------
/SetResolution/Utilities/SerializationUtils.cs:
--------------------------------------------------------------------------------
1 | #region License
2 | /*
3 | **************************************************************
4 | * Author: Rick Strahl
5 | * © West Wind Technologies, 2008 - 2009
6 | * http://www.west-wind.com/
7 | *
8 | * Created: 09/08/2008
9 | *
10 | * Permission is hereby granted, free of charge, to any person
11 | * obtaining a copy of this software and associated documentation
12 | * files (the "Software"), to deal in the Software without
13 | * restriction, including without limitation the rights to use,
14 | * copy, modify, merge, publish, distribute, sublicense, and/or sell
15 | * copies of the Software, and to permit persons to whom the
16 | * Software is furnished to do so, subject to the following
17 | * conditions:
18 | *
19 | * The above copyright notice and this permission notice shall be
20 | * included in all copies or substantial portions of the Software.
21 | *
22 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
24 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
29 | * OTHER DEALINGS IN THE SOFTWARE.
30 | **************************************************************
31 | */
32 | #endregion
33 |
34 | using System;
35 | using System.IO;
36 | using System.Text;
37 | using System.Reflection;
38 |
39 | using System.Xml;
40 | using System.Xml.Serialization;
41 | using System.Runtime.Serialization.Formatters.Binary;
42 | using System.Diagnostics;
43 | using System.Runtime.Serialization;
44 |
45 | namespace Westwind.Utilities
46 | {
47 |
48 | // Serialization specific code
49 |
50 | public static class SerializationUtils
51 | {
52 |
53 | ///
54 | /// Serializes an object instance to a file.
55 | ///
56 | /// the object instance to serialize
57 | ///
58 | /// determines whether XML serialization or binary serialization is used
59 | ///
60 | public static bool SerializeObject(object instance, string fileName)
61 | {
62 | bool retVal = true;
63 |
64 | XmlTextWriter writer = null;
65 | try
66 | {
67 | XmlSerializer serializer =
68 | new XmlSerializer(instance.GetType());
69 |
70 | // Create an XmlTextWriter using a FileStream.
71 | Stream fs = new FileStream(fileName, FileMode.Create);
72 | writer = new XmlTextWriter(fs, new UTF8Encoding());
73 | writer.Formatting = Formatting.Indented;
74 | writer.IndentChar = ' ';
75 | writer.Indentation = 3;
76 |
77 | // Serialize using the XmlTextWriter.
78 | serializer.Serialize(writer, instance);
79 | }
80 | catch (Exception ex)
81 | {
82 | Debug.Write("SerializeObject failed with : " + ex.Message, "West Wind");
83 | retVal = false;
84 | }
85 | finally
86 | {
87 | if (writer != null)
88 | writer.Close();
89 | }
90 |
91 |
92 | return retVal;
93 | }
94 |
95 | ///
96 | /// Overload that supports passing in an XML TextWriter.
97 | ///
98 | ///
99 | /// Note the Writer is not closed when serialization is complete
100 | /// so the caller needs to handle closing.
101 | ///
102 | /// object to serialize
103 | /// XmlTextWriter instance to write output to
104 | /// Determines whether false is returned on failure or an exception is thrown
105 | ///
106 | public static bool SerializeObject(object instance, XmlTextWriter writer, bool throwExceptions)
107 | {
108 | bool retVal = true;
109 |
110 | try
111 | {
112 | XmlSerializer serializer =
113 | new XmlSerializer(instance.GetType());
114 |
115 | // Create an XmlTextWriter using a FileStream.
116 | writer.Formatting = Formatting.Indented;
117 | writer.IndentChar = ' ';
118 | writer.Indentation = 3;
119 |
120 | // Serialize using the XmlTextWriter.
121 | serializer.Serialize(writer, instance);
122 | }
123 | catch (Exception ex)
124 | {
125 | Debug.Write("SerializeObject failed with : " + ex.GetBaseException().Message + "\r\n" + (ex.InnerException != null ? ex.InnerException.Message : ""), "West Wind");
126 |
127 | if (throwExceptions)
128 | throw;
129 |
130 | retVal = false;
131 | }
132 |
133 | return retVal;
134 | }
135 |
136 |
137 | ///
138 | /// Serializes an object into an XML string variable for easy 'manual' serialization
139 | ///
140 | /// object to serialize
141 | /// resulting XML string passed as an out parameter
142 | /// true or false
143 | public static bool SerializeObject(object instance, out string xmlResultString)
144 | {
145 | return SerializeObject(instance, out xmlResultString, false);
146 | }
147 |
148 | ///
149 | /// Serializes an object into a string variable for easy 'manual' serialization
150 | ///
151 | ///
152 | /// Out parm that holds resulting XML string
153 | /// If true causes exceptions rather than returning false
154 | ///
155 | public static bool SerializeObject(object instance, out string xmlResultString, bool throwExceptions)
156 | {
157 | xmlResultString = string.Empty;
158 | MemoryStream ms = new MemoryStream();
159 |
160 | XmlTextWriter writer = new XmlTextWriter(ms, new UTF8Encoding());
161 |
162 | if (!SerializeObject(instance, writer,throwExceptions))
163 | {
164 | ms.Close();
165 | return false;
166 | }
167 |
168 | xmlResultString = Encoding.UTF8.GetString(ms.ToArray(), 0, (int)ms.Length);
169 |
170 | ms.Close();
171 | writer.Close();
172 |
173 | return true;
174 | }
175 |
176 |
177 | ///
178 |
179 | ///
180 | /// Serializes an object to an XML string. Unlike the other SerializeObject overloads
181 | /// this methods *returns a string* rather than a bool result!
182 | ///
183 | ///
184 | /// Determines if a failure throws or returns null
185 | ///
186 | /// null on error otherwise the Xml String.
187 | ///
188 | ///
189 | /// If null is passed in null is also returned so you might want
190 | /// to check for null before calling this method.
191 | ///
192 | public static string SerializeObjectToString(object instance, bool throwExceptions = false)
193 | {
194 | string xmlResultString = string.Empty;
195 |
196 | if (!SerializeObject(instance, out xmlResultString, throwExceptions))
197 | return null;
198 |
199 | return xmlResultString;
200 | }
201 |
202 |
203 |
204 |
205 |
206 | ///
207 | /// Deserializes an object from file and returns a reference.
208 | ///
209 | /// name of the file to serialize to
210 | /// The Type of the object. Use typeof(yourobject class)
211 | /// determines whether we use Xml or Binary serialization
212 | /// determines whether failure will throw rather than return null on failure
213 | /// Instance of the deserialized object or null. Must be cast to your object type
214 | public static object DeSerializeObject(string fileName, Type objectType, bool throwExceptions)
215 | {
216 | object instance = null;
217 |
218 |
219 | XmlReader reader = null;
220 | XmlSerializer serializer = null;
221 | FileStream fs = null;
222 | try
223 | {
224 | // Create an instance of the XmlSerializer specifying type and namespace.
225 | serializer = new XmlSerializer(objectType);
226 |
227 | // A FileStream is needed to read the XML document.
228 | fs = new FileStream(fileName, FileMode.Open, FileAccess.Read);
229 | reader = new XmlTextReader(fs);
230 |
231 | instance = serializer.Deserialize(reader);
232 | }
233 | catch(Exception ex)
234 | {
235 | if (throwExceptions)
236 | throw;
237 |
238 | string message = ex.Message;
239 | return null;
240 | }
241 | finally
242 | {
243 | if (fs != null)
244 | fs.Close();
245 |
246 | if (reader != null)
247 | reader.Close();
248 | }
249 |
250 |
251 | return instance;
252 | }
253 |
254 | ///
255 | /// Deserialize an object from an XmlReader object.
256 | ///
257 | ///
258 | ///
259 | ///
260 | public static object DeSerializeObject(XmlReader reader, Type objectType)
261 | {
262 | XmlSerializer serializer = new XmlSerializer(objectType);
263 | object Instance = serializer.Deserialize(reader);
264 | reader.Close();
265 |
266 | return Instance;
267 | }
268 |
269 | public static object DeSerializeObject(string xml, Type objectType)
270 | {
271 | XmlTextReader reader = new XmlTextReader(xml, XmlNodeType.Document, null);
272 | return DeSerializeObject(reader, objectType);
273 | }
274 |
275 |
276 | ///
277 | /// Returns a string of all the field value pairs of a given object.
278 | /// Works only on non-statics.
279 | ///
280 | ///
281 | ///
282 | ///
283 | public static string ObjectToString(object instanc, string separator, ObjectToStringTypes type)
284 | {
285 | FieldInfo[] fi = instanc.GetType().GetFields();
286 |
287 | string output = string.Empty;
288 |
289 | if (type == ObjectToStringTypes.Properties || type == ObjectToStringTypes.PropertiesAndFields)
290 | {
291 | foreach (PropertyInfo property in instanc.GetType().GetProperties())
292 | {
293 | try
294 | {
295 | output += property.Name + ":" + property.GetValue(instanc, null).ToString() + separator;
296 | }
297 | catch
298 | {
299 | output += property.Name + ": n/a" + separator;
300 | }
301 | }
302 | }
303 |
304 | if (type == ObjectToStringTypes.Fields || type == ObjectToStringTypes.PropertiesAndFields)
305 | {
306 | foreach (FieldInfo field in fi)
307 | {
308 | try
309 | {
310 | output = output + field.Name + ": " + field.GetValue(instanc).ToString() + separator;
311 | }
312 | catch
313 | {
314 | output = output + field.Name + ": n/a" + separator;
315 | }
316 | }
317 | }
318 | return output;
319 | }
320 |
321 | }
322 |
323 | public enum ObjectToStringTypes
324 | {
325 | Properties,
326 | PropertiesAndFields,
327 | Fields
328 | }
329 | }
330 |
331 |
332 |
333 |
334 |
335 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SetResolution: Set Windows Display Resolution from the Command Line
2 |
3 | [](https://www.nuget.org/packages/SetResolution/)
4 | [](https://www.nuget.org/packages/SetResolution/)
5 |
6 | 
7 |
8 | This small command line utility allows you to quickly set Windows Display Resolutions to any of the available display modes available for your active Monitors or virtual display devices.
9 |
10 | * Set an explicit Display Resolution
11 | * Create and use Display Mode Profiles for quick access
12 | * List all available Display Modes and Monitors
13 | * Supports multiple Monitors
14 | * Prompts for confirmation by default to avoid invalid display modes
15 | * Runs as standalone, single file Windows EXE
16 | * Can install and run as `dotnet tool` *(>=0.3 (.NET 9.0), >v0.2 (.NET 8.0),
17 |
18 | 
19 |
20 | ## Basic Usage
21 | Most common usage is via a **pre-defined profile name**:
22 |
23 | ```powershell
24 | # Set to a profile named 1080 on default monitor
25 | SetResolution 1080
26 |
27 | # or shortcut version (sr.exe) on Monitor 2
28 | sr 4k -m2
29 | ```
30 |
31 | We ship a few default profiles:
32 |
33 | * 4k
34 | * 1080
35 | * 1440
36 | * 720
37 |
38 | but you can also edit these or create your own named profiles.
39 |
40 | Alternately you can explicitly pick a resolution, frequency, bit rate and Orientation:
41 |
42 | ```powershell
43 | sr SET -w 2560 -h 1600 -f 60 -b 32 -o 0
44 | ```
45 | *Frequency, BitRate and Orientation are optional*
46 |
47 | To see available resolutions for a specific monitor:
48 |
49 | ```powershell
50 | # default list is filtered to current frequency/bitrate/orientation
51 | # and the `MinResolutionWidth` configuration setting
52 | sr LIST -m1
53 |
54 | # list ALL resolutions/modes
55 | sr LIST -m1 -la
56 | ```
57 |
58 | To create a new profile:
59 |
60 | ```powershell
61 | # Create a new profile
62 | sr CREATEPROFILE -w 2560 -h 1600 -f 60 -b 32 -o 0
63 |
64 | # List all profiles with their settings
65 | sr PROFILES
66 | ```
67 |
68 | ## Installation
69 | You can install this tool in a couple of ways (for now).
70 |
71 | ### Download Single-File EXE Binary
72 | This tool is a small, self-contained Console EXE application. For now, you can download the `SetResolution.exe` (or `sr.exe` file directly from here):
73 |
74 | [Download SetResolution.exe](https://github.com/RickStrahl/SetResolution/raw/master/Binaries/SetResolution.exe)
75 |
76 | I recommend you copy to a folder location that is in your Windows path or add it to your path, so you can run `SetResolution` from any location.
77 |
78 | ### Install as Dotnet Tool (.NET 9.0 SDK required)
79 | For .NET developers the easiest way to install and keep the tool up to date is via Dotnet Tool installation. This requires that the [.NET 9.0 (or later) SDK](https://dotnet.microsoft.com/en-us/download).
80 |
81 | You can install, update and use it with:
82 |
83 | ```powershell
84 | # install
85 | dotnet tool install -g SetResolution
86 |
87 | SetResolution 1080 -m2
88 |
89 | #update
90 | dotnet tool update -g SetResolution
91 | ```
92 |
93 | ### Full Syntax
94 | To show available syntax, run `SetResolution.exe` or `sr.exe` without any parameters or `/?` or `HELP`.
95 | The help information is as follows:
96 |
97 | 
98 |
99 | ## Multi-Monitor Support
100 | This tool supports multiple monitors via the `-m ` command line switch. By default the **Main Windows Monitor** monitor is used which corresponds to the **Main Monitor** setting configured in the Windows Display settings.
101 |
102 | Both the `SET`, `PROFILE` and `LIST` commands support the `-m` switch to specify the monitor that the command applies to. Creating a new profile does not specify a monitor.
103 |
104 | The `-m` switch uses a numbering scheme from 1-n, with monitor numbers identified in the `LIST` command. The numbers also reflect the same value you see in the Windows Display Settings dialog.
105 |
106 | ## List Available Monitors and Display Modes
107 | You can use the `LIST` command to show available Monitors and Display Modes as well as the currently selected monitor and display mode. The display modes available are specific for the Monitor/Video Driver combination that is active.
108 |
109 | If you don't specify the `-m` switch which selects a monitor, the **Windows Main Monitor** is used. The list of Display Modes is always specific to the selected monitor. You can explicitly select a monitor via the `-m` switch.
110 |
111 | The selected monitor and display mode are highlighted in the list (green and *).
112 |
113 | 
114 |
115 | ```powershell
116 | sr LIST -m1
117 | ```
118 | This shows a list of display modes available. By default the list only shows:
119 |
120 | * Sizes with the Width > 800 pixels
121 | * Frequencies that match the current display frequency
122 | * Orientation that match the current orientation
123 |
124 | This list is similar to the list you see in the Windows Display Resolution drop down list.
125 |
126 | If you want to see `all display modes` available for your monitor/video driver combination use the `-la` command line switch:
127 |
128 | ```powershell
129 | sr LIST -m1 -la
130 | ```
131 |
132 | The list displays the selected monitor and display mode for this command in green and with the `*` at the end.
133 |
134 | This displays all displays modes for all sizes, orientations and frequencies. This list tends to very large with many duplicate and overlapping values. However it can be useful to match an exact display mode.
135 |
136 | Use these display modes when you create new Profiles and ensure your Profile matches the Display Modes that are supported.
137 |
138 | ## Profiles
139 | Profiles are 'shortcuts' to a specific set of saved Display Settings with a name that you can access simply by specifying the profile name:
140 |
141 | ```powershell
142 | sr -m1
143 | ```
144 | Profiles are the preferred way to switch resolutions as they give you quick access via a single profile name string, instead of having to specify all the settings individually. The `-m1` switch specifies the monitor to apply to - if not specified the Main Windows Monitor is used.
145 |
146 | A Profile stores the following values:
147 |
148 | * Height and Width
149 | * Monitor Frequency (60)
150 | * Color Bit Size (32)
151 | * Orientation (0)
152 |
153 | *values in parenthesis are optional default values if not specified*
154 |
155 | > ##### Profiles do not store Monitor numbers
156 | > If you need to apply to a specific monitor make sure you add the `-m` switch to explicit specify the specific monitor you want to apply the profile to.
157 |
158 | ### Create a new Profile
159 | You can create a profile with:
160 |
161 | ```powershell
162 | SetResolution CREATEPROFILE -p -w 1280 -h 768 -f 59
163 | ```
164 | #### Manually Edit SetResolution.xml
165 | Profiles are stored in `SetResolution.xml` in the same folder as the .exe, so you can manually edit the XML file to add or edit profiles. In order to remove profiles you have to edit the `SetResolution.xml` file and remove the entry.
166 |
167 | ```xml
168 |
169 |
170 |
171 |
172 | 1080
173 | 1920
174 | 1080
175 | 60
176 | 32
177 | Default
178 |
179 |
180 | 4k
181 | 3840
182 | 2160
183 | 60
184 | 32
185 | Default
186 |
187 |
188 | 1440
189 | 2560
190 | 1440
191 | 60
192 | 32
193 | Default
194 |
195 |
196 | 720
197 | 1280
198 | 720
199 | 60
200 | 32
201 | Default
202 |
203 |
204 | 1280
205 |
206 | ```
207 |
208 | > #### XML? Really?
209 | > Yeah I know XML - but to keep the EXE as a fully self-contained, single EXE file and avoid external dependencies, XML serialization is used since it's built into the core framework runtime.
210 |
211 | > #### Write Permissions required for Profile File
212 | > In order to save a new profile using `CREATEPROFILE` you have to have **Write Permissions in the same folder `SetResolution.exe` or `sr.exe`**. This means that preferrably you'll install this tool into a location that supports writing files.
213 | >
214 | > Alternately you can manually edit the file, or give the file itself full read/write access.
215 |
216 |
217 | ### Setting a Profile
218 | Once a profile has been created you can invoke it.
219 |
220 | ```powershell
221 | # Shortcut way - on monitor 2
222 | SetResolution -m2
223 |
224 | # Full syntax - on main monitor (not specified)
225 | SetResolution SET -p -m1
226 | ```
227 |
228 | ### Default Profiles
229 | A number of default profiles are added for common 16:9 resolutions @ 60hz which is most common:
230 |
231 | ```text
232 | Available Profiles
233 | ------------------
234 | 1080: 1920 x 1080, 32, 60
235 | 4k: 3840 x 2160, 32, 60
236 | 1440: 2560 x 1440, 32, 60
237 | 720: 1280 x 720, 32, 60
238 | ```
239 |
240 | These are loaded on first load of the application and stored in the saved profile file (if writable).
241 |
242 | ### Profiles File Location: SetResolution.xml
243 | Profiles are stored on disk in `SetResolution.xml` in the same folder as the `.exe` and you can add and remove additional profiles there or add via the `CREATEPROFILE` action as described above.
244 |
245 | > **Note:** If you installed the EXE in a location that has no write access, saving of new Profile entries with `CREATEPROFILE` will fail silently. Either give `SetResolution.xml` read/write access or move the application to a location where you are allowed to write files.
246 |
247 |
248 | ## Fark: I set a Resolution that doesn't work. Now what?
249 | While it's really, really difficult to do this, if you somehow managed to accidentally set your monitor into a display mode that isn't supported or just doesn't work with your monitor, it's possible that your screen becomes inaccessible. Because this tool switches the default display settings, once a wrong setting is made the screen simply will be blank and it's not just a simple matter of rebooting as the setting is applied to the Windows settings and persists on a reboot.
250 |
251 | > To reset a non-working display setting you have to **boot into Windows Safe Mode** and select another display mode, then reboot.
252 |
253 | As mentioned it should be really difficult to get the monitor/driver into a non-working state because we:
254 |
255 | * **Check settings for valid display resolutions**
256 | You can't set a resolution that is not supported by the driver/monitor combo at the time of setting the mode. The only way you can get an invalid resolution is if the driver supports a mode, but for some reason the monitor does not. The list SetResolution retrieves for display modes is filtered by Windows to match driver/monitor combos that are expected to work.
257 |
258 | * **Prompt for Confirmation of Mode Change**
259 | We prompt for confirmation after the resolution change and if you don't confirm in 5 seconds the display reverts to the previous mode. This ensures if your screen for some reason goes blank, you will revert back to your last working configuration. While I'm not a fan of confirmation prompts, in this case it's both prudent, and only slightly intrusive as you can simply press a key after submitting the shell command. If it really bugs you you can also run with `-noprompt` which skips the prompt (*not recommended though*).
260 |
261 | ## Changelog
262 |
263 | ### 0.3.2
264 |
265 | * **Fix Persistance across Reboots by Default**
266 | Resolution changes previously did not persist in the registry and so when the machine was rebooted the changed setting would not persist and the last saved setting (from Windows) would be used for resulution. Now by default the resolution - if set successfully - is saved and restored on reboot. You can use the `--nopersist` flag to not store the new settings in the registry and revert back to the previous resolution.
267 |
268 | * **Fix Setting the Frequency**
269 | Frequency changes were ignored in previous versions and they should be properly applied now.
270 |
271 | * **Dotnet Tool now uses the .NET 9.0 SDK**
272 | We switched to the .NET 9.0 SDK for the dotnet tool operation for v0.3 which is required for this update. Older SDK versions are supported with older versions of this tool (v0.2.x .NET 8.0 SDK).
273 |
274 | ## Credits
275 | The initial code that manages retrieving and setting display modes is based on this excellent article on C# Corner by [Mohammad Elseheimy](https://www.c-sharpcorner.com/members/mohammad-elsheimy):
276 |
277 | * [Changing Display Settings Programmatically](https://www.c-sharpcorner.com/uploadfile/GemingLeader/changing-display-settings-programmatically/)
278 |
279 | This derivative tool adds an easy to use Console front-end and provides for multi-monitor support. **Most of the credit for this tool goes to Mohammad's work!**
280 |
281 | ## To do
282 |
283 | nothing
--------------------------------------------------------------------------------
/SetResolution/DisplayManager.cs:
--------------------------------------------------------------------------------
1 | /*
2 | * Based on original code from:
3 | *
4 | * (c) Mohammad Elsheimy
5 | * Changing Display Settings Programmatically
6 | *
7 | * https://www.c-sharpcorner.com/uploadfile/GemingLeader/changing-display-settings-programmatically/
8 | *
9 | * Added support for:
10 | *
11 | * * Listing Monitors and Monitor specific display modes
12 | * * Set display mode for a specific monitor/driver
13 | *
14 | */
15 |
16 | using System;
17 | using System.Collections.Generic;
18 | using System.Runtime.InteropServices;
19 | using static Westwind.SetResolution.DisplayManagerNative;
20 |
21 | namespace Westwind.SetResolution
22 | {
23 | ///
24 | /// Represents a wrapper to the native methods.
25 | ///
26 | public static class DisplayManager
27 | {
28 | ///
29 | /// Returns a DisplaySettings object encapsulates the current display settings.
30 | ///
31 | public static DisplaySettings GetCurrentSettings(string deviceName = null)
32 | {
33 | return CreateDisplaySettingsObject(-1, GetDeviceMode(deviceName));
34 | }
35 |
36 | ///
37 | /// Changes the current display settings with the new settings provided. May throw InvalidOperationException if failed. Check the exception message for more details.
38 | ///
39 | /// The new settings.
40 | ///
41 | /// Internally calls ChangeDisplaySettings() native function.
42 | ///
43 | public static void SetDisplaySettings(DisplaySettings set, string deviceName = null)
44 | {
45 | DisplayManagerNative.DEVMODE mode = GetDeviceMode(deviceName);
46 |
47 | mode.dmPelsWidth = (uint)set.Width;
48 | mode.dmPelsHeight = (uint)set.Height;
49 | mode.dmDisplayOrientation = (uint)set.Orientation;
50 | mode.dmBitsPerPel = (uint)set.BitCount;
51 | mode.dmDisplayFrequency = (uint)set.Frequency;
52 | mode.dmFields = DmFlags.DM_PELSWIDTH | DmFlags.DM_PELSHEIGHT | DmFlags.DM_DISPLAYFREQUENCY | DmFlags.DM_BITSPERPEL | DmFlags.DM_DISPLAYORIENTATION;
53 |
54 |
55 | uint CDS_UPDATEREGISTRY = set.NoPersist ? 0u : 1; // force to persist settings in registry
56 | DisplayChangeResult result = (DisplayChangeResult)DisplayManagerNative.ChangeDisplaySettingsEx(deviceName, ref mode, IntPtr.Zero, CDS_UPDATEREGISTRY, IntPtr.Zero);
57 |
58 | string msg = null;
59 | switch (result)
60 | {
61 | case DisplayChangeResult.BadDualView:
62 | msg = Properties.Resources.InvalidOperation_Disp_Change_BadDualView;
63 | break;
64 | case DisplayChangeResult.BadParam:
65 | msg = Properties.Resources.InvalidOperation_Disp_Change_BadParam;
66 | break;
67 | case DisplayChangeResult.BadFlags:
68 | msg = Properties.Resources.InvalidOperation_Disp_Change_BadFlags;
69 | break;
70 | case DisplayChangeResult.NotUpdated:
71 | msg = Properties.Resources.InvalidOperation_Disp_Change_NotUpdated;
72 | break;
73 | case DisplayChangeResult.BadMode:
74 | msg = Properties.Resources.InvalidOperation_Disp_Change_BadMode;
75 | break;
76 | case DisplayChangeResult.Failed:
77 | msg = Properties.Resources.InvalidOperation_Disp_Change_Failed;
78 | break;
79 | case DisplayChangeResult.Restart:
80 | msg = Properties.Resources.InvalidOperation_Disp_Change_Restart;
81 | break;
82 | }
83 |
84 | if (msg != null)
85 | throw new InvalidOperationException(msg);
86 | }
87 |
88 |
89 | ///
90 | /// Returns the current display mode setting
91 | ///
92 | ///
93 | public static DisplaySettings GetCurrentDisplaySetting(string deviceName = null)
94 | {
95 | var mode = GetDeviceMode(deviceName);
96 | return CreateDisplaySettingsObject(0, mode);
97 | }
98 |
99 | ///
100 | /// Returns a list of all the display settings
101 | ///
102 | ///
103 | public static List GetAllDisplaySettings(string deviceName = null)
104 | {
105 | var list = new List();
106 | DisplayManagerNative.DEVMODE mode = new DisplayManagerNative.DEVMODE();
107 |
108 | mode.Initialize();
109 |
110 | int idx = 0;
111 |
112 | while (DisplayManagerNative.EnumDisplaySettings(DisplayManagerNative.ToLPTStr(deviceName), idx, ref mode))
113 | //while (DisplayManagerNative.EnumDisplaySettings(deviceName, idx, ref mode))
114 | list.Add(CreateDisplaySettingsObject(idx++, mode));
115 |
116 | return list;
117 | }
118 |
119 | public static List GetAllDisplayDevices()
120 | {
121 | var list = new List();
122 | uint idx = 0;
123 | uint size = 256;
124 |
125 | var device = new DisplayManagerNative.DISPLAY_DEVICE();
126 | device.cb = Marshal.SizeOf(device);
127 | int displayIndex = 0;
128 |
129 | while (DisplayManagerNative.EnumDisplayDevices(null, idx, ref device, size) )
130 | {
131 | if (device.StateFlags.HasFlag(DisplayManagerNative.DisplayDeviceStateFlags.AttachedToDesktop))
132 | {
133 | var isPrimary = device.StateFlags.HasFlag(DisplayManagerNative.DisplayDeviceStateFlags.PrimaryDevice);
134 | var deviceName = device.DeviceName;
135 |
136 | DisplayManagerNative.EnumDisplayDevices(device.DeviceName, 0, ref device, 0);
137 | displayIndex++;
138 | var dev = new DisplayDevice()
139 | {
140 | Index = displayIndex,
141 | Id = device.DeviceID,
142 |
143 | MonitorDeviceName = device.DeviceName,
144 | DriverDeviceName = deviceName,
145 |
146 | DisplayName = device.DeviceString,
147 | IsPrimary = isPrimary,
148 | IsSelected = isPrimary
149 | };
150 | list.Add(dev);
151 | }
152 |
153 | idx++;
154 |
155 | device = new DisplayManagerNative.DISPLAY_DEVICE();
156 | device.cb = Marshal.SizeOf(device);
157 | }
158 |
159 | return list;
160 | }
161 |
162 | public class DisplayDevice
163 | {
164 | public int Index { get; set; }
165 | public string MonitorDeviceName { get; set; }
166 | public string Id { get; set; }
167 | public string DriverDeviceName { get; set; }
168 | public string DisplayName { get; set; }
169 | public bool IsPrimary { get; set; }
170 | public bool IsSelected { get; set; }
171 |
172 | public override string ToString()
173 | {
174 | return $"{Index} {DisplayName}{(IsSelected ? " *" : "")}{(IsPrimary ? " (Main)" : "")}";
175 | }
176 | }
177 |
178 | ///
179 | /// Rotates the screen from its current location by 90 degrees either clockwise or anti-clockwise.
180 | ///
181 | /// Set to true to rotate the screen 90 degrees clockwise from its current location, or false to rotate it anti-clockwise.
182 | public static void RotateScreen(bool clockwise)
183 | {
184 | DisplaySettings set = DisplayManager.GetCurrentSettings();
185 |
186 | int tmp = set.Height;
187 | set.Height = set.Width;
188 | set.Width = tmp;
189 |
190 | if (clockwise)
191 | set.Orientation++;
192 | else
193 | set.Orientation--;
194 |
195 | if (set.Orientation < Orientation.Default)
196 | set.Orientation = Orientation.Rotate270;
197 | else if (set.Orientation > Orientation.Rotate270)
198 | set.Orientation = Orientation.Default;
199 |
200 | SetDisplaySettings(set);
201 | }
202 |
203 |
204 | ///
205 | /// A private helper methods used to derive a DisplaySettings object from the DEVMODE structure.
206 | ///
207 | /// The mode index attached with the settings. Starts form zero. Is -1 for the current settings.
208 | /// The current DEVMODE object represents the display information to derive the DisplaySettings object from.
209 | private static DisplaySettings CreateDisplaySettingsObject(int idx, DisplayManagerNative.DEVMODE mode)
210 | {
211 | return new DisplaySettings()
212 | {
213 | Index = idx,
214 | Width = (int)mode.dmPelsWidth,
215 | Height = (int)mode.dmPelsHeight,
216 | Orientation = (Orientation)mode.dmDisplayOrientation,
217 | BitCount = (int)mode.dmBitsPerPel,
218 | Frequency = (int)mode.dmDisplayFrequency
219 | };
220 | }
221 |
222 | ///
223 | /// A private helper method used to retrieve current display settings as a DEVMODE object.
224 | ///
225 | ///
226 | /// Internally calls EnumDisplaySettings() native function with the value ENUM_CURRENT_SETTINGS (-1) to retrieve the current settings.
227 | ///
228 | private static DisplayManagerNative.DEVMODE GetDeviceMode(string deviceName = null)
229 | {
230 | var mode = new DisplayManagerNative.DEVMODE();
231 |
232 | mode.Initialize();
233 |
234 | if (DisplayManagerNative.EnumDisplaySettings(DisplayManagerNative.ToLPTStr(deviceName), DisplayManagerNative.ENUM_CURRENT_SETTINGS, ref mode))
235 | return mode;
236 | else
237 | throw new InvalidOperationException(GetLastError());
238 | }
239 |
240 | private static string GetLastError()
241 | {
242 | int err = Marshal.GetLastWin32Error();
243 |
244 | if (DisplayManagerNative.FormatMessage(DisplayManagerNative.FORMAT_MESSAGE_FLAGS,
245 | DisplayManagerNative.FORMAT_MESSAGE_FROM_HMODULE,
246 | (uint)err, 0, out var msg, 0, 0) == 0)
247 | return Properties.Resources.InvalidOperation_FatalError;
248 | else
249 | return msg;
250 | }
251 | }
252 |
253 | public enum Orientation
254 | {
255 | Default = 0,
256 | Rotate90 = 1,
257 | Rotate180 = 2,
258 | Rotate270 = 3
259 | }
260 |
261 | public class DisplaySettings
262 | {
263 | public int Index { get; set; }
264 | public int Width { get; set; }
265 | public int Height { get; set; }
266 | public Orientation Orientation { get; set; }
267 | public int BitCount { get; set; }
268 | public int Frequency { get; set; }
269 |
270 | ///
271 | /// Determines whether the settings are stored in the registry for
272 | /// persistence for a reboot.
273 | ///
274 | public bool NoPersist { get; set; }
275 |
276 | ///
277 | /// Display Mode string display with full detail
278 | ///
279 | public override string ToString()
280 | {
281 | return ToString(false);
282 | }
283 |
284 | ///
285 | /// Display Mode string display
286 | ///
287 | /// only return height and width
288 | ///
289 | public string ToString(bool noDetails)
290 | {
291 | if (noDetails)
292 | {
293 | return string.Format(System.Globalization.CultureInfo.CurrentCulture, $"{Width} x {Height}");
294 | }
295 |
296 | return string.Format(System.Globalization.CultureInfo.CurrentCulture,
297 | $"{Width} x {Height}, {Frequency}hz, {BitCount}bit{(Orientation != Orientation.Default ? ", " + Orientation.ToString() : "")}");
298 | }
299 |
300 |
301 | public override bool Equals(object d)
302 | {
303 | var disp = d as DisplaySettings;
304 | return (disp.Width == Width && disp.Height == Height &&
305 | disp.Frequency == Frequency &&
306 | disp.BitCount == BitCount &&
307 | disp.Orientation == Orientation);
308 | }
309 |
310 |
311 | public override int GetHashCode()
312 | {
313 | return ("" + "W" + Width + "H" + Height + "F" + Frequency + "B" + BitCount + "O" + Orientation)
314 | .GetHashCode();
315 | }
316 | }
317 |
318 | enum DisplayChangeResult
319 | {
320 | ///
321 | /// Windows XP: The settings change was unsuccessful because system is DualView capable.
322 | ///
323 | BadDualView = -6,
324 | ///
325 | /// An invalid parameter was passed in. This can include an invalid flag or combination of flags.
326 | ///
327 | BadParam = -5,
328 | ///
329 | /// An invalid set of flags was passed in.
330 | ///
331 | BadFlags = -4,
332 | ///
333 | /// Windows NT/2000/XP: Unable to write settings to the registry.
334 | ///
335 | NotUpdated = -3,
336 | ///
337 | /// The graphics mode is not supported.
338 | ///
339 | BadMode = -2,
340 | ///
341 | /// The display driver failed the specified graphics mode.
342 | ///
343 | Failed = -1,
344 | ///
345 | /// The settings change was successful.
346 | ///
347 | Successful = 0,
348 | ///
349 | /// The computer must be restarted in order for the graphics mode to work.
350 | ///
351 | Restart = 1
352 | }
353 |
354 |
355 | }
356 |
--------------------------------------------------------------------------------