<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	>
<channel>
	<title>Comments on: Interfaces and reference equality: beware</title>
	<atom:link href="http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/</link>
	<description>Life, .NET, and Cats</description>
	<pubDate>Sat, 11 Oct 2008 09:44:24 +0000</pubDate>
	<generator>http://wordpress.org/?v=2.5</generator>
		<item>
		<title>By: Chris Morgan</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-18052</link>
		<dc:creator>Chris Morgan</dc:creator>
		<pubDate>Fri, 23 May 2008 10:46:14 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-18052</guid>
		<description>Please can you test your CSS layout with Internet Explorer.</description>
		<content:encoded><![CDATA[<p>Please can you test your CSS layout with Internet Explorer.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Joe</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-17977</link>
		<dc:creator>Joe</dc:creator>
		<pubDate>Fri, 23 May 2008 01:39:07 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-17977</guid>
		<description>Marc is correct. If you're really going to do the thing correctly, any interface should be able to QueryInterface to any other.

So if you're using the "implements" keyword, the object being targeted by "implements" really should descend from TAggregatedObject instead of TInterfacedObject. From the comments in System.pas:

&lt;blockquote&gt;TAggregatedObject and TContainedObject are suitable base classes for interfaced objects intended to be aggregated or contained in an outer controlling object.  When using the "implements" syntax on an interface property in an outer object class declaration, use these types to implement the inner object.

Interfaces implemented by aggregated objects on behalf of the controller should not be distinguishable from other interfaces provided by the controller. ... TAggregatedObject simply reflects QueryInterface calls to its controller.&lt;/blockquote&gt;</description>
		<content:encoded><![CDATA[<p>Marc is correct. If you&#8217;re really going to do the thing correctly, any interface should be able to QueryInterface to any other.</p>
<p>So if you&#8217;re using the &#8220;implements&#8221; keyword, the object being targeted by &#8220;implements&#8221; really should descend from TAggregatedObject instead of TInterfacedObject. From the comments in System.pas:</p>
<blockquote><p>TAggregatedObject and TContainedObject are suitable base classes for interfaced objects intended to be aggregated or contained in an outer controlling object.  When using the &#8220;implements&#8221; syntax on an interface property in an outer object class declaration, use these types to implement the inner object.</p>
<p>Interfaces implemented by aggregated objects on behalf of the controller should not be distinguishable from other interfaces provided by the controller. &#8230; TAggregatedObject simply reflects QueryInterface calls to its controller.</p></blockquote>
]]></content:encoded>
	</item>
	<item>
		<title>By: Marc Rohloff</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-17877</link>
		<dc:creator>Marc Rohloff</dc:creator>
		<pubDate>Thu, 22 May 2008 14:44:48 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-17877</guid>
		<description>Another way to subvert the comparison is to use the 'implements' keyword.
For example:
  TBar = class(IFoo, IBar)
    property SubObject:IFoo implements IFoo;
Then the comparison
   (Bar as IFoo) as IUnknown = Bar as IUnknown will also fail.

However Microsoft's COM guidelines are very specific that casting an object to a given interface, directly or indirectly, should always return the same pointer. In the above case you should override QueryInterface on the subobject to return the parent's IUnknown.</description>
		<content:encoded><![CDATA[<p>Another way to subvert the comparison is to use the &#8216;implements&#8217; keyword.<br />
For example:<br />
  TBar = class(IFoo, IBar)<br />
    property SubObject:IFoo implements IFoo;<br />
Then the comparison<br />
   (Bar as IFoo) as IUnknown = Bar as IUnknown will also fail.</p>
<p>However Microsoft&#8217;s COM guidelines are very specific that casting an object to a given interface, directly or indirectly, should always return the same pointer. In the above case you should override QueryInterface on the subobject to return the parent&#8217;s IUnknown.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Uwe Raabe</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-17853</link>
		<dc:creator>Uwe Raabe</dc:creator>
		<pubDate>Thu, 22 May 2008 11:47:37 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-17853</guid>
		<description>Well, the cast to IInterface may not help if you use the &lt;b&gt;implements&lt;/b&gt; feature. In the example below the assertion will fail. This scenario is of quite common use and not somewhat &lt;i&gt;constructed&lt;/i&gt;.

&lt;code&gt;
uses classes;

type
  TImplementor = class(TInterfacedPersistent, IStreamPersist, IInterfaceList)
  private
    FList: IInterfaceList;
    function GetList: IInterfaceList;
  protected
    property List: IInterfaceList read GetList implements IInterfaceList;
  public
    procedure LoadFromStream(Stream: TStream);
    procedure SaveToStream(Stream: TStream);
  end;

function TImplementor.GetList: IInterfaceList;
begin
  if FList = nil then
    FList := TInterfaceList.Create;
  result := FList;
end;

procedure TImplementor.LoadFromStream(Stream: TStream);
begin
end;

procedure TImplementor.SaveToStream(Stream: TStream);
begin
end;

var
  intf1: IStreamPersist;
  intf2: IInterfaceList;
  obj: TImplementor;
begin
  obj := TImplementor.Create;
  try
    intf1 := obj;
    intf2 := obj;
    Assert((intf1 as IInterface) = (intf2 as IInterface), 'interfaces not equal');
  finally
    obj.Free;
  end;
end;
&lt;/code&gt;</description>
		<content:encoded><![CDATA[<p>Well, the cast to IInterface may not help if you use the <b>implements</b> feature. In the example below the assertion will fail. This scenario is of quite common use and not somewhat <i>constructed</i>.</p>
<p><code><br />
uses classes;</p>
<p>type<br />
  TImplementor = class(TInterfacedPersistent, IStreamPersist, IInterfaceList)<br />
  private<br />
    FList: IInterfaceList;<br />
    function GetList: IInterfaceList;<br />
  protected<br />
    property List: IInterfaceList read GetList implements IInterfaceList;<br />
  public<br />
    procedure LoadFromStream(Stream: TStream);<br />
    procedure SaveToStream(Stream: TStream);<br />
  end;</p>
<p>function TImplementor.GetList: IInterfaceList;<br />
begin<br />
  if FList = nil then<br />
    FList := TInterfaceList.Create;<br />
  result := FList;<br />
end;</p>
<p>procedure TImplementor.LoadFromStream(Stream: TStream);<br />
begin<br />
end;</p>
<p>procedure TImplementor.SaveToStream(Stream: TStream);<br />
begin<br />
end;</p>
<p>var<br />
  intf1: IStreamPersist;<br />
  intf2: IInterfaceList;<br />
  obj: TImplementor;<br />
begin<br />
  obj := TImplementor.Create;<br />
  try<br />
    intf1 := obj;<br />
    intf2 := obj;<br />
    Assert((intf1 as IInterface) = (intf2 as IInterface), 'interfaces not equal');<br />
  finally<br />
    obj.Free;<br />
  end;<br />
end;<br />
</code></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Hallvard Vassbotn</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-17727</link>
		<dc:creator>Hallvard Vassbotn</dc:creator>
		<pubDate>Mon, 19 May 2008 13:18:02 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-17727</guid>
		<description>If the as-IInterface cast produce (potential) problems, you could move down a level and explicitly look at the thunka to compiler creates to find the implementing object, like in my hack:

http://hallvards.blogspot.com/2004/07/hack-7-interface-to-object-in-delphi.html</description>
		<content:encoded><![CDATA[<p>If the as-IInterface cast produce (potential) problems, you could move down a level and explicitly look at the thunka to compiler creates to find the implementing object, like in my hack:</p>
<p><a href="http://hallvards.blogspot.com/2004/07/hack-7-interface-to-object-in-delphi.html" rel="nofollow">http://hallvards.blogspot.com/2004/07/hack-7-interface-to-object-in-delphi.html</a></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: oxffff</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-16779</link>
		<dc:creator>oxffff</dc:creator>
		<pubDate>Tue, 13 May 2008 05:08:04 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-16779</guid>
		<description>You assert 

&#62;In Delphi for Win32, you can’t necessarily use the “equals” operator to tell whether two &#62;interfaces both point to the same object.

And you offer the solution, that is to cast both interfaces to IInterface

&#62;Assert(Foo as IInterface = Bar as IInterface); 

My sample show that although both Interfaces (First IInterface and SomeA) use the same object 
(you may find out this by inspecting the hidden compiler generated stub that fix EAX(in register calling convention), i.e. self param of interface Method 

But casting both Interfaces to Iunknown fails because of overridden QueryInterface method of SomeA Interface, but both interfaces still use the same object. 

To force your solution fail you may

1. create new instance, i.e. delegate implementation to an other object.
2. delegate implementation to inner(aggregated) object.
3. suppress returning any interfaces from QueryInterface and get exception.

:)

Best regards Sergey Antonov.

 


 








This sample shows  that if QueryInterface is override</description>
		<content:encoded><![CDATA[<p>You assert </p>
<p>&gt;In Delphi for Win32, you can’t necessarily use the “equals” operator to tell whether two &gt;interfaces both point to the same object.</p>
<p>And you offer the solution, that is to cast both interfaces to IInterface</p>
<p>&gt;Assert(Foo as IInterface = Bar as IInterface); </p>
<p>My sample show that although both Interfaces (First IInterface and SomeA) use the same object<br />
(you may find out this by inspecting the hidden compiler generated stub that fix EAX(in register calling convention), i.e. self param of interface Method </p>
<p>But casting both Interfaces to Iunknown fails because of overridden QueryInterface method of SomeA Interface, but both interfaces still use the same object. </p>
<p>To force your solution fail you may</p>
<p>1. create new instance, i.e. delegate implementation to an other object.<br />
2. delegate implementation to inner(aggregated) object.<br />
3. suppress returning any interfaces from QueryInterface and get exception.</p>
<p> <img src='http://blog.excastle.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>Best regards Sergey Antonov.</p>
<p>This sample shows  that if QueryInterface is override</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Joe</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-16743</link>
		<dc:creator>Joe</dc:creator>
		<pubDate>Tue, 13 May 2008 00:39:37 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-16743</guid>
		<description>Uh-huh. If you're writing code that returns new instances from QueryInterface, you &lt;i&gt;deserve&lt;/i&gt; to have your tests fail.</description>
		<content:encoded><![CDATA[<p>Uh-huh. If you&#8217;re writing code that returns new instances from QueryInterface, you <i>deserve</i> to have your tests fail.</p>
]]></content:encoded>
	</item>
	<item>
		<title>By: oxffff</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-16401</link>
		<dc:creator>oxffff</dc:creator>
		<pubDate>Sun, 11 May 2008 07:03:17 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-16401</guid>
		<description>HI, Joe White.

:)

And what about the next case?      

  SomeA=interface
  ['{008F39E4-9C7F-4ED8-AD56-56CD7FAD6477}']
  procedure Method1;
  end;

  TABC=class(TInterfacedObject,SomeA)
  protected
  function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
  procedure Method1;
  public
  end;


procedure TForm1.Button1Click(Sender: TObject);
var a:IUnknown;
begin
a:=TABC.create;
if not (A=a as someA as IUnknown) then showmessage('Failed');
end;

procedure TABC.Method1;
begin
//
end;

function TABC.QueryInterface(const IID: TGUID; out Obj): HResult;
var A:TInterfacedObject;
begin
Iunknown(Obj):=TInterfacedObject.Create;
Result:=S_OK;
end;

:)</description>
		<content:encoded><![CDATA[<p>HI, Joe White.</p>
<p> <img src='http://blog.excastle.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </p>
<p>And what about the next case?      </p>
<p>  SomeA=interface<br />
  [&#8217;{008F39E4-9C7F-4ED8-AD56-56CD7FAD6477}&#8217;]<br />
  procedure Method1;<br />
  end;</p>
<p>  TABC=class(TInterfacedObject,SomeA)<br />
  protected<br />
  function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;<br />
  procedure Method1;<br />
  public<br />
  end;</p>
<p>procedure TForm1.Button1Click(Sender: TObject);<br />
var a:IUnknown;<br />
begin<br />
a:=TABC.create;<br />
if not (A=a as someA as IUnknown) then showmessage(&#8217;Failed&#8217;);<br />
end;</p>
<p>procedure TABC.Method1;<br />
begin<br />
//<br />
end;</p>
<p>function TABC.QueryInterface(const IID: TGUID; out Obj): HResult;<br />
var A:TInterfacedObject;<br />
begin<br />
Iunknown(Obj):=TInterfacedObject.Create;<br />
Result:=S_OK;<br />
end;</p>
<p> <img src='http://blog.excastle.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /></p>
]]></content:encoded>
	</item>
	<item>
		<title>By: Joe White&#8217;s Blog &#187; Blog Archive &#187; DUnitLite 0.5 released</title>
		<link>http://blog.excastle.com/2008/05/10/interfaces-and-reference-equality-beware/#comment-16313</link>
		<dc:creator>Joe White&#8217;s Blog &#187; Blog Archive &#187; DUnitLite 0.5 released</dc:creator>
		<pubDate>Sat, 10 May 2008 21:18:55 +0000</pubDate>
		<guid isPermaLink="false">http://blog.excastle.com/?p=2523#comment-16313</guid>
		<description>[...] Should.ReferTo now works with interfaces, and can mix and match between objects and interfaces. It also correctly works around the interface reference-equality problem. [...]</description>
		<content:encoded><![CDATA[<p>[&#8230;] Should.ReferTo now works with interfaces, and can mix and match between objects and interfaces. It also correctly works around the interface reference-equality problem. [&#8230;]</p>
]]></content:encoded>
	</item>
</channel>
</rss>
