Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people, just like you, are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
Solved

RTTI on classes ok.  On interfaces ok too?

Posted on 2000-04-05
12
359 Views
Last Modified: 2010-04-04
I'm getting a compiler error.  
Operator not applicable to this operand type

I just want to see if the Sender is a particular class.  RTTI.   I've done similar things like this before in other projects, but this will not compile:

procedure TfrmMain.editorStartDrag(Sender: TObject;
  var DragObject: TDragObject);
begin
  if (Sender is TSNode) then
    doit( Sender as TSNode );
end;

Why?   TSNode is defined.  But its an interface...

  TSNode = interface(IDispatch)
    ['{717C48CA-1951-11D1-8150-0000C09865B6}']


0
Comment
Question by:abulka
  • 5
  • 4
  • 3
12 Comments
 
LVL 20

Expert Comment

by:Madshi
ID: 2688813
Nope, that doesn't work. Objects and interfaces are a quite different thing.

How is this editorStartDrag called? How could that happen that Sender is an interface? Do you call editorStartDrag with an interface as a parameter?

Regards, Madshi.
0
 

Author Comment

by:abulka
ID: 2689195
The component generates the editorStartDrag() event, though I now doubt it ever sends an interface as a parameter.

So perhaps this question is best anwered in general terms e.g.

I can see if an object is a particular class using 'is'.

I can see if an object supports a particular interface using QueryInterface - but that assumes that the object is derived from InterfacedObject.

I can get to an interface via an object.
Can I get to an object via an interface?

Are these the relevant permutations/combinations - have I missed any useful ones?  This would answer my question.
0
 
LVL 20

Expert Comment

by:Madshi
ID: 2689248
Yes, now you're sounding like you understood the stuff...   :-))

>> Can I get to an object via an interface?

Normally you simply cannot, except if the interface implements a method like "GetObject".

Please look here:

http://community.borland.com/

There you'll find two good articles about interfaces&objects. They might help you to dig even deeper into the material.

Regards, Madshi.
0
Free Tool: Port Scanner

Check which ports are open to the outside world. Helps make sure that your firewall rules are working as intended.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 

Author Comment

by:abulka
ID: 2689360
Adjusted points from 20 to 30
0
 

Author Comment

by:abulka
ID: 2689361
Alternatively to answering the above general questions, here is a revised question based on a REAL problem, which is based on exactly the same issue:

Given
  TSDListIteratorDisp = dispinterface
    ['{717C48CE-1951-11D1-8150-0000C09865B6}']
    procedure moveToStart; dispid 1610743808;
    procedure moveToEnd; dispid 1610743809;
    procedure next; dispid 1610743810;
    procedure previous; dispid 1610743811;
    procedure insertBefore(object_: IDispatch); dispid 1610743812;
    procedure insertAfter(object_: IDispatch); dispid 1610743813;
    function isWithinList: WordBool; dispid 1610743814;
    function getObject: IDispatch; dispid 1610743815;
    function clone: TSDListIterator; dispid 1610743816;
    property locationInDList: Integer readonly dispid 1610743817;
    procedure moveDListAfter(const moveDList: TSDList); dispid 1610743818;
    function moveToObject(object_: IDispatch): WordBool; dispid 1610743819;
    procedure removeCurrentObject; dispid 1610743820;
  end;

....

var
  childrenNodeDList, childrenEdgeList : TSDList;
  iter : TSDListIterator;
  anode : TSNode;
begin
    somenode.findChildren(childrenNodeDList, childrenEdgeList, TS_FIND_DEPTH_ALL);
    iter := childrenNodeDList.newIterator;

    while iter.isWithinList do begin
      if iter.getObject is TSNode then  // FAILS to compile
        anode := TSNode( iter.getObject );
      frmMain.editor.selectNode( anode, false );
      iter.next;
    end;

the problem is that iter.getObject returns something, and I want to make sure it is a TSNode interface so that I can pass it to the selectNode() method.

At the moment the .selectNode method is complaining at runtime that the node I am passing is not really a node.

I'm pretty sure that each .getObject is giving me a node, but perhaps its not quite the right aspect/interface that .selectNode  expects?

This might help:
  TSNode = interface(IDispatch)
    ['{717C48CA-1951-11D1-8150-0000C09865B6}']
    function Get_allowOcclusion: WordBool; safecall;
    procedure Set_allowOcclusion(Value: WordBool); safecall;
    function Get_bottom: Integer; safecall;
    procedure buildExpandedDigraphDList(const expandedDigraphDList: TSDList); safecall;
    function collapse: TSExpandReturnCode; safecall;
    function expand: TSExpandReturnCode; safecall;
    procedure findChildren(const newNodeDList, newEdgeDList: TSDList; depth: Integer); safecall;
....
....

0
 
LVL 20

Expert Comment

by:Madshi
ID: 2691070
This can't work, since GetObject gives you an IDispatch interface, while the selectNode function (or the code "getObject is TSNode") wants to have an object reference. That are simply two different things that don't fit together! You will NEVER get a valid TSNode from getObject, since getObject returns a completely different kind of thing, namely an interface instead of an object.
0
 
LVL 20

Accepted Solution

by:
Madshi earned 30 total points
ID: 2691097
Oh, wait a moment, now you've confused me!!   :-)
You should name interfaces with a "I" as the first letter, so "TSNode" should be "ISNode". I thought it would be an object because of the name...
Well, what type does selectNode wants to have as the first parameter?

You can't do "if interface is IOtherInterface". But you can do this:

var iu1 : IUnknown;
begin
  blabla.getObject.QueryInterface(TSNode, iu1) = 0 then
    // blabla does support TSNode
    selectNode(blabla as TSNode, ...);

Now I guessed that selectNode looks like this:

procedure selectNode(blabla: TSNode; ...);

Right?
0
 

Author Comment

by:abulka
ID: 2808129
> Now I guessed that selectNode
> looks like this:
>
> procedure selectNode(blabla: TSNode; ...);
>
> Right?

Right!  

And the TSNode SHOULD be called ITSnode or something - but the activeX component supplier chose the names :-(  - they are C++ people!

P.S. Sorry for the delay in answering.
0
 

Expert Comment

by:topkapi
ID: 3329974
im sorry Madshi, but you are wrong.

you *can* use the typecast

  (Object as Interface)

as long as the object explicitly supports the IUnknown interface

  TMyObject = class(TInterfacedObject, IUnknown, ISNode);

Delphi (read: the IS and AS operators) use the QueryInterface function of IUnknown to find out wether or not the object supports the interface asked. unfortunatly delphi does 'forget' that any interface descends from IUnknown.

Regards,

-= topkapi =-
0
 

Expert Comment

by:topkapi
ID: 3330451
correction: you can not use IS, but you can use AS with interfaces

a code example:

  IWhatever = interface
    ['{753CC699-582A-11D4-BD41-5254AB1564F8}']
    procedure A;
  end;

  TMyObject = class(TInterfacedObject, IUnknown, IWhatever)

  protected
    procedure A;
  end;


procedure TForm1.Button1Click(Sender: TObject);
var
  obj : TMyObject;
  i, j: IWhatever;
begin
  obj := TMyObject.Create;
  // note: IS can not be used, but QueryInterface can do the same
  obj.QueryInterface(IWhatever, i);
  if assigned(i) then begin
    j := obj as IWhatever;
    j.A;
    // note: object used as interface, so it is cleaned up for us
  end
  else begin
    obj.Free;
  end;
end;

i hope this helps,

-= topkapi =-
0
 
LVL 20

Expert Comment

by:Madshi
ID: 3331290
>> im sorry Madshi, but you are wrong.

No, I'm not.

>> you *can* use the typecast
>>  (Object as Interface)
>> as long as the object explicitly supports the IUnknown interface

Of course, I never said anything different from that.

Regards, Madshi.
0
 

Expert Comment

by:topkapi
ID: 3331815
sorry, i read to fast. you were right ;-)

-= topkapi =-
0

Featured Post

Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Delphi Form ownership 4 112
Convert MS Word document to a PDF file 9 91
CheckListBox usage 3 71
How to build JSON File in Delphi 6 3 45
Introduction The parallel port is a very commonly known port, it was widely used to connect a printer to the PC, if you look at the back of your computer, for those who don't have newer computers, there will be a port with 25 pins and a small print…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
Established in 1997, Technology Architects has become one of the most reputable technology solutions companies in the country. TA have been providing businesses with cost effective state-of-the-art solutions and unparalleled service that is designed…

828 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question