| 1 | // Licensed to the .NET Foundation under one or more agreements. |
| 2 | // The .NET Foundation licenses this file to you under the MIT license. |
| 3 | // See the LICENSE file in the project root for more information. |
| 4 | // |
| 5 | |
| 6 | // |
| 7 | // Contains convenience functionality for lazily loading modules |
| 8 | // and getting entrypoints within them. |
| 9 | // |
| 10 | |
| 11 | #ifndef DelayLoadHelpers_h |
| 12 | #define DelayLoadHelpers_h |
| 13 | |
| 14 | #include "volatile.h" |
| 15 | |
| 16 | namespace DelayLoad |
| 17 | { |
| 18 | //================================================================================================================= |
| 19 | // Contains information needed to load and cache a module. Use through |
| 20 | // the DELAY_LOADED_MODULE macro defined below. |
| 21 | struct Module |
| 22 | { |
| 23 | LPCWSTR const m_wzDllName; |
| 24 | HMODULE m_hMod; |
| 25 | HRESULT m_hr; |
| 26 | Volatile<bool> m_fInitialized; |
| 27 | |
| 28 | // Returns a non-ref-counted HMODULE; will load the module if necessary. |
| 29 | // Do not FreeLibrary the returned value. |
| 30 | HRESULT GetValue(HMODULE *pHMODULE); |
| 31 | }; |
| 32 | } |
| 33 | |
| 34 | //===================================================================================================================== |
| 35 | // Use at global scope to declare a delay loaded module represented as a |
| 36 | // DelayLoad::Module instance. The module may then be accessed as |
| 37 | // 'DelayLoad::Modules::DLL_NAME'. |
| 38 | // |
| 39 | // Parameters: |
| 40 | // DLL_NAME - the simple name (without extension) of the DLL. |
| 41 | // |
| 42 | // Example: |
| 43 | // DELAY_LOADED_MODULE(Kernel32); |
| 44 | // void Foo() { |
| 45 | // HMODULE hModKernel32 = nullptr; |
| 46 | // IfFailThrow(DelayLoad::Modules::Kernel32.GetValue(&hModKernel32)); |
| 47 | // // Use hModKernel32 as needed. Do not FreeLibrary the value! |
| 48 | // } |
| 49 | |
| 50 | #define DELAY_LOADED_MODULE(DLL_NAME) \ |
| 51 | namespace DelayLoad { \ |
| 52 | namespace Modules { \ |
| 53 | SELECTANY Module DLL_NAME = { L#DLL_NAME W(".dll"), nullptr, S_OK, false }; \ |
| 54 | } \ |
| 55 | } |
| 56 | |
| 57 | namespace DelayLoad |
| 58 | { |
| 59 | //================================================================================================================= |
| 60 | // Contains information needed to load a function pointer from a DLL. Builds |
| 61 | // on the DelayLoad::Module functionality, and should be used through |
| 62 | // the DELAY_LOADED_FUNCTION macro defined below. |
| 63 | struct Function |
| 64 | { |
| 65 | Module * const m_pModule; |
| 66 | LPCSTR const m_szFunctionName; |
| 67 | PVOID m_pvFunction; |
| 68 | HRESULT m_hr; |
| 69 | Volatile<bool> m_fInitialized; |
| 70 | |
| 71 | // On success, ppvFunc is set to point to the entrypoint corresponding to |
| 72 | // m_szFunctionName as exported from m_pModule. |
| 73 | HRESULT GetValue(LPVOID * ppvFunc); |
| 74 | |
| 75 | // Convenience function that does the necessary casting for you. |
| 76 | template <typename FnT> inline |
| 77 | HRESULT GetValue(FnT ** ppFunc) |
| 78 | { |
| 79 | return GetValue(reinterpret_cast<LPVOID*>(ppFunc)); |
| 80 | } |
| 81 | }; |
| 82 | } |
| 83 | |
| 84 | //===================================================================================================================== |
| 85 | // Use at global scope to declare a delay loaded function and its associated module, |
| 86 | // represented as DelayLoad::Function and DelayLoad::Module instances, respectively. |
| 87 | // The function may then be accessed as 'DelayLoad::DLL_NAME::FUNC_NAME', and the |
| 88 | // module may be access as described in DELAY_LOADED_MODULE's comment. |
| 89 | // |
| 90 | // Parameters: |
| 91 | // DLL_NAME - unquoted simple name (without extension) of the DLL containing |
| 92 | // the function. |
| 93 | // FUNC_NAME - unquoted entrypoint name exported from the DLL. |
| 94 | // |
| 95 | // Example: |
| 96 | // DELAY_LOADED_FUNCTION(MyDll, MyFunction); |
| 97 | // HRESULT Foo(...) { |
| 98 | // typedef HRESULT MyFunction_t(<args>); |
| 99 | // MyFunction_t * pFunc = nullptr; |
| 100 | // IfFailRet(DelayLoad::WinTypes::RoResolveNamespace.GetValue(&pFunc)); |
| 101 | // return (*pFunc)(...); |
| 102 | // } |
| 103 | |
| 104 | #define DELAY_LOADED_FUNCTION(DLL_NAME, FUNC_NAME) \ |
| 105 | DELAY_LOADED_MODULE(DLL_NAME) \ |
| 106 | namespace DelayLoad { \ |
| 107 | namespace DLL_NAME { \ |
| 108 | SELECTANY Function FUNC_NAME = { &Modules::##DLL_NAME, #FUNC_NAME, nullptr, S_OK, false }; \ |
| 109 | } \ |
| 110 | } |
| 111 | |
| 112 | #endif // DelayLoadHelpers_h |
| 113 | |
| 114 | |