Commandline: Changing resolution

Just had a common issue this morning that would usually require installing an application, but is very easy to solve using the batch file (GIST) from Thursday’s post:

Changing the resolution from a batch file. Specifically, I wanted to lower my display’s resolution whenever I connect via VNC. The first part is simple: Attach a task to the System Event generated by TightVNC Server (Ok, not that easy… this actually involves using Microsoft’s bizarre XPath subset, since TightVNC’s events are not quite as specific as they should be), then set this task to run a batch file.

Now, for some reason, Microsoft doesn’t include anything to do something as simple as setting the resolution by any other means than calling into USER32.DLL directly… and that call is too complex for little old RunDLL32.exe. .NET can’t do it either without calling into USER32.dll. But at least it makes doing so pretty straightforward.

Declare a struct that matches Windows display properties (no need to declare all fields, I just use dummy byte arrays for any fields that I’m not interested in), then call EnumDisplaySettings to retrieve the current settings into that struct. Change the resolution of the retrieved information and pass it back to ChangeDisplaySettings and voilà.

This is also a good example of how to use arguments with C#.CMD. Just don’t. Save them to environment variables instead and retrieve them via System.Environment.GetEnvironmentVariable . SETLOCAL/ENDLOCAL will keep these environment variables from leaking into other parts of your script.

(GIST)

@ECHO OFF
SETLOCAL
SET RES_X=%1
SET RES_Y=%2
echo @^
    using System.Runtime.InteropServices;^
    [StructLayout(LayoutKind.Sequential)]^
    public struct DispSet {^
        [MarshalAs(UnmanagedType.ByValArray,SizeConst=106)]^
            byte[] padding0;^
        public int width, height;^
        [MarshalAs(UnmanagedType.ByValArray,SizeConst=40)]^
            byte[] padding1;^
    };^
    public class App {^
        [DllImport("user32.dll")] public static extern^
        int EnumDisplaySettings(string a, int b, ref DispSet c);^
        [DllImport("user32.dll")] public static extern^
        int ChangeDisplaySettings(ref DispSet a, int b);^
        public static void Main() {^
            var disp = new DispSet();^
            if ( EnumDisplaySettings(null, -1, ref disp) == 0)^
                return;^
            disp.width=int.Parse(System.Environment^
                .GetEnvironmentVariable("RES_X"));^
            disp.height=int.Parse(System.Environment.^
                GetEnvironmentVariable("RES_Y"));^
            ChangeDisplaySettings(ref disp, 1);^
        }^
    }^
 |c#
ENDLOCAL

 

Assuming you have C#.CMD somewhere in your path, you can now simply call this batch file with horizontal resolution as first argument and vertical as second.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.