Программирование служб: подробности. Реферат. Информатика, ВТ, телекоммуникации.

💣 👉🏻👉🏻👉🏻 ВСЯ ИНФОРМАЦИЯ ДОСТУПНА ЗДЕСЬ ЖМИТЕ 👈🏻👈🏻👈🏻
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!
Похожие работы на - Программирование служб: подробности
Скачать Скачать документ
Информация о работе Информация о работе
Скачать Скачать документ
Информация о работе Информация о работе
Скачать Скачать документ
Информация о работе Информация о работе
Скачать Скачать документ
Информация о работе Информация о работе
Скачать Скачать документ
Информация о работе Информация о работе
Скачать Скачать документ
Информация о работе Информация о работе
Нужна качественная работа без плагиата?
Не нашел материал для своей работы?
Поможем написать качественную работу Без плагиата!
Программирование служб: подробности
И на первый взгляд как будто не видна
В статье описаны некоторые детали, относящиеся к
программированию служб Windows NT/2000/XP. Она не претендует на полноту или
уникальность. Кое-что не охвачено, многое (хотя и не всё) из охваченного вы
сможете найти в MSDN или другой литературе. Если вы написали свою первую службу
и хотите двигаться дальше, эта статья вам поможет.
Для понимания написанного ниже вы должны быть знакомы
со службами. Глубоких знаний не потребуется, достаточно представлять себе
архитектуру службы (с точки зрения программиста) и помнить примерное
предназначение нескольких API-функций.
Большая часть содержащихся в статье утверждений
описывает реакцию Windows на какие-то действия со стороны службы. Полноценная
проверка таких утверждений не представляется возможной. Тем более что некоторые
из них не документированы.
В Windows 2000 Server SP1 я постарался проверить всё.
В других версиях только кое-что. Возможно, некоторые полученные факты я
истолковал неверно. Но пока что ошибок я не нашёл.
Если утверждение есть в MSDN и/или другом источнике, я
проверял его два-три раза, если всё сходилось, считал его верным.
Если утверждение противоречит тому, что написано в
MSDN и/или других источниках, продолжительность тестирования зависела от его
важности (с моей точки зрения). В этом случае в статье указаны и мои
результаты, и информация из MSDN или других источников. Если я считаю
утверждение важным, кроме этого указано, какие моменты могли быть упущены во
время тестирования. Эта версия статьи не содержит важных спорных утверждений.
Если утверждение не встретилось мне ни в одном
источнике, я поступал аналогично предыдущему пункту.
В этой части статьи разобраны вопросы, имеющие
непосредственное отношение к любой службе. Разделение на «непосредственные» и
«косвенные» условно и субъективно. Принцип, которого я придерживался, таков:
если проблема/возможность свойственна службам из-за особенностей их
архитектуры, она описана в этой части. Иначе – в следующей.
Работа с любой программой начинается с установки и
заканчивается удалением. Службы – не исключение. Отличие состоит в том, что при
установке службу необходимо зарегистрировать. Можно, конечно, возложить эту
задачу на инсталлятор, но, по-моему, правильней и проще писать службы, умеющие
устанавливаться/удаляться в полуавтоматическом режиме.
На всякий случай: некоторые умные люди,
которые знают, как правильно писать инсталляторы, считают, что в этом вопросе
я заблуждаюсь.
int _tmain(int
argc, TCHAR* argv[])
// Если в командной строке
что-то есть -
// предположительно,
запускает пользователь.
// lstricmp - сравнение
без учёта регистра.
if (lstrcmpi(argv[1],
TEXT("/install"))==0)
else if
(lstrcmpi(argv[1], TEXT("/uninstall"))==0)
TEXT() и _tmain – для
поддержки Unicode (а можно сказать «для поддержки ANSI»). Подробнее в разделе
«Unicode».
CmdLine – пространство
имён. Я их нежно люблю и часто использую.
Вообще-то, то, что в
командной строке «что-то есть» ничего не доказывает, см. «Мелочи».
Функции, выполняющие собственно установку/удаление,
выглядят примерно так:
На некоторых этапах выполнения служба должна выполнить
определённые действия за определённый срок. В MSDN с разной степенью
конкретности перечислены пять требований. В книге Джеффри Рихтера и Джейсона
Кларка «Программирование серверных приложений в Windows 2000» приведено шестое.
Ниже перечислены сами требования и мои комментарии к ним.
Служба должна вызвать StartServiceCtrlDispatcher не
позже, чем через 30 секунд после начала работы, иначе выполнение службы
завершится. Практика подтвердила. Кроме того, в раздел Event Log’а System будет
добавлена запись об ошибке (источник – «Service Control Manager»). Если служба
запускается вручную из программы Services, пользователь получит сообщение
(MessageBox).
Функция ServiceMain должна вызвать
RegisterServiceCtrlHandler[Ex] немедленно. Что будет в противном случае – не
указано. Несоблюдение этого правила – один из случаев «нарушений во время
инициализации» (термин мой), описанных ниже в этом же разделе.
Функция ServiceMain должна вызвать SetServiceStatus
первый раз «почти сразу» после RegisterServiceCtrlHandler[Ex], после чего
служба должна продолжать вызывать её до тех пор, пока инициализация не
закончится. Неправильное использование SetServiceStatus – второй случай
«нарушений во время инициализации».
При обработке сообщения служба должна вернуть
управление из функции Handler[Ex] в течение 30 секунд, иначе SCM сгенерирует
ошибку. Практика подтверждает, запись в Event Log добавляется. Но никаких
репрессивных действий по отношению к службе я не дождался.
При получении сообщения SERVICE_CONTROL_SHUTDOWN
служба должна закончить работу за время, не превышающее число миллисекунд,
указанное в параметре WaitToKillServiceTimeout ключа
HKLM\System\CurrentControlSet\Control, иначе будет завершена принудительно.
Практика подтвердила.
После завершения работы в качестве службы (то есть
после посылки службой уведомления об этом) процессу даётся 20 секунд на
очистку/сохранение/ещё что-то, после этого процесс завершается. Подробнее в
разделе «Корректное завершение».
Если ваша служба быстро инициализируется и мгновенно
обрабатывает сообщения, в результате чего автоматически удовлетворяет всем
пунктам, вам повезло. Если нет, можно использовать несколько потоков. Например,
так:
Дополнительный поток выполняет необходимую
инициализацию, а основной поток вызывает StartServiceCtrlDispatcher.
Один из потоков посылает уведомления о продвижении
процесса, второй выполняет инициализацию. Функция первого потока может быть
такой:
DWORD WINAPI
SendPending(LPVOID dwState)
sStatus.dwCurrentState
= (DWORD) dwState;
if
(WaitForSingleObject(eSendPending, 1000)!=WAIT_TIMEOUT) break;
SetServiceStatus(ssHandle,
&sStatus);
Уведомления посылаются с помощью функции
SetServiceStatus. sStatus – глобальная переменная типа SERVICE_STATUS,
описывающая состояние службы, в dwState передаётся состояние, о котором
необходимо сообщать, eSendPending – событие, установка которого означает
окончание работы этого потока.
Забавно, что при таком подходе для служб, запускаемых
вручную, видимый результат не меняется (см. ниже о нарушениях во время
инициализации).
Идея в том, что, если обработка сообщения может
затянуться, функция Handler[Ex] инициирует её и завершается, не дожидаясь
окончания. Если рабочий поток службы в цикле ожидает каких-то событий,
обработку может выполнить он, Handler[Ex] должна только проинформировать его о
приходе сообщения, если рабочий поток постоянно занят, можно породить ещё один
поток. При подобной реализации необходимо учесть, что следующее сообщение может
прийти в течение обработки предыдущего, то есть до того, как служба пошлёт
уведомление об окончании обработки. С помощью Services этого не сделать, но
пользователь может использовать утилиту Net.exe (синтаксис запуска: net команда
имя_службы) или написать свою.
Ограничения, накладываемые требованиями (5) и (6)
обойти не удаётся. Но, в отличие от (5), в (6) момент посылки уведомления о
завершении регулируете вы. Поэтому можно выполнять всю необходимую
очистку/сохранение/ещё что-то заранее.
Теперь о «нарушениях в процессе инициализации».
Варианты нарушений:
Задержка перед вызовом RegisterServiceCtrlHandler[Ex].
Задержка перед первым вызовом SetServiceStatus.
Слишком большие паузы между вызовами SetServiceStatus.
Не меняется поле dwCheckPoint структуры, передаваемой
SetServiceStatus.
Во всех перечисленных случаях реакция системы будет
одинаковой. А именно:
A) Служба запускается автоматически.
Минуты через две (если за это время «нарушение» не
прекратится и служба не начнёт работать нормально) в Event Log-е появится
запись «The ... service hung on starting.»
Если хоть одна служба
«повисла», пользователь получит сообщение «At least one service or driver failed
during system startup. Use Event Viewer to examine the event log for details.» Такое ощущение, что это сообщение появляется в тот
момент, когда запускается первая «зависшая» служба (сам понимаю, что звучит
нелогично, но что делать...).
B) Служба запускается вручную из Services.
В программе Services в столбце Status служба будет
помечена словом «Starting».
В любом случае служба, в конце концов, запустится.
Эта информация не очень важна (и, кстати, не
документирована), так как даже таких нарушений лучше не допускать. Но
представлять, что будет, если по каким-то причинам, ваша служба слегка
притормозит, полезно.
Этот вопрос возник у меня, когда я писал свою первую
службу. Если чётче сформулировать, то звучит он так: который из потоков можно
использовать в качестве рабочего? На первый взгляд задействовано три потока:
один исполняет main/WinMain, второй – ServiceMain, третий – Handler[Ex] (не
совсем так, см. «Мелочи»). Очевидно, что первый и третий потоки не подходят.
Про второй поток ничего не известно и, вполне возможно, функция ServiceMain
должна возвращать управление. Я поступил просто: создал в ServiceMain
дополнительный поток, который выполнял работу. Окончание функции выглядело так:
// Создаёт рабочий поток и возвращает
управление
Это работает. Никаких дополнительных проблем при таком
подходе не обнаружено.
После внимательного прочтения MSDN выяснилось, что
вообще-то для работы предназначен поток, выполняющий ServiceMain. Более того, в описании написано: «A ServiceMain function does not return
until its services are ready to terminate.» Возвращать
управление из ServiceMain сразу рекомендуется только службам, не нуждающимся в
потоке для выполнения работы (например, вся работа может заключаться в реакции
на сообщения). Я советую следовать рекомендациям Microsoft.
Если ваша служба успешно выполнила свою миссию или,
наоборот, окончательно провалилась (неважно, во время выполнения или
инициализации), её нужно завершить. Несколько вариантов того, «как делать не
надо»:
Завершить все рабочие потоки, поток, выполняющий
Handler[Ex] не трогать. В этом случае SCM «ничего не заметит» и служба
продолжит выполняться. Это не смертельно, но и не очень хорошо, так как
ресурсы-то используются.
Завершить все рабочие потоки, поток, выполняющий
Handler[Ex] завершить вызовом ExitThread при обработке первого следующего
сообщения. SCM генерирует ошибку и добавляет запись о ней в Event Log.
Завершить процесс вызовом ExitProcess. Результат
аналогичен предыдущему, даже ошибка такая же. Странно, что код завершения
процесса не сохраняется.
А теперь о том, как надо. Об окончании работы служба
должна сообщить. Как обычно, для сообщения об изменении состояния используется
функция SetServiceStatus. В данном случае из всех полей передаваемой в неё
структуры SERVICE_STATUS интерес представляют dwCurrentState, dwWin32ExitCode и
dwServiceSpecificExitCode. dwCurrentState в любом случае должно быть
установлено в SERVICE_STOPPED, значения остальных зависят от ситуации.
Служба завершилась успешно. dwWin32ExitCode =
NO_ERROR, в Event Log ничего записано не будет.
Произошла неисправимая ошибка, и это одна из
стандартных ошибок Windows. dwWin32ExitCode = ERROR_..., в Event Log будет
добавлена запись, описывающая ошибку, числовое значение ошибки указано не
будет.
Произошла неисправимая ошибка, специфичная для вашей
службы. dwWin32ExitCode = ERROR_SERVICE_SPECIFIC_ERROR, в
dwServiceSpecificExitCode код ошибки. Так как систему кодирования ошибок вы
придумали сами, расшифровать значение кода можете тоже только вы. В Event Log будет добавлена запись следующего содержания: «The ... service terminated with service-specific error ...» (в местах многоточий – имя службы и код ошибки).
Если для завершения службы необходимо выполнить
продолжительные действия, в процессе их выполнения имеет смысл посылать
уведомления SERVICE_STOP_PENDING. Но это не обязательно.
Ещё один тонкий момент: что будет с вашей службой
после вызова SetServiceStatus? Все потоки прекратят исполняться сразу и
окончательно, или им дадут «умереть естественной смертью»? Я попытался выяснить
это, и получил следующее (это верно для любых вариантов завершения службы, при
которых вызывается SetServiceStatus с соответствующими параметрами, кроме
случая с SERVICE_CONTROL_SHUTDOWN):
Если exe-файл содержит несколько служб и хоть одна из
них (не считая завершающейся) запущена, ничего интересного не произойдёт. То
есть, ни процесс, ни один из потоков не будут завершены насильно.
После завершения последней службы функция
ServiceControlDispatcher возвращает управление в main/WinMain. Если
main/WinMain самостоятельно заканчивается в течение 20-ти секунд, то, как и у
нормального приложения, выполняется функция ExitProcess() и завершаются все
потоки.
Так как ServiceControlDispatcher
возвращает управление в main/WinMain сразу после вызова SetServiceStatus,
main/WinMain может вызвать ExitProcess раньше, чем ваш рабочий поток (или
потоки, если у вас их несколько) закончат выполнение. В результате, например,
могут оказаться невызванными деструкторы стековых объектов. Чтобы избежать
этого можно поступить так:
- получить описатель рабочего потока
(например, с помошью DuplicateHandle) и сохранить его в глобальной переменной
- в main/WinMain дождаться завершения
рабочего потока
Другие (но тоже печальные) возможные
последствия преждевременного вызова ExitProcess описаны в MSDN в Q201349:
"PRB: ServiceMain thread May Get Terminated in DllMain() when a Service
Process Exits Normally".
Большое спасибо Dima2 за это замечание.
Через 20 секунд после завершения последней службы
процесс уничтожается.
В один exe-файл можно поместить несколько служб.
Название раздела характеризует моё отношение к таким проектным решениям. Это
затрудняет кодирование и отладку, а единственный известный мне выигрыш –
экономия ресурсов на компьютере пользователя (если вы пишете несколько
зависимых друг от друга служб, наверное, появляются и другие выигрыши; я этим
ни разу не занимался). Но, тем не менее, на моей машине в service.exe находятся
службы Alerter, AppMgmt, Browser, Dhcp, dmserver, Dnscache, Eventlog,
lanmanserver, lanmanworkstation, LmHosts, Messenger, PlugPlay,
ProtectedStorage, seclogon, TrkWks, W32Time и Wmi. Вряд ли их писали люди
глупее меня.
Интерактивности в службах следует избегать. Службы
предназначены для непрерывной работы в отсутствии пользователей, поэтому
дожидаться, пока оператор нажмёт «OK», можно очень долго. Но, тем не менее,
возможности есть.
Учтите, что все описанные в этом
разделе методы (а о существовании других я не слышал) позволяют
взаимодействовать только с консольной сессией (службы запускаются в
консольной сессии, так как в ней запускается SCM). Поэтому интерактивная (в
широком смысле этого слова) служба будет некорректно работать в Windows
NT/2000 Terminal Service и, что гораздо более важно, в Windows XP при
использовании возможности Fast User Switching. То есть, всё будет корректно,
но, возможно, не совсем так, как вы ожидали. Рекомендую почитать про Terminal
Service (это круто!) и никогда не использовать интерактивность в службах.
Самое простое – отобразить сообщение (MessageBox). Это
может любая служба, какие бы флаги не стояли. Для этого нужно в функцию
MessageBox[Ex] помимо прочих флагов передать MB_SERVICE_NOTIFICATION или
MB_DEFAULT_DESKTOP_ONLY. Первый флаг заставит функцию вывести сообщение на
экран, даже если пользователь ещё не вошёл в систему. Выглядит забавно.
Представьте: на экране приглашение ввести пароль и десяток сообщений,
поздравляющих пользователя с 1 апреля. Но для этого придётся написать десять
служб, так как процесс не может отображать на экране несколько таких сообщений
одновременно, судя по всему, они ставятся в очередь (к MB_DEFAULT_DESKTOP_ONLY
это тоже относится). Если установлен второй флаг, сообщение появится только на
«нормальном» рабочем столе. Более строго, MB_SERVICE_NOTIFICATION заставляет
сообщение появиться на текущем активном desktop-е, а MB_DEFAULT_DESKTOP_ONLY
только на «нормальном». Этими флагами можно пользоваться, если определен макрос
_WIN32_WINNT и его значение больше или равно 0x0400.
Для реализации этой
возможности привлечены неслабые средства. В Spy++ видно, что окна
(MessageBox) принадлежат одному из потоков CSRSS.EXE. Это имеет забавный
побочный эффект: сообщение может висеть на экране даже после завершения
приложения. Соберите и запустите такую программку:
int WINAPI
WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
MessageBox(NULL,
"try to kill me", "undead", MB_SERVICE_NOTIFICATION);
А теперь попробуйте убить
процесс из Task Manager’а. Если сделать несколько потоков, можно проверить
ExitProcess, она в этой ситуации тоже не помогает.
Если пользовательский интерфейс вашей службы должен
быть богаче, существует два выхода. В первом случае должны выполняться
следующие условия:
Служба запущена в контексте безопасности LocalSystem.
Служба должна быть помечена как интерактивная.
Значение параметра NoInteractiveServices ключа
HKLM\SYSTEM\CurrentControlSet\ Control\Windows\ должно быть равно 0.
Если всё это так, служба может выводить на экран что
угодно. Иначе, служба может попробовать самостоятельно открыть и использовать
нужный ей desktop. Подобнее об объектах «desktop» и «window station» смотрите в
MSDN.
Ниже рассмотрены вопросы, имеющие косвенное отношение
к службам, но прямое к их программированию. То есть, при разработке вашей
конкретной службы всё это может вам и не понадобиться, но вообще разбираться в
этом надо. Большинство тем имеют отношение не только к службам, но и к обычным
приложениям. Рассмотрение не очень подробно, но введение дано (кроме вопроса о
системе безопасности).
Есть несколько причин, по которым отлаживать службы
сложнее, чем обычные приложения.
В службе будет как минимум два потока.
Если в exe-файле несколько служб, отладка будет ещё
неприятнее.
Однако чаще всего удаётся написать приложение,
полностью воспроизводящее рабочую часть службы, отладить его и поместить в
обёртку из некоторого стандартного кода, превращающего его в службу. Если ядро
приложения отлажено, и код, реализующий стандартные функции службы, проверен,
при стыковке больших проблем быть не должно. Но (как это ни странно) появляются
средние и мелкие. Помимо «отладки без отладчика» остаётся следующее.
Присоединить отладчик к запущенной службе.
В HKLM\SOFTWARE\Microsoft\Windows
NT\CurrentVersion\Image File Execution Options добавить ключ
«имя_исполяемого_файла.exe» (без пути), в нём создать строковый параметр
Debugger и записать в него полное имя отладчика. При запуске указанного файла,
он будет запущен под отладчиком.
При отладке кода запуска следует помнить, что
ограничение на время (30 секунд) никуда не исчезает, если вы не уложитесь,
служба завершится.
Обычно у службы есть какие-то параметры, которые можно
настраивать. Иногда нужно иметь возможность определять и корректировать текущее
состояние службы.
Изменение состояния и изменение
параметров – это не одно и то же. Например, вы написали какую-то сетевую
службу. Если есть возможность изменять состояние, администратор может,
просмотрев список текущих соединений, какие-то из них разорвать. Изменением
параметров этого не достигнуть.
Остановимся на случае не интерактивной службы, так как
в интерактивной службе проблему можно решить так же, как и в обычном
приложении.
Для администрирования пишется отдельное приложение
(далее – конфигуратор), которое каким-то образом взаимодействует со службой.
Могу предложить следующие варианты:
Параметры хранятся в реестре (обычно в
HKLM\System\CurrentControlSet\Services\имя_службы\Parameters\). Конфигуратор их
изменяет, служба, используя функцию RegNotifyChangeKeyValue, отслеживает эти
изменения.
Параметры хранятся где угодно. После их изменения
конфигуратор посылает службе сообщение. Для этого нужно открыть службу функцией
OpenService с правом доступа SERVICE_USER_DEFINED_CONTROL и послать сообщение
функцией ControlService. Конечно, в службе необходимо предусмотреть
соответствующую обработку.
Используются именованные каналы, сокеты, DCOM или
любое другое средство коммуникации между процессами. В этом случае помимо
передачи параметров можно получать и изменять состояние службы.
Самый простой вариант – служба реагирует на изменение
параметров только после перезапуска.
Это очень большая тема, про которую я очень мало знаю.
Но она имеет прямое отношение к службам, если вы хотите заниматься их
разработкой, вам (и мне, естественно) придется с ней разобраться.
Интерактивность – это нехорошо. Но служба должна
каким-то образом сообщать администратору об ошибках и других важных событиях.
Службам, генерирующим несколько десятков (или больше) сообщений в день,
целесообразно использовать для этого файлы в формате какой-нибудь СУБД. Для
остальных лучшее решение – Event Log. Он достаточно гибок, стандартен,
администратор может просмотреть его утилитой Event Viewer.
Event Log может использоваться любым
приложением. Поскольку статья посвящена службам, я использую слово «служба».
Возможности Event Log-а не
исчерпываются тем, что описано в этом разделе, но обычно ничего большего и не
требуется. Если вам нужно больше, советую обратиться к уже упоминавшейся
книге Джеффри Рихтера и Джейсона Кларка «Программирование серверных приложений
в Windows 2000» или к MSDN.
Если вы хотите записать сообщение в Event Log, нужно:
создать файл сообщений (при разработке службы);
зарегистрировать в реестре новый источник сообщений
(при инсталляции);
Файл сообщений – это exe- или dll-файл, содержащий
ресурс «таблица сообщений». Для получения нужно скомпилировать message
compiler’ом (mc.exe) правильно написанный текстовый файл (ниже), получившийся
файл ресурсов включить в проект и скомпоновать. Mc.exe не интегрирован в Visual
Studio и запускается из командной строки. Ключами можно не пользоваться,
достаточно написать «mc filename.mc». На выходе будет filename.h, filename.rc,
filenameXXXX.bin (в некоторых случаях несколько штук). filename.rc – тот самый
файл ресурсов, он ссылается на filenameXXXX.bin. filename.h содержит
идентификаторы сообщений и используется службой.
«Правильно написанный текстовый файл» имеет следующую
структуру:
Заголовок необязателен, он может отсутствовать или
присутствовать частично. Обычно используется только поле LanguageNames.
Синтаксис несложен:
LanguageNames =
(обозначение_для_языка_1 = LangID_1 : имя_bin_файла_1)
LanguageNames =
(обозначение_для_языка_n = LangID_n : имя_bin_файла_n)
«обозначение_для_языка» и «имя_bin_файла» могут быть
произвольными, таблица LangID есть в MSDN (смотрите GetLocalInfo()).
Смысл этого поля – перечисление поддерживаемых языков.
Если файл сообщений поддерживает несколько языков, в разных локализациях
Windows (русской, английской, ...) Event Log будет отображать разные версии
сообщений.
Hi! I hack you!
You login: %1, you password: %2.
Привет! Я тебя взломал!
Твой логин: %1, твой пароль: %2.
Поля «MessageId», «Severity», «Facility» и
«SymbolicName» составляют заголовок сообщения.
Идентификатор сообщения. Не
обязателен, в случае отсутствия инкрементируется MessageId предыдущего
сообщения (для первого сообщения MessageId – 0).
Тип сообщения, определены
типы «Success», «Informational», «Warning», и «Error», их названия можно
переопределить в заголовке, но на название типа и иконку, отображаемые Event
Viewer’ом, это не повлияет. Не обязательно, в случае отсутствия наследуется
от предыдущего сообщения, по умолчанию – значение «Success».
Позволяет задать категорию
сообщения. Определены значения «System» и «Application», можно определить (в
заголовке файла) ещё около четырёх тысяч. Не обязательно, в случае отсутствия
наследуется от предыдущего сообщения, первое сообщение по умолчанию имеет
значение «Application».
Имя соответствующего
сообщению макроса в генерируемом h-файле.
Тело сообщения начинается после строки «Language =
XXXX» и заканчивается строкой, не содержащей ничего, кроме точки и перевода
строки. На каждый определённый в заголовке язык должно быть по одному «телу»
(если вы не определили ни одного языка, используйте «English»). Вместо «%1» ...
«%99» будут вставлены строки, которые приложение передаст при записи сообщения.
Учтите, что этот механизм предназначен для передачи имён файлов, IP-адресов,
каких-то чисел и т.д. Но не для передачи текста. Можно, конечно, сделать так:
но, с моей точки зрения, это плохая идея. Дело в том,
что в файлах Event Log-а хранится имя источника, номер сообщения, переданные
строки и прикреплённые данные, но не сам текст. Поэтому, если записать
сообщение, а потом изменить dll или значение параметра EventMessageFile в
реестре, текст изменится. Насколько я знаю, это нужно, чтобы, когда
пользователь из Китая, у которого всё на китайском, посылает свой файл с логом
(лог, описываемый в этом разделе, находится в
WinNT\System32\config\AppEvent.Evt) разработчику из Нигерии, тот мог бы,
используя свою dll, прочитать те же сообщения на нигерийском.
В ключе реестра HKLM\System\CurrentControlSet\Services\Eventlog\Application\
нужно создать ключ с любым именем (это имя будет именем источника сообщений), в
этом ключе создать строковый параметр EventMessageFile и записать в него полный
путь к файлу сообщений.
Имя источника сообщений отображается Event Viewer-ом в
колонке «Source», оно же используется для получения описателя (handle) при
записи в Event Log.
Для начала нужно получить описатель.
На вопрос «описатель чего?» я ответить
не могу. Просто описатель.… В MSDN сказано так: «If the function succeeds, the return
value is a handle that can be used with the ReportEvent function.»
Эту операцию выполняет функция RegisterEventSource.
Она выглядит так:
Имя сервера, на котором находится лог.
Для записи в лог текущей машины передавайте NULL.
Имя зарегистрированного источника
сообщений.
Для закрытия описателя используется функция
DeregisterEventSource.
Запись сообщения производит функция ReportEvent.
Описатель, полученный от
RegisterEventSource.
Тип сообщения, должен
совпадать с типом, записанным в файле сообщений. Варианты: EVENTLOG_SUCCESS,
EVENTLOG_INFORMATION_TYPE, EVENTLOG_WARNING_TYPE, EVENTLOG_ERROR_TYPE.
Идентификатор сообщения. Не
равен «MessageId». Берётся из создаваемого mc.exe заголовочного файла.
Массив строк. Если строк
меньше, чем позиций, в лишних позициях будет «%n», где n – номер позиции.
Большинство API-функций, принимающих в качестве
параметров строки, существуют в двух вариантах – ANSI и Unicode. ANSI-вариант
имеет суффикс «A», Unicode-вариант – суффикс «W» (от wide – широкий). В Windows
NT/2000/XP ANSI-функции просто преобразуют переданные строки в Unicode и вызывают
соответствующую Unicode-функцию. Unicode – «родная» кодировка для этих ОС. Для
Win 9x «родная» кодировка – ANSI, в ОС этой группы полностью реализовано всего
несколько Unicode-функций, остальные сразу возвращают ошибку. Поэтому
программа, использующая Unicode, в Windows NT/2000/XP будет работать быстрее, а
в Win 9x не будет работать вообще. Поскольку в Win 9x служба всё равно не
сможет работать, это не должно вас волновать.
Если вы не сталкивались с Unicode раньше и не изучали
заголовочные файлы с объявлениями API-функций, предыдущий абзац может вас
озадачить. Скорее всего, вы неоднократно использовали API-функции, принимающие
строки и точно помните, что у них не было никаких суффиксов. А оказывается –
есть. Ниже приведёна часть файла winbase.h:
Если макрос UNICODE определён, вы будете использовать
EncryptFileW, в противном случае – EncryptFileA. Так можно менять используемую
версию API-функций. Осталось научиться регулировать тип передаваемой строки.
Это тоже несложно, достаточно пользоваться типом TCHAR при объявлении строковых
и символьных переменных и заключать соответствующие константы внутрь макроса
TEXT. И TCHAR, и TEXT определены в tchar.h. Кроме них, в этом файле определёны
макросы для функций стандартной библиотеки С. Например, макрос _tscanf
разворачивается или как wscanf, или как scanf, в зависимости от макроса
UNICODE.
При последовательном употреблении TCHAR, TEXT,
_tscanf,.. можно простым изменением настроек переключаться между ANSI и Unicode
версиями проекта. Вряд ли вы будете часто пользоваться такой возможностью, но то,
что она есть – хорошо.
Никто не заставляет вас использовать
одну и ту же кодировку везде, достаточно просто быть последовательным.
Например, модуль, осуществляющий запись в лог-файл, может явно вызывать
ANSI-функции (с суффиксом «A») и передавать им char-строки. С таким модулем
можно работать, но нужно помнить, что его функциям не стоит передавать
TCHAR-строки. Иначе в ANSI-версии проекта это будет работать, а в
Unicode-версии даже не скомпилируется. В основной части службы
предпочтительнее использовать Unicode.
Здесь собраны факты, знать которые полезно, но не
необходимо.
Служба не обязательно является консольным приложением.
В параметре ImagePath ключа
HKLM\System\CurrentControlSet\Services\имя_службы можно задать командную строку
(можно даже «/uninstall»), но, по-моему, этой возможностью лучше не
пользоваться.
Начиная с Windows 2000 в параметре Description ключа
HKLM\S
Похожие работы на - Программирование служб: подробности Реферат. Информатика, ВТ, телекоммуникации.
Контрольная работа по теме Чисельне розв’язання задач оптимального керування
Курсовая Работа База Данных Sql Автовокзал
Доклад по теме Механизм этногенеза как инструмент исследования этнокультуры
Сочинение 6 Класс Мифы Народов Мира
Реферат: The Huns And The End Of The
Реферат: Физиотерапия при бронхиальной астме. Скачать бесплатно и без регистрации
Отчет По Практике В Прокуратуре
Воспалительные Заболевания В Гинекологии Реферат
Реферат по теме Основные эстетические категории
Реферат: Глобальные проблемы здоровья человечества
Реферат: Смог. Виды смога
Астрономия Контрольная Работа 2
Реферат: Трансформации эволюции, связанные с переходом из водной среды в воздушную
Дипломная работа по теме Анализ речи Президента
Сочинение Отзыв По Пушкину Барышня Крестьянка
Контрольная Работа По Алгебре 10 Класс Глизбург
Сочинение Про Мой Выходной День На Английском
Реальность И Фантастика В Произведениях Гоголя Сочинение
Курсовая На Тему Профилактика
Монтажные Работы Практическая Работа
Статья: Трудности заключения мирового соглашения на стадии исполнения решения суда
Дипломная работа: Противление злу смехом. Н.Тэффи
Похожие работы на - Музыкальная культура Киевской Руси