6

If I implement an interface on a form such as TMyForm = class(TForm, IMyInterface), will the object free itself when there are no more interface references to it? It seems not to, although I couldn't work out how TForm is reference counted (if at all). I'm concerned about the form getting freed when an interface reference goes out of scope, but this does not seem to happen.

I guess there are two parts to the question, firstly whether a form might get unexpectedly freed (the real question), and secondly how forms are reference counted.

Rob Kennedy
  • 161,384
  • 21
  • 275
  • 467
Alister
  • 6,527
  • 4
  • 46
  • 70
  • @TLama TForm descends from TComponent, which implements IInterface and IInterfaceComponentReference. TComponent does implement the _AddRef and _Release, but they seem to only conditionally do reference counting. – Alister Dec 04 '13 at 22:12
  • @Alister: `TComponent` disables reference counting on itself, but will perform reference counting on its `VCLCOMObject` property, if assigned. – Remy Lebeau Dec 04 '13 at 22:17
  • @Alister, sorry, maybe I misunderstood your question (before re-reading it a few times), but I thought you were asking what happens if you add an interface (to be implemented in the `TForm` class). If adding of that interface is dangerous somehow, and if that adds a reference counting to the form. – TLama Dec 04 '13 at 22:22
  • 1
    @TLama: adding an interface to a `TForm` will not add a reference count to the `TForm`. The compiler will still call `_AddRef()` and `_Release()` on interace pointers but they will be no-ops because of `TComponent`. – Remy Lebeau Dec 04 '13 at 22:25
  • It's not that simple, @Free. See what everyone else has written here. In particular, Remy's comment right before yours, Uwe's answer, and the places in the question reporting that it didn't work that way. – Rob Kennedy Dec 05 '13 at 04:37
  • *slap forehead* yes, sure, I forgot about what! – Free Consulting Dec 05 '13 at 04:53

2 Answers2

15

TForm derives from TComponent, which implements _AddRef() and _Release() to disable reference counting on itself. As such, any interface implemented by any TComponent descendant class, like TForm, will not free its implementing TComponent object by default when the interface is released.

However, if an IVCLComObject interface is assigned to the TComponent.VCLCOMObject property, then TComponent will delegate reference counting to that object, so that object can be freed if its reference count falls to 0 (TComponent does not increment the reference count of its IVCLCOMObject reference).

This is valid for all descendants of TComponent, unless they implement any reference counting of their own by overriding _AddRef() and _Release() manually.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
  • I'm more concerned as to what else might set the VCLComObject. – Alister Dec 04 '13 at 22:16
  • @Alister: `TComponent.VCLCOMObject` is set if `TComponent.ComObject` is accessed, which is only valid if the project is using the `VCLCom` unit (otherwise accessing the `ComObject` property will raise an exception). – Remy Lebeau Dec 04 '13 at 22:23
  • 2
    In other words: as long as you don't expose your form somehow through a COM server, where reference counting seems adequate, there is little chance that something will set VCLComObject without your own intervention. – Uwe Raabe Dec 04 '13 at 22:26
0

IF you implement an interface in a form, it can be worth adding your own

_Release as follows:

    function _Release: Integer; stdcall;

function TMyInterfacedForm._Release: Integer;
begin
  result:=-1; 
end;

I found that it was possible to free a form with an interface, and then have the _Release called as the local variable went out of scope. This could produce an access violation, as the Tcomponent implementation checks to see if FVCLComObject is set

  if FVCLComObject = nil then
    Result := -1   // -1 indicates no reference counting is taking place
  else
    Result := IVCLComObject(FVCLComObject)._Release;

Since at this stage, FVCLComobject is undefined, an annoying A/V exception can occur. By hardwiring the -1, it can be called safely without trigger exceptions.

Robbie Matthews
  • 1,404
  • 14
  • 22