Changing the primary display using the Win32 API
blog.lohr.dev
blog.lohr.dev
I admit that finding a way to change monitor brightness [1] or turn off individual displays [2] wasn’t as straightforward and needed a lot of reverse engineering. But macOS has a much nicer API [3] for configuring screen position, resolution, mirroring etc.
It’s not without its quirks however, I ran into a lot of bugs while developing the Blackout feature when having to create multiple mirror sets with multiple displays in each one. I finally had to reverse engineer the MonitorPanel.framework that’s used by System Preferences to get that functionality. [4]
From my understanding, Windows has a native way of disabling a display in software so this wouldn’t even be needed there.
[1] https://alinpanaitiu.com/blog/journey-to-ddc-on-m1-macs/
[2] https://lunar.fyi/#blackout
[3] https://developer.apple.com/documentation/coregraphics/quart...
I'm currently running Windows, and I'd love to check out Lunar if it's available.
You can get TwinkleTray for Windows that can do most of what Lunar does: https://twinkletray.com/
The API is often complex because of how old some parts are and how often things got extended in backwards-compatible ways
https://docs.microsoft.com/en-us/windows/win32/api/winuser/n...
So the whole article is sort of "I reverse engineered software for fun instead of reading the docs"
It's a fun read about the quirks of the Windows API though.
The Win32 documentation admittedly can be pretty good, when you can easily find what you're looking for. There's ben multiple times where I've gone looking for documentation for a still supported API only to be told "oh yeah the best option is to check out this old ass sample code from 2008"
OTOH it's pretty easy to get help. People I know very skilled with the Windows API seems to be documentation themselves. I have seen RE guys casually bring up undocumented behavior of certain APIs off the top of their head.
It would be more interesting to find out why the order of monitors changes “randomly” (computers can't really do anything randomly unless asked specifically). It could be something simple, like background driver updates that reset options they shouldn't reset, or the powered down state of monitors on boot, or video card enumerating connected devices differently, etc.
https://github.com/steinuil/SatouinDp/blob/master/DisplayDev...
One thing I never figured out was how to map the displays you get from EnumDisplayDevices to the names you see in the display settings, or how to list them in a consistent order.
From my experience, changing topology using SetDisplayConfig is straightforward.
let mut num_paths = MaybeUninit::uninit();
let mut num_mode_infos = MaybeUninit::uninit();
GetDisplayConfigBufferSizes(QDC_ONLY_ACTIVE_PATHS, num_paths.as_mut_ptr(), num_mode_infos.as_mut_ptr());
let mut paths = vec![Default::default(); num_paths.assume_init() as _];
let mut mode_infos = vec![Default::default(); num_mode_infos.assume_init() as _];
QueryDisplayConfig(QDC_ONLY_ACTIVE_PATHS, num_paths.as_mut_ptr(), paths.as_mut_ptr(), num_mode_infos.as_mut_ptr(), mode_infos.as_mut_ptr(), null_mut());
(mode_infos[1].Anonymous.sourceMode.position, mode_infos[3].Anonymous.sourceMode.position) = (mode_infos[3].Anonymous.sourceMode.position, mode_infos[1].Anonymous.sourceMode.position);
SetDisplayConfig(&paths, &mode_infos, SDC_APPLY | SDC_USE_SUPPLIED_DISPLAY_CONFIG | SDC_ALLOW_CHANGES);MouseUnSnag solves a problem that annoyed me for a while now, but I wasn't aware that there is already a solution. Thanks!
Windows 9x “parks” minimized windows at (3000, 3000) , a coordinate that is unlikely to be seen, at the time (remember 1024x768 was hi-res?)
https://devblogs.microsoft.com/oldnewthing/20041028-00/?p=37...
The API lets you position each monitor independently on the 'virtual desktop', and sometimes there are constraints which mean certain positions aren't possible - and the API needs to give feedback on if a position, colour depth and resolution is allowed. Then you hit 'apply' and the change takes effect.
I don't really see any better way to implement the API without leaking implementation details which might change in future windows versions.
https://nircmd.nirsoft.net/setprimarydisplay.html
It also has a bunch of other useful features like changing the default audio device (something I use every day) and opening the CD tray ;)
Anyway, it's the best tool I've used for scripting stuff on windows. No GUI, just a bunch of useful or less useful command line utilities.