1 // Copyright 2014 Renato Tegon Forti, Antony Polukhin. 2 // Copyright 2015-2019 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_DETAIL_WINDOWS_PATH_FROM_HANDLE_HPP 9 #define BOOST_DLL_DETAIL_WINDOWS_PATH_FROM_HANDLE_HPP 10 11 #include <boost/dll/config.hpp> 12 #include <boost/dll/detail/system_error.hpp> 13 #include <boost/winapi/dll.hpp> 14 #include <boost/winapi/get_last_error.hpp> 15 16 #ifdef BOOST_HAS_PRAGMA_ONCE 17 # pragma once 18 #endif 19 20 namespace boost { namespace dll { namespace detail { 21 last_error_code()22 inline boost::dll::fs::error_code last_error_code() BOOST_NOEXCEPT { 23 boost::winapi::DWORD_ err = boost::winapi::GetLastError(); 24 return boost::dll::fs::error_code( 25 static_cast<int>(err), 26 boost::dll::fs::system_category() 27 ); 28 } 29 path_from_handle(boost::winapi::HMODULE_ handle,boost::dll::fs::error_code & ec)30 inline boost::dll::fs::path path_from_handle(boost::winapi::HMODULE_ handle, boost::dll::fs::error_code &ec) { 31 BOOST_STATIC_CONSTANT(boost::winapi::DWORD_, ERROR_INSUFFICIENT_BUFFER_ = 0x7A); 32 BOOST_STATIC_CONSTANT(boost::winapi::DWORD_, DEFAULT_PATH_SIZE_ = 260); 33 34 // On success, GetModuleFileNameW() doesn't reset last error to ERROR_SUCCESS. Resetting it manually. 35 boost::winapi::GetLastError(); 36 37 // If `handle` parameter is NULL, GetModuleFileName retrieves the path of the 38 // executable file of the current process. 39 boost::winapi::WCHAR_ path_hldr[DEFAULT_PATH_SIZE_]; 40 boost::winapi::GetModuleFileNameW(handle, path_hldr, DEFAULT_PATH_SIZE_); 41 ec = boost::dll::detail::last_error_code(); 42 if (!ec) { 43 return boost::dll::fs::path(path_hldr); 44 } 45 46 for (unsigned i = 2; i < 1025 && static_cast<boost::winapi::DWORD_>(ec.value()) == ERROR_INSUFFICIENT_BUFFER_; i *= 2) { 47 std::wstring p(DEFAULT_PATH_SIZE_ * i, L'\0'); 48 const std::size_t size = boost::winapi::GetModuleFileNameW(handle, &p[0], DEFAULT_PATH_SIZE_ * i); 49 ec = boost::dll::detail::last_error_code(); 50 51 if (!ec) { 52 p.resize(size); 53 return boost::dll::fs::path(p); 54 } 55 } 56 57 // Error other than ERROR_INSUFFICIENT_BUFFER_ occurred or failed to allocate buffer big enough. 58 return boost::dll::fs::path(); 59 } 60 61 }}} // namespace boost::dll::detail 62 63 #endif // BOOST_DLL_DETAIL_WINDOWS_PATH_FROM_HANDLE_HPP 64 65