指针结构变量的DLL返回结果错误。

haj77 2012-02-03 11:00:39
最近需要编写一个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天了,不知道啥原因???
...全文
119 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
funxu 2012-02-04
  • 打赏
  • 举报
回复
别的不想说了,Lz的代码我调试过了,只要修改一些连编译都过不去的错误,还有按照我先前的提示,在外部申请和释放内存是可以运行的,对指针不了解情有可原,但是你贴出连编译都过不去的代码而且是相当明显的错误,这就说过不去了,不是么?
haj77 2012-02-03
  • 打赏
  • 举报
回复
刚才看了各位建议,将Pchar字符屏蔽,改下字段结构,全部为Byte类型
//定义刷卡记录结构
PEvent = ^TEvent;
TEvent = Packed record
DotID : Byte; //分控机号ID
CardType : Byte; //卡片类型
pNext : PEvent; //指针指向下一组卡
end;
调用dll后,同样只能取到指针第一个内容。
lzg827 2012-02-03
  • 打赏
  • 举报
回复
进DLL跟踪调试吧,好像问题代码的位置都还没找到。
ChipNo赋字符串的位置在DLL内部,问题不大,传入传出的时候注意用Pchar就可以了。
funxu 2012-02-03
  • 打赏
  • 举报
回复
代码太长没仔细看,给两个建议,
1 建议内存在外部申请,外部释放
2 GetMem( lpEvent, sizeof( TEvent ) * EventCount );
这里你申请空间时pchar只是个指针,getmem不会知道给pchar赋多大的地址空间,要么你申请足够大的空间去碰运气,要么把pchar改为char数组
而你给ChipNo赋字符串时,又把字符串的生命周期扯进来了,造成代码引用逻辑混乱
haj77 2012-02-03
  • 打赏
  • 举报
回复
现在是记录指针只能返回一条记录,本来有2条记录的。
bdmh 2012-02-03
  • 打赏
  • 举报
回复
那你就调试一下dll吧,或者记日志记录一下,特别是string类型,别的系统容易出问题
haj77 2012-02-03
  • 打赏
  • 举报
回复
现在可以确定,应该不是Pchar类型问题。
bdmh 2012-02-03
  • 打赏
  • 举报
回复
最好把你的pchar类型定义成定长的char数组,String类型也很不好
DelphiTeacher 2012-02-03
  • 打赏
  • 举报
回复
DLL里申请的内存要在DLL内释放,不然会出现内存泄露(像GetMemory出错啊,或是申请到了未空闲的内存)
你可以从DLL中导出一个释放内存的函数,然后用它来释放指针
haj77 2012-02-03
  • 打赏
  • 举报
回复
谢谢各位指点,重新修改了代码:
将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类型,同样调用报错。

16,749

社区成员

发帖
与我相关
我的任务
社区描述
Delphi 语言基础/算法/系统设计
社区管理员
  • 语言基础/算法/系统设计社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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