1 | /////////1/////////2/////////3/////////4/////////5/////////6/////////7/////////8 |
2 | // test_dll_plugin.cpp |
3 | |
4 | // (C) Copyright 2002 Robert Ramey - http://www.rrsd.com . |
5 | // Use, modification and distribution is subject to the Boost Software |
6 | // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at |
7 | // http://www.boost.org/LICENSE_1_0.txt) |
8 | |
9 | // should pass compilation and execution |
10 | |
11 | // Note this test creates, serializes, and destroys |
12 | // a class instance while knowing nothing more than its |
13 | // exported class ID (GUID) and a base class from which |
14 | // it is derived. This is referred to as a "plugin" |
15 | // since the same program could, without recompilation, |
16 | // manipulate any number of derived types - even those |
17 | // which have not been yet been created. |
18 | |
19 | #include <fstream> |
20 | |
21 | #include <cstdio> // remove |
22 | #include <boost/config.hpp> |
23 | #if defined(BOOST_NO_STDC_NAMESPACE) |
24 | namespace std{ |
25 | using ::remove; |
26 | } |
27 | #endif |
28 | |
29 | #include <boost/archive/archive_exception.hpp> |
30 | |
31 | // for now, only test with simple text and polymorphic archive |
32 | #include "test_tools.hpp" |
33 | |
34 | #include <boost/serialization/base_object.hpp> |
35 | #include <boost/serialization/export.hpp> |
36 | #include <boost/serialization/type_info_implementation.hpp> |
37 | #include <boost/serialization/access.hpp> |
38 | #include <boost/serialization/void_cast.hpp> |
39 | #include <boost/serialization/extended_type_info.hpp> |
40 | |
41 | #include "polymorphic_base.hpp" |
42 | |
43 | // declare and implement a derived class in our own executable |
44 | class polymorphic_derived1 : public polymorphic_base |
45 | { |
46 | friend class boost::serialization::access; |
47 | template<class Archive> |
48 | void serialize(Archive &ar, const unsigned int /* file_version */){ |
49 | ar & BOOST_SERIALIZATION_BASE_OBJECT_NVP(polymorphic_base); |
50 | } |
51 | const char * get_key() const{ |
52 | return |
53 | boost::serialization::type_info_implementation< |
54 | polymorphic_derived1 |
55 | >::type::get_const_instance().get_key(); |
56 | } |
57 | public: |
58 | virtual ~polymorphic_derived1(){} |
59 | }; |
60 | |
61 | // This class is derived from polymorphic_base which uses the no_rtti system |
62 | // rather than the typeid system. This system uses the exported name as the |
63 | // type identifier key. This MUST be exported!!! |
64 | BOOST_CLASS_EXPORT(polymorphic_derived1) |
65 | |
66 | // MWerks users can do this to make their code work |
67 | BOOST_SERIALIZATION_MWERKS_BASE_AND_DERIVED(polymorphic_base, polymorphic_derived1) |
68 | |
69 | // save exported polymorphic class |
70 | void save_exported(const char *testfile) |
71 | { |
72 | test_ostream os(testfile, TEST_STREAM_FLAGS); |
73 | test_oarchive oa(os, TEST_ARCHIVE_FLAGS); |
74 | |
75 | polymorphic_base *rb1 = new polymorphic_derived1; |
76 | |
77 | // get the eti record for the exported type "polymorphic_derived2" |
78 | boost::serialization::extended_type_info const * const d2_eti = |
79 | boost::serialization::extended_type_info::find( |
80 | key: "polymorphic_derived2" |
81 | ); |
82 | assert(NULL != d2_eti); |
83 | |
84 | // create a new instance of the type referred to by this record. |
85 | // in this example, we happen to know that the class constructor |
86 | // takes no arguments. |
87 | void const * const rd2 = d2_eti->construct(); |
88 | assert(NULL != rd2); |
89 | |
90 | // transform the pointer to a pointer to the base class |
91 | polymorphic_base const * const rb2 |
92 | = static_cast<polymorphic_base const *>( |
93 | boost::serialization::void_upcast( |
94 | derived: * d2_eti, |
95 | base: boost::serialization::type_info_implementation<polymorphic_base> |
96 | ::type::get_const_instance(), |
97 | t: rd2 |
98 | ) |
99 | ); |
100 | |
101 | // export will permit correct serialization |
102 | // through a pointer to a base class |
103 | oa << BOOST_SERIALIZATION_NVP(rb1); |
104 | oa << BOOST_SERIALIZATION_NVP(rb2); |
105 | |
106 | // don't need these any more - don't leak memory |
107 | delete rb1; |
108 | // note delete original handle - not runtime cast one !!! |
109 | //delete rb2; |
110 | d2_eti->destroy(rd2); |
111 | } |
112 | |
113 | // save exported polymorphic class |
114 | void load_exported(const char *testfile) |
115 | { |
116 | test_istream is(testfile, TEST_STREAM_FLAGS); |
117 | test_iarchive ia(is, TEST_ARCHIVE_FLAGS); |
118 | |
119 | polymorphic_base *rb1 = NULL; |
120 | polymorphic_base *rb2 = NULL; |
121 | |
122 | // export will permit correct serialization |
123 | // through a pointer to a base class |
124 | ia >> BOOST_SERIALIZATION_NVP(rb1); |
125 | |
126 | BOOST_CHECK_MESSAGE( |
127 | boost::serialization::type_info_implementation<polymorphic_derived1> |
128 | ::type::get_const_instance() |
129 | == |
130 | * boost::serialization::type_info_implementation<polymorphic_base> |
131 | ::type::get_const_instance().get_derived_extended_type_info(*rb1), |
132 | "restored pointer b1 not of correct type" |
133 | ); |
134 | ia >> BOOST_SERIALIZATION_NVP(rb2); |
135 | |
136 | // get the eti record for the exported type "polymorphic_derived2" |
137 | boost::serialization::extended_type_info const * const d2_eti = |
138 | boost::serialization::extended_type_info::find( |
139 | key: "polymorphic_derived2" |
140 | ); |
141 | assert(NULL != d2_eti); |
142 | |
143 | BOOST_CHECK_MESSAGE( |
144 | * d2_eti |
145 | == |
146 | * boost::serialization::type_info_implementation<polymorphic_base> |
147 | ::type::get_const_instance().get_derived_extended_type_info(*rb2), |
148 | "restored pointer b2 not of correct type" |
149 | ); |
150 | |
151 | delete rb1; |
152 | delete rb2; |
153 | } |
154 | |
155 | #ifdef BOOST_WINDOWS |
156 | |
157 | #define WIN32_LEAN_AND_MEAN |
158 | #include <TCHAR.H> |
159 | #include <windows.h> |
160 | |
161 | int |
162 | test_main( int /* argc */, char* /* argv */[] ) |
163 | { |
164 | const char * testfile = boost::archive::tmpnam(NULL); |
165 | BOOST_REQUIRE(NULL != testfile); |
166 | |
167 | HINSTANCE hDLL; // Handle to DLL |
168 | hDLL = LoadLibrary(_T("polymorphic_derived2.dll" )); |
169 | BOOST_CHECK_MESSAGE( |
170 | (0 != hDLL), |
171 | "Failed to find/load polymorphic_derived2" |
172 | ); |
173 | if(0 == hDLL) |
174 | return EXIT_FAILURE; |
175 | |
176 | save_exported(testfile); |
177 | load_exported(testfile); |
178 | FreeLibrary(hDLL); |
179 | |
180 | std::remove(testfile); |
181 | return EXIT_SUCCESS; |
182 | } |
183 | |
184 | #else // presume *nix |
185 | |
186 | #include <dlfcn.h> |
187 | |
188 | int |
189 | test_main( int /* argc */, char* /* argv */[] ) |
190 | { |
191 | const char * testfile = boost::archive::tmpnam(NULL); |
192 | BOOST_REQUIRE(NULL != testfile); |
193 | |
194 | void * hDLL; // Handle to DLL |
195 | hDLL = dlopen(file: "polymorphic_derived2.so" , RTLD_NOW | RTLD_GLOBAL); |
196 | BOOST_CHECK_MESSAGE((0 != hDLL), "Failed to find/load plugin_polymorphic_derived2" ); |
197 | BOOST_CHECK_MESSAGE((0 != hDLL), dlerror() ); |
198 | if(0 == hDLL) |
199 | return EXIT_FAILURE; |
200 | |
201 | save_exported(testfile); |
202 | load_exported(testfile); |
203 | dlclose(handle: hDLL); |
204 | |
205 | std::remove(filename: testfile); |
206 | return EXIT_SUCCESS; |
207 | } |
208 | |
209 | #endif |
210 | |
211 | // EOF |
212 | |