Подробнее о возможностях GINA.DLL.

Что делать, если вы изобрели оригинальное устройство или технологию (например, популярные ныне биометрические технологии) для идентификации пользователей? Или хотите в момент авторизации проверять дополнительные параметры? Или просто изменить графический интерфейс, предоставляемый при регистрации в системе? Или пользоваться ресурсами нестандартных информационных провайдеров, например разработанного своими силами файл-сервера, требующих авторизации?

Архитектура Windows предоставляет разработчикам прекрасные возможности для решения подобных задач. И все, что нужно сделать, — это переписать парочку небольших модулей да реализовать несколько экспортируемых функций. Один из модулей называется Graphical Identification and Authentication dynamic-link library (GINA DLL). Вы взаимодействуете с этим модулем, когда вводите имя и пароль, нажимая на Ctrl-Alt-Del, блокируете рабочую станцию или меняете пароль и т. д. Достаточно переписать модуль, и перед вами раскроются новые горизонты.

В этой статье я остановлюсь на реализации основных функций, которые должна экспортировать GINA.DLL, и на использовании ряда функций подсистемы Local Security Authority (LSA), которая, собственно, и осуществляет аутентификацию пользователя в системе. Подробнее об LSA, которая предоставляет очень интересный API, я расскажу в одной из следующих статей. Здесь же я остановлюсь лишь на взаимодействии данной подсистемы и модуля GINA.

Загрузка Windows

Посмотрим, какие стадии проходит Windows 2000 в процессе загрузки (подробнее об этом рассказано в [1]). После включения компьютера выполняется загрузка BIOS, которая проводит процедуру первоначального тестирования оборудования (POST), считывает запись Master Boot Record (MBR) и передает управление коду, содержащемуся в этой записи. Он выполняет проверку, ищет в корневом каталоге модуль ntldr и передает ему управление (MBR не может читать дерево подкаталогов, поэтому Ntldr всегда находится в корневом каталоге). В свою очередь, Ntldr обрабатывает файл boot.ini, выводит на экран меню вариантов загрузки или, если вариант один, не дожидаясь выбора, переходит к следующему этапу. На нем запускается 16-разрядное приложение ntdetect.com, которое получает информацию об оборудовании от BIOS и сохраняет ее во внутренних структурах. Затем ntldr выводит картинку — индикатор загрузки Windows 2000 — и предлагает нажать на F8. Действия операционной системы при выборе специальных вариантов загрузки по нажатию клавиши F8 мы здесь рассматривать не будем.

Ntldr загружает ядро операционной системы и Hardware Abstraction Layer (HAL), которым, по умолчанию, соответствуют файлы Ntoskrnl.exe и HAL.dll. Далее загружаются необходимые (помеченные флажком SERVICE_BOOT_START) драйверы устройств, описанные в файле SYSTEM, содержащем соответствующий раздел реестра. После этого загрузчик производит действия, необходимые для запуска ntoskrnl.exe, и передает управление его главной функции. Здесь происходит много всяких, во-первых, сложных и, во-вторых, не представляющих сейчас для нас интереса событий. Но в числе прочего создается процесс Smss, который формирует среду пользовательского режима. Smss запускает подсистему Win32, программы, перечисленные в HKLMSYSTEMCurrentControlSet ControlSession ManagerBootExecute, инициализирует реестр, переменные окружения и другие «мелочи» и, наконец, запускает процесс Winlogon.

Далее ответственность за дальнейшую инициализацию системы ложится на Winlogon. Он формирует объект WindowStation и три рабочих стола — пользовательский, хранителя экрана и Winlogon; загружает GINA DLL (!), создает процесс диспетчера управления службами (SCM), загружает все службы и драйверы устройств, помеченные для автоматического запуска, и запускает процесс Lsass. После того как пользователь успешно зарегистрировался, а SCM запустил службы и драйверы, загрузка считается успешно завершенной, и LastKnownGood обновляется в соответствии с текущими установками.

Вот таким образом происходит загрузка Windows 2000. Понимая процесс загрузки, мы можем смело переходить к подробному обсуждению работы интересующего нас модуля — GINA. Свое исследование я хочу начать с того момента, когда пользователь еще не зарегистрировался в системе, а GINA DLL только загружена в память. Заметим, что процесс инициализации GINA и загрузка служб и драйверов происходят параллельно. Этим объясняется, почему для некоторых реализаций GINA в тот момент, когда пользователь хочет предпринять какие-то действия, необходимых служб еще нет.

Подсистема регистрации пользователя в Windows NT/2000/XP состоит из трех компонентов: Winlogon.exe, GINA DLL и, возможно, нескольких сетевых библиотек (Network Providers), осуществляющих вторичную авторизацию, например на файл-сервере собственной разработки. Регистрация выполняется через LSA API. GINA DLL, как показано на Рисунке 1, непосредственно взаимодействует с этой подсистемой и возвращает результаты регистрации Winlogon. В Windows 2000 и более поздних версиях поддерживается механизм notification packages — пакетов уведомлений. Это модули, представляющие собой DLL, которые вызываются Winlogon в моменты, соответствующие тем или иным событиям.

Рисунок 1. Схема подсистемы регистрации.

Среда разработки, выполнения и отладки демонстрационной программы

Код, представленный в листингах, и полный текст демонстрационного модуля GINA DLL, который можно получить на нашем сайте, разработан в Visual C++ 6.0 без пакетов обновления с использованием Platform SDK. Проект представляет собой Win32 Dynamic-Link Library. Необходимо добавить директиву _WIN32_WINNT =0x0500 для препроцессора и дополнительные библиотеки netapi32.lib и Secur32.lib — для компоновщика. Для того чтобы наша реализация GINA DLL загрузилась в память, ее нужно скомпилировать. Программа выполняется на Windows 2000 без пакетов обновления и в более поздних версиях Windows.

С отладкой приложения дело обстоит сложнее. Основная проблема заключается в том, что отладчик запускается на рабочем столе по умолчанию, которым является пользовательский рабочий стол. А GINA выполняется на рабочем столе Winlogon. Можно поступить следующим образом: используя отладочную версию Winlogon, которую можно найти, например, в DDK, получать log-файлы, которые вполне пригодны для анализа. Для этого необходимо в файле Win.ini создать секцию

[WinlogonDebug]
LogFile=C:Winlogon.log
DebugFlags=Flag1[, Flag2...]

Имя файла должно содержать полный путь. Флаги, определяющие, какую информацию нужно записывать в журнал, указаны в Таблице 1. Для запуска отладочной версии Winlogon необходимо в раздел реестра HKLMSoftwareMicrosoftWindows NTCurrentVersionImage File Execution OptionsWinlogon.exe добавить значение Debugger типа REG_SZ со значением ntsd -d (подробнее об отладке компонентов Windows можно прочитать в [1] и [2]). Если такого раздела не существует, а в обычных конфигурациях Windows это именно так, его требуется создать. В статье Q260901 базы знаний MSDN технология, позволяющая отлаживать GINA DLL на одном компьютере, описана более подробно.

Путь к модулю, который загружает Winlogon, находится в значении параметра GinaDLL. По умолчанию это msGINA.dll. Если в реестре этого параметра нет, то Winlogon также использует msGINA.dll. При загрузке в безопасном режиме (Safe Mode) всегда загружается модуль msGINA.dll. Если в папке System32 его нет, то он подгружается из dllcache, в противном случае загрузка прерывается. Поэтому при отладке своей версии модуля не следует уничтожать модуль по умолчанию.

Взаимодействие Winlogon и GINA

Как отмечалось выше, GINA представляет собой DLL, которая экспортирует ряд как обязательных, так и дополнительных функций. Первые необходимо реализовать в своей версии модуля, а для вторых в модуле Winlogon.exe имеется код по умолчанию, который будет выполнен, если библиотека не предоставит их реализацию.

Winlogon взаимодействует с GINA следующим образом:

  1. вызывает экспортируемые GINA функции;
  2. передает сообщения в открытые GINA диалоги. Этот механизм рассматривается ниже, в разделе, посвященном диалогам в GINA;
  3. предоставляет GINA свой API;
  4. с помощью функции WlxSasNotify() принимает от GINA сообщения.

В основе всех этих механизмов лежит понятие secure attention sequence (SAS).

В Таблице 2 приведен полный список экспортируемых GINA для Windows 2000 функций с краткими пояснениями к ним. Галочками помечены функции, реализация которых в GINA DLL обязательна. Напомню, что речь идет о версиях Winlogon WLX_VERSION_1_3 и выше.

Рисунок 2. Алгоритм работы Winlogon.

Вообще говоря, алгоритм работы Winlogon основан на трех возможных состояниях. На Рисунке 2, взятом из MSDN, представлена схема перехода между состояниями. Для каждого состояния возможен определенный набор функций и задан сценарий взаимодействия с GINA и другими компонентами Windows. Рассмотрим несколько примеров сценариев взаимодействия Winlogon и GINA DLL.

Загрузка рабочей станции. Winlogon вызывает WlxNegotiate для согласования версий, а потом WlxInitialize — для создания окружения.

Ожидание регистрации пользователя. GINA ожидает ввода SAS, а потом вызывает WlxSasNotify. Winlogon вызывает WlxLoggedOutSAS, в которой происходит регистрация пользователя. После успешной регистрации Winlogon вызывает WlxActivateUserShell для создания оболочки пользователя и переходит в состояние 2.

Пользователь зарегистрирован. Если в процессе работы возникает SAS, Winlogon вызывает функцию WlxLoggedOnSAS. Внутри этой функции GINA DLL может предложить пользователю различные варианты действий.

Пользователь хочет завершить сеанс и выключить компьютер. Winlogon обращается к WlxLoggedOnSAS, которая возвращает WLX_SAS_ACTION_SHUTDOWN. Далее Winlogon последовательно вызывает функции WlxLogoff и WlxShutdown.

Инициализация GINA

Процесс загрузки GINA происходит в три этапа.

Сначала вызывается функция DllMain. Процесс Winlogon обращается к функции GINA DLL WlxNegotiate. На разных стадиях развития операционной системы — от Windows NT 3.5 до Windows XP и .NET — список функций, поддерживаемых Winlogon, существенно меняется. GINA получает таблицу с указателями на список поддерживаемых функций в структурах WLX_DISPATCH_VERSION_X_X. Версии на настоящий момент могут быть 1_0, 1_1, 1_2, 1_3 (этой версией таблицы мы и будем пользоваться) и 1_4 для Windows XP/.NET. Каждая последующая версия представляет собой расширение предыдущей. Таким образом, более ранние реализации GINA могут работать с более поздними версиями Winlogon.

В функцию WlxNegotiate передаются два параметра (см. Листинг 1). Первый — это версия таблицы, которую поддерживает Winlogon, а во втором GINA сообщает, какая минимальная версия необходима ей для работы. Функция возвращает TRUE, если ее устраивает версия Winlogon, и FALSE — в противном случае. Конечно, можно самому написать GINA таким образом, что будут поддерживаться все возможные наборы функций.

В том случае, если WlxNegotiate возвращает TRUE, Winlogon вызывает функцию WlxInitialize, в которой GINA инициализирует свое окружение (см. Листинг 2). Все функции, экспортируемые GINA, используют некоторую структуру WlxContext. Это определяемая пользователем структура, где хранится необходимая для работы GINA информация. Для используемой в статье программы я выбрал структуру, приведенную в Листинге 3. Что и зачем я сохранил в этой структуре?

hWlx — идентификатор процесса Winlogon, соответствующего текущей window station. Это значение используется в качестве аргумента во время вызовов функций Winlogon.

wszStation — текущая window station. На сегодня все версии Windows поддерживают только одну станцию.

pWlxFuncs — указатель на таблицу функций.

hDllInstance — идентификатор модуля GINA, он потребуется в дальнейшем для доступа к ресурсам — шаблонам диалоговых окон, строковым таблицам и т. д.

hUserToken — маркер доступа (token) пользователя. Это значение необходимо, например, при разблокировке компьютера, да и вообще во всех ситуациях, требующих информации о зарегистрированном пользователе.

Кроме специально оговоренных случаев, все (!) операции c динамической памятью должны осуществляться с помощью функций LocalAlloc, LocalFree и т. д. После заполнения полей определенной мною структуры GINA_CONTEXT я вызываю функцию Winlogon WlxUseCtrlAltDel(). Зачем? В принципе, этого делать не надо. Данная функция в качестве SAS определяет стандартную последовательность Ctrl-Alt-Del. Мне кажется, что это удобно.

Если процесс инициализации прошел успешно, я присваиваю возвращаемому параметру pWlxContext функции WlxInitialize указатель на созданный контекст и возвращаю TRUE, в противном случае — возвращаю FALSE.

В дальнейшем все функции будут получать в качестве входного параметра указатель на созданный контекст. Как реагирует Winlogon на невыполненную процедуру инициализации, можно легко проверить.

Далее Winlogon вызывает функцию GINA WlxDisplaySASNotice. У нее не очень сложная реализация (см. Листинг 4). Алгоритм работы простой. Функция проверяет параметр реестра HKLMSOFTWAREMicrosoftWindows NTCurrentVersionWinlogon DisableCAD. Большая часть настроечных параметров Winlogon находится в разделе HKLMSOFTWARE MicrosoftWindows NTCurrentVersionWinlogon. Далее, если явно не указан другой раздел реестра, подразумевается именно он, и его описание я буду опускать. Так вот, если значение DisableCAD равно 1, вызывается WlxSasNotify, которая эмулирует нажатие клавиш Ctrl-Alt-Del.

В случае, когда это значение равно 0, появляется окно с предложением нажать комбинацию Ctrl-Alt-Del или произвести другие действия, которые должны привести к возможности ввода идентификационной информации. Смысл этого диалога в обеспечении дополнительной защиты системы. Он не позволит написать программу, подменяющую окно ввода пароля.

Вот и пришлось создать первое диалоговое окно. Самое время поговорить о диалогах в GINA, потому что они не совсем обычные.

Диалоговые окна GINA

Диалоги в GINA создаются специальными функциями. Они не сильно отличаются от обычных. А нужны они из-за необходимости пересылать специфические сообщения в эти диалоговые окна. Поэтому Winlogon предоставляет свои функции для регистрации окон, с которыми ему придется работать. Функции, которые Winlogon поддерживает при работе с диалогами, приведены в Таблице 3.

Все эти функции поддерживают только модальные диалоги. Затем созданные с их помощью диалоговые окна получают специфическое для Winlogon сообщение WLX_WM_SAS. wParam для этого сообщения может принимать значения, описанные в Таблице 4.

Как реагировать на сообщения WLX_SAS_TYPE_CTRL_ALT_DEL, WLX_SAS_TYPE_SC_INSERT, WLX_SAS_TYPE_SC_REMOVE — решать разработчику. В принципе, не требует обязательной обработки и сообщение WLX_SAS_TYPE_USER_LOGOFF. Но с тайм-аутами несколько сложнее. Все диалоговые окна, кроме выводимого функцией WlxDisplaySASNotice, которая представляет приветствие Windows и предлагает начать регистрацию с нажатия кнопок Ctrl-Alt-Del, должны завершаться с помощью стандартной функции EndDialog. Возвращаемое же значение должно быть WLX_DLG_INPUT_TIMEOUT для WLX_SAS_TYPE_TIMEOUT и WLX_DLG_SCREEN_SAVER_TIMEOUT — для WLX_SAS_TYPE_SCRNSVR_TIMEOUT (см. Листинг 5). А вот функция диалога из WlxDisplaySASNotice может отработать эти сообщения проще, как показано в Листинге 6.

В остальном же это самые обычные диалоговые окна, к которым применимы обычные функции. Для работы с диалогами GINA я написал класс CGinaDlg, код которого приведен в Листинге 7. Все диалоги в демонстрационной программе наследуют от данного класса и выглядят как белые эллипсы. Я не думаю, что этот код требует дополнительных комментариев.

Регистрация пользователя

Смысл регистрации заключается в получении информации, идентифицирующей пользователя. Заметим, что информацией, идентифицирующей пользователя, может быть не только привычный набор, состоящий из имени пользователя, пароля и имени домена, в котором пользователь будет регистрироваться. Им может быть и цифровой сертификат, и битовые образы отпечатка пальца или рисунка сетчатки глаза. Для того чтобы предоставить GINA DLL возможность ввода и получения маркера доступа — ключевого объекта при регистрации пользователя, о котором мы поговорим ниже, — Winlogon вызывает функцию GINA WlxLoggedOutSAS. Результатом выполнения этой функции должны быть полученные маркер доступа, SID и профиль пользователя. Посмотрим, как все это происходит.

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

В результате мы получаем имя пользователя, пароль и домен, в котором хранится учетная запись пользователя. Что дальше? Можно выбрать простой способ и вызвать функцию LogonUser. Но, хотя мы и получим необходимый нам маркер, возможности этой функции крайне невелики. Windows предоставляет специальную службу — Local Security Authority, — предназначенную для аутентификации и авторизации пользователей.

Процесс регистрации пользователя заключается в открытии сессии LSA, что происходит в функции WlxLoggedOutSAS, и дальнейшей активизации оболочки, которая осуществляется в функции WlxActivateUserShell.

Посмотрим, как формируется сессия пользователя, (см. Листинг 8). Функция WlxLoggedOutSAS, прежде всего, должна создать окно, в котором пользователь введет свое имя, пароль и домен, где хранится информация об учетной записи.

Значение ShutdownWithoutLogon может быть равно 1 или 0. В первом случае пользователь может завершить работу компьютера без регистрации. Для этого в окне ввода регистрационной информации добавляется кнопка Shutdown, как сделано в демонстрационном модуле. После нажатия пользователем этой кнопки функция WlxLoggedOutSAS может вернуть в Winlogon значение WLX_SAS_ACTION_SHUTDOWN_POWER_OFF, если PowerdownAfterShutdown равно 1, и WLX_SAS_ACTION_SHUTDOWN, если это значение равно 0, после чего компьютер выключится. Если сделать ShutdownWithoutLogon равным 0, кнопка Shutdown становится недоступной.

Кроме того, в параметрах реестра DefaultUserName и DefaultDomainName находятся строковые данные, которые можно показать в соответствующих полях ввода. Это несколько ускорит процесс регистрации, но и уменьшит степень защищенности рабочей станции.

Хранители экрана

Я немного рассказал о работе с хранителями экрана, когда рассматривал диалоги в GINA DLL. Но на этом разговор не закончен. Когда мы в течение определенного времени отвлекаемся от любимого занятия, а именно — терзания клавиатуры и беспорядочных перемещений манипулятора «мышь», загружается процесс хранителя экрана. Это происходит при заданных настройках Windows. И в случае, если установлен флаг защиты хранителя экрана паролем, GINA получает сообщение о начале его работы. Winlogon вызывает необязательную для реализации функцию

BOOL WlxScreenSaverNotify( PVOID
 pWlxContext,BOOL *pSecure ).

Я уже упоминал о том, что для необязательных функций выполняется код по умолчанию. Для этой функции код по умолчанию, взятый из MSDN, приведен в Листинге 9. Вообще говоря, проверка параметра *pSecure необязательна, так как эта функция вызывается только в том случае, если хранитель экрана защищен паролем. Но инженеры Microsoft считают, что делать надо так. Этот параметр возвращает TRUE, если после переключения на программу хранителя экрана требуется запрашивать пароль, и FALSE — в противном случае. Функция WlxScreenSaverNotify возвращает TRUE, если хранитель экрана надо загружать, и FALSE — если нет. Если хранитель экрана задействован, то процесс хранителя экрана запускается на отдельном рабочем столе и продолжается до тех пор, пока пользователь не начинает использовать устройства ввода. После чего станция переключается на рабочий стол Winlogon и вызывается функция WlxDisplay LockedNotice. Сценарий ее работы я рассматриваю ниже.

Замечу, что в демонстрационном примере я не стал реализовывать функцию WlxScreenSaverNotify.

Обработчик SAS для незаблокированной рабочей станции

Если в ходе работы пользователь нажимает Ctrl-Alt-Del, Winlogon переключает рабочий стол на стол Winlogon и вызывает функцию WlxLoggedOnSAS, обязательную для реализации в GINA DLL. Внутри этой функции создается диалог, в котором пользователь может выбрать какое-нибудь действие. Для вызова стандартного менеджера задач, завершения сеанса, блокировки или выключения компьютера функция должна вернуть соответствующие значения: WLX_SAS_ACTION_TASKLIST, WLX_SAS_ACTION_LOGOFF, WLX_SAS_ACTION_LOCK_WKSTA и WLX_SAS_ACTION_SHUT DOWN_POWER_OFF. Но некоторые функции можно реализовать внутри GINA DLL, например смену пароля.

Смена пароля

Смена пароля в GINA происходит внутри функции WlxLoggedOnSAS. Для изменения пароля используется функция NetUserChangePassword(). Первые два параметра этой функции — имя пользователя и домен. Для их получения я использую маркер, сохраненный при регистрации пользователя. Как это делается, показано в Листинге 10. Для получения SID пользователя по маркеру я написал дополнительную функцию GetTokenUserInfo, показанную в Листинге 11.

Ещк два параметра — старый и новый пароль — вводятся пользователем в соответствующее диалоговое окно. После успешной смены пароля функция WlxLoggedOnSAS должна вернуть Winlogon значение WLX_SAS_ACTION_PWD_CHANGED, извещающее сетевых провайдеров о смене пароля.

Разблокировка рабочей станции

Для разблокировки рабочей станции Winlogon вызывает необходимую в реализации GINA DLL функцию WlxWkstaLockedSAS. Поставляемая с операционной системой библиотека GINA предоставляет стандартный сценарий разблокирования рабочей станции. Это может сделать либо пользователь, который ее заблокировал, либо член локальной группы администраторов. Во втором случае происходит завершение текущего сеанса. Конечно, в собственной реализации модуля можно избрать какой-нибудь другой сценарий. Например, разрешать разблокировку только зарегистрированному пользователю. Но здесь мы рассмотрим вариант, предлагаемый компанией Microsoft.

Итак, в первую очередь мы должны предоставить пользователю возможность ввести свои идентификационные данные. Это делается тем же способом, который использовался при регистрации пользователя. Только одно отличие: в функции LsaLogonUser для параметра SECURITY_LOGON_TYPE используется значение Unlock. После этого вызова мы получаем маркер.

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

Теперь нам нужно только получить для этого маркера и для маркера, сохраненного после регистрации, SID пользователя и сравнить их. Если значения SID совпадут, значит, пользователь тот же, и рабочую станцию можно разблокировать. Для этого достаточно вернуть значение WLX_SAS_ACTION_UNLOCK_WKSTA из функции WlxWkstaLockedSAS (см. Листинг 12).

Если SID не совпадут, нам нужно проверить, не входит ли пользователь, который пытается разблокировать станцию, в группу администраторов. Код функции, осуществляющей эту проверку, приведен в Листинге 13. В случае если проверка завершилась успешно, нам остается вернуть значение WLX_SAS_ACTION_FORCE_LOGOFF, возможно, поинтересовавшись у пользователя, уверен ли он в необходимости завершения сеанса.

Александр Эпштейн — независимый разработчик и консультант по проблемам низкоуровневого программирования; руководил департаментами разработки программного обеспечения в нескольких крупных российских компаниях. С ним можно связаться по адресу: alex_ep@hotmail.com.


Литература

[1] David A. Solomon, Mark E. Russinovich Insude for Microsoft Windows 2000, Third Edition Microsoft Press (Дэвид Соломон, Марк Русинович «Внутреннее устройство Microsoft Windows 2000». — Русская редакция, 2001)

[2] Sven B. Schreiber Undocumented Windows 2000 secrets. A programming cookbook. Addison-Wesley 2001

[3] Keith Brown Handle Logons in Windows NT and Windows 2000 with Your Own Logon Session Broker


Листинг 1. Проверка версии WinLogon.
BOOL WINAPI WlxNegotiate( DWORD
 dwWinLogonVersion,PDWORD pdwDllVersion )
{
	if( dwWinLogonVersion < WLX_VERSION_1_3 )
	 return FALSE;
	else
	{
		*pdwDllVersion = WLX_VERSION_1_3;
		return TRUE;
	}
} 

Листинг 3. Используемая в данной реализации GINA структура контекста.
typedef struct _tagGINA_CONTEXT
{
	HANDLE			   hWlx;
	LPWSTR			   wszStation;
	PWLX_DISPATCH_VERSION_1_3  pWlxFuncs;
	HANDLE			   hDllInstance;
	HANDLE			   hUserToken;
	SID			   sid;
	HWND			   hWndOwner;
} GINA_CONTEXT, *LPGINA_CONTEXT, *PGINA_CONTEXT;

Листинг 6. Обработка сообщений о тайм-аутах.
case WLX_SAS_TYPE_TIMEOUT:
EndDialog( hWnd,WLX_DLG_INPUT_TIMEOUT );
	nRet = TRUE;
	break;
case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
	EndDialog( hWnd,WLX_DLG_SCREEN_SAVER_
TIMEOUT );
	nRet = TRUE;
	break;
Листинг 5. Возвращаемые значения.
case WLX_SAS_TYPE_TIMEOUT:
case WLX_SAS_TYPE_SCRNSVR_TIMEOUT:
	nRet = wParam; 
	break;

Листинг 9. Код по умолчанию, который обрабатывается обработчиком сообщения от хранителя экрана.
BOOL DefaultScreenSaverNotify( PVOID pWlxContext,
 BOOL *pSecure)
{
	if (*pSecure)
	{
		*pSecure = WlxIsLockOk
(pWlxContext);
	}
	return(TRUE);
}