0

Let me explain my situation. I write a program that should perform certain drawing/rendering actions only when a user sees the screen. In case of a notebook, this means -- only when the lid is open. To determine that I use the PBT_POWERSETTINGCHANGE notification for GUID_LIDSWITCH_STATE_CHANGE, which works great for a single monitor system.

The issue happens when there's one or more externally attached monitors connected to a notebook. In that situation the main notebook screen may remain inactive, while only external monitor(s) are powered on. So in that case the lid would be reported as closed, which should make my program to continue rendering. The problem is how to detect this situation.

I was thinking that I can count monitors using GetSystemMetrics(SM_CMONITORS) but in this case I don't know where the monitor is "coming from", or in other words, is it a notebook's "native" screen, or an externally plugged in one.

So my question is, can I defferentiate between any external monitors plugged in to the system versus the "native" screen of a notebook?

c00000fd
  • 20,994
  • 29
  • 177
  • 400

2 Answers2

2

You can call GetMonitorInfo and interrogate the flag that's returned in the MonitorInfo structure. Look for MONITORINFOF_PRIMARY.

rrirower
  • 4,338
  • 4
  • 27
  • 45
  • Thanks. Is there any way to tell if a specific monitor is powered on or off? – c00000fd Feb 25 '14 at 19:48
  • If you're looking to see if the primary (laptop) monitor is powered on, you should be able to enumerate monitors and check for the primary flag mentioned above. – rrirower Feb 25 '14 at 19:54
  • you can use [`GetDevicePowerState()`](http://msdn.microsoft.com/en-us/library/windows/desktop/aa372690.aspx) to query whether a particular monitor is powered on or off. – Remy Lebeau Feb 25 '14 at 20:22
  • @RemyLebeau: How do you get a device handle for `GetDevicePowerState`? When I try to get it from `CreateFile` on device/monitor name from `MONITORINFOEX::szDevice` that I get from `GetMonitorInfo`, I always get `ERROR_ACCESS_DENIED`. – c00000fd Feb 25 '14 at 22:25
  • Have a look at http://stackoverflow.com/questions/203355/, http://stackoverflow.com/questions/4580994/, and http://msdn.microsoft.com/en-us/library/ms703398.aspx – Remy Lebeau Feb 25 '14 at 23:19
  • A monitor being primary has nothing to do with its integratedness. `DISPLAYCONFIG_TOPOLOGY_ID` may possibly have that information. Or you could try to separate the different kinds of [connector](http://stackoverflow.com/questions/31712915/detect-identify-the-port-hdmi-other-the-monitor-is-connected-to-in-windows-7) between embedded and external (even though as they note [here](http://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/dispmprt/ns-dispmprt-_dxgk_integrated_display_child), you should ponder what your use case is w.r.t. to larger products like AIOs or interactive whiteboards). – mirh Dec 28 '22 at 22:08
0

Unfortunately what you're asking for is not as straightforward as it sounds. There's no way to distinguish between an externally plugged in monitor and a native device screen:

  • MONITORINFOF_PRIMARY flag will be set for whatever monitor is configured as primary, and that can be any external monitor.

  • GetSystemMetrics(SM_CMONITORS) will returns the number of physical monitors and will have no effect on lid open or shut state.

Nonetheless, I've been using the code below that can enumerate (and count in your case) "usable" monitors, or the ones that are currently "used" by Windows. The code should work for the situation when the screen is turned off by closing the device lid as well.

It comes with one caveat though -- it has to run from an interactive user session only. In other words, you cannot call it from a service application.

int CountUsableMonitors()
{
    int count = 0;
    for(int i = 0; ; i++)
    {
        DISPLAY_DEVICE dd = {0};
        dd.cb = sizeof(dd);

        //Get display adapter info
        if(!::EnumDisplayDevices(NULL, i, &dd, 0))
        {
            break;
        }

        //Only if active
        if(dd.StateFlags & DISPLAY_DEVICE_ACTIVE)
        {
            DISPLAY_DEVICE dd2 = {0};
            dd2.cb = sizeof(dd2);

            //Get monitor info
            if(::EnumDisplayDevices(dd.DeviceName, 0, &dd2, 0))
            {
                if(dd2.StateFlags & (DISPLAY_DEVICE_ACTIVE | DISPLAY_DEVICE_ATTACHED))
                {
                    count++;
                }
            }
        }

    }

    return count;
}
ahmd0
  • 16,633
  • 33
  • 137
  • 233