我编了一个DLL,里面有一个自定义类。然后在里面有一个类的实例。有创建,释放函数输出。有一个TLIST的函数总是不对。
procedure TLearnInfo.ReadAllRecord(var List: TList);
var
  Fp:TFileStream;
  Buf:^TCumRecode;
  i,Count:integer;
begin
  count:=RecCount;
  Fp:=TFileStream.Create(FFileName,fmOpenRead);
  Fp.Seek(0,soFromBeginning);
  for i:=0 to Count-1 do
  begin
    Fp.Seek(i*Sizeof(TCumRecode),soFromBeginning);
    GetMem(buf,Sizeof(TCumRecode));
    Fp.ReadBuffer(buf^,Sizeof(TCumRecode));
    List.Add(Buf);
  end;
  Fp.Free;
end;
这个函数在DLL中。
procedure ReadAllRecord(var List:Tlist);//输出函数
begin
  LearnInfo.ReadAllRecord(List);
end;
测试中,总是最后一个LIST.ITEM[*]释放时,总是出无效指针的错误。
但写在一个EXE程序中,没有任何错误,也没有内存泄露。这是为什么。我加了SHAREMM也没用,反而别的函数不能执行了。

解决方案 »

  1.   

    怎么没人呀?(在EXE中)总是最后一个LIST.ITEM[*]释放时,总是出无效指针的错误。
      

  2.   

    你把List更名看看,在DLL中,如果传入的名称与DLL中定义的名称一样的话,就有可能会出问题,怪现象,以前有见过.
      

  3.   

    GetMem 函数一般不适于用于给纪录分配内存, 但是可以给文件分配内存;
     你可以用new函数个纪录分配指针。procedure TLearnInfo.ReadAllRecord(var List: TList);
    var
      Fp: TFileStream;
      Buf: ^TCumRecode;
      i, Count: integer;
    begin
      count := RecCount;
      Fp: =T FileStream.Create(FFileName,fmOpenRead);
      Fp.Seek(0,soFromBeginning);
      for i:=0 to Count - 1 do
      begin
        Fp.Seek(i*Sizeof(TCumRecode),soFromBeginning);
        new(Buf);
        // 用文件信息填充纪录;
        // 可能不能用下面的方法填充,必须先分析出来。
        // 你可以先用常量填充作一些测试.
        //Fp.ReadBuffer(buf^,Sizeof(TCumRecode));
        List.Add(Buf);
      end;
      Fp.Free;
    end;
      

  4.   

    可能是 List.Add(Buf); 出错吧, DLL和主程序一般是不共享内存区域的,new(Buf); 或 GetMem(buf,Sizeof(TCumRecode));都是在DLL内申请空间,应该在释放的时候有无效指针的错误。
    试着将
    procedure TLearnInfo.ReadAllRecord(var List: TList);改为
    Function TLearnInfo.ReadAllRecord: TList;
    然后在主程序中进行
    List.Add(Buf); 吧.希望有些帮助.
      

  5.   

    我也想象楼上的那样做,可是“上面的”让做到DLL中。没办法呀!
    我试了换参数名,无效。
    注意:我出错是在EXE中释放最后一个list.items[i]中的指针出效指针的错误,前面是正常的。
    急.......
    “DLL和主程序一般是不共享内存区域的”如何共享呢?
      

  6.   

    在dll内创建、使用、销毁TList,以避免内存块分在不同的堆中。
      

  7.   

    Function TLearnInfo.ReadAllRecord: TList;
    var
      Fp:TFileStream;
      Buf:^TCumRecode;
      i,count:integer;
      a:TList;
    begin
      a:=TList.Create;
      count:=RecCount;
      Fp:=TFileStream.Create(FFileName,fmOpenRead);
      Fp.Seek(0,soFromBeginning);
      For i:=0 to Count-1 do
      begin
        Fp.Seek(i*SizeOf(TCumRecode),soFromBeginning);
        New(buf);
        Fp.ReadBuffer(buf^,SizeOf(TCumRecode));
        a.Add(buf);
      end;
      Fp.Free;
      Result:=a;
    end;
    更乱了,一会出无效,一会不出。
      

  8.   

    Fp.ReadBuffer(buf^,SizeOf(TCumRecode));
    这句华肯定不对了,你怎么肯定文件中的数据流就是内存的二进制形式要分析出来的。
      

  9.   

    在主程序里用
    List.Add(Buf);
      

  10.   

    procedure **************************
    var
      list:TList;
      i:integer;
      tmp:^TCumRecode;
    begin
      List:=TList.Create;
      ReadAllRecord(List);//DLL中的函数
      for i:=0 to list.Count-1 do
      begin
        tmp:=list.Items[i];
        ListBox1.Items.Add(DateTimeToStr(tmp^.UseDate));
        Dispose(tmp);
      end;
      List.Free;
    end;
    *********************************************
      

  11.   

    注意到你是用gemem分配内存的所以你必须用freemem释放内存。
    freemem(tmp, Sizeof(TCumRecode)); 
    我做了测试,当用dispose释放内存的时候,在程序退出的时候报非法指针。
    改成freemem后错误排除。
      

  12.   

    我的源程序是对应的,NEW,GETMEM都用对应的释放。你试试把分配资源写进DLL中
      

  13.   

    findcsdn(findcsdn)你不信给你源程序
      

  14.   

    我把dll改成下面的情况了type
      TCumRecode = record
        id: integer;
        name: string;
      end;procedure ReadAllRecord(var List: TList);
    var
      Buf: ^TCumRecode;
      i, Count: integer;
    begin
      count := 12;  for i := 0 to Count-1 do
      begin
        GetMem(buf, Sizeof(TCumRecode));
        buf.id := 2;
        buf.name := 'the name is ' + inttostr(I);
        List.Add(Buf);
      end;
    end;
      

  15.   

    findcsdn(findcsdn) 你会不会,回打
      

  16.   

    我试了两种方法,
    1。用sysgetmem在全局对内分配内存,然后用sysfreemem释放没有错。
    2。你把dispose的方法写在dll内,就是释放的时候访到dll中执行也没错。至于为什么在dll中分配内存和在exe中分配内存有什么不一样,我还没搞清楚。不过我调试的时候发现,他们申请的地址段不一样,而且间隔很大。还有就是数据结构中的string等的内存自动管理型的变量到底delphi是怎么管理的能够管理到何种程度我也不太清楚。我觉得还是用delphi推荐的pchar来表示字符串的好,能力有限呀,不过我会继续研究的。
      

  17.   

    别在DLL中free FP,在主程序中声明另一个TFileStream,然后Assign Dll中的Result,释放的时候,直接释放主程序中的TFileStream,就没问题了!
      

  18.   

    别在DLL中free FP,在主程序中声明另一个TFileStream,然后Assign Dll中的Result,释放的时候,直接释放主程序中的TFileStream,就没问题了!