Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

Click here to view the latest version of this page.

libs/serialization/test/test_dll_plugin.cpp

/////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8
// test_dll_plugin.cpp

// (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . 
// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

// should pass compilation and execution

// Note this test creates, serializes, and destroys
// a class instance while knowing nothing more than its
// exported class ID (GUID) and a base class from which
// it is derived.  This is referred to as a "plugin"
// since the same program could, without recompilation, 
// manipulate any number of derived types - even those
// which have not been yet been created.

#include <fstream>

#include <cstdio> // remove
#include <boost/config.hpp>
#if defined(BOOST_NO_STDC_NAMESPACE)
namespace std{ 
    using ::remove;
}
#endif

#include <boost/archive/archive_exception.hpp>

// for now, only test with simple text and polymorphic archive
#include "test_tools.hpp"

#include <boost/serialization/base_object.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/type_info_implementation.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/void_cast.hpp>
#include <boost/serialization/extended_type_info.hpp>

#include "polymorphic_base.hpp"

// declare and implement a derived class in our own executable
class polymorphic_derived1 : public polymorphic_base
{
    friend class boost::serialization::access;
    template<class Archive>
    void serialize(Archive &ar, const unsigned int /* file_version */){
        ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(polymorphic_base);
    }
    const char * get_key() const{
        return
            boost::serialization::type_info_implementation<
                polymorphic_derived1
            >::type::get_const_instance().get_key();
    }
public:
    virtual ~polymorphic_derived1(){}
};

// This class is derived from polymorphic_base which uses the no_rtti system
// rather than the typeid system.  This system uses the exported name as the
// type identifier key.  This MUST be exported!!!
BOOST_CLASS_EXPORT(polymorphic_derived1)

// MWerks users can do this to make their code work
BOOST_SERIALIZATION_MWERKS_BASE_AND_DERIVED(polymorphic_base, polymorphic_derived1)

// save exported polymorphic class
void save_exported(const char *testfile)
{
    test_ostream os(testfile, TEST_STREAM_FLAGS);
    test_oarchive oa(os, TEST_ARCHIVE_FLAGS);

    polymorphic_base *rb1 = new polymorphic_derived1;

    // get the eti record for the exported type "polymorphic_derived2"
    boost::serialization::extended_type_info const * const d2_eti =
        boost::serialization::extended_type_info::find(
            "polymorphic_derived2"
        );
    assert(NULL != d2_eti);

    // create a new instance of the type referred to by this record.
    // in this example, we happen to know that the class constructor
    // takes no arguments.
    void const * const rd2 = d2_eti->construct();
    assert(NULL != rd2);

    // transform the pointer to a pointer to the base class
    polymorphic_base const * const rb2 
        = static_cast<polymorphic_base const *>(
            boost::serialization::void_upcast(
                * d2_eti,
                boost::serialization::type_info_implementation<polymorphic_base>
                    ::type::get_const_instance(),
                rd2
            )
        );

    // export will permit correct serialization
    // through a pointer to a base class
    oa << BOOST_SERIALIZATION_NVP(rb1);
    oa << BOOST_SERIALIZATION_NVP(rb2);

    // don't need these any more - don't leak memory
    delete rb1;
    // note delete original handle - not runtime cast one !!!
    //delete rb2;
    d2_eti->destroy(rd2);
}

// save exported polymorphic class
void load_exported(const char *testfile)
{
    test_istream is(testfile, TEST_STREAM_FLAGS);
    test_iarchive ia(is, TEST_ARCHIVE_FLAGS);

    polymorphic_base *rb1 = NULL;
    polymorphic_base *rb2 = NULL;

    // export will permit correct serialization
    // through a pointer to a base class
    ia >> BOOST_SERIALIZATION_NVP(rb1);

    BOOST_CHECK_MESSAGE(
        boost::serialization::type_info_implementation<polymorphic_derived1>
            ::type::get_const_instance()
        == 
        * boost::serialization::type_info_implementation<polymorphic_base>
            ::type::get_const_instance().get_derived_extended_type_info(*rb1),
        "restored pointer b1 not of correct type"
    );
    ia >> BOOST_SERIALIZATION_NVP(rb2);

    // get the eti record for the exported type "polymorphic_derived2"
    boost::serialization::extended_type_info const * const d2_eti =
        boost::serialization::extended_type_info::find(
            "polymorphic_derived2"
        );
    assert(NULL != d2_eti);

    BOOST_CHECK_MESSAGE(
        * d2_eti
        == 
        * boost::serialization::type_info_implementation<polymorphic_base>
            ::type::get_const_instance().get_derived_extended_type_info(*rb2),
        "restored pointer b2 not of correct type"
    );

    delete rb1;
    delete rb2;
}

#ifdef BOOST_WINDOWS

#define WIN32_LEAN_AND_MEAN
#include <TCHAR.H>
#include <windows.h>

int
test_main( int /* argc */, char* /* argv */[] )
{
    const char * testfile = boost::archive::tmpnam(NULL);
    BOOST_REQUIRE(NULL != testfile);

    HINSTANCE hDLL;               // Handle to DLL
    hDLL = LoadLibrary(_T("plugin_polymorphic_derived2.dll"));
    BOOST_CHECK_MESSAGE(
        (0 != hDLL), 
        "Failed to find/load plugin_polymorphic_derived2"
    );
    if(0 == hDLL)
        return EXIT_FAILURE;

    save_exported(testfile);
    load_exported(testfile);
    FreeLibrary(hDLL);

    std::remove(testfile);
    return EXIT_SUCCESS;
}

#else // presume *nix

#include <dlfcn.h>

int
test_main( int /* argc */, char* /* argv */[] )
{
    const char * testfile = boost::archive::tmpnam(NULL);
    BOOST_REQUIRE(NULL != testfile);

    void * hDLL;               // Handle to DLL
    hDLL = dlopen("plugin_polymorphic_derived2.so", RTLD_NOW | RTLD_GLOBAL);
    BOOST_CHECK_MESSAGE((0 != hDLL), "Failed to find/load plugin_polymorphic_derived2" );
    if(0 == hDLL)
        return EXIT_FAILURE;

    save_exported(testfile);
    load_exported(testfile);
    dlclose(hDLL);

    std::remove(testfile);
    return EXIT_SUCCESS;
}

#endif

// EOF