Boost logo

Boost Users :

Subject: Re: [Boost-users] [Serialization] Unregistered_class exception
From: Robert Ramey (ramey_at_[hidden])
Date: 2009-12-23 12:14:04


**
This scenario is possible. But it is a little tricky for a number of
reasons.
I've just updated the test "test_dll_plugin" on the trunk. I think this
addresses
you're situation.

I am developing a plugin dll , which is loaded in third party main program.
My plugin , say MyPlugin.dll , contains serialization code ( non intrusive
save/load pair ) for classes which are defined in third party dll , say
A.dll. A.dll is suppiled with my third party main program. Both A.dll and
MyPlugin.dll are laoded at runtime in my main program.
Only MyPlugin.dll ( and not A.dll and main program ) links with boost 1.41.0
staticly, if this is relevant at all. And I am using Visual Studio 2005.

***
If this were me, I would do the following:
a) have a header with an abstract base class with an all inline member
functions. That
is with no *.cpp file, at least one function virtual ... = 0; call this Base

The i would make my derived class - Plugin1 derive from Base

What we want to do is to save/load through a pointer to the Base class. The
basic
problem is that when loading through the base class pointer, a instance the
derived class must be created - but which one. This is addressed by the
"export" facility. The serialization library uses this facility to add
information
to the archive indicating the true type which has been saved and to
construct
a new instance of this type when loading. It also instanciates code
otherwise
would be ecluded from the final executable since it's not explicitly
referred to.

First I would do this without going through the DLL process just to make
sure everything works.
Look at demo_pimpl to see how this is done. This totally separates the
derived class definition
from the rest of the program. So make sure that demo_pimpl works in your
setup
and that you understand the motivation for everthing that's in there.

If you get this far, you can move on to test_dll_plugin. (note I recently
uploaded recent
changes to the trunk for this demo). Basically, this test/demo is similar
to demo_pimpl
except that the code for the definition of the derived2 class is totally
implemented
inside a dll. The main application only knows about the base class. When
the
DLL containing the definition of the derived2 class is loaded, the boost
"export"
facility "registers" the derived2 type in a global table. This information
is used
by the library to properly save and restore the true type of an object given
only a pointer to it's base.

Note that my approach guarentees that ALL code related to derived2 is
contained in ONE DLL. This makes sense to me from a code management
standpoint. It also means that there will be only one entry in the global
type table for derived2. The serialization library SHOULD handle the
situation
when code is spread accross multiple DLLs - but why tempt fate?

*** Note that using the statically linked c runtime library in one module
while using the dynamically linked c runtime library in another is known
to cause difficulties. This is unrelated to serialization. The VC IDE
permits one to do this even though it can lead to problems. I would
recommend that if you're going to use DLLS, you link everything
to the dynamically linked version of the c runtime library.

I am doing the following :

/////////////////////MyPlugin.cpp
//all archive classes are included here
namespace boost
{
    namespace serialization
    {
        template<class Archive>
        inline void save(Archive & ar,const ON_Brep& t,const unsigned int
version)
        {
          boost::serialization::void_cast_register<ON_Brep, ON_Geometry>(
        static_cast<ON_Brep*>(NULL),
        static_cast<ON_Geometry *>(NULL));
        //save ON_Brep here

        *** to simplify things I would use
        BOOST_SERIALIZATION_BASE_OBJECT_NVP(ON_Geometry>(*this)
        and make sure the base has a "serialize function even if it's null
        }
        template<class Archive>
        inline void load(Archive & ar,ON_Brep& t,const unsigned int version)
        {
         boost::serialization::void_cast_register<ON_Brep, ON_Geometry>(
        static_cast<ON_Brep*>(NULL),
        static_cast<ON_Geometry *>(NULL));
        //load ON_Brep here
        }
    }
}
BOOST_SERIALIZATION_SPLIT_FREE(ON_Brep)

BOOST_CLASS_EXPORT_GUID(ON_Brep, "ON_Brep")
*** I would put this in a *.cpp file as recommended in the documentation.

void CommandFunction()
{
        ON_Brep* brep=GetBrepObject();
        boost::archive::xml_oarchive oa(ofs);
        *** where is ofs declared?
        oa & BOOST_SERIALIZATION_NVP(brep); // fails to save with
uregistered_class exception
        *** another problem. it looks like ON_Brep is a derived object. I
doubt you want this. if have
        ar << x
        and later
        ar >> y
        then x and y MUST be of the same type. In the case of plugin that
type would be a pointer
        to the BASE class.
}

get_derived_extended_type_info(const T & t) const {
        // note: this implementation - based on usage of typeid (rtti)
        // only does something if the class has at least one virtual
function.
        BOOST_STATIC_WARNING(boost::is_polymorphic<T>::value);
        return
            typeid_system::extended_type_info_typeid_0::get_extended_type_info(
                typeid(t) ); /////// Here the typeid(t) differs from
typeid(ON_Brep) <------------------1
    }

Anyone have seen such a thing ?

*** almost daily

Thanks for any help

*** you're welcome

Robert Ramey


Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net