p>
Перший заголовки зберігає в собі прототип
WLX_NOTIFICATION_INFO. А другий стане в нагоді в процесі створення логів. P>
У нас вже є функція DllMain, люб'язно
надана візард. Залишимо її без змін. Напишемо функцію створення
логів. Оскільки структура WLX_NOTIFICATION_INFO містить в собі Юнікод-рядки,
буде зручно виводити дані в текстовий файл типу Юнікод. p>
void WriteLog (PWSTR pStrEventName, p>
PWLX_NOTIFICATION_INFO
pInfo) p>
( p>
// Перший параметр функції WriteLog буде p>
// містити опис події, p>
// а друге - самі дані. p>
// Задаємо назва log-файлу p>
WCHAR fName [] = L "C: log.txt"; p>
WCHAR buf [1024]; p>
// Готуємо рядок для логів. Варто зазначити
що якби p>
// було оголошено макрос STRICT, висновок
hDesktop p>
// необхідно було б робити по іншому. p>
swprintf (buf, L "Event:% s, User:% s,
Domain:% s, " p>
L "Window station:% s,
User token 0x% p, " p>
L "Desktop
0x% prn ", pStrEventName, p>
pInfo-> UserName,
pInfo-> Domain, pInfo-> WindowStation, p>
pInfo-> hToken,
pInfo-> hDesktop); p>
// Відкриваємо log-файл для запису. p>
HANDLE hFile =
CreateFileW (fName, GENERIC_WRITE, p>
FILE_SHARE_READ, NULL,
OPEN_EXISTING, p>
FILE_ATTRIBUTE_NORMAL,
NULL); p>
DWORD dwWritten; p>
// Якщо такого файлу немає, або сталася якась інша p>
// помилка, пробуємо створити новий файл. p>
if (hFile == INVALID_HANDLE_VALUE) p>
( p>
hFile = CreateFileW (fName,
GENERIC_WRITE, p>
FILE_SHARE_READ, NULL,
CREATE_NEW, p>
FILE_ATTRIBUTE_NORMAL,
NULL); p>
if (hFile ==
INVALID_HANDLE_VALUE) p>
( p>
// Якщо файл не створився, повідомляємо
користувачеві p>
// системним звуком про виникнення
помилки. p>
:: MessageBeep (MB_ICONASTERISK); p>
return; p>
) p>
WCHAR data = 0xFEFF; p>
// Зазначаємо, що створений файл буде p>
// включати текст типу Юнікод. p>
if (! WriteFile (hFile, & data,
sizeof (data), p>
& dwWritten, NULL)) p>
:: MessageBeep (MB_ICONASTERISK); p>
) p>
// Оскільки відкритий файл може бути не
порожнім, p>
// переходимо в його кінець p>
if (SetFilePointer (hFile, 0,
NULL, FILE_END) == p>
INVALID_SET_FILE_POINTER) p>
( p>
:: MessageBeep (MB_ICONASTERISK); p>
return; p>
) p>
// Записуємо рядок логу в файл p>
if (! WriteFile (hFile, buf, wcslen (buf) *
sizeof (WCHAR), p>
& dwWritten, NULL)) p>
:: MessageBeep (MB_ICONASTERISK); p>
// Закінчуємо роботу з файлом p>
CloseHandle (hFile); p>
) p>
Тепер залишилося написати функції-обробники подій.
Заради зручності назвемо їх так само, як показано в таблиці 1. P>
extern "C" void __stdcall p>
WLEventLogon (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "user
logon ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventLogoff (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "user
logoff ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventStartup (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "system
startup ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventShutdown (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "system
shutdown ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventStartScreenSaver (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "screen saver
started ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventStopScreenSaver (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "screen saver
stopped ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventLock (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "Workstation
locked ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventUnlock (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "Workstation
unlocked ", pInfo); p>
) p>
extern "C" void __stdcall p>
WLEventStartShell (PWLX_NOTIFICATION_INFO pInfo) p>
( p>
WriteLog (L "User already
loged on and network " p>
L "resouces are
avaliable ", pInfo); p>
) p>
Тепер необхідно експортувати ці функції для
інших програм. Для цього створимо файл Notify.def і додамо його в проект. У
єдиною секції EXPORTS вкажемо експортовані функції p>
EXPORTS p>
WLEventLogon p>
WLEventLogoff p>
WLEventStartup p>
WLEventShutdown p>
WLEventStartScreenSaver p>
WLEventStopScreenSaver p>
WLEventLock p>
WLEventUnlock p>
WLEventStartShell p>
Після успішної компіляції необхідно підписатися на
події Winlogon. p>
ПОПЕРЕДЖЕННЯ p>
Необхідно пам'ятати, що dll виповнюється
в адресному просторі процесу, який її викликає. Якщо dll спровокує
виняткову ситуацію, тоді, якщо не обробити помилку, робота процесу
буде припинено. Процес Winlogon.exe дуже чутливий до таких речей. При
виникненні помилки він покаже синій екран смерті, а в разі наявності
відповідних установок перевантажить систему. Тому наполегливо рекомендується
тестувати програму на віртуальному комп'ютері. p>
Для цього зайдемо до реєстру і знайдемо ключ: p>
HKEY_LOCAL_MACHINESoftwareMicrosoftWindows
NTCurrentVersionWinlogonNotify p>
Створимо в ньому з'єднання MyNotify і значення, як
показано на малюнку нижче. p>
p>
Малюнок 1. p>
Для зручності помістимо файл Notify.dll за вказаною
шляху. Після перезавантаження системи додаток почне створювати логи. P>
ПРИМІТКА p>
Якщо логи не створюються, перевірте, чи не
чи використовується Notify.dll іншим процесом (якщо файл не вдається
перейменувати - значить, хтось його використовує). Якщо Notify.dll використовується,
а логів ні, швидше за все, неправильно задано одне з значень у назвах
функцій-обробників, або такі функції не експортуються динамічної
бібліотекою. Якщо Notify.dll не використовується, перевірте, чи правильно задано
ключ DllName з назвою бібліотеки. Можливо, бібліотека не зареєстрована
в системі, або не може бути завантажена. p>
Висновок
h2>
Winlogon notification package може стати в нагоді в
зовсім несподіваних місцях. Наприклад, якщо із системної служби необхідно
отримати імена користувачів, що працюють в системі. Усе, що потрібно - це
написати і зареєструвати в системі dll, яка за запитом передасть дані в
службу (або сама буде передавати ці дані у відповідь на деякі потрібні
події). p>
Сподіваюся, що ця стаття розширить знання читача про
інтерфейсах Winlogon, а також допоможе використовувати отримані знання на
практиці. p>
Список літератури h2>
Для підготовки даної роботи були використані
матеріали з сайту http://www.rsdn.ru/
p>