看看这段代码是不是delphi的Bug?

lxwsoft 2004-11-23 09:18:28
procedure TForm1.btn1Click(Sender: TObject);
var
ts:TStrings;
begin
ts:=TStringList.Create;
qry1.GetFieldNames(ts);//qry1为TADOQuery
ShowMessage(ts.CommaText);
ts.Free;
end;
以上代码在Exe里运行无错

procedure Test(qry1:TDataSet);
var
ts:TStrings;
begin
ts:=TStringList.Create;//或ts:=TFieldList.Create(qry1);
qry1.GetFieldNames(ts);
ShowMessage(ts.CommaText);
ts.Free;
end;
exports
Test;

这段代码放在动态库中却报错。
不知是为什么?怎么解决?
...全文
209 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
aiirii 2004-11-23
  • 打赏
  • 举报
回复
to aiirii:不安全但是不应该出错吧
不安全, 就有可能出錯的, dll 與 exe 的內存空間還有些差別, 直接傳對象, 結果不一定正确
kuki84 2004-11-23
  • 打赏
  • 举报
回复
在调试程序时,特别是对于初编写程序经验不足的初手来说,代码检查通过却总得不到预期的结果不能不算作一桩令人头痛的事情,它可能会耗费你比编写程序还要大几倍的精力去检查逻辑错误的所在并修正它,然而程序时不时地得到正确的结果却比总得不到正确的结果还要可恶,因为并不丰富的经验很难判断出到底是什么因素导致的结果出错:是逻辑错误,还是程序之外的其他环境所至?
前不久为一个模拟股市比赛写了个交易系统,经过谨慎测试后才交付使用,在比赛正式举行时,却很出乎意料的发生了有几个帐户的数据发生了严重的混乱:一个帐户资金出现负数,一个帐户股票持量出现负数,另外一些帐户所挂的交易单明明符合交易条件却没有成交,
当日比赛后,检查了n遍源代码都找不到原因,代码中当资金不足或股票持量不足时是不可能执行交易的,怎么可能会有负数;而本应成交却未成交就更莫名其妙,交易单是按照委托价格的顺序进入队列,不可能出现有两个价位成交而介于这两个价位之间的价位却没有成交的情况。一切错误都与规定交易规则的代码明显冲突,百思不得其解,在不解的状态下模拟
交易的数据测试,居然结果时对时错,且无规律可循,就更加疑惑了:没有随机函数之类的调用,又确定不可能有溢出,为什么会时对时错?
一遍又一遍地看代码、输数据,实在不知道该怎么办,眼睛停在显屏上,突然看到DBGrid中的记录位置动了一下,疑神片刻,恍然小悟,赶紧翻开两段代码:
procedure TFrm_option.Timer2Timer(Sender: TObject);
var
i:integer;
myfstream:Tfilestream;
begin
table1.Active:=false;
table2.active:=false;
table3.Active:=false;
//备份数据表文件的代码
·
·
·
table1.Active:=true;
table2.Active:=true;
table3.Active:=true;
end;

procedure TFrm_option.Button1Click(Sender: TObject);
var

s,m,q,temp_min,flag:integer;
n,p:single;
pricestr:string;
begin
·
·
·
with table3 do //定位记录、检查并设定活动资金是否足够
begin
setkey;
fieldbyname('号码').AsInteger:=table1['客户代码'];
gotokey;
end;
table3.Edit;
table3[‘活动资金’]:=table3[‘活动资金’]-table1[‘价格’]*table1[‘数量’];
table3.Post;
·
·
·
showmessage('卖单号:'+inttostr(table2['卖单号']));
·
·
·
table3.Edit;
//执行交易的代码,;
table3.post;
end;


第一个过程是起每五秒备份数据表文件的作用,第二个过程则具体执行交易更新数据表数据,之前检查代码确实很难留意把这两个过程联系一起分析,而问题就恰恰出在计时器和第二个过程的showmessage()函数上,这个showmessage()函数用来告之输入者程序分配给他委托的交易的流水号,一般就被看一眼一带而过,而假如他要记下这个号码而并不很快关掉这个消息框,程序就处于中断而等待消息框“确定”被点击状态,一旦等待时Timer2的Ontime事件被触发,那就惨了:Table1、Table2、Table3被关闭再打开,记录位置便到了首记录,而在第2个过程中showmessage()函数之前有一段定位要修改数据的记录,而之后便是修改数据的代码,消息框打开时一旦ontime事件被触发,消息框关闭后修改的数据便是首记录的数据而非所定位的应该修改数据的记录了。所以,当客户因为用笔在纸上记下号码或做其他的事情而不在下一ontime事件触发之前关掉消息框,遍产生了错误,这个在非所对应的记录上更新数据也正是开始所述的资金、持股量出现负数、成交价位出错和后来测试时结果时对时错的原因所在。
所以,无论是在程序编写还是程序检查时,一定要留意消息框开启的时间也是要算到一个执行过程的执行时间中的,而我当初很谨慎的测试程序时,忽略了这一点——测试程序时没必要去记下消息框的内容,于是总立刻关掉消息框,此间并没有ontime事件的触发,进而每次得到的结果都是对的,全然不知留下了这个bug;而出错之后检查,会偶尔有消息框打开时在思考问题的情形发生,便导致了偶尔出错的发生。
Showmessage(),只是启发我想到这个问题。在程序编写时,如果用到计时器控件或计时性的代码,一定要谨慎考虑周全相关单元文件中影响时间的所有因素,代码的效率影响执行时间是比较容易联想到的因素,然showmessage()函数这类时间上受人为控制的因素也不能忽略。而程序运行后如结果不规律的出现错误,也不妨考虑一下这一点。

kuki84 2004-11-23
  • 打赏
  • 举报
回复
你把ShowMessage(ts.CommaText);去掉呢?不清楚你的其他代码是什么。
呆会发个文章,你看看有没有启发。一般实在找不到原因,可以考虑showmessage的问题
lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
兄弟,有QQ吗?QQ聊方便。7148668加我
cnhgj 2004-11-23
  • 打赏
  • 举报
回复
这一点我也不清楚,可能DLL的数据定义规则跟EXE有差别吧!
lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
我在dll里调PrePareReport()里为什么就报错。我全是动态生成的。
同一段代码copy到Exe里就一点错都没有?
cnhgj 2004-11-23
  • 打赏
  • 举报
回复
控件与DLL不同
我的理解,控件跟你的EXE是的一个整体,而DLL是调用外部的接口!
控件可以不说明DLL就可以。。就是你上面说的为什么在EXE里可以,在DLL里不行
lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
就象如下例子调用FastReport

procedure Test(AOwner:TCustomForm;qry1:TDataSet);
var
frx:TfrxDBDataset;
frxReport1:TfrxReport;
begin
frxReport1:=TfrxReport.Create(AOwner);
frx:=TfrxDBDataset.Create(AOwner);
frx.Name:='frxDBDataset1';
frx.UserName:='frxDBDataset1';
frx.DataSet:=qry1;
frxReport1.DataSet:=frx;
frxReport1.LoadFromFile('D:\test.fr3');
if frxReport1.PrepareReport() then
frxReport1.ShowReport();
frx.Free;
frxReport1.Free;
end;

在frxReport1.PrepareReport()时,FastReport会去调DB.pas里的GetFieldNames,你说TStrings怎么传进去?
lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
传TStrings进去是可以。不过为什么在dll里面建个TStrings就不行了。
而且现在关键是调用TDataSet.GetFieldNames的代码是在第三方组件里。那个TStringList不是我传进去的,是组件内部自己的。
有什么办法可以让他不报错。
cnhgj 2004-11-23
  • 打赏
  • 举报
回复
这样吧,你传TStrings进去

procedure Test(qry1:TDataSet;ts:TStrings);stdcall;
//var
// ts:TFieldList;
begin
//ts:=TFieldList.Create(qry1);//或ts:=TFieldList.Create(qry1);
qry1.GetFieldNames(ts);
ShowMessage(ts.CommaText);
ts.Free;
end;

exports
Test;

var
ts : TStrings;
begin
ts := TStringList.Create;
Test(adoquery1, ts);
end;

lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
to aiirii:不安全但是不应该出错吧
lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
放在单独的单元中当然没问题,你放在dll里,然后写个exe调一下试试
cnhgj 2004-11-23
  • 打赏
  • 举报
回复
测试了一下,放在单独的单元中没问题
aiirii 2004-11-23
  • 打赏
  • 举报
回复
>>procedure Test(qry1:TDataSet);
dll傳遞實例, 并不安全!
lxwsoft 2004-11-23
  • 打赏
  • 举报
回复
报TFieldList不能转换成TStringList;
源代码错误行在delphi的db.pas里。具体的为List.Assign(F....);
martian6125 2004-11-23
  • 打赏
  • 举报
回复
你的动态库里定义qry1这个东东了么
cnhgj 2004-11-23
  • 打赏
  • 举报
回复
什么错?

5,388

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 开发及应用
社区管理员
  • VCL组件开发及应用社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧