Board index » delphi » Interface Question type casting problem

Interface Question type casting problem


2004-11-15 04:15:19 PM
delphi86
Hi Every One,
Can any one shed some light on this.
The problem description is after the class/interface descriptions.
Interface1 = Interface(IInterface)
method1
Method2
interface2 = Interface(IInterface)
Method3
Method4
TClass1 = Class(TInterfaceList, Interface1)
Method1
Method2
TClass2 = Class(TInterfacedObject, Interface1, Interface2)
Method3
method4
property PropInterface1 : IInterface1 Read.. Write ... implements
Interface1;
interface3 = interface(IInterface)
Method5
method6
TClass3 = Class(TClass2, Interface3)
Method5
Method6
...
...
.
.
TClass3 is instanciated and referenced in an Interface3 type variable.
It is is also passed to a list of Interface1 Interfaces. When an
Interface1 instance is retrieved from the list, it cant be cast to
Interface3 or interface2. get Interface not supported error.
Can any one plese tell me what may be the problem.
 
 

Re:Interface Question type casting problem

"Giggler" <XXXX@XXXXX.COM>a écrit dans le message de news:
41986596$XXXX@XXXXX.COM...
Quote
TClass3 is instanciated and referenced in an Interface3 type variable.
It is is also passed to a list of Interface1 Interfaces. When an
Interface1 instance is retrieved from the list, it cant be cast to
Interface3 or interface2. get Interface not supported error.
Have you declared a GUID for each interface ?
Joanna
Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker
 

Re:Interface Question type casting problem

Joanna Carter (TeamB) writes:
Quote
"Giggler" <XXXX@XXXXX.COM>a écrit dans le message de news:
41986596$XXXX@XXXXX.COM...


>TClass3 is instanciated and referenced in an Interface3 type variable.
>It is is also passed to a list of Interface1 Interfaces. When an
>Interface1 instance is retrieved from the list, it cant be cast to
>Interface3 or interface2. get Interface not supported error.


Have you declared a GUID for each interface ?
Yes I do. I even considered regenerateing the GUID for each interface.
But I dont see how that will change any thing
Quote
Joanna

--
Joanna Carter (TeamB)

Consultant Software Engineer
TeamBUG support for UK-BUG
TeamMM support for ModelMaker


 

Re:Interface Question type casting problem

On Mon, 15 Nov 2004 04:15:19 -0400, Giggler writes:
Quote
Can any one plese tell me what may be the problem.
Your code is very sparse. It might help if you make this into a short
compilable example and post the complete code.
--
Marc Rohloff [TeamB]
marc rohloff at myrealbox dot com
 

Re:Interface Question type casting problem

Giggler writes:
Quote
TClass3 is instanciated and referenced in an Interface3 type variable.
It is is also passed to a list of Interface1 Interfaces. When an
Interface1 instance is retrieved from the list, it cant be cast to
Interface3 or interface2. get Interface not supported error.
Can you give more information on the list of 'Interface1 Interfaces'?
Is it just a TInterfaceList?
Below is some code that seems to work with what I interpret you are
trying to achieve.. This is a from with a TButton on it that is
clicked.. (Just add the dfm)
Siegs
</Start>
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls;
type
IInterface1 = interface
['{06E16452-373C-4B43-BBBF-0D1D99D87DCA}']
function Method1: Integer; stdcall;
function Method2: Integer; stdcall;
end;
IInterface2 = interface
['{4B488B64-A345-4E96-B50F-3DEEC750DF30}']
function Method3: Integer; stdcall;
function Method4: Integer; stdcall;
end;
IInterface3 = interface
['{055918FF-FD57-4137-8379-1365FBF8025E}']
function Method5: Integer; stdcall;
function Method6: Integer; stdcall;
end;
TClass1 = class(TInterfacedObject, IInterface1)
function Method1: Integer; stdcall;
function Method2: Integer; stdcall;
end;
TClass2 = class(TInterfacedObject, IInterface1, IInterface2)
private
FInterface1: IInterface1;
public
constructor Create;
published
function Method3: Integer; stdcall;
function Method4: Integer; stdcall;
property Interface1: IInterface1 read FInterface1 implements
IInterface1;
end;
TClass3 = class(TClass2, IInterface3)
function Method5: Integer; stdcall;
function Method6: Integer; stdcall;
end;
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TClass3 }
function TClass3.Method5: Integer;
begin
Result := 0;
end;
function TClass3.Method6: Integer;
begin
Result := 0;
end;
{ TClass2 }
function TClass2.Method4: Integer;
begin
Result := 4;
end;
function TClass2.Method3: Integer;
begin
Result := 3;
end;
constructor TClass2.Create;
begin
inherited;
FInterface1 := TClass1.Create;
end;
{ TClass1 }
function TClass1.Method1: Integer;
begin
Result := 1;
end;
function TClass1.Method2: Integer;
begin
Result := 2;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
aClass2: IInterface2;
aClass3: IInterface3;
InterfaceList : TInterfaceList;
begin
aClass2 := TClass2.Create;
aClass3 := TClass3.Create;
InterfaceList := TInterfaceList.Create;
try
InterfaceList.Add(aClass3);
MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface2).Method3), mtInformation, [mbOK], 0); //Displays '3'
MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface1).Method1), mtInformation, [mbOK], 0); //Displays '1'
finally
InterfaceList.Free;
end;
end;
end.
</>
 

Re:Interface Question type casting problem

Sorry, you can just ignore the aClass2 instance..
rather in the Button onclick - to make it clearer.
(using D7)
..
var
aClass3: IInterface3;
InterfaceList : TInterfaceList;
begin
aClass3 := TClass3.Create;
InterfaceList := TInterfaceList.Create;
try
InterfaceList.Add(aClass3);
MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface2).Method3), mtInformation, [mbOK], 0);
MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface1).Method1), mtInformation, [mbOK], 0);
MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface3).Method6), mtInformation, [mbOK], 0);
finally
InterfaceList.Free;
end;
..
 

Re:Interface Question type casting problem

SiegfriedN <XXXX@XXXXX.COM>writes:
Quote
Giggler writes:
>TClass3 is instanciated and referenced in an Interface3 type variable.
>It is is also passed to a list of Interface1 Interfaces. When an
>Interface1 instance is retrieved from the list, it cant be cast to
>Interface3 or interface2. get Interface not supported error.

Can you give more information on the list of 'Interface1 Interfaces'?

Is it just a TInterfaceList?
the list is a TInterfaceList Decendent.

Below is some code that seems to work with what I interpret you are
trying to achieve.. This is a from with a TButton on it that is
clicked.. (Just add the dfm)

Siegs


</Start>

unit Unit1;

interface

uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls,
Forms,
Dialogs, StdCtrls;

type
IInterface1 = interface
['{06E16452-373C-4B43-BBBF-0D1D99D87DCA}']
function Method1: Integer; stdcall;
function Method2: Integer; stdcall;
end;

IInterface2 = interface
['{4B488B64-A345-4E96-B50F-3DEEC750DF30}']
function Method3: Integer; stdcall;
function Method4: Integer; stdcall;
end;

IInterface3 = interface
['{055918FF-FD57-4137-8379-1365FBF8025E}']
function Method5: Integer; stdcall;
function Method6: Integer; stdcall;
end;

TClass1 = class(TInterfacedObject, IInterface1)
function Method1: Integer; stdcall;
function Method2: Integer; stdcall;
end;

TClass2 = class(TInterfacedObject, IInterface1, IInterface2)
private
FInterface1: IInterface1;
public
constructor Create;
published
function Method3: Integer; stdcall;
function Method4: Integer; stdcall;
property Interface1: IInterface1 read FInterface1 implements
IInterface1;
end;

TClass3 = class(TClass2, IInterface3)
function Method5: Integer; stdcall;
function Method6: Integer; stdcall;
end;

TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;

implementation

{$R *.dfm}

{ TClass3 }

function TClass3.Method5: Integer;
begin
Result := 0;
end;

function TClass3.Method6: Integer;
begin
Result := 0;
end;

{ TClass2 }

function TClass2.Method4: Integer;
begin
Result := 4;
end;

function TClass2.Method3: Integer;
begin
Result := 3;
end;

constructor TClass2.Create;
begin
inherited;
FInterface1 := TClass1.Create;
end;

{ TClass1 }

function TClass1.Method1: Integer;
begin
Result := 1;
end;

function TClass1.Method2: Integer;
begin
Result := 2;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
aClass2: IInterface2;
aClass3: IInterface3;
InterfaceList : TInterfaceList;
begin
aClass2 := TClass2.Create;
aClass3 := TClass3.Create;

InterfaceList := TInterfaceList.Create;
try
InterfaceList.Add(aClass3);

MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface2).Method3), mtInformation, [mbOK], 0); //Displays '3'
MessageDlg(IntToStr((InterfaceList.Items[0] as
IInterface1).Method1), mtInformation, [mbOK], 0); //Displays '1'

finally
InterfaceList.Free;
end;
end;

end.

</>
 

Re:Interface Question type casting problem

giggler writes:
Quote

the list is a TInterfaceList Decendent.

Are the items in this TInterfaceList of IInterface?
Are the interface Items you add to the list created as TClass3?
Does the example code I submitted work for you?
Siegs
 

Re:Interface Question type casting problem

Marc Rohloff [TeamB] writes:
Quote
On Mon, 15 Nov 2004 04:15:19 -0400, Giggler writes:


>Can any one plese tell me what may be the problem.


Your code is very sparse. It might help if you make this into a short
compilable example and post the complete code.

I will try to include and post more code sometime this evening. Is
their someware in newsgroups where I can post the class diagrams that
may help.
 

Re:Interface Question type casting problem

In article <41986596$XXXX@XXXXX.COM>, XXXX@XXXXX.COM
says...
Quote
TClass3 is instanciated and referenced in an Interface3 type variable.
It is is also passed to a list of Interface1 Interfaces. When an
Interface1 instance is retrieved from the list, it cant be cast to
Interface3 or interface2. get Interface not supported error.
You should have no problems if:
* You have GUIDs for all interfaces involved
* Support for each interface is *explicitly* declared in the class OR a
class ancestor
* You are only casting interfaces as other interfaces
A reminder: if Interface2 = interface(Interface1), declaring support for
Interface2 does *not* automatically declare support for Interface1
Now I notice one small thing that is going on here. You use an
"implements" to delegate one of the interfaces to a property. There are
some caveats associated with this.
Quote
TClass2 = Class(TInterfacedObject, Interface1, Interface2)
property PropInterface1 : IInterface1 Read.. Write ...
implements Interface1;
If you cast a TClass2 *as* an IInterface1, you now have a variable
pointing to PropInterface1 (it really is a direct delegation). The
object PropInterface1 refers to -does not know it is contained in
TClass2-, so if you then go and try casting it to Interface2, -it may
not work-.
Reason being because it is PropInterface1.QueryInterface being called,
NOT TClass2.QueryInterface.
You may want to handle the delegation yourself, if you want this
functionality, e.g.
TClass2 = Class(TInterfacedObject, Interface1, Interface2)
private
FPropInterface1 : IInterface1;
public
procedure Method1;
procedure Method2;
property PropInterface1 : IInterface1 Read.. Write ...
end;
procedure TClass2.Method1;
begin
FPropInterface1.Method1;
end;
etc.
This will also be the most compatible with .NET (D8 and D2005/.NET don't
support implements yet)
Then, your Class2Intf as IInterface1 returns a reference to a (TClass2
as IInterface1), and there are no troubles whatsoever casting that to an
IInterface2.
Does that help? :)
-- Ritchie Annand
Senior Software Architect
www.malibugroup.com
nimble.nimblebrain.net
wiki.nimblebrain.net
...
P.S. There's even another way, to confuse things further :)
An alternate method is to use "implements", but use an *object* property
instead. The object should NOT be descended from TInterfacedObject (or
else the delegation will map _AddRef, _Release and QueryInterface to
it), and should NOT *declare* support for Interface1. It SHOULD,
however, *implement* a Method1 and Method2.
TMySubObject = class
public
procedure Method1;
procedure Method2;
end;
TClass2 = Class(TInterfacedObject, Interface1, Interface2)
property PropObject1 : TMySubObject Read.. Write ...
implements Interface1
end;
Delphi will map everything it can in Interface1 to a method in
PropObject1, but anything that is missing will be mapped to TClass2.
Since that would include QueryInterface, then you CAN cast a Class2Intf
as IInterface1 and still be able to cast it later as an IInterface2.
 

Re:Interface Question type casting problem

On Mon, 15 Nov 2004 20:13:40 -0400, Cedric Pemberton writes:
Quote
I will try to include and post more code sometime this evening. Is
their someware in newsgroups where I can post the class diagrams that
may help.
borland.public.attachments
--
Marc Rohloff [TeamB]
marc rohloff at myrealbox dot com
 

Re:Interface Question type casting problem

Ritchie Annand writes:
Quote
In article <41986596$XXXX@XXXXX.COM>, XXXX@XXXXX.COM
says...

>TClass3 is instanciated and referenced in an Interface3 type variable.
>It is is also passed to a list of Interface1 Interfaces. When an
>Interface1 instance is retrieved from the list, it cant be cast to
>Interface3 or interface2. get Interface not supported error.


You should have no problems if:

* You have GUIDs for all interfaces involved

* Support for each interface is *explicitly* declared in the class OR a
class ancestor

* You are only casting interfaces as other interfaces

A reminder: if Interface2 = interface(Interface1), declaring support for
Interface2 does *not* automatically declare support for Interface1

Now I notice one small thing that is going on here. You use an
"implements" to delegate one of the interfaces to a property. There are
some caveats associated with this.


>TClass2 = Class(TInterfacedObject, Interface1, Interface2)
>property PropInterface1 : IInterface1 Read.. Write ...
>implements Interface1;


If you cast a TClass2 *as* an IInterface1, you now have a variable
pointing to PropInterface1 (it really is a direct delegation). The
object PropInterface1 refers to -does not know it is contained in
TClass2-, so if you then go and try casting it to Interface2, -it may
not work-.

Reason being because it is PropInterface1.QueryInterface being called,
NOT TClass2.QueryInterface.
Ok Ritchie. That makes sense. I always assumed that it only applied
when useing TAggregatedObjects, In I had avoided useing TAggreateObjects
because I wanted my objects to be capable of being used as a containing
object or a contained object. So as a solution what if I do something
crazy like...
TMyAggregateObject = Class(TInterfaceObject)
Private
FController : Pointer; Borrowing heavely from TAggregateObject
QueryInterface();
...
...
...
Implemements
eg.
function TMyAggregateObject.QueryInterface
if Assigned(FController) then
Result := IInterface(FController).QueryInterface()
else
Result := inherited QueryInterface();
Quote

You may want to handle the delegation yourself, if you want this
functionality, e.g.

TClass2 = Class(TInterfacedObject, Interface1, Interface2)
private
FPropInterface1 : IInterface1;
public
procedure Method1;
procedure Method2;
property PropInterface1 : IInterface1 Read.. Write ...
end;

procedure TClass2.Method1;
begin
FPropInterface1.Method1;
end;
Intresting but realy don't like the wrapping of the methods. Could
become combersom with a large number of Classes.
Quote
etc.

This will also be the most compatible with .NET (D8 and D2005/.NET don't
support implements yet)

Then, your Class2Intf as IInterface1 returns a reference to a (TClass2
as IInterface1), and there are no troubles whatsoever casting that to an
IInterface2.

Does that help? :)

-- Ritchie Annand
Senior Software Architect
www.malibugroup.com
nimble.nimblebrain.net
wiki.nimblebrain.net

...

P.S. There's even another way, to confuse things further :)

An alternate method is to use "implements", but use an *object* property
instead. The object should NOT be descended from TInterfacedObject (or
else the delegation will map _AddRef, _Release and QueryInterface to
it), and should NOT *declare* support for Interface1. It SHOULD,
however, *implement* a Method1 and Method2.

TMySubObject = class
public
procedure Method1;
procedure Method2;
end;

TClass2 = Class(TInterfacedObject, Interface1, Interface2)
property PropObject1 : TMySubObject Read.. Write ...
implements Interface1
end;

Delphi will map everything it can in Interface1 to a method in
PropObject1, but anything that is missing will be mapped to TClass2.
Since that would include QueryInterface, then you CAN cast a Class2Intf
as IInterface1 and still be able to cast it later as an IInterface2.
 

Re:Interface Question type casting problem

In article <XXXX@XXXXX.COM>, XXXX@XXXXX.COM
says...
Quote
Ok Ritchie. That makes sense. I always assumed that it only applied
when useing TAggregatedObjects, In I had avoided useing TAggreateObjects
because I wanted my objects to be capable of being used as a containing
object or a contained object. So as a solution what if I do something
crazy like...
TMyAggregateObject = Class(TInterfaceObject)
Private
FController : Pointer; Borrowing heavely from TAggregateObject
QueryInterface();
The pointer trick here is just to fool Delphi into not using _AddRef/
_Release on the parent. That way, if the object behind the FController
goes away, it takes the AggregateObject with it (otherwise, the circular
reference counting would make it hang around forever :)
Quote
Implemements
eg.
function TMyAggregateObject.QueryInterface
if Assigned(FController) then
Result := IInterface(FController).QueryInterface()
else
Result := inherited QueryInterface();
That trick can actually work. That said, if you want to use delegations
like that, I would suggest the postscriptum technique I gave after my
signature in the last message. Delegating to objects instead of
interfaces lets you map methods to a sub-object, and all methods missing
from that sub-object (including _AddRef, _Release and QueryInterface if
it's a TObject, but you can even miss out Method1 or Method2 if you
like!) will be mapped to the main, containing object.
You might want to poke around in my presentation on Ins And Outs of
Delphi Interfaces at: nimble.nimblebrain.net/delphi.html
Quote
Intresting but realy don't like the wrapping of the methods. Could
become combersom with a large number of Classes.
Fair enough, though I usually find the number of cases is relatively
limited; you can usually make a base class do the highly manual parts of
the delegation, then just override a function NewDelegate: IInterface1;
or somesuch in descendants.
-- Ritchie Annand
Senior Software Architect
www.malibugroup.com
nimble.nimblebrain.net
wiki.nimblebrain.net