奇怪的问题(100分)

  • 主题发起人 主题发起人 panwen
  • 开始时间 开始时间
P

panwen

Unregistered / Unconfirmed
GUEST, unregistred user!
我在DLL中写了一个函数,但是当程序两次调用这个函数后,在程序推出时就会出错,大家遇到过这样的问题吗?
函数的返回类型:boolean
函数有两个参数,都是指针类型的
其他没什么特别的
 
检查一下调用方式约定,一般都应声明为 stdcall 的。另外,指针是否存在多次释放?
 
使用的静态还是动态载入dll?
 
函数是怎样写的,是怎样调用的?错误提示又是怎样的??
 
这是DLL:

library BFMatRevLib;

uses
SysUtils,
BFMatRevInt,
Classes;

{$R *.res}
function BFOreRev(OreComponentTest:POreComponentTest;OreComponentRev:POreComponentRev):boolean;stdcall;
var
TFe_Test,P_Test,S_Test,FeO_Test,CaO_Test,MgO_Test,SiO2_Test,Al2O3_Test,
MnO_Test,K2O_Test,Na2O_Test,TiO2_Test,Lost_Test,Proportion_Test : Double
//检测成分
Name_Test : string;
TFe_Rev,P2O5_Rev,FeS2_Rev,FeO_Rev,Fe2O3_Rev,CaO_Rev,MgO_Rev,SiO2_Rev,
Al2O3_Rev,MnO2_Rev,K2O_Rev,Na2O_Rev,TiO2_Rev,Lost_Rev,Proportion_Rev : Double
//校正成分
Name_Rev : string;
Total_Component : Double;
iscomplete : boolean;
begin
{ //检测误差 P5 table 1-2
TFe_error := 0.5;
P_error := 0.005;
P2O5_error := P_error*142/62;
S_error := 0.005;
FeS2_error := S_error * 120 / 64;
FeO_error := 0.25
//待定
Fe2O3_error := (TFe_error - FeO_error*56/72 - FeS2_error*56/120)*160/112;
CaO_error := 0.4;
MgO_error := 0.25;
SiO2_error := 0.3;
Al2O3_error := 0.25;
MnO_error := 0.05;
MnO2_error := MnO_error*87/71;
Lost_error := 0.25;
Total_error := P2O5_error + FeS2_error + FeO_error + Fe2O3_error +
CaO_error + MgO_error + SiO2_error + Al2O3_error +
MnO2_error + Lost_error;
}
with OreComponentTest^ do
begin
TFe_Test := TFe;
P_Test := P;
S_Test := S;
FeO_Test := FeO;
CaO_Test := CaO;
MgO_Test := MgO;
SiO2_Test := SiO2;
Al2O3_Test := Al2O3;
MnO_Test := MnO;
K2O_Test := K2O;
Na2O_Test := Na2O;
TiO2_Test := TiO2;
Lost_Test := Lost;
Name_Test := OreName;
Proportion_Test := Proportion;
end;

TFe_Rev := TFe_Test;
P2O5_Rev := P_Test * 142 / 62;
FeS2_Rev := S_Test * 120 / 64;
FeO_Rev := FeO_Test - FeS2_Rev*72/120;
Fe2O3_Rev := (TFe_Rev - FeO_Rev*56/72 - FeS2_Rev*56/120)*160/112;
CaO_Rev := CaO_Test;
MgO_Rev := MgO_Test;
SiO2_Rev := SiO2_Test;
Al2O3_Rev := Al2O3_Test;
MnO2_Rev := MnO_Test*87/71;
K2O_Rev := K2O_Test;
Na2O_Rev := Na2O_Test;
TiO2_Rev := TiO2_Test;
Lost_Rev := Lost_Test;
Name_Rev := Name_Test;
Proportion_Rev := Proportion_Test;

with OreComponentRev^ do
begin
TFe := TFe_Rev;
P2O5 := P2O5_Rev;
FeS2 := FeS2_Rev;
FeO := FeO_Rev;
Fe2O3 := Fe2O3_Rev;
CaO := CaO_Rev;
MgO := MgO_Rev;
SiO2 := SiO2_Rev;
Al2O3 := Al2O3_Rev;
MnO2 := MnO2_Rev;
K2O := K2O_Rev;
Na2O := Na2O_Rev;
TiO2 := TiO2_Rev;
Lost := Lost_Rev;
Total_Component := P2O5 + FeS2 + FeO + Fe2O3 +
CaO + MgO + SiO2 + Al2O3 + MnO2 +
K2O + Na2O + TiO2 + Lost;
MeO := 100 - Total_Component;
OreName := Name_Rev;
Proportion := Proportion_Rev;
end;

if abs(100 - Total_Component)>3 then
iscomplete := false
else
iscomplete := true;

Result := iscomplete;

end;



exports
BFOreRev;
begin
end.
 
这是接口单元:

unit BFMatRevInt;

interface
type
TOreComponentTest = record
TFe,
P,
S,
FeO,
CaO,
MgO,
SiO2,
Al2O3,
MnO,
K2O,
Na2O,
TiO2,
Lost,
Proportion : double;
OreName : String;
end;
POreComponentTest = ^TOreComponentTest;

TOreComponentRev = record
TFe,
P2O5,
FeS2,
FeO,
Fe2O3,
CaO,
MgO,
SiO2,
Al2O3,
MnO2,
K2O,
Na2O,
TiO2,
Lost,
MeO,
Proportion : double;
OreName : String;
end;
POreComponentRev = ^TOreComponentRev;


function BFOreRev(OreComponentTest:POreComponentTest;OreComponentRev:POreComponentRev):boolean;stdcall;

implementation
function BFOreRev
external 'BFMatRevLib.DLL' name 'BFOreRev';

end.
 
这是两次调用:

procedure TForm_Ore.EnterButtonClick(Sender: TObject);
var
i : Integer;
IscompleteOre : boolean;
begin
//第一次调用
for i := 0 to RowOre - 1 do //RowOre 为一全局变量
begin
new(OreComponentTest);
new(OreComponentRev);

with OreComponentTest^ do
begin
OreName := LabelOreName.Caption;
TFe := StrtoFloat(OreTFe.Text);
P := StrtoFloat(OreP.Text);
S := StrtoFloat(OreS.Text);
FeO := StrtoFloat(OreFeO.Text);
CaO := StrtoFloat(OreCaO.Text);
MgO := StrtoFloat(OreMgO.Text);
SiO2 := StrtoFloat(OreSiO2.Text);
Al2O3 := StrtoFloat(OreAl2O3.Text);
MnO := StrtoFloat(OreMnO.Text);
K2O := StrtoFloat(OreK2O.Text);
Na2O := StrtoFloat(OreNa2O.Text);
TiO2 := StrtoFloat(OreTiO2.Text);
Lost := StrtoFloat(OreLost.Text);
Proportion := StrtoFloat(OreProportion.Text);
end;
IscompleteOre := BFOreRev(OreComponentTest,OreComponentRev);
end;

//第二次调用
for i := 0 to RowOre - 1 do
begin
with OreComponentTest^ do
begin
OreName := LabelOreName.Caption;
TFe := StrtoFloat(OreTFe.Text);
P := StrtoFloat(OreP.Text);
S := StrtoFloat(OreS.Text);
FeO := StrtoFloat(OreFeO.Text);
CaO := StrtoFloat(OreCaO.Text);
MgO := StrtoFloat(OreMgO.Text);
SiO2 := StrtoFloat(OreSiO2.Text);
Al2O3 := StrtoFloat(OreAl2O3.Text);
MnO := StrtoFloat(OreMnO.Text);
K2O := StrtoFloat(OreK2O.Text);
Na2O := StrtoFloat(OreNa2O.Text);
TiO2 := StrtoFloat(OreTiO2.Text);
Lost := StrtoFloat(OreLost.Text);
Proportion := StrtoFloat(OreProportion.Text);
end;

IscompleteOre := BFOreRev(OreComponentTest,OreComponentRev);
end;
Close;
end;
 
把两个record中的OreName : String;字段定义成定长字符数组
OreName : array[0..255] of char;
 
咦,铁、钙、锌、镁、钠、钾...成份?医药?
是这样用的吗
var
OreComponentTest:POreComponentTest;
OreComponentRev:POreComponentRev;
begin
...
New(OreComponentTest);
New(OreComponentRev);
try
if not BFOreRev(OreComponentTest,OreComponentRev) then
//do something
else
//do something
finally
Dispose(OreComponentTest);
Dispose(OreComponentRev);
end;
...
end;
 
加 var 试下
function BFOreRev([red]var[/red] OreComponentTest:POreComponentTest;
var OreComponentRev:POreComponentRev):boolean;stdcall;
 
指针、引用、对象变量之类的参数前不需要用var的。
 
OreComponentTest和OreComponentRev确实是全局变量,是指向记录的指针,因此进入函数后可以操作记录。
iscomplete先不用管它,以后再改。
OreComponentTest和OreComponentRev没有释放,应该在什么地方,因为在很多地方还要用到这两个记录数组。
 
我刚试过了,在退出程序时释放OreComponentTest和OreComponentRev,但问题依然存在,看来不是没有释放的原因,大家帮忙看看怎么回事
 
可以这样
//第一次为RowOre赋值时为OreComponentTest、OreComponentRev分配空间。这里假设是100;
RowOre:=100

for i:=0 to RowOre-1 do
begin
new(OreComponentTest);
new(OreComponentRev);
end

//仅仅分配空间即可。不必赋值,只待用时才赋值。

//以后每一次为RowOre赋值之前,释放OreComponentTest、OreComponentRev的空间、资源
if RowOre>0 then
for i:=0 to RowOre-1 do
begin
Dispose(OreComponentTest);
Dispose(OreComponentRev)

end;
RowOre:=100
//假设
//重新为OreComponentTest、OreComponentRev分配空间。
for i:=0 to RowOre-1 do
begin
new(OreComponentTest);
new(OreComponentRev);
end;

程式退出时记得释放一次

为什么每次RowOre变化时,就要释放并分配空间??
假设开始RowOre为100,那两数组也分配了100个单位;
第二次RowOre为200,两数组不释放并分配的话,能访问99以后的数据吗?
 
我之所以把OreComponentTest和OreComponentRev设成全局变量就是想在程序开始给这两个记录数组赋值后,在程序的其他地方可以用这两组记录,如果在用之前都已经被释放掉了,就没有意义了。还有别的方法可以解决这个问题吗?
 
既然这样
那么下一次RowOre发生变化时也跟着改一下
var
iOreTest,iOreRev:Integer;
...
RowOre:=200
//假设
iOreTest:=High(OreComponentTest)
//记录旧值
iOreRev:=High(OreComponentRev)
//记录旧值

if RowOre>iOreRev then //比较一下,是否要新增;否则不管它,让它留着好了。
for i:=iOreRev to RowOre do
New(OreComponentRev);

if RowOre>iOreTest then
for i:=iOreTest to RowOre do
New(OreComponentTest);
这样的话,两个数组中旧的值可以修改,新的值也可以加进来。
最后释放时
for i:=Low(OreComponentRev) to High(OreComponentRev) do
Dispose(OreComponentRev);

for i:=Low(OreComponentTest) to High(OreComponentTest) do
Dispose(OreComponentTest);
 
现在主要的问题还不是RowOre变化的问题,而是两次给记录赋值后程序退出时会报错。

var
i : Integer;
IscompleteOre : boolean;
begin
//第一次调用
for i := 0 to RowOre - 1 do //RowOre 为一全局变量
begin
new(OreComponentTest);
new(OreComponentRev);

with OreComponentTest^ do
begin
OreName := LabelOreName.Caption;
TFe := StrtoFloat(OreTFe.Text);
P := StrtoFloat(OreP.Text);
S := StrtoFloat(OreS.Text);
FeO := StrtoFloat(OreFeO.Text);
CaO := StrtoFloat(OreCaO.Text);
MgO := StrtoFloat(OreMgO.Text);
SiO2 := StrtoFloat(OreSiO2.Text);
Al2O3 := StrtoFloat(OreAl2O3.Text);
MnO := StrtoFloat(OreMnO.Text);
K2O := StrtoFloat(OreK2O.Text);
Na2O := StrtoFloat(OreNa2O.Text);
TiO2 := StrtoFloat(OreTiO2.Text);
Lost := StrtoFloat(OreLost.Text);
Proportion := StrtoFloat(OreProportion.Text);
end;
IscompleteOre := BFOreRev(OreComponentTest,OreComponentRev);
end;
[red]***********************************
for i := 0 to RowOre - 1 do //当加入这段语句后程序退出时就正常
begin //难道给指针变量第二次赋值前都要先释放?
dispose(OreComponentTest);
dispose(OreComponentRev);
end;
***********************************[/red]

//第二次调用
for i := 0 to RowOre - 1 do
begin
with OreComponentTest^ do
begin
OreName := LabelOreName.Caption;
TFe := StrtoFloat(OreTFe.Text);
P := StrtoFloat(OreP.Text);
S := StrtoFloat(OreS.Text);
FeO := StrtoFloat(OreFeO.Text);
CaO := StrtoFloat(OreCaO.Text);
MgO := StrtoFloat(OreMgO.Text);
SiO2 := StrtoFloat(OreSiO2.Text);
Al2O3 := StrtoFloat(OreAl2O3.Text);
MnO := StrtoFloat(OreMnO.Text);
K2O := StrtoFloat(OreK2O.Text);
Na2O := StrtoFloat(OreNa2O.Text);
TiO2 := StrtoFloat(OreTiO2.Text);
Lost := StrtoFloat(OreLost.Text);
Proportion := StrtoFloat(OreProportion.Text);
end;

IscompleteOre := BFOreRev(OreComponentTest,OreComponentRev);
end;
Close;
end;
 
有人知道是怎么回事吗?
 
没时间看代码,原因是不是该释放的没释放,不需要创建的又创建了?
 
我时在FormCreat()中创建的,然后在button1.click()中调用了一次,在button2.click()中又调用了第二次,然后在FormClose()中释放
 
后退
顶部