Dynamic messaging in Delphi

classic Classic list List threaded Threaded
9 messages Options
Reply | Threaded
Open this post in threaded view
|

Dynamic messaging in Delphi

Ryan Joseph
I was asking on the Mac Pascal list if Delphi had any ways to invoke methods on objects which the class was unknown at compile time (like a class that invokes a user defined delegate commonly used in Cocoa Mac programming and I assume Delphi not knowing) and one user told me interfaces will work for this. Btw, I'm aware you can use strings to invoke methods with a single argument but I wanted something better since this has been a real drawback in Pascal for me in recent years.

The idea is Main.pas has a delegate class which implements IMyInterface and MyInterface.pas declares the interface and can invoke its methods using a generic delegate object (typed TObject). This is really typical of UI elements like a button that wants to tell a receiver an action occurred but doesn't know the class of the receiving object. Providing this example works it's sort of a workaround to multiple inheritence but I don't see that Pascal would be capable of this, i.e. simply type casting an object and forcing it to call a method that may or may not exist (I feel like I tried this before and got crashing).

He swears this works and no one else answered otherwise but I'm getting "Error: Class or Object types "TObject" and "IMyInterface" are not related" errors at the line shown below.

Any ideas? Thanks.

====================

{$mode delphi}
{$interfaces corba}

unit MyInterface;
interface

type
        IMyInterface = interface
                procedure DoThis (value: integer);
        end;
       
procedure InvokeDelegate (delegate: TObject);
       
implementation

procedure InvokeDelegate (delegate: TObject);
var
        intfDelegate: IMyInterface;
begin
        ERROR ====> intfDelegate := IMyInterface(delegate);
        intfDelegate.DoThis(1);
end;

end.

====================

{$mode delphi}
{$interfaces corba}

program Main;
uses
        MyInterface;

type
        TMyDelegate = class (TInterfacedObject, IMyDelegate)
                procedure DoThis (value: integer);
        end;

procedure TMyDelegate.DoThis (value: integer);
begin
        writeln('did this ', value);
end;

var
        delegate: TMyDelegate;
begin
        delegate := TMyDelegate.Create;
        TestDelegate(delegate);
end.

Regards,
        Ryan Joseph
        thealchemistguild.com

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Luiz Americo Pereira Camara
Em 24/7/2012 11:13, Ryan Joseph escreveu:
> I was asking on the Mac Pascal list if Delphi had any ways to invoke methods on objects which the class was unknown at compile time (like a class that invokes a user defined delegate commonly used in Cocoa Mac programming and I assume Delphi not knowing) and one user told me interfaces will work for this. Btw, I'm aware you can use strings to invoke methods with a single argument but I wanted something better since this has been a real drawback in Pascal for me in recent years.
>
> The idea is Main.pas has a delegate class which implements IMyInterface and MyInterface.pas declares the interface and can invoke its methods using a generic delegate object (typed TObject). This is really typical of UI elements like a button that wants to tell a receiver an action occurred but doesn't know the class of the receiving object. Providing this example works it's sort of a workaround to multiple inheritence but I don't see that Pascal would be capable of this, i.e. simply type casting an object and forcing it to call a method that may or may not exist (I feel like I tried this before and got crashing).
>
> He swears this works and no one else answered otherwise but I'm getting "Error: Class or Object types "TObject" and "IMyInterface" are not related" errors at the line shown below.

   if delegate.GetInterface(IMyInterface, intfDelegate) then
     intfDelegate.DoThis

Luiz


> Any ideas? Thanks.
>
> ====================
>
> {$mode delphi}
> {$interfaces corba}
>
> unit MyInterface;
> interface
>
> type
> IMyInterface = interface
> procedure DoThis (value: integer);
> end;
>
> procedure InvokeDelegate (delegate: TObject);
>
> implementation
>
> procedure InvokeDelegate (delegate: TObject);
> var
> intfDelegate: IMyInterface;
> begin
> ERROR ====>  intfDelegate := IMyInterface(delegate);
> intfDelegate.DoThis(1);
> end;
>
> end.
>
> ====================
>
> {$mode delphi}
> {$interfaces corba}
>
> program Main;
> uses
> MyInterface;
>
> type
> TMyDelegate = class (TInterfacedObject, IMyDelegate)
> procedure DoThis (value: integer);
> end;
>
> procedure TMyDelegate.DoThis (value: integer);
> begin
> writeln('did this ', value);
> end;
>
> var
> delegate: TMyDelegate;
> begin
> delegate := TMyDelegate.Create;
> TestDelegate(delegate);
> end.
>
> Regards,
> Ryan Joseph
> thealchemistguild.com
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/mailman/listinfo/fpc-pascal
>

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Ryan Joseph
I never heard of this syntax, is it Delphi only? 

Trying this I got "Error: Interface type IMyInterface has no valid GUID". What else do I need to do?

Thanks.

On Jul 24, 2012, at 4:26 PM, Luiz Americo Pereira Camara wrote:

 if delegate.GetInterface(IMyInterface, intfDelegate) then
   intfDelegate.DoThis

Regards,
Ryan Joseph
thealchemistguild.com


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Luiz Americo Pereira Camara
Em 24/7/2012 20:17, Ryan Joseph escreveu:
> I never heard of this syntax, is it Delphi only?
>
> Trying this I got "Error: Interface type IMyInterface has no valid
> GUID". What else do I need to do?

The sintaxe i posted is for COM interfaces.

For CORBA interfaces do

   IMyInterface = interface
    ['myintf']
         procedure DoThis (value: integer);
     end;

if delegate.GetInterface('myintf', intfDelegate) then
    intfDelegate.DoThis


Luiz


>
> Thanks.
>
> On Jul 24, 2012, at 4:26 PM, Luiz Americo Pereira Camara wrote:
>
>>  if delegate.GetInterface(IMyInterface, intfDelegate) then
>>    intfDelegate.DoThis
>
> Regards,
> Ryan Joseph
> thealchemistguild.com <http://thealchemistguild.com>
>
>
>
> _______________________________________________
> fpc-pascal maillist  -  [hidden email]
> http://lists.freepascal.org/mailman/listinfo/fpc-pascal

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Ryan Joseph
Now it works! That seems redundant to declare an identifier when the interface name itself is unique. I would think the CORBA style identifier should default to the name of the interface.

Thanks, I wanted this feature for a while now.

On Jul 24, 2012, at 5:56 PM, Luiz Americo Pereira Camara wrote:

For CORBA interfaces do

 IMyInterface = interface
  ['myintf']
       procedure DoThis (value: integer);
   end;

if delegate.GetInterface('myintf', intfDelegate) then
  intfDelegate.DoThis

Regards,
Ryan Joseph
thealchemistguild.com


_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Graeme Geldenhuys-2
In reply to this post by Ryan Joseph
On 24 July 2012 15:13, Ryan Joseph <[hidden email]> wrote:
> procedure InvokeDelegate (delegate: TObject);
> var
>         intfDelegate: IMyInterface;
> begin
>         ERROR ====> intfDelegate := IMyInterface(delegate);
>         intfDelegate.DoThis(1);
> end;


You could also try the Supports() method. eg:

   if Supports(delegate, IMyInterface, intfDelegate) then
     intfDelegate.DoThis(1);

>
> {$mode delphi}
> {$interfaces corba}
>
> program Main;
> uses
>         MyInterface;
>
> type
>         TMyDelegate = class (TInterfacedObject, IMyDelegate)
>                 procedure DoThis (value: integer);
>         end;


By the way, as far as I know TInterfacedObject is a COM Interface
class only. You are telling the compiler that you want to use CORBA
style interfaces, which don't support IUnknown, thus you shouldn't
(can't) use TInterfaceObject which implements IUnknown.

Change that class definition to something like the following if you
are using CORBA interfaces.

   TMyDelegate = class(TObject, MyDelegate)
      ...
   end;

And that should work correctly with CORBA style interfaces (which
don't have reference counting built-in).


--
Regards,
  - Graeme -


_______________________________________________
fpGUI - a cross-platform Free Pascal GUI toolkit
http://fpgui.sourceforge.net
_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Ryan Joseph

On Jul 26, 2012, at 2:32 AM, Graeme Geldenhuys wrote:

>
> You could also try the Supports() method. eg:
>
>   if Supports(delegate, IMyInterface, intfDelegate) then
>     intfDelegate.DoThis(1);

I'm getting an identifier not found error with the procedure "Supports". Where is this defined?

>
> By the way, as far as I know TInterfacedObject is a COM Interface
> class only. You are telling the compiler that you want to use CORBA
> style interfaces, which don't support IUnknown, thus you shouldn't
> (can't) use TInterfaceObject which implements IUnknown.
>
> Change that class definition to something like the following if you
> are using CORBA interfaces.
>
>   TMyDelegate = class(TObject, MyDelegate)
>      ...
>   end;
>
> And that should work correctly with CORBA style interfaces (which
> don't have reference counting built-in).

That was useless code, you're right, thanks.

Regards,
        Ryan Joseph
        thealchemistguild.com

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

RE : [fpc-pascal] Dynamic messaging in Delphi

Ludo Brands
http://www.freepascal.org/docs-html/rtl/sysutils/supports.html

> I'm getting an identifier not found error with the procedure
> "Supports". Where is this defined?
>
>

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal
Reply | Threaded
Open this post in threaded view
|

Re: Dynamic messaging in Delphi

Ryan Joseph
Great, I got this working now.

This is one small step better because the only string identifier used in code for the interface is in the declaration itself so if the name of the interface gets changed I'll get compiler warnings when I try to invoke it.

Thanks.

On Jul 26, 2012, at 8:41 AM, Ludo Brands wrote:

> http://www.freepascal.org/docs-html/rtl/sysutils/supports.html
>
>> I'm getting an identifier not found error with the procedure
>> "Supports". Where is this defined?

Regards,
        Ryan Joseph
        thealchemistguild.com

_______________________________________________
fpc-pascal maillist  -  [hidden email]
http://lists.freepascal.org/mailman/listinfo/fpc-pascal