Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

.Net Reflection in Delphi2005

1 view
Skip to first unread message

Stefan Badenhorst

unread,
Oct 26, 2005, 6:38:56 AM10/26/05
to


Hi. I have a question on using reflection in my .net application.

I wrote a .Net DLL (or assembly) that contains 2 classes.

One is called ThePluginBase and the other ThePlugin.
ThePlugin inherits from ThePluginBase that inherits from TObject.

The base class has a method called GetMessage that is abstract.
ThePlugin class overrides this method.
ThePlugin also overrides the constuctor and displays a message box when
the constuctor is called.
ThePluginBase class is in a seperate unit from ThePlugin Class.

OK, that takes care of the assembly. Now on to the executable.

In the execuatable I use system.reflection.assembly.LoadFile to load the
assembly. Then I iterate through the classes (using MyAssembly.GetTypes)
and find ThePlugin Class.
This I then store in a varable called aType (of type &Type).
Then I call:

ci := aType.GetConstuctor(BindingFlags.Public or BindingFlags.Instance
or BindingFlags.DeclaredOnly, nil, [], nil );
//ci is of type ConstructorInfo
if (ci <> nil) then
begin
//and this is where my problem starts
//when I call the next line, the class in my assembly shows a message
box. This indicates that the constructor is called.
//But, aObject comes back with no object instance
aObject := ci.Invoke([]); //aObject is a TObject or system.&object
//Because I included the unit that contains the base class for my plugins
//I can cast the retured object to that type
MyPlugin := ThePluginBase(aObject);
MyPlugin.GetMessage; //Error here: Object referance not set to an
instance of an object.
end;


How can I get the constuctor's invoke statement to return a valid
instance of an object? With the debugger, I can see that aObject is
already undefined before it even comes to where I cast and call the
method. The strange thing is that the message box shows up. So I know
that the constructor of the correct class was called.

Marc Rohloff [TeamB]

unread,
Oct 26, 2005, 8:58:59 PM10/26/05
to
On Wed, 26 Oct 2005 12:38:56 +0200, Stefan Badenhorst wrote:

> //and this is where my problem starts
> //when I call the next line, the class in my assembly shows a message
> box. This indicates that the constructor is called.
> //But, aObject comes back with no object instance
> aObject := ci.Invoke([]); //aObject is a TObject or system.&object
> //Because I included the unit that contains the base class for my plugins
> //I can cast the retured object to that type
> MyPlugin := ThePluginBase(aObject);
> MyPlugin.GetMessage; //Error here: Object referance not set to an
> instance of an object.

Just because you get an error on the last line doesn't necessarily
imply that aObject neevr gets assigned, it implies that its type is
not derived from ThePluginBase.

I suggest you put a break just after the Invoke line and check if is
nil, then check the value of aObject.GetType.FullName to find the real
class you have.

You can also look at your assembly with a reflection tool to see
exactly what is being created.

--
Marc Rohloff [TeamB]
marc rohloff -at- myrealbox -dot- com

khariv

unread,
Oct 26, 2005, 11:33:56 PM10/26/05
to
I had a bit of a different approach to a similar problem but I solved it
using interfaces. Basically, I declare an interface which the base class
as well as any sub-classes (by default) implement. I then create the
object, assign the interface and run my procedure. This seemed to work
better than trying to convince .NET to handle casting correctly (which my
experience led to some dodgy behavior). Anyway, here's what I came up
with:

var
o : system.object;
iObjInt : IMyInterface;

o := fClassConstructor.invoke(nil);
iObjInt := o as IMyInterface;

if assigned(iObjInt) then
iObjInt.execute;

Now, that MIGHT work for you but it looks like the larger issue for you
might be the fact that your cast might not be working correctly. I would
check to see if the line:
MyPlugin := ThePluginBase(aObject)
actually assigns a value to MyPlugin at all or is it still unassigned?
Does the process work any better if you include the unit in the executable
itself (i.e. does the issue only show up if you're loading the object from
an assembly? shouldnt make any difference, but figured I'd ask).

khariV

--- posted by geoForum on http://delphi.newswhat.com

Stefan Badenhorst

unread,
Oct 27, 2005, 4:18:43 AM10/27/05
to
I've tried what you suggested and this time the debugger tells me that I
have a object reference. But I get a 'Specified cast is not valid'
error. I haven't used interfaces allot so I might be doing something stupid.

Here is my code:

unit ATestPlugin;

interface

const constPluginID = 'TEST_PLUGIN';

type

IPlugin = interface
function GetName : string;
end;

TPlBase = class(TObject, IPlugin)
public
function GetName : string; virtual; abstract;
end;

TTestPlugin = class(TPlBase)
public
function GetName : string; override;
constructor Create;
end;

implementation

uses
Dialogs;

constructor TTestPlugin.Create;
begin
inherited;
ShowMessage('Created');
end;

function TTestPlugin.GetName: string;
begin
inherited;
Result := constPluginID;
ShowMessage('GetName');
end;

end.

And the main form from the exe:

procedure TfrmMain.Button2Click(Sender: TObject);
var atype : &type;
i : Integer;
obj : system.&object;
ci : ConstructorInfo;
objInt : IPlugin;
begin
ListBox3.Clear;
for i := 0 to FPluginListClassTypes.Count -1 do
begin
atype := &type(FPluginListClassTypes.Items[i]);
ci := aType.GetConstructor( BindingFlags.Public or

BindingFlags.Instance or BindingFlags.DeclaredOnly, nil, [], nil );

if (ci <> nil) then
begin

obj := ci.Invoke(nil); // I now get a valid object ref
objInt := obj as IPlugin; // Specified cast is not valid
if Assigned(objInt) then
ListBox3.Items.Add(objInt.GetName);
end;
end;
end;

Marc Rohloff [TeamB]

unread,
Oct 27, 2005, 7:51:42 PM10/27/05
to
On Wed, 26 Oct 2005 20:58:59 -0400, Marc Rohloff [TeamB] wrote:

> Just because you get an error on the last line doesn't necessarily
> imply that aObject neevr gets assigned, it implies that its type is
> not derived from ThePluginBase.

One reason this could happen is that there are two ThePluginBase
classes that have the same name but are defined in two different
places. .NET will consider them to be different classes and not let
you typecast.

You need to have an assembly which defines the base class and make
sure that your exe and plugin assembly both share it and do not
include their own definitions of the classes.

To get this to work you will need to use the New\Package menu option
and not the New\Assembly option. There is a slight difference.

Stefan Badenhorst

unread,
Oct 28, 2005, 6:09:21 AM10/28/05
to
I finally got it working.
Your tip on using packages was invaluable.
I first did a package of the base class, but that still did not work.
then I made the actual plugin a package and not a library. That works.
What exactly is the difference?

Craig Stuntz [TeamB]

unread,
Oct 28, 2005, 1:33:24 PM10/28/05
to
Stefan Badenhorst wrote:

> I first did a package of the base class, but that still did not work.
> then I made the actual plugin a package and not a library. That works.
> What exactly is the difference?

A library in Delphi for .NET is intended *only* for doing unmanaged
(Win32) exports. For everything else you should use a package to create
an assembly DLL.

--
Craig Stuntz [TeamB] · Vertex Systems Corp. · Columbus, OH
Delphi/InterBase Weblog : http://blogs.teamb.com/craigstuntz
All the great TeamB service you've come to expect plus (New!)
Irish Tin Whistle tips: http://learningtowhistle.blogspot.com

Marc Rohloff [TeamB]

unread,
Oct 28, 2005, 5:20:41 PM10/28/05
to
On Fri, 28 Oct 2005 12:09:21 +0200, Stefan Badenhorst wrote:

> I finally got it working.
> Your tip on using packages was invaluable.
> I first did a package of the base class, but that still did not work.
> then I made the actual plugin a package and not a library. That works.
> What exactly is the difference?

Delphi won't let you reference an assembly created by Delphi. It
requires the extra information stored in the package.

Rudy Velthuis [TeamB]

unread,
Oct 28, 2005, 8:04:53 PM10/28/05
to
At 23:20:41, 28.10.2005, Marc Rohloff [TeamB] wrote:

> On Fri, 28 Oct 2005 12:09:21 +0200, Stefan Badenhorst wrote:
>
> > I finally got it working.
> > Your tip on using packages was invaluable.
> > I first did a package of the base class, but that still did not work.
> > then I made the actual plugin a package and not a library. That works.
> > What exactly is the difference?
>
> Delphi won't let you reference an assembly created by Delphi. It
> requires the extra information stored in the package.

I think that needs some clarification.

In Delphi for .NET, packages are compiled to assemblies. Libraries (i.e.
projects that start with the keyword "library", as DLLs do in Win32) are
only meant to contain .NET code that can, without alteration or any extra
work, be called by Win32 code directly.

But AFAIK, the Delphi 2005 help tells you this, somewhere. I just can't
find it, right now. <weak g>
--
Rudy Velthuis [TeamB] http://velthuis.homepage.t-online.de

"And God said, 'Let there be light' and there was light, but the
Electricity Board said He would have to wait until Thursday to be
connected." -- Spike Milligan.

Rudy Velthuis [TeamB]

unread,
Oct 28, 2005, 8:24:32 PM10/28/05
to
At 02:04:53, 29.10.2005, Rudy Velthuis [TeamB] wrote:

> In Delphi for .NET, packages are compiled to assemblies. Libraries (i.e.
> projects that start with the keyword "library", as DLLs do in Win32) are
> only meant to contain .NET code that can, without alteration or any
> extra work, be called by Win32 code directly.

A little more on this here:

http://homepages.borland.com/abauer/archives/2004_01_25_archive.php

--
Rudy Velthuis [TeamB] http://velthuis.homepage.t-online.de

"Real punks help little old ladies across the street because
it shocks more people than if they spit on the sidewalk."
-- Unknown

0 new messages