EOutOfResources字符异常
近日,用Delphi编程时,遇到一个莫名其妙的异常:EOutOfResources,这是一个可以重复再现的异常。开始以为是程序中创建的对象太多,导致占用了过多的资源,引起了这个异常。于是在代码中将许多不必要创建的对象统统删减,对代码进行了彻底的大瘦身,谁知竟然毫无效果!
此时才注意到提示中有一句:“EOutOfResources with message 'RichEdit line insertion error'”。这就奇怪了,RichEdit控件中明明才添加了很少的几行文字,怎么会引起EOutOfResources这样的异常呢?
在著名的大富翁论坛上搜索了一下,发现有关于此问题的两个讨论,其中一位仁兄认为初始化时加上这句就行了:
SendMessage(RichEdit1.Handle,WM_USER+53,0,$7FFFFFFF);
这句的意图是为RichEdit1分配指定大小($7FFFFFFF)的空间,看起来不错,但实际试验了一下,不行。很显然,虽然抛出的是EOutOfResources异常,但实际上并非真的资源不足。
也有人认为是DELPHI VCL的BUG。在
procedure TRichEditStrings.Insert(Index: Integer; const S: string);
这个例程中有一句:
if RichEdit.SelStart <> (Selection.cpMax + Length(Str)) then
raise EOutOfResources.Create(sRichEditInsertError); // 这里报错了!!
这位仁兄认为是WINDOWS RTF计算长度的方法与DELPHI不一致造成了这个bug。
很偶然地,我发现RichEdit的这个异常实际上与使用了不恰当的字符集有关。例如:
RichEdit1.SelAttributes.Name := 'Symbol';
RichEdit1.SelAttributes.Charset := SYMBOL_CHARSET;
RichEdit1.Lines.Add(‘这里输入中文字符就出错’);
以上一段代码先指定RichEdit1的字符集为SYMBOL_CHARSET(即“符号”字符集),但随后添加的文本却是由中文字符组成的。Delphi按照SYMBOL_CHARSET字符集计算长度,结果当然与中文字符的长度不同,因为中文字符是双字节字符。此时,RichEdit1就会抛出一个EOutOfResources异常。
再例如,想在RichEdit中加入希腊字母a,写如下语句:
RichEdit1.Lines.Add(‘α’);
其中的α是用输入法的软键盘输入的。这样也会引起EOutOfResources异常。正确的写法应该是:
RichEdit1.SelAttributes.Name := 'Symbol';
RichEdit1.SelAttributes.Charset := SYMBOL_CHARSET;
RichEdit1.Lines.Add(‘a’);
字母a在SYMBOL_CHARSET中就是希腊字母a。
至此,真相大白。原来是不同字符集下计算长度的规则不同引起了这个异常。差点错怪了Borland!不过,其实Borland也不能算太冤,分明是字符集设置不当,却偏要不明不白地抛出个EOutOfResources异常来,帮助文档中也没有提到这个问题,看来Borland可能的确疏忽了些什么。