]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
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 | "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 | * d2_eti, | |
95 | boost::serialization::type_info_implementation<polymorphic_base> | |
96 | ::type::get_const_instance(), | |
97 | 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 | "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 | |
b32b8144 | 168 | hDLL = LoadLibrary(_T("polymorphic_derived2.dll")); |
7c673cae FG |
169 | BOOST_CHECK_MESSAGE( |
170 | (0 != hDLL), | |
b32b8144 | 171 | "Failed to find/load polymorphic_derived2" |
7c673cae FG |
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 | |
b32b8144 | 195 | hDLL = dlopen("polymorphic_derived2.so", RTLD_NOW | RTLD_GLOBAL); |
7c673cae | 196 | BOOST_CHECK_MESSAGE((0 != hDLL), "Failed to find/load plugin_polymorphic_derived2" ); |
b32b8144 | 197 | BOOST_CHECK_MESSAGE((0 != hDLL), dlerror() ); |
7c673cae FG |
198 | if(0 == hDLL) |
199 | return EXIT_FAILURE; | |
200 | ||
201 | save_exported(testfile); | |
202 | load_exported(testfile); | |
203 | dlclose(hDLL); | |
204 | ||
205 | std::remove(testfile); | |
206 | return EXIT_SUCCESS; | |
207 | } | |
208 | ||
209 | #endif | |
210 | ||
211 | // EOF |