Библиотека VCL, используемая в программах, редко дает сбои при работе. Даже если программа выполнит недопустимую операцию, вероятность аварийного завершения работы невелика. Конечно же, есть фатальные ошибки, которые прерывают дальнейшее выполнение кода, но это встречается редко и в основном из-за ошибок программиста, а не ошибок в VCL.

Пользователь не будет сильно рад, если появится сообщение типа "Access Violation* или "Программа выполнила недопустимую операцию". Когда-то я в своих программах вообще не обрабатывал ошибки и надеялся на надежность откомпилированного кода и библиотеку VCL. Но когда пользователи начали жаловаться на появление подобных сообщений, я понял свою ошибку. Ни пользователю, ни мне это сообщение ни о чем не говорит, и невозможно определить источник проблемы.

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

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

Допустим, что вы ищете в компоненте TListBox строку с текстом 11, но этой строки нет, и конструкция ListBoxl. Items. IndexOf (' 11") возвратит значение -1. Далее это отрицательное значение может сыграть в вашем коде злую шутку. Но самое интересное, что только в вашем коде. Следующий пример не выдаст ошибки:

ListBoxl.Items Delete(ListBoxl.Items.IndexOf('11')):

Здесь мы пытаемся удалить элемент, который содержит текст 11. Если такой строки не будет, то метод IndexOf возвратит значение -1 и метод Delete будет пытаться удалить строку с этим индексом. Элементы нумеруются с нуля, и элемента с индексом -1 не существует, - по идее, должна быть ошибка В большинстве других языков программирования такой код может вызвать ошибку, а в Delphi ничего не произойдет.

Не обращайте внимания на отличные возможности VCL, а делайте проверки абсолютно каждого шага. В следующем примере (листинг 1.5) элементы удаляются в три этапа: поиск элемента, проверка полученного значения, удаление. Результирующий код увеличится ненамного, скорость выполнения практически не пострадает, а вот надежность повысится, а значит, вы приобретете новых пользователей.

Листинг 1.5. Правильное удаление элементов

var
index: Integer: begi n
index := ListBoxl.Items.IndexOf('11'):

if index = -1 then begin ShowMessage("Такой элемент не найден'); exit:

end:
ListBoxl.Items.Delete(index):
end;

Итак, регулярно используйте практику проверки значений, возвращаемых функциями. Это должно выполняться автоматически. Лично я редко делал проверки, поэтому сейчас уже трудно переучиваться, но я стараюсь и заставляю себя. Да, это отнимает процессорное время, но это намного лучше, чем если пользователь увидит ошибку. Об оптимизации мы еще будем говорить в будущем, но не надо ускорять код в ущерб проверке и стабильности.

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

Допустим, что вы хотите сделать программу сервисом. В Win9x это делалось с помощью вызова функции registerserviceprocess, но в NT-системах сервисы работают по-другому и там процесс регистрации происходит иначе, поэтому вызов функции приведет к ошибке. Такой функции в системе Windows NT нет. Как можно решить эту проблему? В лучшем варианте будет проверить версии ОС, а потом, в зависимости от этого, использовать нужную функцию, но в такой ситуации проверка может быть недоступна. Тогда можно воспользоваться исключительными ситуациями:

try asm push 1 push О

call registerserviceprocess;
end;
except
// Регистрация для NT-систем end;

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

Если стоит выбор между двумя вариантами, то без проблем можно воспользоваться возможностями try. .except. При выборе из трех вариантов нельзя строить вложенность из исключительных ситуаций как в листинге 1.6. Вложенные проверки внутри блока except.. end ухудшают не только читабельность кода и дальнейшее сопровождение, но и совсем не повышают надежность.

Листинг 1.6. Вложенная исключительная ситуация

try asm

push 1 push О

call registerserviceprocess;
end: except try

// Регистрация для NT-систем except

// Регистрация для .NET-систем end;
end:

Теперь рассмотрим, как можно превратить недостатки в преимущества. Во всех процедурах, где используется обращение к памяти или есть "сомнительный" код можно использовать исключительные ситуации следующего вида:

procedure Имя(параметры):

begin
try

// Код процедуры except

ShowMessageC'Эта возможность еще недоступна, ждите новых версий');
end;
end;

Таким образом, пользователь будет ждать новой версии. Если же появится ошибка, то программа будет удалена, а вы потеряете клиента.

Вот такой хитрый прием в стиле Билла Гейтса может сыграть вам на руку и даже повысить продажи программы.

1.6.3. Освобождайте ресурсы || Оглавление || 1.7. Используемые технологии


Delphi в шутку и всерьез: что умеют хакеры



Новости за месяц

  • Декабрь
    2021
  • Пн
  • Вт
  • Ср
  • Чт
  • Пт
  • Сб
  • Вс
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31