Thursday, May 16, 2019

Getting the real current screen resolution from the command line

Getting the real current screen resolution, as shown in the display settings and as desired by this Super User question, is surprisingly tricky to do programmatically. Some ways get the maximum resolution supported by the display and others produce wrong results on high-DPI screens. The most reliable way seems to be GetDeviceCaps. In SprintDLL:
call user32.dll!GetDC /return native /into hdc (native 0)
call gdi32.dll!GetDeviceCaps /return int (slotdata hdc, int 118)
call gdi32.dll!GetDeviceCaps /return int (slotdata hdc, int 117)

The first call returns the width, the second gets the height. Or in PowerShell:
Add-Type @"
using System;
using System.Runtime.InteropServices;
public class PInvoke {
    [DllImport("user32.dll")] public static extern IntPtr GetDC(IntPtr hwnd);
    [DllImport("gdi32.dll")] public static extern int GetDeviceCaps(IntPtr hdc, int nIndex);
}
"@
$hdc = [PInvoke]::GetDC([IntPtr]::Zero)
[PInvoke]::GetDeviceCaps($hdc, 118) # width
[PInvoke]::GetDeviceCaps($hdc, 117) # height

2 comments:

  1. I want to use $hdc further for comparison with a particular height as below but the condition does not seem to work and is always falling in else part. What am I doing wrong here:
    if(1366 -eq $hdc) {
    write-host("Resolution is correct")
    }else {
    write-host("Resolution is not correct")
    }
    }

    ReplyDelete
    Replies
    1. $hdc here is an opaque handle rather than a resolution measurement. You probably want to compare against the "width" and "height" expressions in my last two lines.

      Delete