Imports System.Runtime.InteropServices
Imports System
Imports System.Windows.Forms
Imports System.Threading
Partial Public Class ScreenSaverTest
Inherits Form
Private killTimer As System.Threading.Timer
Private killState As Integer = 1
Private killPeriod As Integer = 8000
' msec
Private timerState As Integer = STOPPED
Private ssIsActive As Boolean = False
Private ssTimeout As Integer = 5
' sec
Private ssSaveTimeout As Int32 = 0
Private hThisWnd As IntPtr = IntPtr.Zero
Private Const STOPPED As Integer = 0
Private Const RUNNING As Integer = 1
Private Const [FALSE] As Integer = 0
Private Const [TRUE] As Integer = 1
' This delegate enables asynchronous calls for setting
' the text property on a TextBox control.
Private Delegate Sub SetTextCallback(ByVal text As String)
Public Sub New()
InitializeComponent()
Dim timerDelegate As New TimerCallback(AddressOf KillTimer_Elapsed)
killTimer = New System.Threading.Timer(timerDelegate, Nothing, System.Threading.Timeout.Infinite, killPeriod)
' Save off this Window's handle. Used in the kill event handler.
hThisWnd = ScreenSaver.GetForegroundWindow()
' Save off the original Settings values
ssIsActive = ScreenSaver.GetScreenSaverActive()
ssSaveTimeout = ScreenSaver.GetScreenSaverTimeout()
UpdateSettingsValues()
End Sub
Private Sub buttonActivate_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonActivate.Click
' Toggle Screen Saver Active
ScreenSaver.SetScreenSaverActive(If((ScreenSaver.GetScreenSaverActive()), [FALSE], [TRUE]))
UpdateSettingsValues()
End Sub
Private Sub UpdateSettingsValues()
valueScreenSaverActive.Text = ScreenSaver.GetScreenSaverActive().ToString()
valueScreensaverTimeout.Text = ScreenSaver.GetScreenSaverTimeout().ToString()
buttonActivate.Text = If((ScreenSaver.GetScreenSaverActive()), "Deactivate", "Activate")
End Sub
Private Sub buttonUpdateTimeout_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonUpdateTimeout.Click
ScreenSaver.SetScreenSaverTimeout(ssTimeout)
UpdateSettingsValues()
End Sub
Private Sub buttonRefresh_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonRefresh.Click
UpdateSettingsValues()
End Sub
Private Sub buttonRestore_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonRestore.Click
' Restore original screen saver settings
ScreenSaver.SetScreenSaverActive(If((ssIsActive), [TRUE], [FALSE]))
ScreenSaver.SetScreenSaverTimeout(ssSaveTimeout)
UpdateSettingsValues()
End Sub
Private Sub entryScreensaverTimeout_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles entryScreensaverTimeout.ValueChanged
ssTimeout = CInt(entryScreensaverTimeout.Value)
End Sub
Private Sub entryKillPeriod_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles entryKillPeriod.ValueChanged
killPeriod = CInt(entryKillPeriod.Value) * 1000
' convert to msec
End Sub
Private Sub KillTimer_Elapsed(ByVal state As Object)
' Toggle kill state to indicate activity
killState = If((killState = 1), 0, 1)
Me.SetText(killState.ToString())
' Stop the screen saver if it's active and running, otherwise reset the screen saver timer.
' Apparently it's possible for GetScreenSaverRunning( ) to return TRUE before the
' screen saver has time to actually become the foreground application. So...
' Make sure we're not the foreground window to avoid killing ourself.
If ScreenSaver.GetScreenSaverActive() Then
If ScreenSaver.GetScreenSaverRunning() Then
If ScreenSaver.GetForegroundWindow() <> hThisWnd Then
ScreenSaver.KillScreenSaver()
End If
Else
' Reset the screen saver timer, so the screen saver doesn't turn on until after a full
' timeout period. If killPeriod is less than ssTimeout the screen saver should never activate.
ScreenSaver.SetScreenSaverActive([TRUE])
End If
End If
End Sub
Private Sub SetText(ByVal text As String)
' InvokeRequired required compares the thread ID of the
' calling thread to the thread ID of the creating thread.
' If these threads are different, it returns true.
If valueKillState.InvokeRequired Then
Dim d As New SetTextCallback(AddressOf SetText)
Me.Invoke(d, New Object() {text})
Else
valueKillState.Text = text
End If
End Sub
Private Sub ScreenSaverTest_FormClosing(ByVal sender As Object, ByVal e As FormClosingEventArgs)
' Restore original screen saver settings
ScreenSaver.SetScreenSaverActive(If((ssIsActive), [TRUE], [FALSE]))
ScreenSaver.SetScreenSaverTimeout(ssSaveTimeout)
End Sub
Private Sub buttonStartStopTimer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonStartStopTimer.Click
timerState = If((timerState = RUNNING), STOPPED, RUNNING)
If timerState = RUNNING Then
' Start the kill event timer
killTimer.Change(0, killPeriod)
entryKillPeriod.Enabled = False
entryScreensaverTimeout.Enabled = False
buttonStartStopTimer.Text = "Stop Timer"
Else
' Stop the kill event from triggering
killTimer.Change(System.Threading.Timeout.Infinite, killPeriod)
entryKillPeriod.Enabled = True
entryScreensaverTimeout.Enabled = True
buttonStartStopTimer.Text = "Start Timer"
End If
End Sub
Private Sub buttonClose_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles buttonClose.Click
Me.Close()
End Sub
End Class
#Region "ScreenSaver Class"
Public NotInheritable Class ScreenSaver
Private Sub New()
End Sub
' Signatures for unmanaged calls
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SystemParametersInfo(ByVal uAction As Integer, ByVal uParam As Integer, ByRef lpvParam As Integer, ByVal flags As Integer) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function SystemParametersInfo(ByVal uAction As Integer, ByVal uParam As Integer, ByRef lpvParam As Boolean, ByVal flags As Integer) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function PostMessage(ByVal hWnd As IntPtr, ByVal wMsg As Integer, ByVal wParam As Integer, ByVal lParam As Integer) As Integer
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function OpenDesktop(ByVal hDesktop As String, ByVal Flags As Integer, ByVal Inherit As Boolean, ByVal DesiredAccess As UInteger) As IntPtr
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function CloseDesktop(ByVal hDesktop As IntPtr) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function EnumDesktopWindows(ByVal hDesktop As IntPtr, ByVal callback As EnumDesktopWindowsProc, ByVal lParam As IntPtr) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Private Shared Function IsWindowVisible(ByVal hWnd As IntPtr) As Boolean
End Function
<DllImport("user32.dll", CharSet:=CharSet.Auto)> _
Public Shared Function GetForegroundWindow() As IntPtr
End Function
' Callbacks
Private Delegate Function EnumDesktopWindowsProc(ByVal hDesktop As IntPtr, ByVal lParam As IntPtr) As Boolean
' Constants
Private Const SPI_GETSCREENSAVERACTIVE As Integer = 16
Private Const SPI_SETSCREENSAVERACTIVE As Integer = 17
Private Const SPI_GETSCREENSAVERTIMEOUT As Integer = 14
Private Const SPI_SETSCREENSAVERTIMEOUT As Integer = 15
Private Const SPI_GETSCREENSAVERRUNNING As Integer = 114
Private Const SPIF_SENDWININICHANGE As Integer = 2
Private Const DESKTOP_WRITEOBJECTS As UInteger = 128
Private Const DESKTOP_READOBJECTS As UInteger = 1
Private Const WM_CLOSE As Integer = 16
' Returns TRUE if the screen saver is active (enabled, but not necessarily running).
Public Shared Function GetScreenSaverActive() As Boolean
Dim isActive As Boolean = False
SystemParametersInfo(SPI_GETSCREENSAVERACTIVE, 0, isActive, 0)
Return isActive
End Function
' Pass in TRUE(1) to activate or FALSE(0) to deactivate the screen saver.
Public Shared Sub SetScreenSaverActive(ByVal Active As Integer)
Dim nullVar As Integer = 0
SystemParametersInfo(SPI_SETSCREENSAVERACTIVE, Active, nullVar, SPIF_SENDWININICHANGE)
End Sub
' Returns the screen saver timeout setting, in seconds
Public Shared Function GetScreenSaverTimeout() As Int32
Dim value As Int32 = 0
SystemParametersInfo(SPI_GETSCREENSAVERTIMEOUT, 0, value, 0)
Return value
End Function
' Pass in the number of seconds to set the screen saver timeout value.
Public Shared Sub SetScreenSaverTimeout(ByVal Value As Int32)
Dim nullVar As Integer = 0
SystemParametersInfo(SPI_SETSCREENSAVERTIMEOUT, Value, nullVar, SPIF_SENDWININICHANGE)
End Sub
' Returns TRUE if the screen saver is actually running
Public Shared Function GetScreenSaverRunning() As Boolean
Dim isRunning As Boolean = False
SystemParametersInfo(SPI_GETSCREENSAVERRUNNING, 0, isRunning, 0)
Return isRunning
End Function
' From Microsoft's Knowledge Base article #140723: http://support.microsoft.com/kb/140723
' "How to force a screen saver to close once started in Windows NT, Windows 2000, and Windows Server 2003"
Public Shared Sub KillScreenSaver()
Dim hDesktop As IntPtr = OpenDesktop("Screen-saver", 0, False, DESKTOP_READOBJECTS Or DESKTOP_WRITEOBJECTS)
If hDesktop <> IntPtr.Zero Then
EnumDesktopWindows(hDesktop, New EnumDesktopWindowsProc(AddressOf KillScreenSaverFunc), IntPtr.Zero)
CloseDesktop(hDesktop)
Else
PostMessage(GetForegroundWindow(), WM_CLOSE, 0, 0)
End If
End Sub
Private Shared Function KillScreenSaverFunc(ByVal hWnd As IntPtr, ByVal lParam As IntPtr) As Boolean
If IsWindowVisible(hWnd) Then
PostMessage(hWnd, WM_CLOSE, 0, 0)
End If
Return True
End Function
End Class
#End Region