Topic: DLLs - Exporting Modified Classes


Author: "S. Mark Courter" <smcourte@sprynet.com>
Date: 1997/09/30
Raw View
Here is a situation that has surely arisen before:

I have an VC++ 5 MFC application consisting of a Main App supported by
several extension DLL's.

A Class that contains data and functions I need to share among the various
modules is defined in the main app and exported to the DLL's.  A global
variable containing an instance of this class is also exported.

I discover that I need to add some data members to the Class in one of the
modules but I don't
want to recompile and redistribute the modules that don't use the new data.
I add the data members to the Class and rebuild.

Are there any gotchas to this?

I have tried experiments doing this and it seems to work.  The DLL with the
old definition of the class still receives data in members it knows about,
and the App with the new definition has access to any new data members.


One thing I'm worried about is that in the VC++ debugger I can't inspect
the exported variable when I am in the DLL, it says the symbol is
undefined.


In summary
 [IN MAIN APP]
   class AFX_CLASS_EXPORT myClass
   {
  int a;
  int b; //add a member after original def.
   }

 AFX_DATA_EXPORT myClass glob_myclass_var;


[IN A DLL]
 AFX_DATA_IMPORT myClass glob_myclass_var;


I can access glob_myclass_var.a and glob_myclass_var.b in the Main App

I can access glob_myclass_var.a in the DLL.

I can inspect glob_myclass_var when debugger is in the Main App, but not
when it's in the
DLL.

S. Mark Courter
smcourte@sprynet.com
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: fjh@murlibobo.cs.mu.OZ.AU (Fergus Henderson)
Date: 1997/09/30
Raw View
"S. Mark Courter" <smcourte@sprynet.com> writes:

>A Class that contains data and functions I need to share among the various
>modules is defined in the main app and exported to the DLL's.  A global
>variable containing an instance of this class is also exported.
>
>I discover that I need to add some data members to the Class in one of the
>modules but I don't
>want to recompile and redistribute the modules that don't use the new data.
>I add the data members to the Class and rebuild.
>
>Are there any gotchas to this?

Doing this violates the "One Definition Rule" --
see section 3.2 [basic.def.odr] paragraph 5 in the draft C++ standard.
The behaviour is undefined.

Note that the situation in C is somewhat different.
See James Kanze's article in the thread "!= template and enum...".

>I have tried experiments doing this and it seems to work.

Whether or not it works in practice is another question.
An implementation is free to make it work.
But the standard does not guarantee that it will.

--
Fergus Henderson <fjh@cs.mu.oz.au>   |  "I have always known that the pursuit
WWW: <http://www.cs.mu.oz.au/~fjh>   |  of excellence is a lethal habit"
PGP: finger fjh@128.250.37.3         |     -- the last words of T. S. Garp.
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]





Author: David R Tribble <david.tribble@central.beasys.com>
Date: 1997/10/01
Raw View
"S. Mark Courter" <smcourte@sprynet.com> asked:
>
> A Class that contains data and functions I need to share among the various
> modules is defined in the main app and exported to the DLL's.  A global
> variable containing an instance of this class is also exported.
>
> I discover that I need to add some data members to the Class in one of the
> modules but I don't
> want to recompile and redistribute the modules that don't use the new data.
> I add the data members to the Class and rebuild.
>
> Are there any gotchas to this?

Plenty.  They're all based on the fact that you've got two sets of code
(the old code and the new code) compiled with different concepts of
what is in your class.

1.  If you've changed the size of the object, un-recompiled code that
does 'p = new Foo' or declares an 'auto Foo' object will not allocate a
chunk of memory of the right size for the object.  Not to mention
allocating arrays of your object type.

This won't be a problem if all the allocators for the class are in your
new code and you've disallowed 'new' and 'auto' creations of the class
type.  Or if the only objects of your class type are static/global and
are defined only in the new code.

It will be a problem if the old code makes assumptions about sizeof(Foo),
such as subscripting into an array of Foo objects.

2.  The new member(s) you've added may not be located at the end of the
new object but in the middle somewhere (C++ only guarantees relative
ordering within public/protected/private groups in a class).  Presto,
you've got two sets of code that think 'p->memb' is at different offsets
within '*p'.

If you've been farsighted enough to add padding (a.k.a. reserved space)
at the end of your struct (before your first release), this problem is
avoidable.  But you have to know how the compiler arranges the class
members within the object to make this work right, and such things are
inherently unportable (which may or may not matter to you) if you're
dealing with non-POD classes.

3.  Adding a member variable to a struct may change its alignment.
For example:
    class Foo
    {
    public:
        short   x;      // Original member
        long    y;      // New member
    };

Foo objects originally could be halfword aligned, but now they must be
fullword aligned (on most RISC CPUs anyway) because of the new 'y'
member.

Again, this isn't a problem if the new code has complete control over
object allocation.

4.  If you've added virtual member functions, you may have changed the
offset of the function pointers in the class's _vtbl pointer table.
Very bad, since the old code may now invoke the wrong member functions.

5.  Same bad news for member function pointers.  Adding a member function
may shift the function offsets within the class.

To avoid such problems (which can also arise when customers compile code
using one version of our headers and execute their programs with a
different version of the class library/DLL), we here at work usually add
a magic number and a version number to our objects (always as the first
two members in the class).

The magic number allows us to verify that the object (*this) is a bona
fide object of the expected type instead of an errant pointer (or pointer
to a deleted object).  The magic number is set at object construction and
changed at object destruction.  The version number allows us to check
which version of the object we're dealing with; the version number is
incremented whenever the class declaration changes.  All class member
functions call an 'isValid()' member function that checks these two
member variables and raises an error if they're handed an improper object.
This strategy ensures that client code (which may create the object)
agrees with the library member functions (which operate on the object)
from release to release.  It doesn't solve all our problems, but it nails
some of the big ones.  Other strategies exist, too.

--------------------.      BEA Systems, Inc. ,-.  +1-972-738-6125 Office
David R. Tribble     \   ,------------------'   \ +1-972-738-6111 Fax
http://www.beasys.com `-'  Dallas, TX 75248      `-----------------------
david.tribble@noSPAM.beasys.com            http://www.flash.net/~dtribble
-------------------------------------------------------------------------
Support the anti-Spam amendment, join at http://www.cauce.org/
---
[ comp.std.c++ is moderated.  To submit articles: try just posting with      ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu         ]
[ FAQ:      http://reality.sgi.com/employees/austern_mti/std-c++/faq.html    ]
[ Policy:   http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++-request@ncar.ucar.edu                             ]