我想在动态链接库中填充一个TStringList。对于内存管理文档,我的方法似乎是错误的,但它可以工作,不会导致错误或AV。
有人能告诉我,如果密码没问题吗?不确定如何在DLL中填充类。
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代码:
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版本编译的,并且只调用虚拟方法。
结论:
只要使用虚拟方法或接口,内存管理就没有问题。这意味着,在何处创建或释放对象并不重要。
发布于 2012-08-02 13:38:30
如果您希望跨模块边界传递类,则需要使用运行时包链接到RTL/VCL。这是确保DLL中的TStringList类与EXE中的类完全相同的唯一方法。这是当前方法的根本问题。另一方面,如果您已经使用运行时包链接到RTL,那么您就可以了。
如果您不想使用运行时包,那么需要完全重新设计您的界面。您需要停止跨模块边界传递类。您可以使用接口,但不能使用类。您需要控制内存分配,以确保总是在分配内存的模块中释放内存。或者开始使用ShareMem。
发布于 2012-08-02 20:00:15
对于这种类型的功能,为了保持共享-mem无包,我将在dll中使用带有枚举器方法的回调。例如,这就是从windows检索字体的方法。下面是我所指的模拟:
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。
发布于 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经理失望。
https://stackoverflow.com/questions/11777592
复制相似问题