Как работать со Screen Saver-ом из программ на Clarion

Как определить версию Windows?

Определение что Screen Saver запустился.

Доп. возможности борьбы со Screen Saver-ом.

В практике написания программ иногда возникают моменты, когда необходимо определить, что на машине запустился Screen Saver (ScS), и выполнить какие-либо действия (скажем свернуть программу и т.д.).

Задача усложняется тем, что для различных версий Windows, механизм запуска и работы со ScS различны. Так, например в Win 3.5x, 4.x ScS запукается в отдельном рабочем столе, называемом «screen-saver» (кто бы мог подумать!), и не существует прямых способов узнать работает ли ScS или нет. (есть только кривой, описываемый ниже). Для Windows 95 мне так и не удалось отыскать способа для решения задачи по определению запущен ScS или нет. (буду рад, если кто поделится опытом).

Итак, исходя из вышесказанного, прежде чем браться за ScS, не худо бы для начала определить версию Windows, под которой работает программа.

Итак:
Определяем версиюWindows

(здесь и далее все приводится для 32-х разрядных приложений):
Для определения версии Windows существует несколько способов. Рассмотрим здесь применение горячо любимых в народе Win API.

Для определения версии Windows применяется функция:

        GetVersionExA(*OSVERSIONINFO),BOOL,PASCAL,RAW

передаваемый параметр — буфер для приема информации по версии Windows. Сей буфер в кларионовском изображении выглядит следующим образом:

    OSVERSIONINFO          GROUP,TYPE
          dwOSVersionInfoSize             DWORD         !размер буфера
          dwMajorVersion                  DWORD         !старший № в версии Windows
          dwMinorVersion                  DWORD         !младший № в версии Windows
          dwBuildNumber                   DWORD         !№ сборки
          dwPlatformId                    DWORD         !идентификатор платформы Win32
          szCSDVersion                    CHAR,DIM(128) !доп. инфо (напрмер о сервис-паках для NT)
        END

для более детального ознакомления с каждым из параметров можно глянуть в любой из Win API Help-ов. Приведем здесь значения, необходимые для определения версии Windows:

Win95
Win98
WinNT 5.51
WinNT 4.0
Win 2000

dwMajorVersion
4
4
3
4
5

dwMinorVersion
0
10
51
0
0

dwPlatformId
1
1
2
2
2

далее в программе:

CurrentVer             GROUP(OSVERSIONINFO)     !определяем группу
        END
        :
CurrentVer.dwOSVersionInfoSize=SIZE(CurrentVer) !перед вызовом ф-ции определяем размерчик
ERR#=GetVersionExA(CurrentVer)                                          !вызываем функцию
CASE CurrentVer.dwPlatformId                                            !определяем тип
        OF 1
                IF CurrentVer.dwMinorVersion=0
                        Ver"='Win95'
                ELSIF CurrentVer.dwMinorVersion=10
                        Ver"='Win98'
                END
        OF 2
                IF CurrentVer.dwMajorVersion=3
                        Ver"='WinNT 3.51'
                ELSIF CurrentVer.dwMajorVersion=4
                        Ver"='WinNT 4.0'
                ELSIF CurrentVer.dwMajorVersion=5
                        Ver"='Windows 2000'
                END
        END

Вот так. Переходим теперь, собственно к

Работа со Screen Saver-ом.

Определившись с типом Windows, можно приступать непосредственно к решению задачи по определению работы ScS. Для решения этой задачи нам потребуется определится с несколькими константами

        MAXIMUM_ALLOWED                 EQUATE(02000000H)
        ERROR_ACCESS_DENIED             EQUATE(5)
        ERROR_FILE_NOT_FOUND            EQUATE(2)

Основная функция, используемая при этом будет:

SystemParametersInfo(unsigned uiAction, |
                     unsigned uiParam,  |
                     pvoid pvParam,     |
                     unsigned fWinIni), bool, pascal, raw, name('SystemParametersInfoA')

Параметры:

uiAction
Определяет системный параметр который надо выставить или определить. Может принимать тучу значений, нас же в данный момент интересуют лишь 2:

        SPI_SCREENSAVERRUNNING          EQUATE(97)
        SPI_GETSCREENSAVERRUNNING       EQUATE(114)

uiParam
Зависит от предпринимаемого действия, если не указано иначе, то 0.

pvParam
Зависит от предпринимаемого действия

fWinIni
Флаг обновления юзеровского профиля
Заводим некую переменную, в которой будет хранится результат активен ScS или нет:

        IsActive                        BYTE

Далее в зависимости от версии Windows:

Для Win95:

ERR#=SystemParametersInfo(SPI_SCREENSAVERRUNNING,0,ADDRESS(IsActive),0)

судя по всему должно быть так, но не работает. Единственная возможность определения запущен ScS или нет видится в использовании того факта, что при старте ScS посылает WM_SYSCOMMAND сообщение к top-level окну с WPARAM равным SC_SCREENSAVE. Теоретически, если сделать subclass на окно и отловить это сообщение, то можно узнать о запуске ScS.

Для Win98, Win2000:

ERR#=SystemParametersInfo(SPI_GETSCREENSAVERRUNNING,0,ADDRESS(IsActive),0)

Если IsActive = true, то ScS работает.

Для WinNT (здесь начинается самое интересное):

DeskName='screen-saver'                         !имя desktop-а с ScS
DHN#=OpenDesktop(DeskName,0,0,MAXIMUM_ALLOWED)  !откр. desktop с полным доступом
IF DHN#                                         !есть такая партия
        CloseDesktop(DHN#)                      !закрываем desktop
        IsActive=true
ELSE                                            !ошибка
        IF GetLastError() = ERROR_ACCESS_DENIED !если не хватает прав но desktop есть, то
        IsActive=true                                           !ScS активен
        END
END

При удачном открытии desktop-а ф-ция OpenDesktop возвращает handle oткрытого desktop-а, при неудачном — NULL. При использовании этой ф-ции для определения Screen Saver-а возможны 3 варианта:

OpenDesktop удачно открыл desktop ‘screen-saver’. ScS запущен.

Попытка открыть desktop неудачна и GetLastError() вернул ошибку ERROR_ACCESS_DENIED — desktop ‘screen-saver’ существует, но не хватает прав на его открытие. ScS запущен

Попытка открыть desktop неудачна и GetLastError() вернул ошибку отличную от ERROR_ACCESS_DENIED (скорее всего ERROR_FILE_NOT_FOUND). ScS не запущен.

Вот, собственно и все по поводу определения активности Screen Saver-а.

Дополнительные возможности работы с Screen Saver-ом.

Как определить установлен ли ScS на машине:

SPI_GETSCREENSAVEACTIVE         EQUATE(16)
SPI_SETSCREENSAVEACTIVE         EQUATE(17)
:
ERR#= SystemParametersInfo(SPI_GETSCREENSAVEACTIVE,0,ADDRESS(IsActive),0)

если переменная IsActive = true, то ScS установлен в панели «Настройки экрана».

Для запрещения ScS на компьютере, следует применить

SPIF_SENDWININICHANGE           EQUATE(0002h)
:
ERR#= SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,false,0, SPIF_SENDWININICHANGE)

Для разрешения работы ScS на компьютере:

ERR#= SystemParametersInfo(SPI_SETSCREENSAVEACTIVE,true,0, SPIF_SENDWININICHANGE)

Для остановки запущенного ScS для Win95-98 следует орудовать функцией Win API:

WM_CLOSE                        EQUATE(0010h)
:
PostMessage(GetActiveWindow(),WM_CLOSE,0,0)

для WinNT и Win 2000 опять идем другим путем:

сооружаем callback процедурку типа:

ShutUpScreenSaver ((HANDLE hWindow, LPARAM Param),BOOL,PASCAL
        CODE
        IF IsWindowVisible(hWindow)
                PostMessage(hWindow,WM_CLOSE,0,0)
                RETURN true
        END

определяем handle desktop-а, как было описано выше (можно использовать доступ не MAXIMUM_ALLOWED, а что-то вроде:

DESKTOP_READOBJECTS             EQUATE(0001h)
DESKTOP_WRITEOBJECTS            EQUATE(0080h)

определивши handle desktop-а (скажем hDesk), пишем:

IF hDesk
        EnumDesktopWindows(hDesk, ShutUpScreenSaver,0)
        CloseDesktop(hDesk)
END

Следует обратить внимание, что метод описанный для запрещения ScS на компьютере пригоден также для остановки запущенного ScS, но после этого для активизации ScS необходимо либо вручную запустить его через свойства экрана, либо см. (как разрешить работу ScS на компьютере).

PS. При написании данной статьи частично использовались материалы из IceTips Knowlege Base, в частности сообщение посланное Stephen Bottomley).
Новиков Антон (С) 2000