При работе с системным журналом событий в операционных системах семейства Windows разработчики могут столкнуться с различными проблемами. Одной из таких является ошибка с кодом 997, которая указывает на состояние "I/O PENDING". В данной статье мы подробно рассмотрим, что может стать причиной возникновения этой ошибки, и как её можно решить, рассмотрев примеры кода на Object Pascal, который используется в среде разработки Delphi.
Описание проблемы
Ошибка 997 (I/O PENDING) может возникать при вызове функции RegisterEventSource, которая используется для регистрации источника событий в журнале событий Windows. Эта ошибка указывает, что операция ввода-вывода не была завершена, и результат её выполнения ещё не доступен.
Контекст проблемы
Рассмотрим пример кода, который может привести к возникновению ошибки 997:
procedure TForm1.Button111Click(Sender: TObject);
var
hEventLog: THandle;
p: PChar;
wynik: Boolean;
errnumber: cardinal;
begin
hEventLog := RegisterEventSource(nil, PChar('app'));
errnumber := GetLastError; // Здесь может быть получен код ошибки 997
if hEventLog > 0 then
begin
p := PChar('Test');
wynik := ReportEvent(
hEventLog,
EVENTLOG_INFORMATION_TYPE, // Тип события
22, // Идентификатор категории события
500, // Идентификатор события
nil,
1,
0,
@p,
nil
);
errnumber := GetLastError; // И снова здесь может быть код ошибки 997
DeRegisterEventSource(hEventLog);
end;
end;
Подтверждённый ответ
Проблема заключается в том, что функция GetLastError вызывается независимо от результата работы RegisterEventSource. Вызов GetLastError должен происходить только в случае, если RegisterEventSource возвращает нулевой указатель (ошибка), то есть hEventLog равен 0. Это следует из документации по API.
Альтернативный ответ и комментарии
В комментариях к альтернативному ответу указано, что проверка на ноль должна осуществляться с использованием операции hEventLog<>0, так как документация указывает, что RegisterEventSource возвращает 0 при неудачной попытке. Также упоминается вопрос о возможности удаления источника событий из журнала, но это выходит за рамки данного вопроса.
Решение проблемы
Исправим код, чтобы он соответствовал требованиям документации:
procedure TForm1.Button111Click(Sender: TObject);
var
hEventLog: THandle;
p: PChar;
wynik: Boolean;
errnumber: cardinal;
begin
hEventLog := RegisterEventSource(nil, PChar('app'));
if hEventLog = 0 then
begin
errnumber := GetLastError; // Получаем код ошибки только если RegisterEventSource вернула 0
ShowMessage(IntToStr(errnumber)); // Выводим сообщение об ошибке
Exit; // Завершаем процедуру, так как дальнейшие действия невозможны
end
else
begin
// Продолжаем работу с журналом событий
p := PChar('Test');
wynik := ReportEvent(
hEventLog,
EVENTLOG_INFORMATION_TYPE,
22,
500,
nil,
1,
0,
@p,
nil
);
// Проверяем результат вызова ReportEvent
if GetLastError <> 0 then
begin
errnumber := GetLastError;
ShowMessage(IntToStr(errnumber)); // Выводим сообщение, если ReportEvent завершилась с ошибкой
end;
DeRegisterEventSource(hEventLog);
end;
end;
Заключение
При работе с системным журналом событий Windows важно понимать, как функционируют основные операции, такие как регистрация источника событий и запись событий. Следуя документации и правильно обрабатывая результаты выполнения функций, можно избежать многих распространённых ошибок, включая ошибку 997 I/O PENDING.
Разработчики сталкиваются с ошибкой 997 при работе с системным журналом событий в Windows, что связано с неправильным использованием функции `GetLastError` после вызова `RegisterEventSource`.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS