首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在DLL中填充TStringList

在DLL中填充TStringList
EN

Stack Overflow用户
提问于 2012-08-02 12:37:25
回答 4查看 1.8K关注 0票数 3

我想在动态链接库中填充一个TStringList。对于内存管理文档,我的方法似乎是错误的,但它可以工作,不会导致错误或AV。

有人能告诉我,如果密码没问题吗?不确定如何在DLL中填充类。

代码语言:javascript
复制
programm EXE

function MyClass_Create: IMyClass; stdcall; external ...

var
  _myClass_DLL: IMyClass; //shared interface in exe and dll

procedure FillList;
var
  list: TStringList;      
begin
  list := TStringList.Create(true); //memory allocated in EXE
  try
    _myClass_DLL.FillList(list);  //memory allocated in DLL???
    ShowMessage(list.Text);
  finally
    list.Free; //memory freed in EXE, frees also TObject created in DLL
  end;
end;

DLL代码:

代码语言:javascript
复制
library DLL

TMyClass = class(TInterfacedObject, IMyClass)
public
  procedure FillList(aList: TStringList);
end;

procedure TMyClass.FillList(aList: TStringList);
begin
  aList.AddObject('Text1', TObject.Create); //memory allocation in DLL?
  aList.AddObject('Text2', TObject.Create); //memory allocation in DLL?
end;

我不使用BORLNDMM.DLL或任何其他ShareMem单元。

编辑:

我将aList.Add()调用扩展到aList.AddObject()。它也不会崩溃,尽管TObject是在DLL中创建并在EXE中释放的。

答案:

对于下面可接受的答案中的注释,该代码是正确的,因为exe和dll是用相同的delphi版本编译的,并且只调用虚拟方法。

结论:

只要使用虚拟方法或接口,内存管理就没有问题。这意味着,在何处创建或释放对象并不重要。

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-08-02 13:38:30

如果您希望跨模块边界传递类,则需要使用运行时包链接到RTL/VCL。这是确保DLL中的TStringList类与EXE中的类完全相同的唯一方法。这是当前方法的根本问题。另一方面,如果您已经使用运行时包链接到RTL,那么您就可以了。

如果您不想使用运行时包,那么需要完全重新设计您的界面。您需要停止跨模块边界传递类。您可以使用接口,但不能使用类。您需要控制内存分配,以确保总是在分配内存的模块中释放内存。或者开始使用ShareMem

票数 4
EN

Stack Overflow用户

发布于 2012-08-02 20:00:15

对于这种类型的功能,为了保持共享-mem无包,我将在dll中使用带有枚举器方法的回调。例如,这就是从windows检索字体的方法。下面是我所指的模拟:

代码语言:javascript
复制
type
  TMyClass = class
  private
    FList: TStringList;  // obv you need to construct this

  public
    function EnumListItem(s: string): integer;
  end;

function TMyClass.EnumListItem(s: string): integer;
begin
  FList.Add(s);
end;

procedure TMyClass.FillList;
begin
  _myClass_DLL.FillList(@EnumListItem);
  ShowMessage(FList.Text);
end;

这只是给你一个起点..。在DLL端,使用函数指针对程序进行回调,每次传入字符串1。

票数 2
EN

Stack Overflow用户

发布于 2012-08-02 15:31:14

如果您严重反对BPLs,那么您最好坚持DLL和接口的COM约定。

特别是在COM中有类似TStream的接口。并且VCL有TStreamAdapter类在COM IStream和VCL TStream之间进行转换。

通过这种方式,DLL应该创建一个数据流,并将其包装到COM IStream中并传递给exe。EXE将从TStream中转换回并填充字符串列表。

更快速和低技术的方法是感觉内存缓冲区,就像Windows函数所做的那样。他们不是感觉到了,就是返回程序错误,请求更大的缓冲区。那么,您将调用函数两次-获取缓冲区大小并执行实际工作。如果将指针类型(如PChar )混合为PAnsiChar或PWideChar,或者传递错误的缓冲区大小--您没有编译器提供的安全网,您只是损坏了内存。但这将比COM IStream更快。

也许您会使COM支持的缓冲区对象具有特殊类型的析构函数,而不是释放内存,而是传递对DLL后台空闲内存回忆线程的引用。因此,当主EXe中不再需要它时,它迟早会在DLL本身中被释放。它仍然不像TStream那样舒适,但至少不会让Heap经理失望。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/11777592

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档