How do I get the number of displays in windows?
Asked Answered
R

3

11

I want to count the number of active displays. For Mac I can use the following:

CGDisplayCount nDisplays;
CGGetActiveDisplayList(0,0, &nDisplays);
log.printf("Displays connected: %d",(int)nDisplays);

How can I achieve the same in Windows? I've found EnumDisplayMonitors but I can't work out how to use it.

Reest answered 14/10, 2011 at 11:37 Comment(1)
The MSDN page you linked mentions using GetSystemMetrics(SM_CMONITORS) to count the number of physical displays. Does that work for you?Biotype
V
26

As you have discovered, EnumDisplayMonitors() will do the job but it is a little tricky to call. The documentation states:

The EnumDisplayMonitors function enumerates display monitors (including invisible pseudo-monitors associated with the mirroring drivers) that intersect a region formed by the intersection of a specified clipping rectangle and the visible region of a device context. EnumDisplayMonitors calls an application-defined MonitorEnumProc callback function once for each monitor that is enumerated. Note that GetSystemMetrics (SM_CMONITORS) counts only the display monitors.

This leads us to an easier solution: GetSystemMetrics(SM_CMONITORS). Indeed this may be even better than EnumDisplayMonitors() if you have psuedo-monitors.


As illustration of calling EnumDisplayMonitors() try this:

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
{
    int *Count = (int*)dwData;
    (*Count)++;
    return TRUE;
}

int MonitorCount()
{
    int Count = 0;
    if (EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, (LPARAM)&Count))
        return Count;
    return -1;//signals an error
}
Volley answered 14/10, 2011 at 11:42 Comment(4)
This only works in 32bit for me ... Is there a trick to get working in 64bit?Sewoll
Should work fine in 64 bit. Very hard for anyone to help unless you provide more information about what "only works" actually means.Volley
OK sorry for that. I use the same code and when I compile it with "win32" it works, with x64 does not work. But I got the point.Sewoll
The code works just fine in x64. Paste it into a brand new console app to see that. I'm sure you have a problem somewhere, but I don't believe it is with this code. If you can't work it out, post a question.Volley
C
4

Not tested, but essentially you only need to provide the callback for the enum function:

int numMonitors = 0;

BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor, HDC hdcMonitor, LPRECT lprcMonitor, LPARAM dwData)
  {
  //lprcMonitor holds the rectangle that describes the monitor position and resolution)

  numMonitors++;
  return true;
  }

int main()
  {
  EnumDisplayMonitors(NULL, NULL, MonitorEnumProc, NULL);
  }
Cockboat answered 14/10, 2011 at 11:43 Comment(0)
P
1

The problem with above approaches is that they do not detect the correct number of monitors in Clone, Internal, External topologies. They get the correct number only in Extended topology. There is a way to get the correct number of monitors in any topology with QueryDisplayConfig function. You have to use QDC_ALL_PATHS in flags and count only unique monitors found.

    DISPLAYCONFIG_TOPOLOGY_ID currTopologyId = 0;
    UINT32 numPathArrayElements = 0;
    UINT32 numModeInfoArrayElements = 0;
    LONG retCode = ::GetDisplayConfigBufferSizes(flags, &numPathArrayElements, &numModeInfoArrayElements);
    auto pathArray = std::make_unique<DISPLAYCONFIG_PATH_INFO[]>(numPathArrayElements);
    auto modeInfoArray = std::make_unique<DISPLAYCONFIG_MODE_INFO[]>(numModeInfoArrayElements);
    retCode = ::QueryDisplayConfig(flags, &numPathArrayElements, pathArray.get(), &numModeInfoArrayElements, modeInfoArray.get(), &currTopologyId);

Use DisplayConfigGetDeviceInfo to get the monitor name from the path target.

    DISPLAYCONFIG_TARGET_DEVICE_NAME targetName = {};
    targetName.header.type = DISPLAYCONFIG_DEVICE_INFO_GET_TARGET_NAME;
    targetName.header.size = sizeof(targetName);
    targetName.header.adapterId = pathInfo.targetInfo.adapterId;
    targetName.header.id = pathInfo.targetInfo.id;

    LONG retCode = ::DisplayConfigGetDeviceInfo(&targetName.header);

You will get the monitor name in:

targetName.monitorDevicePath, targetName.monitorFriendlyDeviceName
Provencher answered 25/11, 2020 at 22:20 Comment(3)
Does it work? social.msdn.microsoft.com/Forums/windowsapps/en-US/…Intuitive
@Intuitive Yes, it does work, I actually used similar code in production to handle monitor configurations.Provencher
Possibly related: #10238437Intuitive

© 2022 - 2024 — McMap. All rights reserved.