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

RTTI and DLLs

257 views
Skip to first unread message

Eric Pascual

unread,
Apr 17, 2001, 8:37:51 AM4/17/01
to
Hello,

I'm facing a strange problem (perhaps not strange at all for most of you,
but...) with RTTI information.

I've written a DLL containing, among of other stuff, a function which
creates an object of a specific class and returns it to the caller as a
generic object, let's say :

function CreateAnObject : TObject ;
begin
result := TMyObject.Create ;
end ;

The problem is that when I test the object class in the application using
this DLL, bot "is" as "as" operators fail. In other words :
1/ CreateAnObject is TMyObject evaluates as false,
2/ of course, CreateAnObject as TMyObject raises and exception.

The strange thing is that CreateAnObject.ClassName = 'TMyObject' evaluates
as true. Obviously, if the function is embedded in the caller code or is
part of a statically linked unit, there is no problem, and both 1/ and 2/
behave as expected.

I suspected some shared memory problem, so I've added the ShareMem unit as
first one in both the DLL and the using application project, but without any
noticeable effect on this point.

So, what am I missing ?

Thanks a lot in advance for shedding some light.

Best regards.

--
==============================================================
Eric PASCUAL - Directeur Technique Etablissement
Centre Scientifique et Technique du Bātiment
299, Route des Lucioles - BP 209
F-06904 Sophia Antipolis - France
http://www.cstb.fr
==============================================================

John Langley

unread,
Apr 17, 2001, 11:14:27 AM4/17/01
to
Delphi can't assume that equivalent class names mean equivalent classes when
using DLLs. But if you use BPLs, "is" and "as" will work and you won't need
ShareMem.

"Eric Pascual" <eric.p...@analis.fr> wrote in message
news:3adc3920$1_2@dnews...
[snip]


> The strange thing is that CreateAnObject.ClassName = 'TMyObject' evaluates
> as true.

[snip]


Eric Pascual

unread,
Apr 17, 2001, 11:33:25 AM4/17/01
to
Thanks John for your reply.

> Delphi can't assume that equivalent class names mean equivalent classes
when
> using DLLs. But if you use BPLs, "is" and "as" will work and you won't
need
> ShareMem.

I'm okay with this, but :

1/ I tried to use BPL but it does not work for me (or at least, I don't know
how to make it works the way I need).

To be more precise, I'm writing an environment composed of a kernel and
extensions provided as DLLs (or BPLs if feasible). Extensions must provide
predefined entry points that allow communication between the kernel and the
extensions (if fact, all this is some kind of ISAPI mechanism, but used in a
different context). Besides, binding must be done at runtime only, the same
way an ISAPI is loaded and activated when it is invoked through an URL.

My first idea was to use BPLs, but I was not able to do the binding by
retrieving entry point addresses via GetProcAddress. The result is always
nil, although the BPLs has been properly loaded and entry points exist as
named (I checked this by inspecting the BPL binary). If I develop the
extension as a standard DLL, this binding process works fine. I guess I'm
doing something wrong, but I can't see what.

2/ I understand that the name of a class is not a reliable enough
identification to warrant that this is the right class. So what can of
additional process BPL context provides for such a validation ?

Regards
Eric


Igor Raskin

unread,
Apr 17, 2001, 12:02:53 PM4/17/01
to
"Eric Pascual" <eric.p...@analis.fr> wrote in message
news:3adc6246_2@dnews...

> My first idea was to use BPLs, but I was not able to do the binding by
> retrieving entry point addresses via GetProcAddress. The result is always
> nil, although the BPLs has been properly loaded and entry points exist as
> named (I checked this by inspecting the BPL binary). If I develop the
> extension as a standard DLL, this binding process works fine. I guess I'm
> doing something wrong, but I can't see what.

You can still use DLLs provided you compile them and main application
with run-time packages.

Igor


Motty Adler

unread,
Apr 17, 2001, 12:32:38 PM4/17/01
to
I once used a hack like this.

In the kernel I had a procedure that the client could call that would return a
pointer to the VMT of the main application that the client can then create

John Langley

unread,
Apr 17, 2001, 3:17:57 PM4/17/01
to
I'm failing to grasp the requirements of your system clearly enough to make
a useful suggestion.

The following is probably irrelevant, but FWIW...

1) Assuming you need to implement a regular DLL that is extensible by way of
adding new classes to the object model: 2) Perhaps you could dynamically
load BPLs into a kernel DLL and a) call virtual methods of a base object
known to the kernell DLL b) which methods are overriden in the descendent
classes loaded by the BPLs.


Michael Tien

unread,
Apr 17, 2001, 6:30:52 PM4/17/01
to
Create the class in the main application instead of inside the DLL. Then
the 'is' operation will work just fine.
The following article may help.

http://www.obsof.com/delphi_tips/DL613.html

Roman Krejci

unread,
Apr 18, 2001, 2:49:06 AM4/18/01
to

"Eric Pascual" <eric.p...@analis.fr> píąe v diskusním příspěvku
news:3adc3920$1_2@dnews...
> Hello,

>
>
> I've written a DLL containing, among of other stuff, a function which
> creates an object of a specific class and returns it to the caller as a
> generic object,...............
> .............

> The problem is that when I test the object class in the application using
> this DLL, bot "is" as "as" operators fail. In other words :
> 1/ CreateAnObject is TMyObject evaluates as false,
> 2/ of course, CreateAnObject as TMyObject raises and exception.

The reason is that class created in the DLL and "the equivalent" class
created in
the EXE are NOT the same classes, because they have physically DIFFERENT
Virtual Method Tables. Class created in the DLL has its VMT located within
DLL, class created in the EXE has its VMT located in the EXE.
And it is the address of the VMT that matters when IS operator is evaluated.
BTW, it is BAD practice to export classes from the DLL. Such a DLL can be
used
only by EXE compiled with exactly the same Delphi version,
otherwise you get lot of AV's when using such exported objects.
--
Roman
(please remove 'stopspam' in header when replying)
mail: in...@rksolution.cz
URL: www.rksolution.cz

Eric Pascual

unread,
Apr 18, 2001, 6:14:28 AM4/18/01
to
Roman,

> The reason is that class created in the DLL and "the equivalent" class
> created in
> the EXE are NOT the same classes, because they have physically DIFFERENT
> Virtual Method Tables. Class created in the DLL has its VMT located within
> DLL, class created in the EXE has its VMT located in the EXE.
> And it is the address of the VMT that matters when IS operator is
evaluated.

Thanks a lot for clarifying the situation. Your explanation about VMT being
different answers my interrogations. How stupid I am not having thought to
this "detail" :-(

> BTW, it is BAD practice to export classes from the DLL. Such a DLL can be
> used
> only by EXE compiled with exactly the same Delphi version,
> otherwise you get lot of AV's when using such exported objects.

I note this point. But AFAIK, the same problem seems to exist with BPL,
since for components for instance, one needs to provide a BPL compiled for
the right Delphi version. Besides, what about using in the DLL (or BPL)
objects created by the application ? I must have missed some point, but
don't realize which one.

To illustrate my concern, the problem is the following :

- the application builds an object modelization of a building plan, based on
the STEP ISO standard and specialized schemas for buildings. This
modelization produces a complex model, composed by a network of instances of
the basic building blocks identified by the mentioned standard. In AI
terminology, this is more or less a "fact base", and that's the way we call
it.
- it then needs to check this fact base with respect to different concerns,
for instance, security regulations, disabled person circulation,.... each
of this concern being translated into a "rule base"
- in order for the system to be extensible, we have imagined to provide the
rule bases corresponding to concerns as dynamically loaded code packages
(DLL, BPL,...) so that it is easy to "plug" subsequent rule bases into the
system
- of course, each of this plug-in conforms to a predefined interface, so
that it can be used by the application kernel. For instance, there is a
public function which looks more or less like this :
function ApplyRulesOn (aFactBase : TFactBase) : TDiagnosticList ;
- as you can notice, code inside the plug-in needs to access to objects
belonging to the model instanciated by the application and transmitted via
the above mentioned function. Besides, this process will create items
populating the returned diagnostic information.

How would you implement such a thing ?

Thanks again in advance for any suggestion or remark.

Best regards

Eric

Roman Krejci

unread,
Apr 18, 2001, 6:38:49 AM4/18/01
to

"Eric Pascual" <eric.p...@analis.fr> píąe v diskusním příspěvku
news:3add6909_2@dnews...
> [SNIP].........., code inside the plug-in needs to access to objects

> belonging to the model instanciated by the application and transmitted via
> the above mentioned function. Besides, this process will create items
> populating the returned diagnostic information.
>
> How would you implement such a thing ?
>

You can consider using BPLs - the VMT problem does not apply to packages -
- the VMTs for all classes are stored only once - in the respective BPL.
The packages technology makes sure that all VMTs are shared.

OR

You may consider using COM interfaces instead of classes. Such
implementation would not
tie your plugins to any particular Delphi version and, in fact, could be
reused in any
language capable of using COM interfaces.

Personally, I would prefer to use interfaces.

Roman


Eric Pascual

unread,
Apr 18, 2001, 7:29:08 AM4/18/01
to
> You can consider using BPLs - the VMT problem does not apply to packages -
> - the VMTs for all classes are stored only once - in the respective BPL.
> The packages technology makes sure that all VMTs are shared.

It was my first attempt. The problem I was faced with is that I tried to
retrieve entry points with the GetProcAddress approach (as ordinarly done
with stadard DLLs) and it did not work : GetProcAddress returned nil
whichever proc I tried to bind with. I imagine that the GetProcAddress
approach is not the right one in BPLs world, but I confess I'm not clear
enough on the subject.

What have I to do ? Use some class registration mechanism, which would be
automatically activated when loading the BPL (and if yes, how) ?

Thanks again Roman for your help.

Best regards

Eric

Jeff Overcash (TeamB)

unread,
Apr 18, 2001, 10:10:29 AM4/18/01
to
Eric Pascual wrote:
>
> > You can consider using BPLs - the VMT problem does not apply to packages -
> > - the VMTs for all classes are stored only once - in the respective BPL.
> > The packages technology makes sure that all VMTs are shared.
>
> It was my first attempt. The problem I was faced with is that I tried to
> retrieve entry points with the GetProcAddress approach (as ordinarly done
> with stadard DLLs) and it did not work : GetProcAddress returned nil
> whichever proc I tried to bind with. I imagine that the GetProcAddress
> approach is not the right one in BPLs world, but I confess I'm not clear
> enough on the subject.
>

Make certain you are using the Export keyword somewhere and exporting the
procedures. Otherwise the package will mangle the procedure names and you will
need to do GetProcAddress using the mangled name.

> What have I to do ? Use some class registration mechanism, which would be
> automatically activated when loading the BPL (and if yes, how) ?
>
> Thanks again Roman for your help.
>
> Best regards
>
> Eric


--
Jeff Overcash (TeamB) On waves of silver I dreamed of gold
(Please do not email 'Till I lost the peace that dreaming gives
me directly unless I dreamed of the moment of my own death
asked. Thank You) That no one ever dreams and lives (Marillion)

John Langley

unread,
Apr 18, 2001, 11:36:38 AM4/18/01
to
see inline comments.

"Eric Pascual" <eric.p...@analis.fr> wrote in message

news:3add7a8a_2@dnews...
[snip]


>I imagine that the GetProcAddress
> approach is not the right one in BPLs world, but I confess I'm not clear
> enough on the subject.

I believe it is the wrong approach with BPLs. You simply want to call
methods of objects. A problem, of course, arises if the BPL defines new
classes. This can be solved by polymorphism: i.e. setting up a base class
whose methods are known both to the caller and the BPL. It can also be
solved by using interfaces.

The caller can create the classes defined in the BPL using GetClass or
FindClass. This assumes that the BPL has registered the classes and that the
caller has the name of the class in a string.

> What have I to do ? Use some class registration mechanism, which would be
> automatically activated when loading the BPL (and if yes, how) ?

The classes defined in a BPL can be registered in the initialization section
of the unit where it is defined, and unregistered in the finalization
section. (The initialization and finalization sections are run when the BPL
is loaded and unloaded.)

But as Roman said, it may be preferable to use COM objects rather than
packages.


Eric Pascual

unread,
Apr 18, 2001, 2:07:10 PM4/18/01
to
> The caller can create the classes defined in the BPL using GetClass or
> FindClass. This assumes that the BPL has registered the classes and that
the
> caller has the name of the class in a string.

I've tried this too, just as you describe. The problem is that GetClass
returns nil when used in the "client" application of the BPL. I suspect this
has to do with the fact that the class registration is done in the "scope"
of the DLL, resulting in the class information being added to a class list
instance which is not "visible" from the client application. In fact it
seems that there is a class list being instanciated on the application side,
and another one on the DLL side. Even if DLL and application share the same
address space (thus making cross-addressing valid), there is two distinct
data area (segments ?). I've seen this by poking in Classes.pas and playing
with the debugger.

> But as Roman said, it may be preferable to use COM objects rather than
> packages.

You're right. This is more "elegant" by the way and remove the problem of
keeping client app and pluging compiled with the same version of the
compiler.

Thanks to everybody having provided me with help.

Best regards

Eric

Eric Pascual

unread,
Apr 18, 2001, 1:59:10 PM4/18/01
to
> Make certain you are using the Export keyword somewhere and exporting the
> procedures. Otherwise the package will mangle the procedure names and you
will
> need to do GetProcAddress using the mangled name.

Jeff,

Where am I supposed to add this "export" directive ?

I have tried to append it to the declaration of some public procedure, but
the name is mangled the same way as if the directive was not there.

Regards
Eric Pascual

Craig Stuntz (TeamB)

unread,
Apr 18, 2001, 6:17:42 PM4/18/01
to

Eric Pascual wrote:
>
> Where am I supposed to add this "export" directive ?
>
> I have tried to append it to the declaration of some public procedure, but
> the name is mangled the same way as if the directive was not there.

Jeff meant to type "exports" (note the 's'). Export is completely
different and is essentially ignored by the compiler.

Look up "exports (reserved word)" in online Help. The exports clause
goes in your interface. For an example, look at any .DLL source.

HTH,

-Craig

--
Craig Stuntz (TeamB) Senior Developer, Vertex Systems Corp.
Delphi/InterBase weblog: http://delphi.weblogs.com
Use Borland servers; posts via others are not seen by TeamB.
For more info, see http://www.borland.com/newsgroups/genl_faqs.html

Eric Pascual

unread,
Apr 19, 2001, 7:18:55 AM4/19/01
to
> Jeff meant to type "exports" (note the 's'). Export is completely
> different and is essentially ignored by the compiler.

The problem is that exports (I have guessed there was a typo) is not allowed
in a *package*. Only possible in a *library*.

Anyway, I have solved my plugin problem with regular DLLs, taking care not
to use IS and AS operators. I have also studied a COM approach as suggested
by several people here, but it is quite overkill for the need, and will make
plugin modules somewhat bigger, since I assume they need to embed all the
factory and COM server stuff.

Regards
Eric Pascual

Craig Stuntz (TeamB)

unread,
Apr 19, 2001, 10:05:12 AM4/19/01
to

Eric Pascual wrote:
>
> The problem is that exports (I have guessed there was a typo) is not allowed
> in a *package*. Only possible in a *library*.

Not true. Exports works in a package. I just compiled the following
unit as part of a package:

unit UDFTest;

interface

function GetMaximum(var Num1, Num2: Double): Double; cdecl; overload;
export;

exports
GetMaximum(var Num1, Num2: Double) name 'GetMaximum',

implementation

[...etc...]

I then used a PE viewer to confirm that the GetMaximum function is
being exported without name mangling. Exports works correctly in a
package.

Guido Gybels

unread,
Apr 19, 2001, 10:33:23 AM4/19/01
to
Craig Stuntz (TeamB) wrote in message
<3ADEF098.A4B4F042@no_spam.vertexsoftware.com>...

>>Only possible in a *library*.
>
> Not true. Exports works in a package.

Since packages are a fancy kind of library, I'm pretty sure exports *will*
work.

Guido GYBELS
Programmer (GDG GROEP BELGIUM)


Danilo Luiz Rheinheimer

unread,
Apr 19, 2001, 12:13:40 PM4/19/01
to
>You can consider using BPLs - the VMT problem does not apply to packages -
>- the VMTs for all classes are stored only once - in the respective BPL.
>The packages technology makes sure that all VMTs are shared.
>

I am with the same problem here. I start a thread called "Can not
create object inside library" because this.
I am not undestanding in how to use BPL to solve this problem.
In my problem I need to see all dll in a directory. Then for each
dll I will :

- Load it
- Call a method who will return me a object.
- This object will be used in my application

The point is I do not know how many dll I will have, I do not know
the dll names. If I put this inside a package how will I load this
package ?



>OR
>
>You may consider using COM interfaces instead of classes. Such
>implementation would not
>tie your plugins to any particular Delphi version and, in fact, could be
>reused in any
>language capable of using COM interfaces.
>

But this is not portable. And something who works in Kylix is a need
to me.
And it is a lot of overhead too.

Eric Pascual

unread,
Apr 19, 2001, 1:05:07 PM4/19/01
to
OKAY Craig.

I was not aware that you could put exports in units like you illutrate it.
I've only tried to put exports in the package main source (as one do in the
library main source) and, of course, the compiler rejected it.

Your feedback opens me some new horizons, and I thank you a lot for this :-)

Best regards

Eric


"Craig Stuntz (TeamB)" <cstuntz@no_spam.vertexsoftware.com> a écrit dans le
message news: 3ADEF098.A4B4F042@no_spam.vertexsoftware.com...

John Langley

unread,
Apr 19, 2001, 1:54:53 PM4/19/01
to
"Danilo Luiz Rheinheimer" <dani...@yahoo.com> wrote in message
news:iv2udt05ajpc1o0jj...@4ax.com...
...

> I am not undestanding in how to use BPL to solve this problem.
> In my problem I need to see all dll in a directory. Then for each
> dll I will :
>
> - Load it
> - Call a method who will return me a object.
> - This object will be used in my application
...

In msg <3addb3dc_1@dnews> of this thread, there is a general outline of how
to use BPLs for this purpose. It would probably be the responsibility of the
BPL package to register any classes (see RegisterClass) that it introduces
and to notify (possibly through the Registry or a Windows message) the
calling application of the name of those classes, so that they can be
instantiated dynamically. These tasks can be carried out by code in the
packaged units initialization sections. It will be the responsibility of the
calling application to load and unload the package (see Un/LoadPackage) and
to find the introduced classes (see GetClass) using the class names. This
method may require an object model that makes base methods of the packaged
classes available to the calling application at design time.


Danilo Luiz Rheinheimer

unread,
Apr 19, 2001, 7:23:28 PM4/19/01
to

Please look in the thread "Creation of objects inside a dll"

0 new messages