24

Does anyone know if there is an API to get the current monitor state (on or off) in Windows (XP/Vista/2000/2003)?

All of my searches seem to indicate there is no real way of doing this.

This thread tries to use GetDevicePowerState which according to Microsoft's docs does not work for display devices.

In Vista I can listen to GUID_MONITOR_POWER_ON but I do not seem to get events when the monitor is turned off manually.

In XP I can hook into WM_SYSCOMMAND SC_MONITORPOWER, looking for status 2. This only works for situations where the system triggers the power off.

The WMI Win32_DesktopMonitor class does not seem to help out as well.

Edit: Here is a discussion on comp.os.ms-windows.programmer.win32 indicating there is no reliable way of doing this.

Anyone else have any other ideas?

Sam Saffron
  • 128,308
  • 78
  • 326
  • 506
  • Related question: http://stackoverflow.com/questions/328490/monitoring-a-displays-state-in-python – CesarB Nov 30 '08 at 15:45
  • 1
    What are you trying to accomplish with this information? Maybe we could help solve the real problem. Regards. – Mick Mar 08 '09 at 17:24
  • 1
    To estimate roughly the power consumed by monitors physically connected to a computer – Sam Saffron Mar 08 '09 at 19:47

9 Answers9

16

GetDevicePowerState sometimes works for monitors. If it's present, you can open the \\.\LCD device. Close it immediately after you've finished with it.

Essentially, you're out of luck—there is no reliable way to detect the monitor power state, short of writing a device driver and filtering all of the power IRPs up and down the display driver chain. And that's not very reliable either.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
Roger Lipscombe
  • 89,048
  • 55
  • 235
  • 380
  • 1
    I think this is the closest answer to the question. Its a real failure of the hardware mfgs for not giving us that level of comms in the DVI standard. – Sam Saffron Mar 04 '09 at 23:50
  • 1
    Seriously though, close it immediately after you've finished with it. I once broke presentation mode on Michael Dell's laptop by failing to do that :) – Roger Lipscombe Mar 08 '18 at 08:33
  • Documentation for [GetDevicePowerState](https://learn.microsoft.com/en-us/windows/win32/api/winbase/nf-winbase-getdevicepowerstate) says "This function cannot be used to query the power state of a display device." – skst Jul 27 '21 at 22:39
  • Unless they changed something between Windows Vista and now (which is possible), the documentation's wrong. The function cannot be used to _reliably_ query the power state of a display device, but it did work on a majority of the (several thousand) computers we tried it on. – Roger Lipscombe Aug 01 '21 at 16:44
13

You could hook up a webcam, point it at your screen and do some analysis on the images you receive ;)

thijs
  • 3,445
  • 1
  • 27
  • 46
  • 6
    But then you may mistake reflections for screen action.. I think you're turning a device driver problem into an image processing problem.. I LIKE IT :) – cpatrick Mar 06 '09 at 19:54
  • 3
    This technique has been used to monitor racks full of equipment in remote locations. Point a camera at the rack, and watch for "unusual" changes in the indicator lights. Its brute force, but in some cases it is the only reasonable answer. – RBerteig Mar 08 '09 at 23:07
7

Before doing anything based on the monitor state, just remember that users can use a machine with remote desktop of other systems that don't require a monitor connected to the machine - so don't turn off any visualization based on the monitor state.

Nir
  • 29,306
  • 10
  • 67
  • 103
  • 2
    The windows API allow you to figure out if a monitor is "real" or not. See: DISPLAY_DEVICE_MIRRORING_DRIVER. – Sam Saffron Mar 04 '09 at 23:48
  • Remote desktop apps still affect the screen saver, don't they? (At least RealVNC does.) I know windows's own Remote Desktop sessions uses another system, so things might differ there. – Macke Mar 08 '09 at 11:13
7

You can't.

Look like all monitor power capabilities connected to the "power safe mode"
After searching i found here code that connecting between SC_MONITORPOWER message and system values (post number 2)
I use the code to testing if the system values is changing when i am manually switch off the monitor.

int main()
{
    for(;monitorOff()!=1;)
        Sleep(500);
    return 0;
}//main

And the code is never stopped, no matter how long i am switch off my monitor.
There the code of monitorOff function:

int monitorOff()
{
    const GUID MonitorClassGuid =
        {0x4d36e96e, 0xe325, 0x11ce, 
            {0xbf, 0xc1, 0x08, 0x00, 0x2b, 0xe1, 0x03, 0x18}};

    list<DevData> monitors;
    ListDeviceClassData(&MonitorClassGuid, monitors);

    list<DevData>::iterator it = monitors.begin(),
                            it_end = monitors.end();
    for (; it != it_end; ++it)
    {
        const char *off_msg = "";

        //it->PowerData.PD_PowerStateMapping
        if (it->PowerData.PD_MostRecentPowerState != PowerDeviceD0)
        {
            return 1;
        }
    }//for

    return 0;
}//monitorOff

Conclusion : when you manually switch of the the monitor, you cant catch it by windows (if there is no unusual driver interface for this), because all windows capabilities is connected to "power safe mode".

Avram
  • 4,267
  • 33
  • 40
2

In Windows XP or later you can use the IMSVidDevice Interface.

See http://msdn.microsoft.com/en-us/library/dd376775(VS.85).aspx

(not sure if this works in Sever 2003)

Fraser
  • 15,275
  • 8
  • 53
  • 104
1

With Delphi code, you can detect invalid monitor geomerty while standby in progress:

i := 0
('Monitor'+IntToStr(i)+': '+IntToStr(Screen.Monitors[i].BoundsRect.Left)+', '+
IntToStr(Screen.Monitors[i].BoundsRect.Top)+', '+
IntToStr(Screen.Monitors[i].BoundsRect.Right)+', '+
IntToStr(Screen.Monitors[i].BoundsRect.Bottom))

Results:

Monitor geometry before standby:

Monitor0: 0, 0, 1600, 900

Monitor geometry while standby in Deplhi7:

Monitor0: 1637792, 4210405, 31266576, 1637696

Monitor geometry while standby in DeplhiXE:

Monitor0: 4211194, 40, 1637668, 1637693
CubeJockey
  • 2,209
  • 8
  • 24
  • 31
Delphi
  • 11
  • 1
1

This is a really old post but if it can help someone, I have found a solution to detect a screen being available or not : the Connecting and Configuring Displays (CCD) API of Windows.

It's part of User32.ddl and the interesting functions are GetDisplayConfigBufferSizes and QueryDisplayConfig. It give us all informations that can be viewed in the Configuration Panel of windows.

In particular the PathInfo contains a TargetInfo property that have a targetAvailable flag. This flag seems to be correctly updated on all the configurations I have tried so far.

This allow you to know the state of every screens connected to the PC and set their configurations.

Here a CCD wrapper for .Net

Emrys Myrooin
  • 2,179
  • 14
  • 39
  • 3
    This did not work for me with single Dell monitor connected via DisplayPort to Windows 10 PC. targetAvailable was always 1 regardless of monitor power state. Thanks for sharing your results though. – Greg Jun 29 '17 at 00:44
1

I added a vcl timer to the form to check monitor status.

it simply worked for me for one monitor system. hope this helps someone.

function GetDevicePowerState(hDevice: DWORD; var pfOn: BOOL): BOOL; stdcall;
external kernel32;

function CheckMonitorState: boolean;
var
Hwnd: THandle;
Stat: LongBool;
begin
Hwnd := CreateFile('\\.\LCD', 0, 0, nil, OPEN_EXISTING, 0, 0);
if Hwnd <> INVALID_HANDLE_VALUE then
  GetDevicePowerState(Hwnd, Stat);
Result := Stat;
CloseHandle(Hwnd);
end;

procedure TForm1.Timer2Timer(Sender: TObject);
begin
  if CheckMonitorState then
  Memo1.Lines.Append('Monitor ON')
  else
    Memo1.Lines.Append('Monitor OFF');
end;
Zen Of Kursat
  • 2,672
  • 1
  • 31
  • 47
0

If your monitor has some sort of built-in USB hub, you could try and use that to detect if the monitor is off/on.
This will of course only work if the USB hub doesn't stay connected when the monitor is consider "off".

Angus Johnston
  • 45
  • 1
  • 3
  • 7