I am trying to implement bi-directional interfaces between a WinForms host and a Delphi non-visual plugin. Attached are my sample projects. I can create the.
In some part of my application, I have the situation where I receive an interface which I know to be an object, albeit I don't know the exact class. I have to store that object in an interface-type variable.
Eventually, I might receive another instance of that type, and the first one must be discarded and replaced with the new one. For that, I need to free the memory that interfaced object uses (my interface provides an AsObject method so I can use the TObject methods on it). My problem is, when I want to assign 'nil' to that variable again, I get an access violation.
I wrote a small program that reproduces my situation. I post it here to clarify the situation.
So the question is: how can I free that object correctly?
RRUZ125k13 gold badges313 silver badges445 bronze badges
Pablo VenturinoPablo Venturino3,8724 gold badges25 silver badges40 bronze badges
4 Answers
Assuming that you have a legitimate reason for doing this (and using TComponent it is quite possible that you do - see end of answer for why), then the problem occurs as a result of changing the reference of an interface variable after you have destroyed the object it currently references.
Any change to an interface reference generates code like this:
becomes (in simple terms):
If you relate that to your code, you should see the problem:
becomes:
So you can see that it is the generated call to Release() that results from assigning NIL to the interface that causes your access violation.
You should also quickly see that there is a simple way to avoid this, simply defer the freeing of the object until after you have NIL'd the interface reference:
BUT
The key question here is why are you explicitly free'ing an object that is interfaced (and presumably reference counted).
When you change the code to cache the object reference and NIL the interface before explicitly Free'ing the object, you may find that obj.Free will then cause an access violation as the NIL'ing of the interface reference might itself result in the object being free'd.
The ONLY way to be sure that explicitly free'ing the interfaced object is safe is:
1) That the interfaced object has overridden/reimplemented IUnknown and eliminated the reference counted lifetime management
AND
2) That you have no other interfaced references to that object elsewhere in your code.
If the first of these conditions doesn't make much sense to you then, without wishing to be patronising, this is probably a good sign that you shouldn't be explicitly freeing the object as it is almost certainly being managed by reference count.
Having said that, since you are using an interfaced TComponent class then as long as your TComponent class does not encapsulate a COM Object, then TComponent meets condition #1, so all that then remains is that you ensure the rest of your code meets condition #2.
DelticsDeltics19.7k2 gold badges34 silver badges62 bronze badges
You should not use TComponent as base class for your interfaced objects, you should use TInterfacedObject instead. TInerfacedObject has implemented the necessary functions to handle lifetime management for interfaces in Delphi. You should also never mix accessing your interface as interface and object. Here is a modification of your code that works just fine with no memory leaks.
Mikael ErikssonMikael Eriksson118k19 gold badges163 silver badges234 bronze badges
When you have an interface variable such as your ISomeInterface var, you don't need to free it, as it is reference counted and will free it's self when it drops out of scope.
Read Rob Kennedy's answer to this question:Delphi7, passing object's interface - causes Invalid Pointer Operation when freeing the object
From http://delphi.about.com/od/beginners/l/aa113004a.htm
As soon as the interface goes out of scope, Delphi will actually free the interface for you automatically! Interface's declared within a procedure or function will naturally fall out of scope when the procedure ends. Interface's declared within a class or are declared globally will naturally fall out of scope when the object is freed or the program ends.
If in doubt try using FastMM memory manager and tuning on the memory leak detection, to see if the object is leaked.
Community♦
Re0slessRe0sless8,2844 gold badges42 silver badges63 bronze badges
You're mixing it. All depends on
_AddRef
and _Release
methods. Check how TInterfacedObject
in system.pas
is declared.Delphi just calls _AddRef and _Release methods during using Interafaces, calling Free depends on how object implements _Relase method.
TComponent
is not automatically destroyed (except Com object components).DiGiDiGi