]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Copyright 2014 Renato Tegon Forti, Antony Polukhin. |
2 | // Copyright 2015-2016 Antony Polukhin. | |
3 | // | |
4 | // Distributed under the Boost Software License, Version 1.0. | |
5 | // (See accompanying file LICENSE_1_0.txt | |
6 | // or copy at http://www.boost.org/LICENSE_1_0.txt) | |
7 | ||
8 | #ifndef BOOST_DLL_SHARED_LIBRARY_IMPL_HPP | |
9 | #define BOOST_DLL_SHARED_LIBRARY_IMPL_HPP | |
10 | ||
11 | #include <boost/config.hpp> | |
12 | #include <boost/dll/shared_library_load_mode.hpp> | |
13 | #include <boost/dll/detail/aggressive_ptr_cast.hpp> | |
14 | #include <boost/dll/detail/system_error.hpp> | |
15 | #include <boost/dll/detail/windows/path_from_handle.hpp> | |
16 | ||
17 | #include <boost/move/utility.hpp> | |
18 | #include <boost/swap.hpp> | |
19 | #include <boost/filesystem/path.hpp> | |
20 | #include <boost/filesystem/operations.hpp> | |
21 | ||
22 | #include <boost/detail/winapi/dll.hpp> | |
23 | ||
24 | #ifdef BOOST_HAS_PRAGMA_ONCE | |
25 | # pragma once | |
26 | #endif | |
27 | ||
28 | namespace boost { namespace dll { namespace detail { | |
29 | ||
30 | class shared_library_impl { | |
31 | BOOST_MOVABLE_BUT_NOT_COPYABLE(shared_library_impl) | |
32 | ||
33 | public: | |
34 | typedef boost::detail::winapi::HMODULE_ native_handle_t; | |
35 | ||
36 | shared_library_impl() BOOST_NOEXCEPT | |
37 | : handle_(NULL) | |
38 | {} | |
39 | ||
40 | ~shared_library_impl() BOOST_NOEXCEPT { | |
41 | unload(); | |
42 | } | |
43 | ||
44 | shared_library_impl(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT | |
45 | : handle_(sl.handle_) | |
46 | { | |
47 | sl.handle_ = NULL; | |
48 | } | |
49 | ||
50 | shared_library_impl & operator=(BOOST_RV_REF(shared_library_impl) sl) BOOST_NOEXCEPT { | |
51 | swap(sl); | |
52 | return *this; | |
53 | } | |
54 | ||
55 | void load(boost::filesystem::path sl, load_mode::type mode, boost::system::error_code &ec) { | |
56 | typedef boost::detail::winapi::DWORD_ native_mode_t; | |
57 | unload(); | |
58 | ||
59 | if (!sl.is_absolute() && !(mode & load_mode::search_system_folders)) { | |
60 | ||
61 | boost::system::error_code current_path_ec; | |
62 | boost::filesystem::path prog_loc = boost::filesystem::current_path(current_path_ec); | |
63 | if (!current_path_ec) { | |
64 | prog_loc /= sl; | |
65 | sl.swap(prog_loc); | |
66 | } | |
67 | } | |
68 | mode &= ~load_mode::search_system_folders; | |
69 | ||
70 | // Trying to open with appended decorations | |
71 | if (!!(mode & load_mode::append_decorations)) { | |
72 | mode &= ~load_mode::append_decorations; | |
73 | ||
74 | handle_ = boost::detail::winapi::LoadLibraryExW((sl.native() + L".dll").c_str(), 0, static_cast<native_mode_t>(mode)); | |
75 | if (!handle_) { | |
76 | // MinGW loves 'lib' prefix and puts it even on Windows platform | |
77 | const boost::filesystem::path load_path = (sl.has_parent_path() ? sl.parent_path() / L"lib" : L"lib").native() + sl.filename().native() + L".dll"; | |
78 | handle_ = boost::detail::winapi::LoadLibraryExW( | |
79 | load_path.c_str(), | |
80 | 0, | |
81 | static_cast<native_mode_t>(mode) | |
82 | ); | |
83 | } | |
84 | ||
85 | if (handle_) { | |
86 | return; | |
87 | } | |
88 | } | |
89 | ||
90 | // From MSDN: If the string specifies a module name without a path and the | |
91 | // file name extension is omitted, the function appends the default library | |
92 | // extension .dll to the module name. | |
93 | // | |
94 | // From experiments: Default library extension appended to the module name even if | |
95 | // we have some path. So we do not check for path, only for extension. We can not be sure that | |
96 | // such behavior remain across all platforms, so we add L"." by hand. | |
97 | if (sl.has_extension()) { | |
98 | handle_ = boost::detail::winapi::LoadLibraryExW(sl.c_str(), 0, static_cast<native_mode_t>(mode)); | |
99 | } else { | |
100 | handle_ = boost::detail::winapi::LoadLibraryExW((sl.native() + L".").c_str(), 0, static_cast<native_mode_t>(mode)); | |
101 | } | |
102 | ||
103 | // LoadLibraryExW method is capable of self loading from program_location() path. No special actions | |
104 | // must be taken to allow self loading. | |
105 | ||
106 | if (!handle_) { | |
107 | ec = boost::dll::detail::last_error_code(); | |
108 | } | |
109 | } | |
110 | ||
111 | bool is_loaded() const BOOST_NOEXCEPT { | |
112 | return (handle_ != 0); | |
113 | } | |
114 | ||
115 | void unload() BOOST_NOEXCEPT { | |
116 | if (handle_) { | |
117 | boost::detail::winapi::FreeLibrary(handle_); | |
118 | handle_ = 0; | |
119 | } | |
120 | } | |
121 | ||
122 | void swap(shared_library_impl& rhs) BOOST_NOEXCEPT { | |
123 | boost::swap(handle_, rhs.handle_); | |
124 | } | |
125 | ||
126 | boost::filesystem::path full_module_path(boost::system::error_code &ec) const { | |
127 | return boost::dll::detail::path_from_handle(handle_, ec); | |
128 | } | |
129 | ||
130 | static boost::filesystem::path suffix() { | |
131 | return L".dll"; | |
132 | } | |
133 | ||
134 | void* symbol_addr(const char* sb, boost::system::error_code &ec) const BOOST_NOEXCEPT { | |
135 | if (is_resource()) { | |
136 | // `GetProcAddress` could not be called for libraries loaded with | |
137 | // `LOAD_LIBRARY_AS_DATAFILE`, `LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE` | |
138 | // or `LOAD_LIBRARY_AS_IMAGE_RESOURCE`. | |
139 | ec = boost::system::error_code( | |
140 | boost::system::errc::operation_not_supported, | |
141 | boost::system::generic_category() | |
142 | ); | |
143 | ||
144 | return NULL; | |
145 | } | |
146 | ||
147 | // Judging by the documentation of GetProcAddress | |
148 | // there is no version for UNICODE on desktop/server Windows, because | |
149 | // names of functions are stored in narrow characters. | |
150 | void* const symbol = boost::dll::detail::aggressive_ptr_cast<void*>( | |
151 | boost::detail::winapi::get_proc_address(handle_, sb) | |
152 | ); | |
153 | if (symbol == NULL) { | |
154 | ec = boost::dll::detail::last_error_code(); | |
155 | } | |
156 | ||
157 | return symbol; | |
158 | } | |
159 | ||
160 | native_handle_t native() const BOOST_NOEXCEPT { | |
161 | return handle_; | |
162 | } | |
163 | ||
164 | private: | |
165 | bool is_resource() const BOOST_NOEXCEPT { | |
166 | return false; /*!!( | |
167 | reinterpret_cast<boost::detail::winapi::ULONG_PTR_>(handle_) & static_cast<boost::detail::winapi::ULONG_PTR_>(3) | |
168 | );*/ | |
169 | } | |
170 | ||
171 | native_handle_t handle_; | |
172 | }; | |
173 | ||
174 | }}} // boost::dll::detail | |
175 | ||
176 | #endif // BOOST_DLL_SHARED_LIBRARY_IMPL_HPP | |
177 |