在dll内定义的派生嵌套类的序列化

时间:2014-10-06 14:32:29

标签: c++ dll derived-class boost-serialization

因为很多天我试图解决派生嵌套类的DLL序列化问题。我已经尝试了很多我发现的例子(即export_keys),但我总是得到运行时错误。访问序列化功能存在一些问题。我写了一个类似于我们根据boost serialization tests (polymorphic_derived2)使用的类的简化类。

// ############# dll ###################

// PlugInClass_Derived_2.h //

#pragma once

#ifdef PLUGIN
// All functions in this file are exported
#else
// All functions in this file are imported
#define PLUGIN __declspec(dllimport)
#endif

#include "PlugInClass_Derived_1.h"

class PlugInClass_Derived_2 : public PlugInClass_Derived_1
{
public:

    class DLL_DECL(BOOST_PP_EMPTY()) Parameter : public PlugInClass_Derived_1::Parameter
    {
    public:

        Parameter(void);
        virtual ~Parameter(void){};

    private:
        friend class boost::serialization::access;

        template <typename Archive>
        void serialize(Archive &ar, const unsigned int version);

    public:
        virtual const char * get_key() const {
            return "PlugInClass_Derived_2_Parameter";
        }
    };

public:

    /** @brief  standard constructor */
    PlugInClass_Derived_2(){};
    virtual ~PlugInClass_Derived_2(){};

    PLUGIN virtual boost::shared_ptr<PlugInClass_Base::Parameter> getInitParameter();
};



extern "C" PLUGIN PlugInClass_Base* Create(/*void** params, const int number*/);
extern "C" PLUGIN void Destroy(PlugInClass_Base* p);

// we use this because we want to assign a key to this type
// but we don't want to explicitly instantiate code every time
// we do so!!!.  If we don't do this, we end up with the same
// code in BOTH the DLL which implements polymorphic_derived2
// as well as the main program.
BOOST_CLASS_EXPORT_KEY(PlugInClass_Derived_2::Parameter)

// note the mixing of type_info systems is supported.
BOOST_CLASS_TYPE_INFO(
PlugInClass_Derived_2::Parameter,
boost::serialization::extended_type_info_typeid<PlugInClass_Derived_2::Parameter>
)

#undef DLL_DECL

// PlugInClass_Derived_2.cpp

/* boost headers go here */

/* plugin headers go here */
#define POLYMORPHIC_DERIVED2_EXPORT
#include "PlugInClass_Derived_2.h"

PlugInClass_Derived_2::Parameter::Parameter(){
    d = -2.;
    /*nothing*/
}

template <typename Archive>
void PlugInClass_Derived_2::Parameter::serialize(Archive &ar, const unsigned int version)
{
    ar & boost::serialization::base_object<PlugInClass_Derived_1::Parameter>(*this);
}

boost::shared_ptr<PlugInClass_Base::Parameter> PlugInClass_Derived_2::getInitParameter(){
    // get local data pointer;
    boost::shared_ptr<PlugInClass_Base::Parameter> localParameter(new  PlugInClass_Derived_2::Parameter());
    // update parent information

    // return local data
    return localParameter;
}


PlugInClass_Base* Create(/*void** params, const int number*/) {
    return new PlugInClass_Derived_2();
}


void Destroy(PlugInClass_Base* p) {
    delete p;
}



// instantiate code for text archives
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

template EXPORT_DECL(void) PlugInClass_Derived_2::Parameter::serialize(
    boost::archive::text_oarchive & ar,
    const unsigned int version
    );
template EXPORT_DECL(void) PlugInClass_Derived_2::Parameter::serialize(
    boost::archive::text_iarchive & ar,
    const unsigned int version
    );

// instantiate code for polymorphic archives
#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>

template EXPORT_DECL(void) PlugInClass_Derived_2::Parameter::serialize(
    boost::archive::polymorphic_oarchive & ar,
    const unsigned int version
    );
template EXPORT_DECL(void) PlugInClass_Derived_2::Parameter::serialize(
    boost::archive::polymorphic_iarchive & ar,
    const unsigned int version
    );


// MWerks users can do this to make their code work
BOOST_SERIALIZATION_MWERKS_BASE_AND_DERIVED(
    PlugInClass_Derived_1::Parameter
    , PlugInClass_Derived_2::Parameter)

    // note: export has to be AFTER #includes for all archive classes
    BOOST_CLASS_EXPORT_IMPLEMENT(PlugInClass_Derived_2::Parameter)

// PlugInClass_Derived_1.h

#pragma once

#ifdef PLUGIN
// All functions in this file are exported
#else
// All functions in this file are imported
#define PLUGIN __declspec(dllimport)
#endif

#include "PlugInClass_Base.h"

class PlugInClass_Derived_1 : public PlugInClass_Base
{
public:

    class DLL_DECL(BOOST_PP_EMPTY()) Parameter : public PlugInClass_Base::Parameter
    {
    public:

        int a, b, c;

        Parameter(void);
        virtual ~Parameter(void){};

    private:
        friend class boost::serialization::access;

        template <typename Archive>
        void serialize(Archive &ar, const unsigned int version);

    public:
        virtual const char * get_key() const {
            return "PlugInClass_Derived_1_Parameter";
        }
    };

public:

    /** @brief  standard constructor */
    PlugInClass_Derived_1(){};
    virtual ~PlugInClass_Derived_1(){};

    virtual boost::shared_ptr<PlugInClass_Base::Parameter> getInitParameter();
};


// we use this because we want to assign a key to this type
// but we don't want to explicitly instantiate code every time
// we do so!!!.  If we don't do this, we end up with the same
// code in BOTH the DLL which implements polymorphic_derived2
// as well as the main program.
BOOST_CLASS_EXPORT_KEY(PlugInClass_Derived_1::Parameter)

// note the mixing of type_info systems is supported.
BOOST_CLASS_TYPE_INFO(
PlugInClass_Derived_1::Parameter,
boost::serialization::extended_type_info_typeid<PlugInClass_Derived_1::Parameter>
)

// PlugInClass_Derived_1.cpp

/* boost headers go here */

/* plugin headers go here */
#define POLYMORPHIC_DERIVED2_EXPORT
#include "PlugInClass_Derived_1.h"

PlugInClass_Derived_1::Parameter::Parameter():
a(1),
b(2),
c(3)
{
    d = -1.;
    /*nothing*/
}

template <typename Archive>
void PlugInClass_Derived_1::Parameter::serialize(Archive &ar, const unsigned int version)
{
    ar & boost::serialization::base_object<PlugInClass_Base::Parameter>(*this);
    ar & a;
    ar & b;
    ar & c;

}

boost::shared_ptr<PlugInClass_Base::Parameter> PlugInClass_Derived_1::getInitParameter(){
    // get local data pointer;
    boost::shared_ptr<PlugInClass_Base::Parameter> localParameter(new  PlugInClass_Derived_1::Parameter());
    // update parent information

    // return local data
    return localParameter;
}


// instantiate code for text archives
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>

template EXPORT_DECL(void) PlugInClass_Derived_1::Parameter::serialize(
    boost::archive::text_oarchive & ar,
    const unsigned int version
    );
template EXPORT_DECL(void) PlugInClass_Derived_1::Parameter::serialize(
    boost::archive::text_iarchive & ar,
    const unsigned int version
    );

// instantiate code for polymorphic archives
#include <boost/archive/polymorphic_iarchive.hpp>
#include <boost/archive/polymorphic_oarchive.hpp>

template EXPORT_DECL(void) PlugInClass_Derived_1::Parameter::serialize(
    boost::archive::polymorphic_oarchive & ar,
    const unsigned int version
    );
template EXPORT_DECL(void) PlugInClass_Derived_1::Parameter::serialize(
    boost::archive::polymorphic_iarchive & ar,
    const unsigned int version
    );


// MWerks users can do this to make their code work
BOOST_SERIALIZATION_MWERKS_BASE_AND_DERIVED(
    PlugInClass_Base::Parameter
    , PlugInClass_Derived_1::Parameter)

    // note: export has to be AFTER #includes for all archive classes
    BOOST_CLASS_EXPORT_IMPLEMENT(PlugInClass_Derived_1::Parameter)

// PlugInClass_Base.h

#pragma once

#ifdef PLUGIN
// All functions in this file are exported
#else
// All functions in this file are imported
#define PLUGIN __declspec(dllimport)
#endif

// boost headers
#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/tracking.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/type_info_implementation.hpp>
#include <boost/serialization/extended_type_info_no_rtti.hpp>
#include <boost/serialization/extended_type_info_typeid.hpp>

#include <boost/preprocessor/empty.hpp>

// export_decl, import_decl from http://www.boost.org/doc/libs/1_55_0/libs/serialization/test/
#ifdef BOOST_HAS_DECLSPEC // defined in config system
#if ! defined(EXPORT_DECL)
#if defined(__BORLANDC__)
#define EXPORT_DECL(T)  T __export
#else
#define EXPORT_DECL(T) __declspec(dllexport) T 
#endif
#endif
#if ! defined(IMPORT_DECL)
#if defined(__BORLANDC__)
#define IMPORT_DECL(T)    T __import
#else
#define IMPORT_DECL(T)    __declspec(dllimport) T 
#endif
#endif
#else
#define IMPORT_DECL(T) T
#define EXPORT_DECL(T) T
#endif // BOOST_HAS_DECLSPEC

#if defined(POLYMORPHIC_DERIVED_IMPORT)
#define DLL_DECL IMPORT_DECL
#elif defined(POLYMORPHIC_DERIVED_EXPORT)
#define DLL_DECL EXPORT_DECL
#else
#define DLL_DECL(x)
#endif

class PlugInClass_Base
{
public:

    class DLL_DECL(BOOST_PP_EMPTY()) Parameter
    {
    public:

        double d;

        virtual ~Parameter(void){};

    private:
        friend class boost::serialization::access;

        template <typename Archive>
        void serialize(Archive &ar, const unsigned int version){
            ar & d;
        };

    public:
        virtual const char * get_key() const = 0;
    };

public:

    /** @brief  standard constructor */
    PlugInClass_Base(){};
    virtual ~PlugInClass_Base(){};

    PLUGIN virtual boost::shared_ptr<PlugInClass_Base::Parameter> getInitParameter(){return NULL;};
};

BOOST_SERIALIZATION_ASSUME_ABSTRACT(PlugInClass_Base::Parameter)

// we use this because we want to assign a key to this type
// but we don't want to explicitly instantiate code every time
// we do so!!!.  If we don't do this, we end up with the same
// code in BOTH the DLL which implements polymorphic_derived2
// as well as the main program.
BOOST_CLASS_EXPORT_KEY(PlugInClass_Base::Parameter)

// note the mixing of type_info systems is supported.
BOOST_CLASS_TYPE_INFO(
PlugInClass_Base::Parameter,
boost::serialization::extended_type_info_typeid<PlugInClass_Base::Parameter>
)

/// ######### dll结束################### ///

//至少是主要的

#include <stdio.h>
#include <tchar.h>
#include <fstream>
#include <sstream>

#include <boost/serialization/serialization.hpp>
#include <boost/archive/text_oarchive.hpp>
#include <boost/archive/text_iarchive.hpp>
#include <boost/serialization/vector.hpp>
#include <boost/serialization/export.hpp>
#include <boost/serialization/base_object.hpp>
#include <boost/serialization/shared_ptr.hpp>
#include <boost/serialization/assume_abstract.hpp>
#include <boost/serialization/tracking.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/nvp.hpp>
#include <boost/serialization/access.hpp>
#include <boost/serialization/type_info_implementation.hpp>
#include <boost/serialization/extended_type_info_no_rtti.hpp>

#include "PlugIn_Derived\PlugInClass_Base.h"

#include <windows.h>
int main(int argc, char** argv)
{

    boost::shared_ptr<PlugInClass_Base> dll_;

    /// ######### load dll ################### ///
    std::string pluginPath_ = "PlugInClass_Derived_2.dll";

    HINSTANCE currLibrary = LoadLibrary(pluginPath_.c_str());

    if (!currLibrary) {
        throw std::runtime_error("The plugin could not be loaded.");
    }

    // load the plugin class interface from the library using its factory functions
    typedef PlugInClass_Base *(*CreatePluginFuncDef)();
    CreatePluginFuncDef pluginCreateFactoryPtr = (CreatePluginFuncDef)GetProcAddress(currLibrary, "Create");
    typedef void(*DestroyPluginFuncDef)(PlugInClass_Base*);
    DestroyPluginFuncDef pluginDestroyPtr = (DestroyPluginFuncDef)GetProcAddress(currLibrary, "Destroy");
    // create object within dll
    dll_ = boost::shared_ptr<PlugInClass_Base>(pluginCreateFactoryPtr(), pluginDestroyPtr);

    /// ######### get object from dll ################### ///
    boost::shared_ptr<PlugInClass_Base::Parameter> parameterPtr = dll_->getInitParameter();

    /// ######### serialization ################### ///
    std::string s;
    // create and open a character archive for output
    {
        std::ostringstream os;
        // save data to archive
        boost::archive::text_oarchive oa(os);

        // write class instance to archive
        oa << parameterPtr; // HERE RUNTIME ERROR
        // Unhandled exception at xxxx in test_dll_simple_example.exe: 
        // Microsoft C++ exception: boost::archive::archive_exception at memory location xxxx

        s = os.str();
    }

    // ... some time later restore the class instance to its orginal state

    std::system("pause");
    return 0;
}

正如你所看到的那样,我希望序列化是一个嵌套类“参数”,它来自“dll” - 接口(PlugInClass_Base)的派生类,并派生自基类的参数类(即PlugInClass_Derived_1 :: Parameter)。 dll-function“getInitParameter”返回指向我们想要存储的参数类的基类的基指针。

你能看到我在序列化过程中做错了什么吗?如果你能给我一些提示,我会很高兴的。

亚历山德罗。

2 个答案:

答案 0 :(得分:0)

我发现,如果将基指针转换为派生指针,则序列化可以正常工作。

    /// ######### get object from dll ################### ///
    boost::shared_ptr<PlugInClass_Base::Parameter> parameterPtr = dll_->getInitParameter();
    boost::shared_ptr<PlugInClass_Derived_2::Parameter> derivedParameterPtr = boost::static_pointer_cast<PlugInClass_Derived_2::Parameter>(parameterPtr);

    /// ######### serialization ################### ///
    std::string s;
    // create and open a character archive for output
    {
        std::ostringstream os;
        // save data to archive
        boost::archive::text_oarchive oa(os);

        oa << derivedParameterPtr; // It works !!!

        s = os.str();
    }

因此,不知何故,序列化无法遍历基指针中的所有派生指针。 基类是一个抽象类

(BOOST_SERIALIZATION_ASSUME_ABSTRACT(PlugInClass_Base::Parameter))

并导出密钥

BOOST_CLASS_EXPORT_KEY(PlugInClass_Base::Parameter)

并且每个派生类的实现都是导出的(在cpp文件中)

BOOST_CLASS_EXPORT_IMPLEMENT(PlugInClass_Derived_1::Parameter)

嵌套类的键是否有问题?否则,所有派生类都有自己的get_key()函数。

任何假设?

答案 1 :(得分:0)

最后一篇文章错了。 它有效,因为对于基类指针的转换,必须链接派生类 - &gt;静态的。

这意味着dll序列化仍无法正常工作