项目急急,麻烦Delphi高手帮我看看内存溢出问题

韩老猫 2018-05-13 12:06:27
厂家提供了CRT_310_NR01.dll动态库,封装了所有操作读卡器(串口访问设备)的方法函数,我自己写了个CRT_310_NR01Handler.pas负责具体的调用这个DLL的方法实现所有操作读卡器的功能,又创建了一个Form类ICCardTest.pas负责界面的操作,下面我把两个文件的源码都贴出来,目前经过我的测试,感觉是CRT_310_NR01Handler.pas文件写的有问题,在Delphi7环境下,只要一编译文件生成可执行EXE时,Delphi就报错“内存溢出”,麻烦Delphi高手帮我看看,就剩下150分都给了。
CRT_310_NR01Handler.pas文件源码:

unit CRT_310_NR01Handler;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, ShareMem, StdCtrls, TLoggerUnit;

const
//$30:弹出卡到前端;$31:回收卡;$36:弹出卡到后端;$38:弹出卡到前端不持卡位
InCardState : array[0..3] of Byte = ($30,$31,$36,$38);

//密码为
A_KEY: array[0..5] of Byte = ($00,$00,$00,$00,$00,$00);

//金额所在块
MONEY_BLOCK = $10;
MONEY_BLOCK_1 = $11;
Sector_Number = $04;

//金额检验位
MONEY_KEY: array[0..9] of Char = ('F','E','D','C','B','A','9','8','7','6');

type
TTrackInfo =packed record
ReadStute : String; //读卡状态
TrackData : String; //数据
end;
TPACKET=array[0..1024] of Byte;
//主类
TNR01Handler = class
private
{ Private declarations }
SHandles :THandle;
rec :integer;
FPortOpen :Boolean;
public
{ Public declarations }
//16位块数据
CardBlock :Array[0..15] of Byte;
//磁卡卡号数据
BankCard :string;
//磁卡二轨数据
MagCardSid :String;
//磁卡三轨数据
MagCardTid :string;
//IC卡号
ICCardNumber :string;
//卡内余额值
ICCardBalance :String;
//是否需要重新初始化读卡器硬件
YNInitICCard :Boolean;
//类初始化
Constructor Create(Aowner:TComponent);
destructor Destroy; override;
//打开串口
function OpenSerialPort(CardComPort :String;CardBaudRate :Integer): Boolean; stdcall;
//关闭串口
procedure CloseSerialPort(); stdcall;
//初始化读卡器
function InitICCardHandler(): Boolean; stdcall;
//串口是否已打开
function IsPortOpen(): Boolean;
//解析错误信息
procedure ICRWErrMsg(StError1:Byte;StError0:Byte); stdcall;
//操作硬件日志 ,出错时才写
procedure WriteOpLog(Memo: String); stdcall;
//设置前端禁止进卡方式
function NoCardIn() :Boolean; stdcall;
//查询电动读卡器内卡片状态
function CardStatus() :SmallInt; stdcall;
//设置前端开关进卡方式
function InCardBySwitch() :Boolean; stdcall;

end;

function CRT310NROpenWithBaut(Port:String;Const BautRate:Integer):THANDLE; stdcall; external 'CRT_310_NR01.dll';
Function CRT310NRClose(ComHandle:THANDLE):Integer; stdcall;external 'CRT_310_NR01.dll';
function CancelCommand(ComHandle: Integer): Integer; stdcall;external 'CRT_310_NR01.dll';
function RS232_ExeCommand(ComHandle: Integer; CmCode:Byte; CpCode:Byte;CmDatalen:Integer;CmData:TPACKET;var ReType:Byte;var St0:Byte;var St1:Byte;var ReDataLen:Integer;var ReData:TPACKET): Integer; stdcall;external 'CRT_310_NR01.dll';

var
NR01Handler :TNR01Handler;

implementation

constructor TNR01Handler.Create(Aowner:TComponent);
begin
SHandles := INVALID_HANDLE_VALUE;
rec :=0;
FPortOpen :=False;
YNInitICCard :=True;
inherited Create;
end;

destructor TNR01Handler.Destroy;
begin
if SHandles<>INVALID_HANDLE_VALUE then
begin
CloseHandle(SHandles);
FreeLibrary(SHandles);
end;
end;

//打开串口
function TNR01Handler.OpenSerialPort(CardComPort :String;CardBaudRate :Integer): Boolean; stdcall;
begin
Result := False;
FPortOpen :=False;
SHandles := INVALID_HANDLE_VALUE;
try
SHandles := CRT310NROpenWithBaut(CardComPort,CardBaudRate);
if SHandles<>INVALID_HANDLE_VALUE then
begin
FPortOpen := True;
Result :=True;
end else
Result := False;
except
WriteOpLog(CardComPort+'*'+IntToStr(CardBaudRate)+'*电动读卡器端口打开失败');
Result := false;
end;
end;

//关闭电动读卡器串口端口
procedure TNR01Handler.CloseSerialPort(); stdcall;
begin
if SHandles<>INVALID_HANDLE_VALUE then
begin
rec := CRT310NRClose(SHandles);
end;
end;

//初始化电动读卡器设备
function TNR01Handler.InitICCardHandler(): Boolean; stdcall;
var
CmData,ReData:TPACKET;
CmDataLen,ReDataLen,i :integer;
CmCode,PmCode,ReType,St1,St0 :Byte;
begin
Result :=False;
if SHandles = 0 then begin
Result :=False;
exit;
end;
for i := 0 to 1024 do begin
CmData[i]:=0 ;
ReData[i]:=0 ;
end;
CmCode:=$30;
PmCode:=$31;
CmDataLen:=13;
CmData[0]:= $33;
CmData[1]:= $32;
CmData[2]:= $34;
rec:=RS232_ExeCommand(SHandles,CmCode,PmCode,CmDataLen,CmData,ReType,St0,St1,ReDataLen,ReData);
if rec <> 0 then begin
Result :=False;
exit;
end;
if Retype=$50 then begin
Result :=True;
YNInitICCard :=False;
end
else if Retype=$4e then begin
Result :=False;
ICRWErrMsg(St0,St1);
end
else begin
WriteOpLog('Communication Error');
end ;
end;

function TNR01Handler.IsPortOpen(): Boolean;
begin
Result := FPortOpen;
end;

//记录详细的错误日志
procedure TNR01Handler.ICRWErrMsg(StError1:Byte;StError0:Byte); stdcall;
begin
WriteOpLog(' Error Code:'+chr(StError1)+chr(StError0));
YNInitICCard := True;
end;

//写硬件日志
procedure TNR01Handler.WriteOpLog(Memo: String); stdcall;
begin
TLogger.GetInstance.Debug('读卡器错误信息:'+Memo);
end;

//设置前端禁止进卡方式
function TNR01Handler.NoCardIn() :Boolean; stdcall;
var
CmData,ReData:TPACKET;
CmDataLen,ReDataLen,i :integer;
CmCode,PmCode,ReType,St1,St0 :Byte;
begin
Result :=False;
if SHandles = 0 then begin
Result :=False;
exit;
end;

for i := 0 to 1024 do begin
CmData[i]:=0 ;
ReData[i]:=0 ;
end;
CmCode:=$3A;
PmCode:=$31;
CmDataLen:=0;

rec:=RS232_ExeCommand(SHandles,CmCode,PmCode,CmDataLen,CmData,ReType,St0,St1,ReDataLen,ReData);

if rec <> 0 then begin
Result :=False;
exit;
end;
if Retype=$50 then begin
Result :=True;
end
else if Retype=$4e then begin
Result :=False;
ICRWErrMsg(St0,St1);
end
else begin
WriteOpLog('NoCardIn :Communication Error');
end ;
end;

//查询电动读卡器内卡片状态
function TNR01Handler.CardStatus() :SmallInt; stdcall;
var
CmData,ReData:TPACKET;
CmDataLen,ReDataLen,i :integer;
CmCode,PmCode,ReType,St1,St0 :Byte;
begin
Result :=0;
if SHandles = 0 then begin
Result :=0;
exit;
end;

for i := 0 to 1024 do begin
CmData[i]:=0 ;
ReData[i]:=0 ;
end;
CmCode:=$31;
PmCode:=$30;
CmDataLen:=0;

rec:=RS232_ExeCommand(SHandles,CmCode,PmCode,CmDataLen,CmData,ReType,St0,St1,ReDataLen,ReData);

if rec <> 0 then begin
Result :=0;
exit;
end;
if Retype=$50 then begin
case St1 of
$30 : Result :=1;//卡机内无卡(包括出卡口)
$31 : Result :=2;//出卡口处有一张卡
$32 : Result :=3;//卡机内有卡
end;
end
else if Retype=$4e then begin
Result :=0;
ICRWErrMsg(St0,St1);
end
else begin
WriteOpLog('CardStatus :Communication Error');
end ;
end;

//设置前端“开关”进卡方式
function TNR01Handler.InCardBySwitch() :Boolean; stdcall;
var
CmData,ReData:TPACKET;
CmDataLen,ReDataLen,i :integer;
CmCode,PmCode,ReType,St1,St0 :Byte;
begin
Result :=False;
if SHandles = 0 then begin
Result :=False;
exit;
end;

for i := 0 to 1024 do begin
CmData[i]:=0 ;
ReData[i]:=0 ;
end;
CmCode:=$3A;
PmCode:=$30;
CmDataLen:=1;
CmData[0]:=$30;
rec:=RS232_ExeCommand(SHandles,CmCode,PmCode,CmDataLen,CmData,ReType,St0,St1,ReDataLen,ReData);

if rec <> 0 then begin
Result :=False;
exit;
end;
if Retype=$50 then begin
Result :=True;
end
else if Retype=$4e then begin
Result :=False;
ICRWErrMsg(St0,St1);
end
else begin
WriteOpLog('InCardBySwitch :Communication Error');
end ;
end;

end.


ICCardTest.pas源码:

unit ICCardTest;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, CRT_310_NR01Handler;

type
TForm1 = class(TForm)
CommRateCombo: TComboBox;
CommPortCombo: TComboBox;
Label2: TLabel;
Label1: TLabel;
OpenCommPortBtn: TButton;
CloseCommPortBtn: TButton;
CardStatusBtn: TButton;
ReaderResetBtn: TButton;
btn1: TButton;
procedure OpenCommPortBtnClick(Sender: TObject);
procedure CloseCommPortBtnClick(Sender: TObject);
procedure ReaderResetBtnClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
NR01Handler :TNR01Handler;
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
NR01Handler := NR01Handler.Create(self);
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
if NR01Handler<>nil then
begin
NR01Handler.Free;
end;
end;

procedure TForm1.OpenCommPortBtnClick(Sender: TObject);
begin
NR01Handler.OpenSerialPort('COM2',38400);
if NR01Handler.IsPortOpen() then
ShowMessage('串口初始化成功!')
else
ShowMessage('串口打开失败!');
end;

procedure TForm1.CloseCommPortBtnClick(Sender: TObject);
begin
NR01Handler.CloseSerialPort();
end;

procedure TForm1.ReaderResetBtnClick(Sender: TObject);
begin
if NR01Handler.InitICCardHandler() then
ShowMessage('初始化成功')
else
ShowMessage('初始化失败');
end;

procedure TForm1.btn1Click(Sender: TObject);
begin
Close;
end;
end.


编译时Delphi7报错的提示窗口:


...全文
1808 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
天行归来 2018-05-15
  • 打赏
  • 举报
回复
引用 13 楼 weixin_41738800 的回复:
dll接口函数中String类型的定义的确有问题,我已经改成PChar类型了,但是编译还是能通过,同样问题一运行就报那个内存溢出错误,问题应该不是出在这里; 哪位大神能帮忙给调试一下,我可以把源码发给他,我的邮箱:42388176@qq.com,13909515455,酬金也可。 急、急、急!!!!
你把这块代码跟业务剥离出来,弄成一个设备调试小工具,代码放在百度网盘,别人就可以帮你找问题。
韩老猫 2018-05-15
  • 打赏
  • 举报
回复
dll接口函数中String类型的定义的确有问题,我已经改成PChar类型了,但是编译还是能通过,同样问题一运行就报那个内存溢出错误,问题应该不是出在这里; 哪位大神能帮忙给调试一下,我可以把源码发给他,我的邮箱:42388176@qq.com,13909515455,酬金也可。 急、急、急!!!!
SupermanTm 2018-05-15
  • 打赏
  • 举报
回复
引用 13 楼 weixin_41738800 的回复:
dll接口函数中String类型的定义的确有问题,我已经改成PChar类型了,但是编译还是能通过,同样问题一运行就报那个内存溢出错误,问题应该不是出在这里; 哪位大神能帮忙给调试一下,我可以把源码发给他,我的邮箱:42388176@qq.com,13909515455,酬金也可。 急、急、急!!!!
酬金就算了,发来给我帮你看看吧: 414474074@qq.com
hj8090 2018-05-14
  • 打赏
  • 举报
回复
dll接口函数中一般不会出现string,一般是pansichar,或者pwidechar。
  • 打赏
  • 举报
回复
function CRT310NROpenWithBaut(Port:String;Const BautRate:Integer):THANDLE; stdcall; external 'CRT_310_NR01.dll'; 这是厂家SDK中的声明还是你自己翻译的?
天行归来 2018-05-14
  • 打赏
  • 举报
回复
引用 5 楼 weixin_41738800 的回复:
我是在Delphi7环境下编写的,在编译的时候没有报错,一运行就直接报这个内存溢出错误了。我按照你说的做了如下改动: 1、TForm1中FormCreate里改成了“NR01Handler:= TNR01Handler.Create(Self);”; 2、取消了在TForm1的private中的“NR01Handler :TNR01Handler;”定义; 3、在CRT_310_NR01Handler.pas 中的Create里增加了“NR01Handler :=nil;”; 4、在CRT_310_NR01Handler.pas中的Destroy里增加调用下父类的destroy“inherited Destroy;”; 但是这次编译的时候还是通过了,但是一运行还是报内存溢出,但有了报错的提示位置,如下图:
提供信息不够,可以具体到调用哪个函数出错,另外提供下第三方dll接口原型,或许你在调用的时候,参数类型错误之类。
yuzhizhi 2018-05-14
  • 打赏
  • 举报
回复
用断点判断.这类似的情况主要是创建与回收这二个方面。 比如说:TNR01Handler.Create TNR01Handler.destroy. 是手动还是自动等。
cqs6616 2018-05-14
  • 打赏
  • 举报
回复
dll调用 不会用string的, 指针传递的
SupermanTm 2018-05-14
  • 打赏
  • 举报
回复
“3、在CRT_310_NR01Handler.pas 中的Create里增加了“NR01Handler :=nil;”;” 不是在Create里增加的,你既然要Create又怎会让它nil呢?应该在单元的 initialization 段里加。 你的内存溢出是在对象的内部TList成员添加元素时发生的,你可以再 View/Call stack看看调用链到底是哪个子程序调用
韩老猫 2018-05-13
  • 打赏
  • 举报
回复
我是在Delphi7环境下编写的,在编译的时候没有报错,一运行就直接报这个内存溢出错误了。我按照你说的做了如下改动:
1、TForm1中FormCreate里改成了“NR01Handler:= TNR01Handler.Create(Self);”;
2、取消了在TForm1的private中的“NR01Handler :TNR01Handler;”定义;
3、在CRT_310_NR01Handler.pas 中的Create里增加了“NR01Handler :=nil;”;
4、在CRT_310_NR01Handler.pas中的Destroy里增加调用下父类的destroy“inherited Destroy;”;
但是这次编译的时候还是通过了,但是一运行还是报内存溢出,但有了报错的提示位置,如下图:
SupermanTm 2018-05-13
  • 打赏
  • 举报
回复
procedure TForm1.FormCreate(Sender: TObject); begin NR01Handler := NR01Handler.Create(self); end; 这一句肯定错了,应该是 NR01Handler:= TNR01Handler.Create(Self); 另外,你的 NR01Handler 出现了两次定义,一次是 unit CRT_310_NR01Handler,作为一个全局变量 另一次是在 TForm1 的 private,作为 Form1的一个成员,这样肯定出现作用域上的冲突(你搞不清何时使用了哪一个) 建议去掉 TForm1 / private 里的那个,只保留全局变量定义,而且在 CRT_310_NR01Handler.pas 中写成 NR01Handler: TNR01Handler = nil; 初始化成nil
SupermanTm 2018-05-13
  • 打赏
  • 举报
回复
编译过程出错还是运行出错?
天行归来 2018-05-13
  • 打赏
  • 举报
回复
这种情况很像是哪个函数死循环调用。可以单步跟踪执行下 另外,创建NR01Handler有问题 procedure TForm1.FormCreate(Sender: TObject); begin NR01Handler := NR01Handler.Create(self); =>TNR01Handler.Create(self); end; Destroy函数最好也调用下父类的destroy,即 inherited;
lyhoo163 2018-05-13
  • 打赏
  • 举报
回复
F4 执行到光标处,再F8一步一步地执行,找到出错的代码。

5,392

社区成员

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

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