Delphi错误:Stack overflow的解决方法
在编译Delphi程序时,执行一个内存记忆体的时候,提示:Project.exe raised exception class E* with message : Stack overflow.这是堆栈溢出错误。
原因就是字符串所存储的内容超过DELPHI系统堆栈默认的大小 16*100000 。我们可以改大这个默认值。
那么如何给我们的应用程序分配更大的内存空间以避免堆栈溢出呢?其实,在每个Delphi项目中都有一个设置应用程序内存大小的地方。
解决方法:
点击 Project 菜单中 -> Options -> Linker -> Memory sizes -> 按照需要,改变 Max stack size 的大小。比如飘易这里改成了 1,000,000 ,即 16*1,000,000 。
注:Max stack size 的默认大小为 16*100,000 ,允许的范围在 65,536-16,777,216 。
Delphi异常处理try except语句和try finally语句用法以及区别
Delphi异常处理try except语句和try finally语句用法以及区别
一直写程序都没管他们,也尽量很少用,今天终于想把他给弄个明白,在网上找来,记下!
主要是前面小部分,后面的是详细说明(很啰嗦!)
一、异常的来源
在Delphi的应用程序中,下列的情况都比较有可能产生异常。
(1)文件处理
(2)内存分配
(3)Windows资源
(4)运行时创建对象和窗体
(5)硬件和操作系统冲突
二、异常的处理
(1)try…except…end;
在try体内的代码发生异常时,系统将转向except部分进行异常的处理。这是Delphi处理异常的最基本的方式之一。
(2)try…finally…end;
这种异常处理结构一般用于保护Windows的资源分配等方面,它确保了无论try体内的代码是否发生异常,都需要由系统进行最后的统一处理的一些Windows对象的正确处理。
和try…except…end不同,该结构的finally部分总被执行。
(3)不存在try…except…finally…end结构来既处理异常,又保护资源分配的结构,但是,try…except…end结构允许嵌套到try…finally…end结构中,从而实现既处理异常,又保护资源的分配。
三、异常的精确处理
(1)定义一个异常。
在Delphi中,每个异常都是Exception[1]类的一个派生类[2]。因此,定义一个异常就是定义一个Exception类的派生类。
type EMyException = class(Exception);
当然,基类可以是Exception或者Exception的任何一个任何层次的派生类。
(2)在程序中抛出一个异常。
根据不同的情况抛出异常是使用异常的最基本的模式。在Delphi中,由raise语句来实现。
【语法】raise 异常类.Create(‘异常的缺省说明’);
(3)在try…except…end中更加精确的捕捉异常。
使用on E:异常类 do…结构可以在do体内处理特定异常类所抛出的异常。
四、异常的调试
在Delphi IDE中,解除“Debugger Options”(可以使用菜单Tools—>Debugger Options…进行访问)中的Integrated Debugging复选框的勾选状态可以进行异常的调试。
五、异常的补充说明
(1)每一段程序都有可能产生错误!这是软件业的一个不容置疑的现象和规律。事实上,传统的if…else…结构完全可以解决所有的错误,使用Exception机制也没能够回避在最原始的层次,通过遍历可能的情况来产生异常的做法,那么,为什么还要异常机制?
答案很清楚:异常提供了一种更加灵活和开放的方式,使得后来的编程者可以来根据实际的情况处理这种错误,而不是使用预先设定好的处理结果。
Delphi7异常处理
了解什么是异常和Delphi7中提供的异常类
掌握Delphi7环境下自定义异常的方法和异常
处理的语法结构与实现
异常
什么是异常
程序开发过程中,有编译期错误和运行期错误,编译期错误很容易发现,而运行期错误(逻辑错误和异常)往往很难预料.为了程序的稳定性和可靠性,就需要对程序异常处理和保护.
异常:理解为一种特殊的事件,该事件发生时,程序的正常执行将被打断.
由程序导致的不正常情况是错误而不是异常,程序错误与异常不是相同的概念.
异常是为方便用户报告错误并处理错误而创建的机制,一般是由操作系统完成的.
运行期错误处理
软件开发过程中,程序员必须提供适度的方式来处理不可避免的错误.一般方法如下:
1 传统方法
2 使用异常进行错误处理
传统方法
在Pascal早期版本中,程序员必须借助编译器开关和状态变量去检测和处理存在的错误.
{$I-}{此编译器指令关闭I/O检测}
Assign(InFile,InputName);
Reset(InFile);
{$I+}{此编译器指令恢复I/O检测}
If IOResult0 then
{错误处理代码};
使用异常进行错误处理
结构化异常处理是Delphi语言内建的特性.为我们处理异常提供了方便.处理异常有两方面:
1 异常处理可确保适当地恢复在应用程序中分配或改变的任何资源.
2 结构化异常处理为开发人员提供了一种一致的处理各种类型运行期错误的方式
Delphi7异常处理机制
异常处理的基本思想是通过提供规范方式处理软,硬件错误的能力,使程序更加健壮.
异常处理可以将处理错误的代码与正常的逻辑处理代码相分离.
Delphi缺省的方式是在应用程序收到异常之前捕获异常.IDE会给出一个”预警”对话框,以指明应用程序将要产生异常.
异常处理机制是一种程序设计安全策略,它是建立在保护块思想上,通过try和end语句块对代码的封装确保在程序发生异常时,程序能够正常运行或释放所占用的资源.
Delphi7异常处理机制
传统程序设计中,用如下的伪代码方法来检查和处理程序错误:
执行一个任务
If 前一个任务未能正确执行
执行错误处理
执行下一个任务
If 前一个任务未能正确执行
执行错误处理
……
Delphi7异常处理机制
例;
try
Age := StrToInt(Edit1.Text);
ShowMessage(Format(‘生于%d年‘, [YearOf(Now) - Age]));
except
on EConvertError do
showmessage(‘输入编辑框的不是一个有效的数字!‘);
on ERangeError do
showmessage(‘输入编辑框的年龄值太大!‘);
end;
异常类
Delphi7根据异常类型定义了相应的异常类.所有异常类的基类都是Exception类.
Delphi7内置了大量的异常类,用户也可以通过Exception类自定义异常类.
记住异常类的要点:
1 异常类是响应不同异常现象的入口.
2 熟悉异常类的层次结构.
Exception异常类
Exception是所有异常类的基类,它并不是以’T‘开头,而是以’E‘开头,它的派生类也是以’E‘开头的.
Exception类定义于SysUtils单元中.
Exception类最常用的方法是Create方法:
Constructor Create(const Msg:string);
Exception.Create(‘我自己创建的异常!’);
该方法用于创建一个异常类的实例,也可以显示错误信息,也可直接用这个方法提交一个异常
raise Exception.Create(‘我抛出的异常!’);
例:
try
raise Exception.Create(‘我抛出的异常!‘);
except
on E: Exception do
showmessage(‘异常类名称:‘ + E.ClassName
+ #13#10 + ‘异常信息:‘ + E.Message);
end;Delphi7内置的异常类
Delphi7根据异常现象的类型定义了相应的异常类,这些异常类又称为Delphi7内置的异常类.
具体分为运行时库异常类,对象异常类和组件异常类三大类.
运行时库异常类(RTL)
运行时库异常类可分为以下几种:
1 整数计算异常 2 浮点计算异常 3 硬件异常 4 堆异常 5 输入输出异常(I/O异常) 6 字符转换异常 7 类型转换异常 8 哑异常
整数计算异常
EIntError 整数计算异常(基类)
EDivByZero 整数除0溢处
EIntOverFlow 整数溢出
ERangeError 整数越界
浮点计算异常
EMathError 浮点计算异常(基类)
EInvalidOp 无效浮点操作指令
Eoverflow 浮点操作上溢
Eunderflow 浮点操作下溢
EZeroDivide 浮点计算除0
硬件异常
EProcessorException 硬件异常(基类)
ESingleStep 应用程序产生单步中断
Ebreakpoint 应用程序产生断点中断
Efault 故障(继承EProcessorException,也是基类)
EStackFault 对处理器栈段的非法访问
EPageFault 内存管理器无法正确使用交换文件
EGPFault 保护性错误,一般由未初始化指针或对象造成
EInvalidOpCode 处理器遇到未定义指令
堆异常和(I/O异常)
堆异常:
EOutOfMemory 堆中没有足够的内存完成操作
EInvalidPointer 试图访问一个堆外的指针
(I/O异常)
EInOutError DOS输入/输出错误
字符转换/类型转换异常和哑异常
字符转换异常
EConvertError 数字到字符串或字符串到数
字转换错误
类型转换异常
EInvalidCast 类型转换异常
哑异常
EAbort 调用Abort产生,不显示错误提示框
对象异常类
对象异常类是针对非组件对象引发的异常而定义的.
对象异常类包括:
1 流异常类
2 打印异常类
3 图形异常类
4 字符串链表异常类
流异常类
流异常是指在程序中进行与流相关的操作时产生的异常.流异常类的基类是EStreamError,其他流异常类都直接或间接从它派生.
派生关系见书48页图
打印异常
打印异常是由于应用程序向不存在的打印机发送打印命令或由于某种原因打印工作无法送到打印机时引发的.
打印异常类为Eprinter,定义于Printers单元
图形异常
图形异常主要包括EInvalidGraphic和
EInvalidGraphicOperation两个类均定义于Graphics单元
EInvalidGraphic异常满足下列情况之一时引发:
当应用程序试图向一个并不包含合法的位图,图象,元文件或用户自定义图形类型的文件中装入图象时.
当应用程序试图装入不可识别扩展名的文件时
当图象与LoadFromClipboardFormat或SaveToClipboardFormat中的格式不匹配时.
当应用程序试图将图象的PixelFormat设为不支持的值
EInvalidGraphicOperation异常在满足下列条件之一时发生:
应用程序访问图象中不存在的扫描线时.
应用程序不能成功写入图象时.
应用程序在画布未处于有效状态时进行绘制.
应用程序装入未知或不支持的图象格式时.
应用程序将图象的PixelFormat设为不支持的值时
不能分配该操作的句柄时.
字符串链表异常
字符串链表异常是由于用户对字符串链表进行非法操作时引发的.
包括EStringListError,EListError等.由于许多部件都有一个Tstrings抽象类的属性(如Tiistbox组件的Items属性等),因而字符串链表异常在组件编程中很重要.
EStringListError一般在字符串链表越界时产生.而EListError异常通常在以下情况下发生:
当索引项超出链表范围时
当字符串链表的Duplicates属性设置为dupError
同时应用程序试图加入一个重复的字符串时.
当向已排序的字符串链表中插入字符串时.
组件异常类
组件异常类用于响应组件异常,组件异常是由于对VCL组件进行操作时,违反了组件的使用规则及其特征而引发的,可分为两大类:
通用组件异常、专用组件异常、通用组件异常。
常见的有非法操作异常,组件异常和资源不足异常三种类型,对应于EInvalidOpetation,EComponentError和EOutOfResource异常类.
引发非法操作异常的原因有:
应用程序试图对Parent属性为nil的组件进行一些需要窗口句柄的操作.
试图对窗体拖放操作.
引发组件异常的原因有:
Delphi不能注册某个组件
应用程序不能重命名某个组件
资源不足异常被引发是由于当应用程序试图创建窗口句柄而操作系统没有多余的句柄可分配
专用组件异常:许多组件都定义了相应的组件异常类.
列出几个典型的组件异常类:
EMenuError异常,菜单异常,是由于程序对菜单的非法操作而引发的.定义于Memus单元
EInvalidGridOperation异常.非法的网格操作,如试图引用一个不存在的网格单元时引发.定义于Grids单元
EDatabaseError异常.数据库异常是由于对数据库的非法操作引起的.
用户自定义异常类
创建用户自定义异常类的方法
抛出自定义异常
用户自定义异常类与内置异常类的区别
异常类对象与其他类对象的区别
创建用户自定义异常类的方法
选择Exception作为基类,按照定义类的一般方法,建立自定义的异常类就可以了.
如:
type
EMyException = class(Exception)
//需要定义属性或方法时,写在此处即可
end;抛出自定义异常
Delphi不会管理用户自定义异常的抛出,程序员必须自己抛出自己创建的异常.用raise语句可抛出异常:
raise EMyException.Create(‘My Exception‘);用户自定义异常类与内置异常类的区别
Delphi不会自动响应用户自定义的异常类,所以用户自定义的异常类需要使用raise语句抛出,而内置异常类与运行期真实的异常现象相对应,当异常发生时,操作系统会捕捉到此异常,通知Delphi去响应.
异常类对象与其他类对象的区别
异常类对象创建后,不需要由用户释放它,当异常处理之后,系统会自动调用析构函数释放异常类对象.而其他类需要由用户来释放.
Delphi7的异常处理结构
try…finally 语句块
Try…except语句块
使用raise抛出异常
try…finally 语句块
try…finally 语句块是用于资源保护和恢复系统状态,不管try部分的操作是否有异常发生,finally部分的操作都要进行.
语法如下:
try
被保护语句
finally
处理语句(无论异常是否发生,都必须处理)
end;try…finally 语句块主要用于资源保护
应用程序向系统申请了资源(如内存,图形句柄),当不需要这些资源时,就应该及时释放资源.
句柄:系统资源是有限的,一般构成一个资源链,链的长度是有限的,当系统给应用程序分配资源时,给每个资源设置一个ID号,这个ID号就是句柄.(系统资源相当于一个个房间,而句柄就相当于房间号.)
句柄有限:1 资源是有限的;2数字表达的范围也是有限的(整数有范围的)
Try…except语句块
Try…except语句块用于运行期错误处理,程序员可以用它编写对不同类型异常的处理.
异常发生后,判断异常的类型,正确处理异常.
Try…except语句块一般和On…Do子句连用;
语法如下:
function Test(x, y: Real): Real;
begin
try
Result := x / y;//被保护语句
except
on EInvalidOp do Result := 0;//异常处理语句
on EZeroDivide do Result := 0;
on EOverFlow do Result := 0;
on EUnderFlow do Result := 0;
end;
end;Try…except语句块主要处理 缺省异常
用户一般只处理一些特殊的异常,并不是处理所有的异常.对那些用户不关心的异常就可以采用缺省异常来处理.
try
//正常程序代码
except
on EExceptionClass do //处理特定类型的异常
else //缺省异常处理
end;注:else块必须位于except块的最后,可响应任何类型的异常
异常的传递
Delphi对异常的处理方式是向后扫描程序的调用栈.假如过程A内有过程保护代码块,在此代码块内又调用了过程B,过程B没有异常保护,过程B调用了过程C,在C内发生了异常.如C内有该异常的处理程序,那么程序调用C的异常处理代码
Delphi异常处理总结
以前写delphi程序一直不注意异常处理,对其异常处理机制总是一知半解,昨天程序中的一个bug,让我对异常有了更深入的认识,必须要对可能产生异常的地方进行异常处理,否则可能给程序造成灾难,就像昨天,因为写的filecopy函数没有做异常捕获处理,导致复制文件出错时整个程序崩溃,用户只能通过杀进程的方式重启程序再进行其它操作(汗~)。后来对程序进行异常处理,遇到意外只是提示下用户,然后可以继续运行下去,表现很完美,才意识到异常处理的重要性,故要总结下Delphi异常处理相关的知识。
Delphi异常处理机制建立在保护块(Protected Blocks)的概念上。所谓保护块是用保留字try和end封装的一段代码。保护块的作用是当应用程序发生错误时自动创建一个相应的异常类(Exception)。程序可以捕获并处理这个异常类,以确保程序的正常结束以及资源的释放和数据不受破坏。如果程序不进行处理,则系统会自动提供一个消息框。每一段程序都有可能产生错误!这是软件业的一个不容置疑的现象和规律。事实上,传统的if…else…结构完全可以解决所有的错误,使用Exception机制也没能够回避在最原始的层次,通过遍历可能的情况来产生异常的做法,但异常提供了一种更加灵活和开放的方式,使得后来的编程者可以来根据实际的情况处理这种错误,而不是使用预先设定好的处理结果。
一、异常的来源
在Delphi的应用程序中,下列的情况都比较有可能产生异常。
(1)文件处理
(2)内存分配
(3)Windows资源
(4)运行时创建对象和窗体
(5)硬件和操作系统冲突
二、异常处理
(1)try…except…end;
在try体内的代码发生异常时,系统将转向except部分进行异常的处理。这是Delphi处理异常的最基本的方式之一。try语句块指出了需要进行异常保护的代码。如果在这部分有不正常的事件发生,则引发一个异常对象。except是异常处理部分,被保护部分引发的异常对象将执行<异常处理语句>或由这部分代码捕获并进行处理。
try except语句的一般格式如下:
try //try保护代码块
被保护语句
except //异常处理块
异常处理语句 //异常不发生,不处理
end;
或
try //try保护代码块
被保护语句
except //异常处理块
on <异常对象类型1> do <语句1> //捕获指定类型的异常对象,进行处理
on <异常对象类型n> do <语句n> //捕获指定类型的异常对象,进行处理
else
<语句n+1> //缺省的异常处理代码
end;
(2)try…finally…end;
这种异常处理结构一般用于保护Windows的资源分配等方面,它确保了无论try体内的代码是否发生异常,都需要由系统进行最后的统一处理的一些Windows对象的正确处理。
和try…except…end不同,该结构的finally部分总被执行。在try-finally语句中,当try部分产生异常后,应用程序直接执行Finally部分的资源释放语句。
try finally语句的一般格式如下:
try //try保护代码块
被保护语句
finally //异常处理块
异常处理语句 //无论异常发生否,都必须处理
end;
若用作创建一个资源保护块时,它的格式可写成:
(分配系统资源)
try
(使用系统资源的语句)
finanlly
(释放系统资源)
end;
(3)不存在try…except…finally…end结构来既处理异常,又保护资源分配的结构,但是,try…except…end结构允许嵌套到try…finally…end结构中,从而实现既处理异常,又保护资源的分配。
(4) raise:知道一些情况不合理,直接手工弹异常对话框。如:raise 异常类.Create(‘异常的缺省说明‘);
try...finally结构与try...except结构在用法上主要有以下区别:
(1) 对于try...finally结构来说,不管try部分的代码是否触发异常,finally部分总是执行的。如果发生异常,就提前跳到finally部分。而对于try...except结构来说,只有当触发了异常后,才会执行except部分的代码。
(2) 在try...except结构中,当异常被处理后异常对象就被释放,除非重新触发异常。而在try...finally结构中,即使finally部分对异常作了处理,异常对象仍然存在。
(3) finally部分不能处理特定的异常,因为它没有try...except结构中的异常句柄,无法知道确切的异常类型。因此,在finally部分只能对异常作笼统的处理。
(4) 在try…finally结构中,如果在try部分调用标准命令Exit、Break或Continue,将导致程序的执行流程提前跳到finally部分。finally部分不允许调用上述三个命令。
三、Delphi中的异常类结构
Delphi提供的所有异常类都是类Exception的子类。用户也可以从Exception派生一个自定义的异常类。即Exception是所有异常类的基类,它并不是以‘T‘开头,而是以‘E‘开头,它的派生类也是以‘E‘开头的.Delphi提供了一个很庞大的异常类体系,从大的方面可以把异常类分为运行库异常、对象异常、组件异常三类。
3.2.1 运行库异常类(RTL Exception)
运行库异常可以分为七类,它们都定义在SysUtils库单元中。
1.I/O异常
I/O异常类EInOutError是在程序运行中试图对文件或外设进行操作失败后产生的,它从Exception派生后增加了一个公有数据成员ErrorCode,用于保存所发生错误的代码。这一成员可用于在发生I/0异常后针对不同情况采取不同的对策。
当设置编译指示{$I-}时,不产生I/0异常类而是把错误代码返回到预定义变量IOResult中。
2.堆异常
堆异常是在动态内存分配中产生的,包括两个类EOutOfMemory和EInvalidPointer,如表3-1所示。
表3-1 堆异常类及其产生原因
异常类 引发条件
EOutOfMemory 没有足够的空间用于满足所要求的内存分配
EInvalidPointer 非法指针。一般是由于程序试图去释放一个已释放的指针而引起的
3.整数异常
整数异常都是从一个EIntError类派生的,但程序运行中引发的总是它的子类:EDivByZero,ERangeError,EIntOverFlow,如表3-2所示。
表3-2 整数异常及其产生原因
异常类 引发条件
EDivByZero 试图被零除
ERangeError 整数表达式越界
EIntOverFlow 整数操作溢出
ERangeError当一个整数表达式的值超过为一个特定整数类型分配的范围时引发。比如下面一段代码将引发一个ERangeError异常。
var
SmallNumber:ShortInt;
X,Y:Integer;
begin
X:=100;
Y:=75;
SmallNumber:=X*Y;
end;
特定整数类型包括ShortInt、Byte以及与整数兼容的枚举类型、布尔类型等。例如:
type
THazard=(Safety,Marginal,Critical,Catastrophic);
var
Haz:THazard;
Item:Integer;
begin
Item:=5;
Haz:=THazard(Item);
end;
由于枚举类型越界而引发一个ERangeError异常。数组下标越界也会引发一个ERangeError异常,如:
var
Values:array[1..10] of Integer;
I:Integer;
begin
for I:=1 to 11 do
Values[I]:=I;
end;
ERangeError异常只有当范围检查打开时才会引发。这可以在代码中包含{$R+}编译指示或设置IDE Option|Project的Range_Checking Option选择框。注意,Delphi不对长字符串做范围检查。
EIntOverFlow异常类在Integer、Word、Longint三种整数类型越界时引发。如下面的代码将引发一个EIntOverFlow异常:
var
I:Integer;
a,b,c:Word;
begin
a:=10;
b:=20;
c:=1;
for I:=0 to 100 do
c:=a*b*c;
end;
EIntOverFlow异常类只有在编译选择框Option|Project|Over_Flow_Check Option选中时才产生。当关闭溢出检查,则溢出后变量的值是丢弃溢出部分后的剩余值。
4.浮点异常
浮点异常是在进行实数操作时产生的,它们都从一个EMathError类派生,但与整数异常相同,程序运行中引发的总是它的子类EInvalidOp、EZeroDivide、EOverFlow、EunderFlow (表3-3)。
表3-3 浮点异常类及其引发条件
异常类 引发条件
EInvalidOp 处理器碰到一个未定义的指令
EZeroDivide 试图被零除
EOverFlow 浮点上溢
EUnderFlow 浮点下溢
EInvalidOp最常见的引发条件是没有协处理器的机器遇到一个协处理器指令。由于在缺省情况下Delphi总是把浮点运算编译为协处理器指令,因而在386以下微机上常常会碰到这个错误。此时只需要在单元的接口部分设置全局编译指示{$N-},选择利用运行库进行浮点运算,问题就可以解决了。
各种类型的浮点数(Real、Single、Double、Extended)越界引起同样的溢出异常。
5.类型匹配异常
类型匹配异常EInvalidCast当试图用As操作符把一个对象与另一类对象匹配失败后引发。
6.类型转换异常
类型转换异常EConvertError当试图用转换函数把数据从一种形式转换为另一种形式时引发,特别是当把一个字符串转换为数值时引发。下面程序中的两条执行语句都将引发一个EConvertError异常。
var
r1:Real;
int:Integer;
begin
r1:=StrToFloat(‘$140.48‘);
int:=StrToInt(‘1,402‘);
end;
要注意,并不是所有的类型转换函数都会引发EConvertError异常。比如函数Val当它无法完成字符串到数值的转换时只把错误代码返回。利用这一点我们实现了输入的类型和范围检查。
7.硬件异常
硬件异常发生的情况有两种:或者是处理器检测到一个它不能处理的错误,或者是程序产生一个中断试图中止程序的执行。硬件异常不能编译进动态链接库(DLLs)中,而只能在标准的应用中使用(表3-4)。
硬件异常都是EProcessor异常类的子类。但运行时并不会引发一个EProcessor异常。
表3-4 硬件异常类及其产生原因
异常类 引发条件
EFault 基本异常类,是其它异常类的父类
EGPFault 一般保护错,通常由一个未初始化的指针或对象引起
EStackFault 非法访问处理器的栈段
EPageFault Windows内存管理器不能正确使用交换文件
EInvalidOpCode 处理器碰到一个未定义的指令,这通常意味着处理器试图去操作非法数据或未初始化的内存
EBreakPoint 应用程序产生一个断点中断
ESingleStep 应用程序产生一个单步中断
EFault、EGPFault往往意味着致命的错误。而EBreakPoint、ESingleStep被Delphi IDE的内置调试器处理。事实上前边的五种硬件异常的响应和处理对开发者来说都是十分棘手的问题。
3.2.2 对象异常类
所谓对象异常是指非组件的对象引发的异常。Delphi定义的对象异常包括流异常、打印异常、图形异常、字符串链表异常等。
1.流异常类
流异常类包括EStreamError、EFCreateError、EFOpenError、EFilerError、EReadError、EWriteError、EClassNotFound。
流异常在Classes库单元中定义。
流异常引发的原因如表3-5所示。
表3-5 流异常类及其产生原因
异常类 引发条件
EStreamError 利用LoadFromStream方法读一个流发生错误
EFCreateError 创建文件时发生错误
EFOpenError 打开文件时发生错误
EFilerError 试图再次登录一个存在的对象
EReadError ReadBuffer方法不能读取特定数目的字节
EWriteError WriteBuffer方法不能写特定数目的字节
EClassNotFound 窗口上的组件被从窗口的类型定义中删除
2.打印异常类
打印异常类EPrinter当打印发生错误时引发。它在printers库单元中定义。例如应用程序试图向一个不存在的打印机打印或由于某种原因打印工作无法送到打印机时,就会产生一个打印异常。
3.图形异常类
图形异常类定义在Graphic库单元中,包括EInvalidGraphic和EInvalidGraphicOperation两类。
EInvalidGraphic当应用程序试图从一个并不包含合法的位图、图标、元文件或用户自定义图形类型的文件中装入图形时引发。例如下面的代码:
Image1.Picture.LoadFromFile(‘Readme.txt‘);
由于Readme.txt并不包含一个合法的图形,因而将引发一个EInvalidGraphic异常。
EInvalidGraphicOperation当试图对一个图形进行非法操作时引发。例如试图改变一个图标的大小。
var
AnIcon:TIcon;
begin
AnIcon:=TIcon.Create;
AnIcon.LoadFromFile(‘C:/WINDOWS/DIRECTRY.ICO‘);
AnIcon.Width:=100; {引发一个图形异常}
end;
4.字符串链表异常
字符串链表异常EStringListError、EListError在用户对字符串链表进行非法操作时引发。
由于许多组件(如TListBox,TMemo,TTabSet,…)都有一个TStrings类的重要属性,因而字符串链表异常在组件操作编程中非常有用。
EStringListError异常一般在字符串链表越界时产生。例如对如下初始化的列表框:
ListBox1.Items.Add(‘Firstitem‘);
ListBox1.Items.Add(‘Seconditem‘);
ListBox1.Items.Add(‘Thirditem‘);
则以下操作都会引起EStringListError异常:
ListBox1.Item[3]:=‘NotExist‘;
Str:=ListBox1.Item[3];
EListError异常一般在如下两种情况下引发:
(1)当字符串链表的Duplicates属性设置为dupError时,应用程序试图加入一个重复的字符串。
(2)试图往一个排序的字符串链表中插入一个字符串。
3.2.3 组件异常类
1.通用组件异常类
通用组件异常类常用的有三个:EInvalidOperation、EComponentError、EOutOfResource。其中EInvalidOperation、EOutOfResource在Controls单元中定义;EComponentError在Classes单元中定义。
(1)非法操作异常EInvalidOperation
EInvalidOperation引发的原因可能有:
a. 应用程序试图对一个Parent属性为nil的组件进行一些需要Windows句柄的操作
b. 试图对一个窗口进行拖放操作
c. 操作违反了组件属性间内置的相互关系等
例如,ScrollBar、Gauge等组件要求Max属性大于等于Min属性,因而下面的语句:
ScrollBar1.Max:=ScrollBar1.Min-1;
将引发一个EInvalidOperation异常。
(2)组件异常EComponentError
引发该异常的原因可能有:
a. 在Register过程之外试图登录一个组件(常用于自定义组件开发中)
b. 应用程序在运行中改变了一个组件的名称并使该组件与另一个组件重名
c. 一个组件的名称改变为一个Object Pascal非法的标识符
d. 动态生成一个组件与已存在的另一组件重名
(3)资源耗尽异常EOutOfResource
当应用程序试图创建一个Windows句柄而Windows却没有多余的句柄分配时引发该异常。
2.专用组件异常类
许多组件都定义了相应的组件异常类。但并不是有关组件的任何错误都会引发相应的异常类。许多情况下它们将引发一个运行时异常或对象异常。
下面列出几个典型的组件异常类。
(1)EMenuError
非法的菜单操作,例如试图删除一个不存在的菜单项。这一异常类在Menus库单元中定义。
(2)EInvalidGridOpertion
非法的网格操作,比如试图引用一个不存在的网格单元。这一异常类在Grids库单元中定义。
(3)EDDEError
DDE异常。比如应用程序找不到特定的服务器或会话,或者一个连接意外中止。这一异常类在DDEMan库单元中定义。
(4)EDatabaseError,EReportError
数据库异常(EDatabaseError)和报表异常(EReportError)在进行数据库和报表操作出现错误时引发。