Delphi 6. Обработка ошибок в Graphics.
От: DmitryShevelev  
Дата: 02.06.05 13:18
Оценка: 57 (1)
Win 2000 Professional.
Раз в неделю-две у каждого из моих операторов выскакивает EOutOfResources с разными сообщениями.
Ошибка генерится в TCustomForm.CreateWnd -> TCustomForm.GetIconHandle -> ... -> ReadIcon
после того, как CreateIcon возвращает 0.
Ту же ошибку нетрудно сгенерировать самостоятельно (освобождение объектов после возникновения ошибки опустим):

var
S : TMemoryStream;
begin
S := TMemoryStream.Create;
Application.Icon.SaveToStream(S);
repeat
S.Seek(0, soFromBeginning);
With TIcon.Create do begin
LoadFromStream(S);
Handle;
end;
until false;
end;

Действительно достигается предел по ресурсам? У меня сложилось впечатление, что нет.

Во-первых, анализ GetLastError в ходе выполнения ReadIcon показывает, что ошибка, по которой формируется текст для EOutOfResources после того, как CreateIcon вернул 0, вообще не имеет никакого отношения к этой функции. В данном случае GetIcon вообще НЕ УСТАНАВЛИВАЕТ LastError. Код ошибки остаётся неизменным в ходе всего выполнения процедуры ReadIcon. Т.е., если отредактировать копию Graphics и добавить SetLastError(0) в начале ReadIcon, то после GetIcon = 0 ошибка так и будет нулевая.

Во-вторых, проверка ограничений на количество ресурсов даёт устойчивый результат (как для User-, так и для GDI-объектов): 10000 handle на приложение и 16000 на систему. Данная ошибка происходит, когда до этого ограничения далеко. Причем, в количестве handle на момент ошибки нет никакой системы. От пары тысяч до десяти тысяч для GDI-объектов и так же для User-объектов.

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

Отладка копии Graphics показала, что предвестником проблемы является ошибка в другом месте ReadIcon (которая почему-то вообще не проверяется разработчиками). На три строчки выше GetIcon находится вызов GetBitmapBits(XorBits, XorLen, XorMem); В вызове, когда GetIcon возвращает 0, GetBitmapBits возвращает 0, т.е. не происходит копирование BitMap. GetLastError и в этом случает не показывает ошибку.

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