Friday, October 7, 2011

Supports killing objects

Today I had a really bad "d'oh!" moment... feel free to laugh at me because I did not know better. ;)

You all may use the Supports routine - so did I without further thinking about it - until today. I shamefully have to admit that I should have looked at its code and/or the documentation earlier.

What happened? In my bindings I check the source and target objects for special interfaces (f.i. INotifyPropertyChanged). I changed some code and strange things started happening in form of access violations. So I quickly found out that the Supports call caused a Destroy on the object when it did not support the given interface. Looking at the source revealed why: Supports does not only call GetInterface with the given guid, no it also does it for IUnknown causing _AddRef and _Release calls. And we know how that ends on some refcounted object that has the initial refcount of 0.

Actually there is a comment saying: "NOTE: Calling this overload on a ref-counted object that has REFCOUNT=0 will result in it being freed upon exit from this routine." And the documentation says: "Warning [...] For objects that have a reference count of zero, this will result in the object destruction."

Just another reason why Delphi sometimes is a pain in the ass if you are using object references and interfaces. Some may say: "Just use interfaces!" No, I do not want to write interfaces for simple data objects and other things. But I want to use interfaces for certain aspects (f.i. INotifyPropertyChanged). And most important: I do not want my objects getting destroyed if they DO NOT implement the requested interface.

Actually I have no idea why this was implemented like this long ago. Anyway I wrote my own Supports overload now:

function Supports(const Instance: TObject; const IID: TGUID; out Intf): Boolean;
  Result := Assigned(Instance) and Instance.GetInterface(IID, Intf);

If your instance is assigned for sure you just might call the GetInterface method. I know there might be cases where the other Supports returns true and this one not like when having a customized QueryInterface. But in my cases it should solve my problem of instances getting shot in the head by the Supports call.

Let me know if I missed something about this implementation.