4

When I want to export a class within a DLL, is it the right approach to derive it from an interface and return that interface by an exported function?

//exported dll function, which is used in the exe.
function MyClass_Create: IMyClass;
begin
  result := TMyClass.Create;
end;

What about the memory management? Can I than pass in/out different interfaces and strings without worries and crashes?

IMyClass = interface
  procedure SetString(aMsg: string);
  function GetString: string;

  procedure SetClass(aClass: ITestClass);
  function GetClass: ITestClass;
end;
BenMorel
  • 34,448
  • 50
  • 182
  • 322
markus_ja
  • 2,931
  • 2
  • 28
  • 36

2 Answers2

5

Interface references are orthogonal to memory management. Usually you export a function that returns interface reference from dll, and don't care about memory management. With reference counting interfaces you can be sure that object instance that implements interface will be freed in dll too.

Strings are different. It does not matter whether you export interface or export flat functions - the same restrictions applies.

BTW your question title is incorrect, there are no 'interface instances' in Delphi.

kludg
  • 27,213
  • 5
  • 67
  • 118
  • Be aware of potential memory-leak issues when using circular references of interfaces (that is, an implementation class which refers to a shared interface) - in this case, Delphi is lacking a Garbage Collector or "Zeroing Weak pointers" features. See http://blog.synopse.info/post/2011/12/08/Avoiding-Garbage-Collector%3A-Delphi-and-Apple-on-the-same-side – Arnaud Bouchez Jan 13 '12 at 09:15
  • Circular references is a common problem for reference counting. Dirty trick `Pointer(IntRef):= nil` that nulls interface reference without changing refcount can help. – kludg Jan 13 '12 at 10:26
3

Using interfaces like this will ensure that the object implementing the interface will be created and freed on the same heap.

However, this will not solve the problem of dynamic string types being allocated and deallocated on different heaps. There are many possible solutions to this, but in my view the best approach is to use WideString across the module boundary.

The WideString type is a wrapper around the COM BSTR and is allocated on the shared COM heap. You only need to use WideString for the interface. The internals of the implementing classes can use native Delphi strings.

Just as strings present problems so do dynamic arrays. Attempting to pas dynamic arrays across module boundaries is not safe. There is no solution analagous to WideString that is as convenient. You can use variant arrays but that's pretty clunky in comparison to WideString.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490