DynamicallyLinkedFunctionPtr.h (4185B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_DynamicallyLinkedFunctionPtr_h 8 #define mozilla_DynamicallyLinkedFunctionPtr_h 9 10 #include <windows.h> 11 12 #include <utility> 13 14 #include "mozilla/Attributes.h" 15 16 namespace mozilla { 17 namespace detail { 18 19 template <typename T> 20 struct FunctionPtrCracker; 21 22 template <typename R, typename... Args> 23 struct FunctionPtrCracker<R (*)(Args...)> { 24 using ReturnT = R; 25 using FunctionPtrT = R (*)(Args...); 26 }; 27 28 #if defined(_M_IX86) 29 template <typename R, typename... Args> 30 struct FunctionPtrCracker<R(__stdcall*)(Args...)> { 31 using ReturnT = R; 32 using FunctionPtrT = R(__stdcall*)(Args...); 33 }; 34 35 template <typename R, typename... Args> 36 struct FunctionPtrCracker<R(__fastcall*)(Args...)> { 37 using ReturnT = R; 38 using FunctionPtrT = R(__fastcall*)(Args...); 39 }; 40 #endif // defined(_M_IX86) 41 42 template <typename T> 43 class DynamicallyLinkedFunctionPtrBase { 44 public: 45 using ReturnT = typename FunctionPtrCracker<T>::ReturnT; 46 using FunctionPtrT = typename FunctionPtrCracker<T>::FunctionPtrT; 47 48 DynamicallyLinkedFunctionPtrBase(const wchar_t* aLibName, 49 const char* aFuncName) 50 : mModule(::LoadLibraryW(aLibName)), mFunction(nullptr) { 51 if (!mModule) { 52 return; 53 } 54 55 mFunction = 56 reinterpret_cast<FunctionPtrT>(::GetProcAddress(mModule, aFuncName)); 57 58 if (!mFunction) { 59 // Since the function doesn't exist, there is no point in holding a 60 // reference to mModule anymore. 61 ::FreeLibrary(mModule); 62 mModule = nullptr; 63 } 64 } 65 66 DynamicallyLinkedFunctionPtrBase(const DynamicallyLinkedFunctionPtrBase&) = 67 delete; 68 DynamicallyLinkedFunctionPtrBase& operator=( 69 const DynamicallyLinkedFunctionPtrBase&) = delete; 70 71 DynamicallyLinkedFunctionPtrBase(DynamicallyLinkedFunctionPtrBase&&) = delete; 72 DynamicallyLinkedFunctionPtrBase& operator=( 73 DynamicallyLinkedFunctionPtrBase&&) = delete; 74 75 template <typename... Args> 76 ReturnT operator()(Args&&... args) const { 77 return mFunction(std::forward<Args>(args)...); 78 } 79 80 explicit operator bool() const { return !!mFunction; } 81 82 protected: 83 HMODULE mModule; 84 FunctionPtrT mFunction; 85 }; 86 87 } // namespace detail 88 89 /** 90 * In most cases, this class is the one that you want to use for resolving a 91 * dynamically-linked function pointer. It should be instantiated as a static 92 * local variable. 93 * 94 * NB: It has a trivial destructor, so the DLL that is loaded is never freed. 95 * Assuming that this function is called fairly often, this is the most 96 * sensible option. OTOH, if the function you are calling is a one-off, or the 97 * static local requirement is too restrictive, use DynamicallyLinkedFunctionPtr 98 * instead. 99 */ 100 template <typename T> 101 class MOZ_STATIC_LOCAL_CLASS StaticDynamicallyLinkedFunctionPtr final 102 : public detail::DynamicallyLinkedFunctionPtrBase<T> { 103 public: 104 StaticDynamicallyLinkedFunctionPtr(const wchar_t* aLibName, 105 const char* aFuncName) 106 : detail::DynamicallyLinkedFunctionPtrBase<T>(aLibName, aFuncName) {} 107 108 /** 109 * We only offer this operator for the static local case, as it is not 110 * possible for this object to be destroyed while the returned pointer is 111 * being held. 112 */ 113 operator typename detail::DynamicallyLinkedFunctionPtrBase<T>::FunctionPtrT() 114 const { 115 return this->mFunction; 116 } 117 }; 118 119 template <typename T> 120 class MOZ_NON_PARAM MOZ_NON_TEMPORARY_CLASS DynamicallyLinkedFunctionPtr final 121 : public detail::DynamicallyLinkedFunctionPtrBase<T> { 122 public: 123 DynamicallyLinkedFunctionPtr(const wchar_t* aLibName, const char* aFuncName) 124 : detail::DynamicallyLinkedFunctionPtrBase<T>(aLibName, aFuncName) {} 125 126 ~DynamicallyLinkedFunctionPtr() { 127 if (!this->mModule) { 128 return; 129 } 130 131 ::FreeLibrary(this->mModule); 132 } 133 }; 134 135 } // namespace mozilla 136 137 #endif // mozilla_DynamicallyLinkedFunctionPtr_h