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
16namespace 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
57namespace 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