在DLL程序和调用程序中都定义了如下的记录类型数据.
TRecordInfo = packed record
BH : string; //表号
UserID : string; // 用户号
BCCM : string; //本次抄码
BYSL : string; //本月用水量
Alarm : String; //报警信息
BLX : string; //表类型
PointPos : string; //小数点位置
end;
TDynamicArray = array of TRecordInfo;且在DLL和调用程序中都引用了ShareMem;程序调用如下:procedure TfTest.Button6Click(Sender: TObject);
var
GroupNo:Integer;
Temp : string;
i,RecordNum:integer;
RecordInfo : TDynamicArray;
begin
GroupNo:=StrToInt(edtGroupNo.Text);
RecordNum := GetGroupRecordInfo(GroupNo,RecordInfo);
case RecordNum of
-1: application.MessageBox('串口未打开','信息提示',MB_OK);
-2: application.MessageBox('连接超时','信息提示',MB_OK);
-3: application.MessageBox('返回数据错误','信息提示',MB_OK);
else
begin
Temp :='';
try
Temp:='BH UserID BCCM BYSL BLX PointPos ' + chr(13);
for i:=0 to RecordNum-1 do
begin
Temp := Temp + RecordInfo[i].BH + ' ' + RecordInfo[i].UserID + ' ' + RecordInfo[i].BCCM + ' ' + RecordInfo[i].BYSL + ' ' + RecordInfo[i].BLX + ' ' + RecordInfo[i].PointPos + chr(13);
end;
except
on e:Exception do
ShowMessage(e.Message);
end;
ShowMessage(temp);
end;
end;
end;
上面这段程序调用DLL中的函数可以取出数据也没有什么问题,可当我退出调用DLL的程序时会出现如下的错误:
---------------------------
Debugger Exception Notification
---------------------------
Project TestDLL.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'. Process stopped. Use Step or Run to continue.
---------------------------还有各位赐教.这是什么问题引起的.
TRecordInfo = packed record
BH : string; //表号
UserID : string; // 用户号
BCCM : string; //本次抄码
BYSL : string; //本月用水量
Alarm : String; //报警信息
BLX : string; //表类型
PointPos : string; //小数点位置
end;
TDynamicArray = array of TRecordInfo;且在DLL和调用程序中都引用了ShareMem;程序调用如下:procedure TfTest.Button6Click(Sender: TObject);
var
GroupNo:Integer;
Temp : string;
i,RecordNum:integer;
RecordInfo : TDynamicArray;
begin
GroupNo:=StrToInt(edtGroupNo.Text);
RecordNum := GetGroupRecordInfo(GroupNo,RecordInfo);
case RecordNum of
-1: application.MessageBox('串口未打开','信息提示',MB_OK);
-2: application.MessageBox('连接超时','信息提示',MB_OK);
-3: application.MessageBox('返回数据错误','信息提示',MB_OK);
else
begin
Temp :='';
try
Temp:='BH UserID BCCM BYSL BLX PointPos ' + chr(13);
for i:=0 to RecordNum-1 do
begin
Temp := Temp + RecordInfo[i].BH + ' ' + RecordInfo[i].UserID + ' ' + RecordInfo[i].BCCM + ' ' + RecordInfo[i].BYSL + ' ' + RecordInfo[i].BLX + ' ' + RecordInfo[i].PointPos + chr(13);
end;
except
on e:Exception do
ShowMessage(e.Message);
end;
ShowMessage(temp);
end;
end;
end;
上面这段程序调用DLL中的函数可以取出数据也没有什么问题,可当我退出调用DLL的程序时会出现如下的错误:
---------------------------
Debugger Exception Notification
---------------------------
Project TestDLL.exe raised exception class EInvalidPointer with message 'Invalid pointer operation'. Process stopped. Use Step or Run to continue.
---------------------------还有各位赐教.这是什么问题引起的.
CloseComPort()这个DLL中的函数如下: function CloseComPort():Integer ;stdcall;
begin
Result := frmZHCJQ.CloseComPort;//关闭前面打的的串口
ReleaseDLLRes;//释放DLL中创建窗体的资源
end;
其它的就没有访问了.
Debugger Exception Notification
---------------------------
Project TestDLL.exe raised exception class EAccessViolation with message 'Access violation at address 21C14667. Read of address 21C14667'. Process stopped. Use Step or Run to continue.
---------------------------
To:fuzhong 在DLL中没有涉及到数据库的连接.-------------------------------------To:bdmh这个关闭过程中如何设置断点进行跟踪.
貼下工程的開始代碼。和DLL中的函數出來。
一般是这样:
从主调中生成结构体,并定义结构体指针,再定义数组指针,把地址传入dll,dll接收指针,按类型提取数据!
另外如果稍微想公共一些的话,最好在结构体内用基础类型,如Char(10)等,也避免了在释放结构体时不小心造成的结构体内部对象的内存泄露!
library ZHCJQ;{ ...}uses
ShareMem,
SysUtils,
Classes,
Activex,
UnitZHCJQ in 'UnitZHCJQ.pas' {frmZHCJQ};{$R *.res}
//type
//TDynamicArray = array of TRecordInfo;
procedure InitDLL;
begin
CoInitialize(nil);
if not Assigned(frmZHCJQ) then
frmZHCJQ := TfrmZHCJQ.Create(nil);
CoUnInitialize();
end;
procedure ReleaseDLLRes;stdcall;
begin
FreeAndNil(frmZHCJQ);
end;
{============================================================================
函数说明:function OpenComPort(Port : Integer): Integer;stdcall;
函数功能: 打开指定串口号
函数参数:Port : 打开的串口号
函数返回: 0: 成功打开串口
-1: 串口已经打开
-2: 打开串口出现错误
创建日期: 2008-01-30
修改日期: <序号> <作者> <时间> <版本> <描述>
=============================================================================}
function OpenComPort(Port : Integer): Integer;stdcall;
begin
InitDLL;
Result := frmZHCJQ.OpenComPort(Port);
//ReleaseDLLRes;
end;
{============================================================================
函数说明:Function CloseComPort(): Integer;stdcall;
函数功能: 关闭串口
函数参数:无
函数返回: 0: 成功成功串口
-1: 串口已经关闭
-2: 关闭串口出现错误
创建日期: 2008-01-30
修改日期: <序号> <作者> <时间> <版本> <描述>
=============================================================================}
function CloseComPort():Integer ;stdcall;
begin
if not Assigned(frmZHCJQ) then
Exit;
Result := frmZHCJQ.CloseComPort;
ReleaseDLLRes;
//ReleaseDLLRes;
end;
//......多个函数省略
{============================================================================
函数说明:Function GetGroupRecordInfo(GroupNo:Integer;var RecordInfo : TDynamicArray):Integer;stdcall;
函数功能: 获取手抄机中GroupNo组中的水表记录信息(包括水表号、用户号、报警信息、本次抄码)。
函数参数:GroupNo:显示器组数
函数返回:RecordInfo: 返回一个记录型数组,每组的数据保存在这里面
>0: GroupNo组中的水表数量
-1: 串口未打开
-2: 连接超时(即读取时间过了还没有读到相关的数据)
-3: 返回数据有误
创建日期: 2008-01-30
修改日期: <序号> <作者> <时间> <版本> <描述>
1 ZhengJianxian 2009-03-27
作 者:ZhengJianxian
=============================================================================}
function GetGroupRecordInfo(GroupNo:Integer;var RecordInfo : TDynamicArray):Integer ;stdcall
begin
//InitDLL;
Result:=frmZHCJQ.GetGroupRecordInfo(GroupNo,RecordInfo);
end;exports
OpenComPort,
CloseComPort,
GetSCJType,
GetGroupNum,
GetRecordNum,
GetGroupRecordNum,
GetGroupRecordInfo,
ClearRecordData,
ReleaseDLLRes;
GetGroupRecordInfo函数如下:
{============================================================================
函数说明:Function GetGroupRecordInfo(GroupNo:Integer;var RecordInfo : TDynamicArray):Integer;
函数功能: 获取手抄机中GroupNo组中的水表记录信息(包括水表号、用户号、报警信息、本次抄码)。
函数参数:GroupNo:显示器组数
函数返回:>0: GroupNo组中的水表数量
-1: 串口未打开
-2: 连接超时(即读取时间过了还没有读到相关的数据)
-3: 返回数据有误
创建日期: 2008-01-30
修改日期: <序号> <作者> <时间> <版本> <描述>
=============================================================================}
function TfrmZHCJQ.GetGroupRecordInfo(GroupNo:Integer;var RecordInfo : TDynamicArray): Integer ;
var
SendCmd : array of byte; //发送命令数组
ReceiveData : array of byte; //接收采集器数据数组
TBackRecord : array of byte;
TimeOut : integer; //超时标志
Jyh ,i: integer; //校验采集器返回数据校验码
begin
try
SetLength(SendCmd,5); //设备命令数组的长数
//将命令存入数组中
SendCmd[0]:=$1E;
SendCmd[1]:=$02;
//查询第n组的数据---这里CommandData[2]与 CommandData[3]两个字节来表示一个四位的十六进制数
SendCmd[2]:=StrToInt('$'+LeftStr(IntToHex(GroupNo,4),2));
SendCmd[3]:=StrToInt('$'+RightStr(IntToHex(GroupNo,4),2));
//SendCmd[2]:=$00;
//SendCmd[3]:=$01;
//对前面的命令进行校验,即为校验码
SendCmd[4]:=(SendCmd[0]+SendCmd[1]+SendCmd[2]+SendCmd[3]) and $FF;
if mscm1.PortOpen=True then
begin
mscm1.Output:=SendCmd; // 将命令发送给采集器
Sleep(300);
mscm1.InputLen:=5; //表示取缓冲区中前五个字节数据
TimeOut:=1;
while mscm1.PortOpen=True do
begin
if mscm1.InBufferCount>=5 then
Begin
ReceiveData:=mscm1.Input; //将数据保存在ReceiveData中
break;
end
else
begin
if TimeOut>8000 then
begin
//showmessage('连接设备超时,请检查设备的数据线并查看设备是否开启!');
Result:=-2;
exit;
end
else
TimeOut:=Timeout+1;
end;
end; // end while
mscm1.InputLen:=0; //表示取缓冲区中的所有数据
repeat
//循环等待所有的数据都保存在缓冲区时,退出循环
until mscm1.InBufferCount=ReceiveData[4];
TBackRecord:=mscm1.Input;
//校验返回数据
Jyh:=(frmZHCJQ.JiaoYianHe(TBackRecord) + frmZHCJQ.JiaoYianHe(ReceiveData) + ReceiveData[4]) mod 256;
//application.MessageBox(pchar(Temp),'提示信息',MB_OK);
//校验数据正确则进行采集数据
if Jyh=TBackRecord[ReceiveData[4]-1] then
begin
//读取AAT采集器数据
if (ReceiveData[0]=$1A) and (ReceiveData[1]=$02) then
begin
SetLength(RecordInfo,TBackRecord[5] div 12);
for i:=1 to TBackRecord[5] div 12 do
begin
//New(RecordInfo[i]);
try
RecordInfo[i-1].BH :=IntToHex(TbackRecord[0],2)+IntToHex(TBackRecord[1],2)+IntToHex(TBackRecord[2],2)+IntToHex(TBackRecord[3],2);
RecordInfo[i-1].UserID:=IntToHex(TBackRecord[(i-1)*12+8],2)+IntToHex(TBackRecord[(i-1)*12+9],2); //获取表用户号
RecordInfo[i-1].BLX:=Copy(IntToHex(TBackRecord[(i-1)*12+7],2),1,1); //获取表类型
RecordInfo[i-1].PointPos:=Copy(IntToHex(TBackRecord[(i-1)*12+7],2),0,1); //获取小数点的位数
//获取表水量
RecordInfo[i-1].BCCM:=IntToHex(TBackRecord[(i-1)*12+10],2)+IntToHex(TBackRecord[(i-1)*12+11],2)+IntToHex(TBackRecord[(i-1)*12+12],2)+IntToHex(TBackRecord[(i-1)*12+13],2);
//将小数位数插入到表水量中,使之得到实际的水量值
//RecordInfo[i-1].BCCM:=GetLeft(pchar(BSL),StrLen(pchar(BSL))-StrToInt(BSLPoint))+'.'+GetRight(BSL,StrToInt(BSLPoint));
except
on e:Exception do
ShowMessage(e.Message);
end;
end; //end for
//RecordInfo:=nil;
Result := TBackRecord[5] div 12;
end
else
begin
Result:=-3; //CRC校验不通过,即返回数据有错
exit;
end;
end
else
begin
result:=-1; //串口未打开
exit;
end;
except
on e:Exception do
ShowMessage(e.Message);
end;
end;
program TestDLL;uses
ShareMem,
Forms,
Test in 'Test.pas' {fTest};{$R *.res}begin
Application.Initialize;
Application.CreateForm(TfTest, fTest);
Application.Run;
end.
汗~~~不知道什么原因引起的.代码中所调用的函数已经贴出来的.
ReleaseDLLRes;
问题最大,看不到代码
var
GroupNo:Integer;
Temp : string;
i,RecordNum:integer;
RecordInfo : TDynamicArray;
begin
GroupNo:=StrToInt(edtGroupNo.Text);
setLength(RecordInfo,10); // 先分配內存試下。
RecordNum := GetGroupRecordInfo(GroupNo,RecordInfo);
case RecordNum of
-1: application.MessageBox('串口未打开','信息提示',MB_OK);
-2: application.MessageBox('连接超时','信息提示',MB_OK);
-3: application.MessageBox('返回数据错误','信息提示',MB_OK);
else
begin
Temp :='';
try
Temp:='BH UserID BCCM BYSL BLX PointPos ' + chr(13);
for i:=0 to RecordNum-1 do
begin
Temp := Temp + RecordInfo[i].BH + ' ' + RecordInfo[i].UserID + ' ' + RecordInfo[i].BCCM + ' ' + RecordInfo[i].BYSL + ' ' + RecordInfo[i].BLX + ' ' + RecordInfo[i].PointPos + chr(13);
end;
except
on e:Exception do
ShowMessage(e.Message);
end;
ShowMessage(temp);
end;
end;
end;
当然我在程序里添加这个发现也没有什么错误.程序运行也是可以的.
你调试一下,看看dll中哪里报错