2014-10-06 2 views
0

С многих дней я пытаюсь решить 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; 
} 

Как вы можете видеть класс я так хочу сериализации всегда находится вложенный класс «Параметр» определен в DERIV ed из «dll» -interface (PlugInClass_Base) и получен из класса параметров базового класса (например, PlugInClass_Derived_1 :: Parameter). Dll-функция «getInitParameter» возвращает базовый указатель на базовый класс класса параметров, который мы хотим сохранить.

Вы видите, что я делаю неправильно во время сериализации? Я был бы рад, если бы вы могли дать мне несколько советов.

Alexandros.

ответ

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().

Любые предположения?

0

Последнее сообщение неверное. Он работает, потому что для кастования базового указателя производный класс должен быть связан -> static.

Это означает, что dll-сериализация все еще не работает

Смежные вопросы