In my application, I need to allow the user to pick which screen will display customer information. It's a situation where the primary monitor is facing the person at a desk, the other is facing the customer.
The application currently loops through System.Windows.Forms.Screen.AllScreens (I'm using C#) and shows the Screen object's DeviceName in a drop down menu. Most commonly, what is shown is "\\.\DISPLAY1" and "\\.\DISPLAY2", but sometimes it will show something like "\\.\DISPLAY4" and "\\.\DISPLAY5" - probably because other displays numbered 1-3 have been attached earlier.
What I would like to show is the number that Windows Settings uses to identify connected, active displays. In Windows, right click on the desktop and pick Display Settings. If you have multiple monitors, you will see each monitor with a number on it. Clicking "Identify" will show how these number are mapped to each monitor.
Instead of the menu being:
- \\.\DISPLAY1
- \\.\DISPLAY2
I'd like it to contain the screen ID. Something like:
- Monitor (2)
- Monitor (1)
Where the number in parenthesis is the Display ID.
I’ve tried getting it from these WMI CIMs: Win32_DesktopMonitor, Win32_VideoController, Win32_DisplayConfiguration, Win32_Desktop, and WmiMonitorID.
I looked at the info returned from EnumDisplayDevices and EnumDisplayMonitors.
I tried to find patterns in:
HKLM\SYSTEM\CurrentControlSet\Enum\DISPLAY
HKLM\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Configuration
HKLM\SYSTEM\CurrentControlSet\Control\GraphicsDrivers\Connectivity
HKLM \SYSTEM\CurrentControlSet\Control\Video
I even ran procmon to see if anything interesting happens when I open the system display settings.
UPDATE:
The second answer from How can I get monitors numbers from Screen Resolution dialog in win7 programmatically? looked promising, but it doesn't seem to be correct.
For Windows versions supporting WDDM, which Windows 7 does, you can simply use DXGI which is part of DirectX. DXGI allows you to very easily enumerate the existing display adapters, the available display outputs per adapter and the supported display modes per display output. While enumerating there's a lot of additional data you can read out, like handles, identifiers and device names. All of this can easily be used to retrieve the working areas as well. The order in which adapters and outputs are enumerated is defined by the system and matches the order of your configuration screen.
I used SharpDX, a DXGI wrapper, to test this:
var factory1 = new Factory1();
var adapters = factory1.Adapters;
int i = 1;
foreach (var adapter in adapters)
{
Console.WriteLine($"Adapter Description: {adapter.Description.Description}");
Console.WriteLine("-----------");
foreach (var output in adapter.Outputs)
{
Console.WriteLine($"DeviceName: {output.Description.DeviceName}");
Console.WriteLine($"DesktopBounds: L:{output.Description.DesktopBounds.Left}, T:{output.Description.DesktopBounds.Top}, R:{output.Description.DesktopBounds.Right}, B:{output.Description.DesktopBounds.Bottom}");
Console.WriteLine($"ID (?): {i++}");
}
}
Results:
Adapter Description: NVIDIA Quadro M1200
DeviceName: \.\DISPLAY4
DesktopBounds: L:0, T:0, R:1920, B:1080
ID (?): 1
DeviceName: \.\DISPLAY5
DesktopBounds: L:1920, T:0, R:3840, B:1080
ID (?): 2
Adapter Description: Intel(R) HD Graphics 630
Adapter Description: Microsoft Basic Render Driver
According to my Display settings, the left monitor, \.\DISPLAY4, is 2, and \.\DISPLAY5, the right monitor, is 1. I can't assume that the order is simply reversed, because when testing with the same computer at home, with different monitors, DISPLAY1 (left) is ID=1 and DISPLAY4 (right) is ID=2.
UPDATE 2:
We created a ticket with Microsoft to get help with this issue. There is no way to get the number that Windows uses to identify screens in the display settings. The answer from them is summed up here:
How can I get monitors numbers from Screen Resolution dialog in win7 programmatically?