How to turn off a monitor using VBScript.

123

Senior Member
This was a truly hard-won victory and I hope this information will help fellow Cocooners.

I've connected a touchscreen to my, formerly headless, HA server. To conserve power, I want the ability to turn the touchscreen on and off via my HA application. For example, upon arming my security system (via a keypad) I want the touchscreen to go into sleep mode.

One technique would be to use a simple X10 appliance module to control the monitor's power source. However, Windows has programmatic control of the monitor's power-mode so there must be a way of doing it in software (and not by calling an external EXE).

If you think there's a WMI method to control the monitor's powerstate, you'd be both right and wrong! Curiously, Microsoft has documented the SetPowerState method yet indicated it is "not implemented"!?!

The primary means of controlling a monitor's powerstate is by using the Windows SendMessage function. Yup, you have to make a low-level call to USER32.dll, in the OS's innards, to get the job done. The procedure is straightforward if you use C, C++, VB, or a .NET language. There are several articles on the subject in CodeProject.

Unfortunately, VBScript does not support calls to the Win32 API. AutoIT does but VBScript doesn't.

The solution is an obscure DLL described in WinHelpLine.info. I can't read German but, after skimming the thread, I found a link to a helper called DynaCall (enhanced version is called DynaWrap). DynaCall allows you to make Win32 API calls using VBScript.

After downloading and registering DynaCall, you can use the following code to control a monitor's powerstate:

Code:
' To power-down a monitor
Set oItem = CreateObject("DynamicWrapper")
oItem.Register "USER32.DLL", "SendMessageA", "I=llll", "f=s", "R=l"
oItem.SendMessageA -1, 274, 61808, 2

' To power-up a monitor
Set oItem = CreateObject("DynamicWrapper")
oItem.Register "USER32.DLL", "SendMessageA", "I=llll", "f=s", "R=l"
oItem.SendMessageA -1, 274, 61808, -1

I found that if you pass the numeric parameters in hexadecimal format, as shown in most examples, the function will not work. They're supposed to be Long values yet casting the hex numbers as Long didn't help either ... go figure. Supplying them as decimal values did the trick.

All of that I=, f=, and R= gibberish is quite important because it tells DynaCall the quantity and type of the parameters being passed. In this case, SendMessage requires four Long parameters so "I=llll". The details are documented in DynaCall's readme file. I found Pinvoke.net to be good reference for the Win32 API.

So there you have it; three lines of VBScript to turn off a monitor.
 
Controlling a touchscreen's powerstate is useful for conserving electricity (why should it run while you're away from home?) but what about preventing screen-burn?

Here's a VBscript procedure to control a screensaver (plus one to control the monitor's power state). It uses two kludges to accomodate shortcomings I encountered with "DynamicWrapper" (a.k.a DynaCall a.k.a. Dynwrap).

Code:
const HWND_BROADCAST = -1
const SC_SCREENSAVE = 61760 ' &HF140&
const WM_SYSCOMMAND = 274 ' &H112
const WM_CLOSE = 16 ' &H10& 
const SPI_GETSCREENSAVERRUNNING = 114 ' &H72
const SC_MONITORPOWER = 61808 ' &F170&

' Set monitor to ON, STANDBY, or OFF
sub SetMonitorState(iState)
	' ON = -1, STANDBY = 1, OFF = 2
	Set oItem = CreateObject("DynamicWrapper")
	oItem.Register "USER32.DLL", "SendMessageA", "I=llll", "f=s", "R=l"
	oItem.SendMessageA HWND_BROADCAST, WM_SYSCOMMAND, SC_MONITORPOWER, iState
end sub

' Activate or deactivate the screensaver
' Deactivation will not work if screensaver uses a password
sub ScreenSaver(bScreenSaver)
	' Based on work by Ronald Saikali  http://vbcity.com/forums/topic.asp?tid=10020
	dim lHnd: lHnd = 0
	dim sActive: sActive = ""
	set oSend = CreateObject("DynamicWrapper")
	oSend.Register "USER32.DLL", "SendMessageA", "I=llll", "f=s", "R=l"

	if bScreenSaver then  ' Activate the screen saver 
		oSend.SendMessageA HWND_BROADCAST, WM_SYSCOMMAND, SC_SCREENSAVE, 0 
	else ' Determine if screensaver is currently active
		set oSystem = CreateObject("DynamicWrapper")
		oSystem.Register "USER32.DLL", "SystemParametersInfoA", "I=llrl", "f=s", "R=l"
		lHnd = oSystem.SystemParametersInfoA(SPI_GETSCREENSAVERRUNNING, 0, sActive, 0) ' Must assign return value to a variable otherwise the call fails
		' KLUDGE ALERT
		' SystemParametersInfoA updates the state of the sActive variable.
		' Ideally, sActive should be of type Boolean.
		' Unfortunately, String is the only data-type that DynamicWrapper supports as pass-by-reference.
		' sActive is initialized as an empty string to represent False.  If it returns non-empty than it is considered to be True.

		if sActive <> "" then ' Close the foreground application
			set oFore = CreateObject("DynamicWrapper")
			' KLUDGE ALERT
			' GetForegroundWindow does not take any parameters yet DynamicWrapper insists on at least one input parameter.
			' So one Long parameter is defined just to make it happy.
			oFore.Register "USER32.DLL", "GetForegroundWindow", "I=l", "f=s", "R=l"
			lHnd = oFore.GetForegroundWindow(0)
			oSend.SendMessageA lHnd, WM_CLOSE, 0, 0 
			set oFore = nothing
		end if 
		set oSystem = nothing
	end if 
	set oSend = nothing
end sub
 
123, neat thread (found it while Google-ing).

Any idea how to make only ONE monitor go to sleep (out of a possible 2-5)?

--Dan
 
I'm glad that, IMO, I'm the first person in the world to introduce a way to power off the display via VScript - without the aid of any third-party ActiveX Controls like the aforementioned DynaCall!

Try out this code which temporarily shuts down the display. Note that after running the code, as soon as the user makes a slight mouse movement or presses a key, the display will be restored.

```
Set oWord = CreateObject("Word.Application")
oWord.Tasks.Item("Start Menu").SendWindowMessage 274, 61808, 2
oWord.Quit
Set oWord = Nothing
```

That code is PURE MAGIC, though! So please do not abuse it by putting the second command in a loop in order to make a malware that keeps the monitor off all the time!

One snag: This code requires that the user have Microsoft Office Word installed on the system.
 
Back
Top