因为很多天我试图解决派生嵌套类的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”返回指向我们想要存储的参数类的基类的基指针。
你能看到我在序列化过程中做错了什么吗?如果你能给我一些提示,我会很高兴的。
亚历山德罗。
答案 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序列化仍无法正常工作