最近需要编写一个DLL文件,供其他系统调用,目的是返回大量数据记录,记录结构包括:卡号、时间、机号。
DLL程序如下:
uses
ShareMem, SysUtils...; // 使用到ShareMem
type
//定义刷卡记录结构
PEvent = ^TEvent;
TEvent = Packed record
ChipNo : Pchar; //芯片号码
DotID : Byte; //分控机号ID
Time : Pchar; //刷卡时间
CardType : Byte; //卡片类型
pNext : PEvent; //指针指向下一组卡
end;
//NetIp--设备IP EventCount--返回的总记录数 lpEvent--记录指针
Function GetEvent(NetIp:Pchar;Var EventCount:Word;var lpEvent: PEvent):LongInt; stdcall;
var
EventCount : Word;
pNext : PEvent;
m ,DevID : Integer;
ChipNo ,dTime :String;
begin
EventCount := 2 ;
GetMem( lpEvent, sizeof( TEvent ) * EventCount ); //lpEvent作为变量,在此分配内存 ,不知道对不?
pNext := lpEvent;
For m :=1 to EventCount do
begin
ChipNo :='4A5B3E12'; //芯片号码
dTime :='20111213234512';//刷卡时间
DevID := 1; //刷卡设备 Buffer := AllocMem(Length(ChipNo)+1);
StrpCopy(Buffer,Pchar(ChipNo));
pNext^.ChipNo :=Buffer ;
pNext^.DotID :=DevID; Buffer := AllocMem(Length(dTime)+1);
StrpCopy(Buffer,Pchar(dTime));
pNext^.Time :=Buffer; if M<>EventCount-1 then
begin
pNext^.pNext := PEvent( DWord( pNext ) + sizeof( TEvent ) );
pNext := pNext^.pNext;
end
else
begin
pNext^.pNext := nil;
end;
end;
Result :=0;
end;
主程序如下:
TGetEvent =Function(NetIp:Pchar;Var EventCount:Word;var lpEvent: PEvent):LongInt; stdcall;
procedure TTestMain_Frm.Button15Click(Sender: TObject);
var
Rest : Longint;
NetIp : Pchar;
pCard : PEvent;
begin
NetIp := Pchar('192.168.1.1');
//GetMem( pCard, sizeof( TEvent ) * 2); // 定义内存空间也报错!
Rest := GetEvent (NetIp,EventCount,pCard);
if Rest=0 then
begin
for i:=0 to 1 do //这里只能取到到最后一条记录,循环2次就报错!
begin
if ppNext <> nil then
begin
Str := IntToStr(i+1)+' 卡芯片号码:'+Pchar(ppNext^.ChipNo)+ ' 卡类型:'+IntToStr(ppNext^.CardType);
memo1.Lines.Add(str);
ppNext := ppNext^.pNext;
end
else break;
end ;
dispose(pCard); //释放变量指针内存。
end;
end;问题:
DLL代码如果不封装,直接放到Delphi中,以上代码没有问题,能取到2条记录;但是封装DLL后,调用,就报错,这个DLL还用提供其他语言使用,搞了2天了,不知道啥原因???
DLL程序如下:
uses
ShareMem, SysUtils...; // 使用到ShareMem
type
//定义刷卡记录结构
PEvent = ^TEvent;
TEvent = Packed record
ChipNo : Pchar; //芯片号码
DotID : Byte; //分控机号ID
Time : Pchar; //刷卡时间
CardType : Byte; //卡片类型
pNext : PEvent; //指针指向下一组卡
end;
//NetIp--设备IP EventCount--返回的总记录数 lpEvent--记录指针
Function GetEvent(NetIp:Pchar;Var EventCount:Word;var lpEvent: PEvent):LongInt; stdcall;
var
EventCount : Word;
pNext : PEvent;
m ,DevID : Integer;
ChipNo ,dTime :String;
begin
EventCount := 2 ;
GetMem( lpEvent, sizeof( TEvent ) * EventCount ); //lpEvent作为变量,在此分配内存 ,不知道对不?
pNext := lpEvent;
For m :=1 to EventCount do
begin
ChipNo :='4A5B3E12'; //芯片号码
dTime :='20111213234512';//刷卡时间
DevID := 1; //刷卡设备 Buffer := AllocMem(Length(ChipNo)+1);
StrpCopy(Buffer,Pchar(ChipNo));
pNext^.ChipNo :=Buffer ;
pNext^.DotID :=DevID; Buffer := AllocMem(Length(dTime)+1);
StrpCopy(Buffer,Pchar(dTime));
pNext^.Time :=Buffer; if M<>EventCount-1 then
begin
pNext^.pNext := PEvent( DWord( pNext ) + sizeof( TEvent ) );
pNext := pNext^.pNext;
end
else
begin
pNext^.pNext := nil;
end;
end;
Result :=0;
end;
主程序如下:
TGetEvent =Function(NetIp:Pchar;Var EventCount:Word;var lpEvent: PEvent):LongInt; stdcall;
procedure TTestMain_Frm.Button15Click(Sender: TObject);
var
Rest : Longint;
NetIp : Pchar;
pCard : PEvent;
begin
NetIp := Pchar('192.168.1.1');
//GetMem( pCard, sizeof( TEvent ) * 2); // 定义内存空间也报错!
Rest := GetEvent (NetIp,EventCount,pCard);
if Rest=0 then
begin
for i:=0 to 1 do //这里只能取到到最后一条记录,循环2次就报错!
begin
if ppNext <> nil then
begin
Str := IntToStr(i+1)+' 卡芯片号码:'+Pchar(ppNext^.ChipNo)+ ' 卡类型:'+IntToStr(ppNext^.CardType);
memo1.Lines.Add(str);
ppNext := ppNext^.pNext;
end
else break;
end ;
dispose(pCard); //释放变量指针内存。
end;
end;问题:
DLL代码如果不封装,直接放到Delphi中,以上代码没有问题,能取到2条记录;但是封装DLL后,调用,就报错,这个DLL还用提供其他语言使用,搞了2天了,不知道啥原因???
解决方案 »
- 关于日期问题
- 再请教一个SQL语句问题,多谢:)
- 在读ini文件时,如果某个标签的值在不断变化怎么读取?
- 用DBGrid控件显示数据的奇怪问题!急!!!! 就这么多分了,全部了
- 有问题求救!UP有分!
- listview拖动的问题,拖动后itemindex不改变
- 高手挑站:菜鸟大放100分,如何在自己已有的特色上再继承其它FORM,使得在设计期间,就可看到被继承窗体的控件?
- 关于delphi使用blob字段的问题!
- 怎样在系统菜单中加入自己的子项,像winzip那样add to zip ?????
- 究竟如何实现TImage和Printer的转化???
- stringgrid 的问题!
- 求Delphi怎样快速搜索游戏的内存啊?
1 建议内存在外部申请,外部释放
2 GetMem( lpEvent, sizeof( TEvent ) * EventCount );
这里你申请空间时pchar只是个指针,getmem不会知道给pchar赋多大的地址空间,要么你申请足够大的空间去碰运气,要么把pchar改为char数组
而你给ChipNo赋字符串时,又把字符串的生命周期扯进来了,造成代码引用逻辑混乱
ChipNo赋字符串的位置在DLL内部,问题不大,传入传出的时候注意用Pchar就可以了。
//定义刷卡记录结构
PEvent = ^TEvent;
TEvent = Packed record
DotID : Byte; //分控机号ID
CardType : Byte; //卡片类型
pNext : PEvent; //指针指向下一组卡
end;
调用dll后,同样只能取到指针第一个内容。
将Pchar字符屏蔽,改下字段结构,全部为Byte类型,去掉所有PChar变量、参数,就返回Byte数据
//定义刷卡记录结构
PEvent = ^TEvent;
TEvent = Packed record
DotID : Byte; //分控机号ID
CardType : Byte; //卡片类型
pNext : PEvent; //指针指向下一组卡
end; //EventCount--返回的总记录数 lpEvent--记录指针
Function GetEvent(Var EventCount:Word;var lpEvent: PEvent):LongInt; stdcall;
var
EventCount : Word;
pNext : PEvent;
m ,DevID : Integer;
ChipNo ,dTime :String;
begin
EventCount := 2 ;
GetMem( lpEvent, sizeof( TEvent ) * EventCount ); pNext := lpEvent;
For m :=1 to EventCount do
begin
pNext^.DotID :=1;
pNext^.CardType:=M;
if M<>EventCount then //以前贴上来临时写错
begin
pNext^.pNext := PEvent( DWord( pNext ) + sizeof( TEvent ) );
pNext := pNext^.pNext;
end
else
begin
pNext^.pNext := nil;
end;
end;
Result :=0;
end;
主程序如下:
TGetEvent =Function(Var EventCount:Word;var lpEvent: PEvent):LongInt; stdcall;
procedure TTestMain_Frm.Button15Click(Sender: TObject);
var
Rest : Longint;
pCard : PEvent;
begin
//GetMem( pCard, sizeof( TEvent ) * 2); // 定义内存空间也报错!
Rest := GetEvent (EventCount,pCard);
if Rest=0 then
begin
for i:=0 to 1 do //这里只能取到到最后一条记录,循环2次就报错!
begin
if pCard<> nil then
begin
Str := IntToStr(i+1)+' 卡芯片号码:'+Pchar(pCard^.ChipNo)+ ' 卡类型:'+IntToStr(pCard^.CardType);
memo1.Lines.Add(str);
ppNext := pCard^.pNext;
end
else break;
end ;
dispose(pCard); //释放变量指针内存。
end;
end;
以上修改:全掉所有PChar类型,同样调用报错。
你可以从DLL中导出一个释放内存的函数,然后用它来释放指针