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#include "stdafx.h"
12
13#include "crtwrap.h"
14#include "winwrap.h"
15#include "utilcode.h"
16#include "clrhost.h"
17#include "holder.h"
18#include "delayloadhelpers.h"
19
20namespace DelayLoad
21{
22 //=================================================================================================================
23 // Used to synchronize initialization. Is not used when initialization has already taken place.
24
25 static CRITSEC_COOKIE g_pLock = nullptr;
26
27 //=================================================================================================================
28 // Creates and initializes g_pLock when first used.
29
30 static HRESULT InitializeLock()
31 {
32 STATIC_CONTRACT_LIMITED_METHOD;
33 HRESULT hr = S_OK;
34
35 CRITSEC_COOKIE pLock = ClrCreateCriticalSection(CrstLeafLock, CRST_REENTRANCY);
36 IfNullRet(pLock);
37 if (InterlockedCompareExchangeT<CRITSEC_COOKIE>(&g_pLock, pLock, nullptr) != nullptr)
38 {
39 ClrDeleteCriticalSection(pLock);
40 }
41
42 return S_OK;
43 }
44
45 //=================================================================================================================
46 HRESULT Module::GetValue(HMODULE *pHMODULE)
47 {
48 STATIC_CONTRACT_LIMITED_METHOD;
49 HRESULT hr = S_OK;
50
51 if (pHMODULE == nullptr)
52 {
53 return E_INVALIDARG;
54 }
55
56 if (!m_fInitialized)
57 {
58 IfFailRet(InitializeLock());
59
60 HModuleHolder hMod = ::LoadLibraryW(m_wzDllName);
61 hr = (hMod == nullptr) ? HRESULT_FROM_GetLastError() : S_OK;
62 _ASSERTE(FAILED(hr) == (hMod == nullptr));
63
64 { // Lock scope
65 CRITSEC_Holder lock(g_pLock);
66 if (!m_fInitialized)
67 {
68 m_hr = hr;
69 m_hMod = hMod.Extract();
70 m_fInitialized = true;
71 }
72 }
73 }
74
75 _ASSERTE(m_fInitialized);
76 *pHMODULE = m_hMod;
77 return m_hr;
78 }
79
80 //=================================================================================================================
81 HRESULT Function::GetValue(LPVOID * ppvFunc)
82 {
83 STATIC_CONTRACT_LIMITED_METHOD;
84 HRESULT hr = S_OK;
85
86 if (ppvFunc == nullptr)
87 {
88 return E_INVALIDARG;
89 }
90
91 if (!m_fInitialized)
92 {
93 HMODULE hMod = nullptr;
94 IfFailRet(m_pModule->GetValue(&hMod));
95
96 LPVOID pvFunc = reinterpret_cast<LPVOID>(::GetProcAddress(hMod, m_szFunctionName));
97 hr = (pvFunc == nullptr) ? HRESULT_FROM_GetLastError() : S_OK;
98
99 { // Lock scope
100 CRITSEC_Holder lock(g_pLock);
101 if (!m_fInitialized)
102 {
103 m_hr = hr;
104 m_pvFunction = pvFunc;
105 m_fInitialized = true;
106 }
107 }
108 }
109
110 _ASSERTE(m_fInitialized);
111 *ppvFunc = m_pvFunction;
112 return m_hr;
113 }
114}
115