1 (изменено: Alexs37, 2008-05-24 22:03:36)

Тема: VBS: Как определить выполняется скринсейвер??

Можно как-то определить, что на компе работает скринсейвер.  Надо проверить, если в данный момент запущен скрин, то делаем нужные команды в цикле, как только скринсейвер перестал работу (то есть человек сел за комп) делать паузу выполнения скрипта. И ждать пока снова не запустится скрин, и тогда продолжить работу??

2

Re: VBS: Как определить выполняется скринсейвер??

Option Explicit

Dim objWMIService
Dim objSWbemSink

Dim strScreenSaver_exe
Dim boolState


Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objSWbemSink  = WScript.CreateObject("WbemScripting.SWbemSink","SWbemSink_")

strScreenSaver_exe = GetScreenSaver()

If Len(strScreenSaver_exe) = 0 Then
    QuitInfo "Screen Saver not defined! Exiting...", 1, 3
End If

objWMIService.ExecNotificationQueryAsync objSWbemSink, _
    "SELECT * FROM __InstanceOperationEvent WITHIN 1 " & _
    "WHERE TargetInstance ISA 'Win32_Process' " & _
    "AND TargetInstance.Name = '" & strScreenSaver_exe & "'"

Do
    If boolState Then
        WScript.Echo Now(), "ScreenSaver is executing."
        ' Что-то делаем
    Else
        WScript.Echo Now(), "ScreenSaver is not executing."
        ' Прекращаем что-то делать
    End If
    
    WScript.Sleep 500
Loop

WScript.Quit 0
'=============================================================================

'=============================================================================
Function GetScreenSaver()
    Const HKEY_CURRENT_USER = &H80000001
    Const strPath2PolicyOfParameters = "Software\Policies\Microsoft\Windows\Control Panel\Desktop"
    Const strPath2Parameters         = "Control Panel\Desktop"
    
    
    Dim objStdRegProv
    Dim strScreenSaveActive
    Dim strSCRNSAVE_EXE_Path
    
    
    Set objStdRegProv = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
    
    GetScreenSaver = ""
    
    ' Задана политика хранителя экрана?
    If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2PolicyOfParameters, "ScreenSaveActive", strScreenSaveActive) = 0 Then
        If strScreenSaveActive = "1" Then ' Политика хранителя экрана задана
            ' Задан ли путь к исполняемому файлу хранителя экрана?
            If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2PolicyOfParameters, "SCRNSAVE.EXE", strSCRNSAVE_EXE_Path) = 0 Then
                If Len(strSCRNSAVE_EXE_Path) <> 0 Then        ' Путь к исполняемому файлу хранителя экрана задан
                    GetScreenSaver = Mid(strSCRNSAVE_EXE_Path, InStrRev(strSCRNSAVE_EXE_Path, "\") + 1)
                    
                    Exit Function
                End If
            End If
        End If
    End If
    
    ' Хранитель экрана задан?
    If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2Parameters, "ScreenSaveActive", strScreenSaveActive) = 0 Then
        If strScreenSaveActive = "1" Then ' Хранитель экрана задан
            ' Задан ли путь к исполняемому файлу хранителя экрана?
            If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2Parameters, "SCRNSAVE.EXE", strSCRNSAVE_EXE_Path) = 0 Then
                If Len(strSCRNSAVE_EXE_Path) <> 0 Then        ' Путь к исполняемому файлу хранителя экрана задан
                    GetScreenSaver = Mid(strSCRNSAVE_EXE_Path, InStrRev(strSCRNSAVE_EXE_Path, "\") + 1)
                    
                    Exit Function
                End If
            End If
        End If
    End If
    
    Set objStdRegProv = Nothing
End Function
'=============================================================================

'=============================================================================
Sub SWbemSink_OnObjectReady(objLatestEvent, objAsyncContext)
    ' Какое именно событие произошло?
    Select Case objLatestEvent.Path_.Class
        Case "__InstanceCreationEvent"
            ' Хранитель экрана вызван операционной системой?
            ' (хранитель экрана также может быть исполнен «вручную» или из \Панель управления\Экран\Заставка)
            If StrComp(GetProcessNameByPID(objLatestEvent.TargetInstance.ParentProcessID), "winlogon.exe") = 0 Then
                boolState = True
            End If
        Case "__InstanceModificationEvent"
            ' Nothing to do
        Case "__InstanceDeletionEvent"
            ' Хранитель экрана вызван операционной системой?
            ' (хранитель экрана также может быть исполнен «вручную» или из \Панель управления\Экран\Заставка)
            If StrComp(GetProcessNameByPID(objLatestEvent.TargetInstance.ParentProcessID), "winlogon.exe") = 0 Then
                boolState = False
            End If
        Case Else
    End Select
End Sub
'=============================================================================

'=============================================================================
Function GetProcessNameByPID(PID)
    Dim objProcess
    Dim collProcesses
    
    Set collProcesses = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessID = '" & PID & "'")
    
    For Each objProcess in collProcesses
        GetProcessNameByPID = objProcess.Name
        
        Exit For
    Next
    
    Set collProcesses = Nothing
End Function
'=============================================================================

'=============================================================================
Sub QuitInfo(strInfo, intErrorlevel, intPause)
    With WScript
        If Len(strInfo) <> 0 Then
            .Echo strInfo
        End If
        
        If intPause <> 0 Then
            .Sleep intPause * 1000
        End If
        
        .Quit intErrorlevel
    End With
End Sub
'=============================================================================

В качестве примера. Реализация будет сильно зависеть от типа основной задачи, вплоть до смены типа событий, на которые происходит подписка.

P.S. Коллеги, кто-нибудь помнит, в каком ключе реестре хранится значение, в течение которого операционная система не будет блокировать (Lock) рабочий стол пользователя после того, как будет запущен хранитель экрана [если он задан, конечно]. В течение этого времени, произведя какие-либо манипуляции с мышкой/клавиатурой, можно всё ещё отменить блокировку рабочего стола пользователя. Единственное, что помню, значение по умолчанию — 5 секунд.

3

Re: VBS: Как определить выполняется скринсейвер??

спасибо, не думал что будет так грамоздко... буду разбираться.

4

Re: VBS: Как определить выполняется скринсейвер??

alexii пишет:

P.S. Коллеги, кто-нибудь помнит, в каком ключе реестре хранится значение, в течение которого операционная система не будет блокировать (Lock) рабочий стол пользователя после того, как будет запущен хранитель экрана [если он задан, конечно]. В течение этого времени, произведя какие-либо манипуляции с мышкой/клавиатурой, можно всё ещё отменить блокировку рабочего стола пользователя.

If you dismiss the screen saver within the grace period, it will not prompt for a password.

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon]
"ScreenSaverGracePeriod"="5"

Источники:
ScreenSaverGracePeriod: Core Services
Screen saver grace period bypasses password protection

5

Re: VBS: Как определить выполняется скринсейвер??

Уточнённый вариант скрипта из #2, учитывающий How to write a 32bit screen saver:


Command-line arguments
The behaviour expected of the saver depends on the command-line arguments it is given. The code snippet below shows how you might parse the command line. If the command line arguments are invalid, then the saver should terminate immediately without doing anything.

    * /c, /c ####, or no arguments at all - in response to any of these the saver should pop up its configuration dialog. If there are no arguments then NULL should be used as the parent: this will end up happening if the user clicks on the saver in the Explorer. With /c as an argument, the dialog should use GetForegroundWindow() as its parent. With /c #### the saver should treat #### as the decimal representation of an HWND, and use this as its parent.
    * /s - this indicates that the saver should run itself as a full-screen saver.
    * /p ####, or /l #### - here the saver should treat the #### as the decimal representation of an HWND, should pop up a child window of this HWND, and should run in preview mode inside that window.
    * /a #### - this command-line argument is only ever used in '95 and Plus! The saver should pop up a password-configuration dialog as a child of ####.

When parsing command-line options, note that the letters may appear as lower-case or upper-case, and that there might be either a forward slash or a hyphen prefixing the letter, and that there may be either a space or a colon after the letter. Thus, you should respond to /p #### and -P:#### and all options in between.

Option Explicit

Dim objWMIService
Dim objSWbemSink

Dim strScreenSaver_exe
Dim strPartCmdLine
Dim boolState


Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Set objSWbemSink  = WScript.CreateObject("WbemScripting.SWbemSink","SWbemSink_")

strScreenSaver_exe = GetScreenSaver()

If Len(strScreenSaver_exe) = 0 Then
    QuitInfo "Screen Saver not defined! Exiting...", 1, 3
End If

objWMIService.ExecNotificationQueryAsync objSWbemSink, _
    "SELECT * FROM __InstanceOperationEvent WITHIN 1 " & _
    "WHERE TargetInstance ISA 'Win32_Process' " & _
    "AND TargetInstance.Name = '" & strScreenSaver_exe & "'"

Do
    If boolState Then
        WScript.Echo Now(), "ScreenSaver is executing."
        ' Что-то делаем
    Else
        WScript.Echo Now(), "ScreenSaver is not executing."
        ' Прекращаем что-то делать
    End If
    
    WScript.Sleep 500
Loop

WScript.Quit 0
'=============================================================================

'=============================================================================
Function GetScreenSaver()
    Const HKEY_CURRENT_USER = &H80000001
    Const strPath2PolicyOfParameters = "Software\Policies\Microsoft\Windows\Control Panel\Desktop"
    Const strPath2Parameters         = "Control Panel\Desktop"
    
    
    Dim objStdRegProv
    Dim strScreenSaveActive
    Dim strSCRNSAVE_EXE_Path
    
    
    Set objStdRegProv = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\default:StdRegProv")
    
    GetScreenSaver = ""
    
    ' Задана политика хранителя экрана?
    If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2PolicyOfParameters, "ScreenSaveActive", strScreenSaveActive) = 0 Then
        If strScreenSaveActive = "1" Then ' Политика хранителя экрана задана
            ' Задан ли путь к исполняемому файлу хранителя экрана?
            If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2PolicyOfParameters, "SCRNSAVE.EXE", strSCRNSAVE_EXE_Path) = 0 Then
                If Len(strSCRNSAVE_EXE_Path) <> 0 Then        ' Путь к исполняемому файлу хранителя экрана задан
                    GetScreenSaver = Mid(strSCRNSAVE_EXE_Path, InStrRev(strSCRNSAVE_EXE_Path, "\") + 1)
                    strPartCmdLine     = strSCRNSAVE_EXE_Path & " /s"
                    
                    Exit Function
                End If
            End If
        End If
    End If
    
    ' Хранитель экрана задан?
    If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2Parameters, "ScreenSaveActive", strScreenSaveActive) = 0 Then
        If strScreenSaveActive = "1" Then ' Хранитель экрана задан
            ' Задан ли путь к исполняемому файлу хранителя экрана?
            If objStdRegProv.GetStringValue(HKEY_CURRENT_USER, strPath2Parameters, "SCRNSAVE.EXE", strSCRNSAVE_EXE_Path) = 0 Then
                If Len(strSCRNSAVE_EXE_Path) <> 0 Then        ' Путь к исполняемому файлу хранителя экрана задан
                    GetScreenSaver = Mid(strSCRNSAVE_EXE_Path, InStrRev(strSCRNSAVE_EXE_Path, "\") + 1)
                    strPartCmdLine     = strSCRNSAVE_EXE_Path & " /s"
                    
                    Exit Function
                End If
            End If
        End If
    End If
    
    Set objStdRegProv = Nothing
End Function
'=============================================================================

'=============================================================================
Sub SWbemSink_OnObjectReady(objLatestEvent, objAsyncContext)
    ' Какое именно событие произошло?
    Select Case objLatestEvent.Path_.Class
        Case "__InstanceCreationEvent"
            ' Хранитель экрана вызван операционной системой?
            ' (хранитель экрана также может быть исполнен «вручную» или из \Панель управления\Экран\Заставка)
            If StrComp(GetProcessNameByPID(objLatestEvent.TargetInstance.ParentProcessID), "winlogon.exe") = 0 And _
                UCase(Left(objLatestEvent.TargetInstance.CommandLine, Len(strPartCmdLine))) = UCase(strPartCmdLine) Then
                
                boolState = True
            End If
        Case "__InstanceModificationEvent"
            ' Nothing to do
        Case "__InstanceDeletionEvent"
            ' Хранитель экрана вызван операционной системой?
            ' (хранитель экрана также может быть исполнен «вручную» или из \Панель управления\Экран\Заставка)
            If StrComp(GetProcessNameByPID(objLatestEvent.TargetInstance.ParentProcessID), "winlogon.exe") = 0 And _
                UCase(Left(objLatestEvent.TargetInstance.CommandLine, Len(strPartCmdLine))) = UCase(strPartCmdLine) Then
                
                boolState = False
            End If
        Case Else
    End Select
End Sub
'=============================================================================

'=============================================================================
Function GetProcessNameByPID(PID)
    Dim objProcess
    Dim collProcesses
    
    Set collProcesses = objWMIService.ExecQuery("Select * from Win32_Process Where ProcessID = '" & PID & "'")
    
    For Each objProcess in collProcesses
        GetProcessNameByPID = objProcess.Name
        
        Exit For
    Next
    
    Set collProcesses = Nothing
End Function
'=============================================================================

'=============================================================================
Sub QuitInfo(strInfo, intErrorlevel, intPause)
    With WScript
        If Len(strInfo) <> 0 Then
            .Echo strInfo
        End If
        
        If intPause <> 0 Then
            .Sleep intPause * 1000
        End If
        
        .Quit intErrorlevel
    End With
End Sub
'=============================================================================

6

Re: VBS: Как определить выполняется скринсейвер??

ОФФ: у меня на компе вообще скринсейвер отключен.

В то же время при работающем скринсейвере может идти большая расчетная задача и дополнительная загрузка процессора нецелесообразна.

Может за критерий начала работы скрипта взять загрузку процессора, а не работу скринсейвера?

7

Re: VBS: Как определить выполняется скринсейвер??

OFF: На мой взгляд, лучший вариант — написание самого хранителя экрана. То бишь, перевод своего кода с VBScript на, к примеру, AutoIt (дабы осталась поддержка OLE Automation + лицензионная чистота, потому про «большой» VB/VB.Net не поминаю) и добавление кода, реализующего минимальную обработку ключей запуска этого хранителя экрана («/c», «/s», «/p») и остановку по приходу события от клавиатуры/мыши. Ну, а в нём уже делай, что хочешь, хоть внутри себя, хоть внешним приложением — никто мешать не будет, ведь он сам и есть хранитель экрана. Примерно на такой основе сделан хранитель экрана Avast .

8

Re: VBS: Как определить выполняется скринсейвер??

alexii, возможен ли автоматический запуск стандартного скринсейвера на экране выбора пользователя при условии, что у пользователя уже выполнен вход в систему?

9

Re: VBS: Как определить выполняется скринсейвер??

Не пойму вопроса, ypppu.

10

Re: VBS: Как определить выполняется скринсейвер??

Первый случай. Экран выбора пользователя. Ни один пользователь не выполнил вход в систему. Через 10 минут бездействия автоматически запускается заставка winlogon.scr.

Второй случай. Экран выбора пользователя. Хотя бы один пользователь выполнил вход в систему. Спустя 10 минут бездействия заставка почему-то не запускается.

Хотелось бы, чтоб во втором случае заставка автоматически запускалась.

11

Re: VBS: Как определить выполняется скринсейвер??

Понял. Я просто не пользую «переключение пользователей». Посему ответа не знаю.

12

Re: VBS: Как определить выполняется скринсейвер??

штатный планировщик умеет

Я конечно далек от мысли... (с)

13

Re: VBS: Как определить выполняется скринсейвер??

smaharbA, большое спасибо за подсказку!