summaryrefslogtreecommitdiff
path: root/src/binder
diff options
context:
space:
mode:
Diffstat (limited to 'src/binder')
-rw-r--r--src/binder/.gitmirror1
-rw-r--r--src/binder/CMakeLists.txt45
-rw-r--r--src/binder/applicationcontext.cpp487
-rw-r--r--src/binder/assembly.cpp434
-rw-r--r--src/binder/assemblybinder.cpp1953
-rw-r--r--src/binder/assemblyidentitycache.cpp72
-rw-r--r--src/binder/assemblyname.cpp704
-rw-r--r--src/binder/binder.targets50
-rw-r--r--src/binder/binderinterface.cpp191
-rw-r--r--src/binder/bindinglog.cpp332
-rw-r--r--src/binder/cdebuglog.cpp482
-rw-r--r--src/binder/clrprivbinderassemblyloadcontext.cpp259
-rw-r--r--src/binder/clrprivbindercoreclr.cpp309
-rw-r--r--src/binder/coreclrbindercommon.cpp188
-rw-r--r--src/binder/debuglog.cpp416
-rw-r--r--src/binder/dirs.proj20
-rw-r--r--src/binder/failurecache.cpp85
-rw-r--r--src/binder/fusionassemblyname.cpp1857
-rw-r--r--src/binder/fusionhelpers.cpp114
-rw-r--r--src/binder/inc/.gitmirror1
-rw-r--r--src/binder/inc/applicationcontext.hpp197
-rw-r--r--src/binder/inc/applicationcontext.inl110
-rw-r--r--src/binder/inc/assembly.hpp222
-rw-r--r--src/binder/inc/assembly.inl218
-rw-r--r--src/binder/inc/assemblybinder.hpp178
-rw-r--r--src/binder/inc/assemblyentry.hpp62
-rw-r--r--src/binder/inc/assemblyhashtraits.hpp59
-rw-r--r--src/binder/inc/assemblyidentity.hpp149
-rw-r--r--src/binder/inc/assemblyidentitycache.hpp116
-rw-r--r--src/binder/inc/assemblyname.hpp112
-rw-r--r--src/binder/inc/assemblyname.inl144
-rw-r--r--src/binder/inc/assemblyversion.hpp60
-rw-r--r--src/binder/inc/assemblyversion.inl183
-rw-r--r--src/binder/inc/binderinterface.hpp69
-rw-r--r--src/binder/inc/bindertypes.hpp132
-rw-r--r--src/binder/inc/bindinglog.hpp82
-rw-r--r--src/binder/inc/bindinglog.inl46
-rw-r--r--src/binder/inc/bindresult.hpp64
-rw-r--r--src/binder/inc/bindresult.inl229
-rw-r--r--src/binder/inc/cdebuglog.hpp67
-rw-r--r--src/binder/inc/clrprivbinderassemblyloadcontext.h86
-rw-r--r--src/binder/inc/clrprivbindercoreclr.h100
-rw-r--r--src/binder/inc/contextentry.hpp146
-rw-r--r--src/binder/inc/coreclrbindercommon.h58
-rw-r--r--src/binder/inc/debuglog.hpp118
-rw-r--r--src/binder/inc/failurecache.hpp38
-rw-r--r--src/binder/inc/failurecachehashtraits.hpp88
-rw-r--r--src/binder/inc/fusionassemblyname.hpp217
-rw-r--r--src/binder/inc/fusionhelpers.hpp95
-rw-r--r--src/binder/inc/list.hpp358
-rw-r--r--src/binder/inc/loadcontext.hpp49
-rw-r--r--src/binder/inc/loadcontext.inl90
-rw-r--r--src/binder/inc/propertyhashtraits.hpp95
-rw-r--r--src/binder/inc/propertymap.hpp35
-rw-r--r--src/binder/inc/stringlexer.hpp100
-rw-r--r--src/binder/inc/stringlexer.inl266
-rw-r--r--src/binder/inc/textualidentityparser.hpp70
-rw-r--r--src/binder/inc/utils.hpp57
-rw-r--r--src/binder/inc/variables.hpp66
-rw-r--r--src/binder/propertymap.cpp62
-rw-r--r--src/binder/stringlexer.cpp173
-rw-r--r--src/binder/textualidentityparser.cpp763
-rw-r--r--src/binder/utils.cpp319
-rw-r--r--src/binder/v3binder/.gitmirror1
-rw-r--r--src/binder/v3binder/CMakeLists.txt4
-rw-r--r--src/binder/v3binder/v3binder.nativeproj15
-rw-r--r--src/binder/v3binder_crossgen/.gitmirror1
-rw-r--r--src/binder/v3binder_crossgen/CMakeLists.txt6
-rw-r--r--src/binder/v3binder_crossgen/v3binder_crossgen.nativeproj15
-rw-r--r--src/binder/variables.cpp134
70 files changed, 14124 insertions, 0 deletions
diff --git a/src/binder/.gitmirror b/src/binder/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/binder/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/binder/CMakeLists.txt b/src/binder/CMakeLists.txt
new file mode 100644
index 0000000000..84b35b9cbc
--- /dev/null
+++ b/src/binder/CMakeLists.txt
@@ -0,0 +1,45 @@
+set(CMAKE_INCLUDE_CURRENT_DIR ON)
+include_directories(BEFORE "../vm/${ARCH_SOURCES_DIR}")
+include_directories(BEFORE "../vm")
+include_directories(BEFORE "inc")
+
+set(BINDER_COMMON_SOURCES
+ variables.cpp
+ utils.cpp
+ assemblyname.cpp
+ propertymap.cpp
+ applicationcontext.cpp
+ assembly.cpp
+ failurecache.cpp
+ assemblybinder.cpp
+ stringlexer.cpp
+ clrprivbindercoreclr.cpp
+ binderinterface.cpp
+ debuglog.cpp
+ bindinglog.cpp
+ cdebuglog.cpp
+ textualidentityparser.cpp
+ assemblyidentitycache.cpp
+ coreclrbindercommon.cpp
+ fusionassemblyname.cpp
+ fusionhelpers.cpp
+)
+
+set(BINDER_SOURCES
+ ${BINDER_COMMON_SOURCES}
+ clrprivbinderassemblyloadcontext.cpp
+)
+
+set(BINDER_CROSSGEN_SOURCES
+ ${BINDER_COMMON_SOURCES}
+)
+
+convert_to_absolute_path(BINDER_SOURCES ${BINDER_SOURCES})
+convert_to_absolute_path(BINDER_CROSSGEN_SOURCES ${BINDER_CROSSGEN_SOURCES})
+
+if(CLR_CMAKE_PLATFORM_UNIX)
+ add_compile_options(-fPIC)
+endif(CLR_CMAKE_PLATFORM_UNIX)
+
+add_subdirectory(v3binder)
+add_subdirectory(v3binder_crossgen)
diff --git a/src/binder/applicationcontext.cpp b/src/binder/applicationcontext.cpp
new file mode 100644
index 0000000000..e5c3025787
--- /dev/null
+++ b/src/binder/applicationcontext.cpp
@@ -0,0 +1,487 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// ApplicationContext.cpp
+//
+
+
+//
+// Implements the ApplicationContext class
+//
+// ============================================================
+
+#ifndef FEATURE_CORESYSTEM
+#define DISABLE_BINDER_DEBUG_LOGGING
+#endif
+
+#include "applicationcontext.hpp"
+#include "stringarraylist.h"
+#include "loadcontext.hpp"
+#include "propertymap.hpp"
+#include "failurecache.hpp"
+#include "assemblyidentitycache.hpp"
+#ifdef FEATURE_VERSIONING_LOG
+#include "debuglog.hpp"
+#endif // FEATURE_VERSIONING_LOG
+#include "utils.hpp"
+#include "variables.hpp"
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ STDMETHODIMP ApplicationContext::QueryInterface(REFIID riid,
+ void **ppv)
+ {
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ hr = E_POINTER;
+ }
+ else
+ {
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown *>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ }
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) ApplicationContext::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) ApplicationContext::Release()
+ {
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+ }
+
+ ApplicationContext::ApplicationContext()
+ {
+ m_cRef = 1;
+ m_dwAppDomainId = 0;
+ m_pExecutionContext = NULL;
+ m_pInspectionContext = NULL;
+ m_pFailureCache = NULL;
+ m_contextCS = NULL;
+ m_pTrustedPlatformAssemblyMap = nullptr;
+ m_pFileNameHash = nullptr;
+ }
+
+ ApplicationContext::~ApplicationContext()
+ {
+ SAFE_RELEASE(m_pExecutionContext);
+ SAFE_RELEASE(m_pInspectionContext);
+ SAFE_DELETE(m_pFailureCache);
+
+ if (m_contextCS != NULL)
+ {
+ ClrDeleteCriticalSection(m_contextCS);
+ }
+
+ if (m_pTrustedPlatformAssemblyMap != nullptr)
+ {
+ delete m_pTrustedPlatformAssemblyMap;
+ }
+
+ if (m_pFileNameHash != nullptr)
+ {
+ delete m_pFileNameHash;
+ }
+ }
+
+ HRESULT ApplicationContext::Init()
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("ApplicationContext::Init"));
+ BINDER_LOG_POINTER(W("this"), this);
+
+ ReleaseHolder<ExecutionContext> pExecutionContext;
+ ReleaseHolder<InspectionContext> pInspectionContext;
+
+ PropertyMap *pPropertyMap = NULL;
+ FailureCache *pFailureCache = NULL;
+
+ // Allocate context objects
+ SAFE_NEW(pExecutionContext, ExecutionContext);
+ SAFE_NEW(pInspectionContext, InspectionContext);
+
+ SAFE_NEW(pFailureCache, FailureCache);
+
+ m_contextCS = ClrCreateCriticalSection(
+ CrstFusionAppCtx,
+ CRST_REENTRANCY);
+ if (!m_contextCS)
+ {
+ SAFE_DELETE(pPropertyMap);
+ SAFE_DELETE(pFailureCache);
+ hr = E_OUTOFMEMORY;
+ }
+ else
+ {
+ m_pExecutionContext = pExecutionContext.Extract();
+ m_pInspectionContext = pInspectionContext.Extract();
+
+ m_pFailureCache = pFailureCache;
+ }
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ m_fCanExplicitlyBindToNativeImages = false;
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("ApplicationContext::Init"), hr);
+ return hr;
+ }
+
+ HRESULT GetNextPath(SString& paths, SString::Iterator& startPos, SString& outPath)
+ {
+ HRESULT hr = S_OK;
+
+ bool wrappedWithQuotes = false;
+
+ // Skip any leading spaces or path separators
+ while (paths.Skip(startPos, W(' ')) || paths.Skip(startPos, PATH_SEPARATOR_CHAR_W)) {}
+
+ if (startPos == paths.End())
+ {
+ // No more paths in the string and we just skipped over some white space
+ outPath.Set(W(""));
+ return S_FALSE;
+ }
+
+ // Support paths being wrapped with quotations
+ if (paths.Skip(startPos, W('\"')))
+ {
+ wrappedWithQuotes = true;
+ }
+
+ SString::Iterator iEnd = startPos; // Where current path ends
+ SString::Iterator iNext; // Where next path starts
+ if (wrappedWithQuotes)
+ {
+ if (paths.Find(iEnd, W('\"')))
+ {
+ iNext = iEnd;
+ // Find where the next path starts - there should be a path separator right after the closing quotation mark
+ if (paths.Find(iNext, PATH_SEPARATOR_CHAR_W))
+ {
+ iNext++;
+ }
+ else
+ {
+ iNext = paths.End();
+ }
+ }
+ else
+ {
+ // There was no terminating quotation mark - that's bad
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+ }
+ else if (paths.Find(iEnd, PATH_SEPARATOR_CHAR_W))
+ {
+ iNext = iEnd + 1;
+ }
+ else
+ {
+ iNext = iEnd = paths.End();
+ }
+
+ // Skip any trailing spaces
+ while (iEnd[-1] == W(' '))
+ {
+ iEnd--;
+ }
+
+ _ASSERTE(startPos < iEnd);
+
+ outPath.Set(paths, startPos, iEnd);
+ startPos = iNext;
+ Exit:
+ return hr;
+ }
+
+ HRESULT ApplicationContext::SetupBindingPaths(SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths,
+ BOOL fAcquireLock)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("ApplicationContext::SetupBindingPaths"));
+ BINDER_LOG_POINTER(W("this"), this);
+
+#ifndef CROSSGEN_COMPILE
+ CRITSEC_Holder contextLock(fAcquireLock ? GetCriticalSectionCookie() : NULL);
+#endif
+ if (m_pTrustedPlatformAssemblyMap != nullptr)
+ {
+#if defined(BINDER_DEBUG_LOG)
+ BINDER_LOG(W("ApplicationContext::SetupBindingPaths: Binding paths already setup"));
+#endif // BINDER_LOG_STRING
+ GO_WITH_HRESULT(S_OK);
+ }
+
+
+ //
+ // Parse TrustedPlatformAssemblies
+ //
+ m_pTrustedPlatformAssemblyMap = new SimpleNameToFileNameMap();
+ m_pFileNameHash = new TpaFileNameHash();
+
+ sTrustedPlatformAssemblies.Normalize();
+
+ for (SString::Iterator i = sTrustedPlatformAssemblies.Begin(); i != sTrustedPlatformAssemblies.End(); )
+ {
+ SString fileName;
+ HRESULT pathResult = S_OK;
+ IF_FAIL_GO(pathResult = GetNextPath(sTrustedPlatformAssemblies, i, fileName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+ // Find the beginning of the simple name
+ SString::Iterator iSimpleNameStart = fileName.End();
+
+ if (!fileName.FindBack(iSimpleNameStart, DIRECTORY_SEPARATOR_CHAR_W))
+ {
+#ifdef CROSSGEN_COMPILE
+ iSimpleNameStart = fileName.Begin();
+#else
+ // Couldn't find a directory separator. File must have been specified as a relative path. Not allowed.
+ GO_WITH_HRESULT(E_INVALIDARG);
+#endif
+ }
+ else
+ {
+ // Advance past the directory separator to the first character of the file name
+ iSimpleNameStart++;
+ }
+
+ if (iSimpleNameStart == fileName.End())
+ {
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+
+ SString simpleName;
+ bool isNativeImage = false;
+
+ // GCC complains if we create SStrings inline as part of a function call
+ SString sNiDll(W(".ni.dll"));
+ SString sNiExe(W(".ni.exe"));
+ SString sNiWinmd(W(".ni.winmd"));
+ SString sDll(W(".dll"));
+ SString sExe(W(".exe"));
+ SString sWinmd(W(".winmd"));
+
+ if (fileName.EndsWithCaseInsensitive(sNiDll) ||
+ fileName.EndsWithCaseInsensitive(sNiExe))
+ {
+ simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 7);
+ isNativeImage = true;
+ }
+ else if (fileName.EndsWithCaseInsensitive(sNiWinmd))
+ {
+ simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 9);
+ isNativeImage = true;
+ }
+ else if (fileName.EndsWithCaseInsensitive(sDll) ||
+ fileName.EndsWithCaseInsensitive(sExe))
+ {
+ simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 4);
+ }
+ else if (fileName.EndsWithCaseInsensitive(sWinmd))
+ {
+ simpleName.Set(fileName, iSimpleNameStart, fileName.End() - 6);
+ }
+ else
+ {
+ // Invalid filename
+ GO_WITH_HRESULT(E_INVALIDARG);
+ }
+
+ const SimpleNameToFileNameMapEntry *pExistingEntry = m_pTrustedPlatformAssemblyMap->LookupPtr(simpleName.GetUnicode());
+
+ if (pExistingEntry != nullptr)
+ {
+ //
+ // We want to store only the first entry matching a simple name we encounter.
+ // The exception is if we first store an IL reference and later in the string
+ // we encounter a native image. Since we don't touch IL in the presence of
+ // native images, we replace the IL entry with the NI.
+ //
+ if ((pExistingEntry->m_wszILFileName != nullptr && !isNativeImage) ||
+ (pExistingEntry->m_wszNIFileName != nullptr && isNativeImage))
+ {
+ BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Skipping TPA entry because of already existing IL/NI entry for short name "), fileName.GetUnicode());
+ continue;
+ }
+ }
+
+ LPWSTR wszSimpleName = nullptr;
+ if (pExistingEntry == nullptr)
+ {
+ wszSimpleName = new WCHAR[simpleName.GetCount() + 1];
+ if (wszSimpleName == nullptr)
+ {
+ GO_WITH_HRESULT(E_OUTOFMEMORY);
+ }
+ wcscpy_s(wszSimpleName, simpleName.GetCount() + 1, simpleName.GetUnicode());
+ }
+ else
+ {
+ wszSimpleName = pExistingEntry->m_wszSimpleName;
+ }
+
+ LPWSTR wszFileName = new WCHAR[fileName.GetCount() + 1];
+ if (wszFileName == nullptr)
+ {
+ GO_WITH_HRESULT(E_OUTOFMEMORY);
+ }
+ wcscpy_s(wszFileName, fileName.GetCount() + 1, fileName.GetUnicode());
+
+ SimpleNameToFileNameMapEntry mapEntry;
+ mapEntry.m_wszSimpleName = wszSimpleName;
+ if (isNativeImage)
+ {
+ mapEntry.m_wszNIFileName = wszFileName;
+ mapEntry.m_wszILFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszILFileName;
+ }
+ else
+ {
+ mapEntry.m_wszILFileName = wszFileName;
+ mapEntry.m_wszNIFileName = pExistingEntry == nullptr ? nullptr : pExistingEntry->m_wszNIFileName;
+ }
+
+ m_pTrustedPlatformAssemblyMap->AddOrReplace(mapEntry);
+
+ FileNameMapEntry fileNameExistenceEntry;
+ fileNameExistenceEntry.m_wszFileName = wszFileName;
+ m_pFileNameHash->AddOrReplace(fileNameExistenceEntry);
+
+ BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added TPA entry"), wszFileName);
+ }
+
+ //
+ // Parse PlatformResourceRoots
+ //
+ sPlatformResourceRoots.Normalize();
+ for (SString::Iterator i = sPlatformResourceRoots.Begin(); i != sPlatformResourceRoots.End(); )
+ {
+ SString pathName;
+ HRESULT pathResult = S_OK;
+
+ IF_FAIL_GO(pathResult = GetNextPath(sPlatformResourceRoots, i, pathName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+ m_platformResourceRoots.Append(pathName);
+ BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added resource root"), pathName);
+ }
+
+ //
+ // Parse AppPaths
+ //
+ sAppPaths.Normalize();
+ for (SString::Iterator i = sAppPaths.Begin(); i != sAppPaths.End(); )
+ {
+ SString pathName;
+ HRESULT pathResult = S_OK;
+
+ IF_FAIL_GO(pathResult = GetNextPath(sAppPaths, i, pathName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+ m_appPaths.Append(pathName);
+ BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added App Path"), pathName);
+ }
+
+ //
+ // Parse AppNiPaths
+ //
+ sAppNiPaths.Normalize();
+ for (SString::Iterator i = sAppNiPaths.Begin(); i != sAppNiPaths.End(); )
+ {
+ SString pathName;
+ HRESULT pathResult = S_OK;
+
+ IF_FAIL_GO(pathResult = GetNextPath(sAppNiPaths, i, pathName));
+ if (pathResult == S_FALSE)
+ {
+ break;
+ }
+
+ m_appNiPaths.Append(pathName);
+ BINDER_LOG_STRING(W("ApplicationContext::SetupBindingPaths: Added App NI Path"), pathName);
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("ApplicationContext::SetupBindingPaths"), hr);
+ return hr;
+ }
+
+ HRESULT ApplicationContext::GetAssemblyIdentity(LPCSTR szTextualIdentity,
+ AssemblyIdentityUTF8 **ppAssemblyIdentity)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("ApplicationContext::GetAssemblyIdentity"));
+ BINDER_LOG_POINTER(W("this"), this);
+
+ _ASSERTE(szTextualIdentity != NULL);
+ _ASSERTE(ppAssemblyIdentity != NULL);
+
+ CRITSEC_Holder contextLock(GetCriticalSectionCookie());
+
+ AssemblyIdentityUTF8 *pAssemblyIdentity = m_assemblyIdentityCache.Lookup(szTextualIdentity);
+ if (pAssemblyIdentity == NULL)
+ {
+ NewHolder<AssemblyIdentityUTF8> pNewAssemblyIdentity;
+ SString sTextualIdentity;
+
+ SAFE_NEW(pNewAssemblyIdentity, AssemblyIdentityUTF8);
+ sTextualIdentity.SetUTF8(szTextualIdentity);
+
+ IF_FAIL_GO(TextualIdentityParser::Parse(sTextualIdentity, pNewAssemblyIdentity));
+ IF_FAIL_GO(m_assemblyIdentityCache.Add(szTextualIdentity, pNewAssemblyIdentity));
+
+ pNewAssemblyIdentity->PopulateUTF8Fields();
+
+ pAssemblyIdentity = pNewAssemblyIdentity.Extract();
+ }
+
+ *ppAssemblyIdentity = pAssemblyIdentity;
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("ApplicationContext::GetAssemblyIdentity"), hr);
+ return hr;
+ }
+
+ bool ApplicationContext::IsTpaListProvided()
+ {
+ return m_pTrustedPlatformAssemblyMap != nullptr;
+ }
+};
diff --git a/src/binder/assembly.cpp b/src/binder/assembly.cpp
new file mode 100644
index 0000000000..8fcc7cf54f
--- /dev/null
+++ b/src/binder/assembly.cpp
@@ -0,0 +1,434 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Assembly.cpp
+//
+
+
+//
+// Implements the Assembly class
+//
+// ============================================================
+#include "common.h"
+#include "clrprivbinderutil.h"
+#include "assembly.hpp"
+#include "utils.hpp"
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ BOOL IsPlatformArchicture(PEKIND kArchitecture)
+ {
+ return ((kArchitecture != peMSIL) && (kArchitecture != peNone));
+ }
+
+ HRESULT GetAssemblyRefTokens(IMDInternalImport *pMDImport,
+ mdAssembly **ppAssemblyRefTokens,
+ DWORD *pdwCAssemblyRefTokens)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pMDImport != NULL);
+ _ASSERTE(ppAssemblyRefTokens != NULL);
+ _ASSERTE(pdwCAssemblyRefTokens != NULL);
+
+ mdAssembly *pAssemblyRefTokens = NULL;
+ COUNT_T assemblyRefCount;
+
+ HENUMInternalHolder hEnumAssemblyRef(pMDImport);
+ IF_FAIL_GO(hEnumAssemblyRef.EnumInitNoThrow(mdtAssemblyRef, mdTokenNil));
+
+ assemblyRefCount = hEnumAssemblyRef.EnumGetCount();
+
+ pAssemblyRefTokens = new (nothrow) mdAssemblyRef[assemblyRefCount];
+ if (pAssemblyRefTokens == NULL)
+ {
+ IF_FAIL_GO(E_OUTOFMEMORY);
+ }
+ ZeroMemory(pAssemblyRefTokens, assemblyRefCount * sizeof(mdAssemblyRef));
+
+ for (COUNT_T i = 0; i < assemblyRefCount; i++)
+ {
+ bool ret = hEnumAssemblyRef.EnumNext(&(pAssemblyRefTokens[i]));
+ _ASSERTE(ret);
+ }
+
+ *ppAssemblyRefTokens = pAssemblyRefTokens;
+ pAssemblyRefTokens = NULL;
+
+ *pdwCAssemblyRefTokens= assemblyRefCount;
+ hr = S_OK;
+
+Exit:
+ SAFE_DELETE_ARRAY(pAssemblyRefTokens);
+
+ return hr;
+ }
+ };
+
+ STDMETHODIMP Assembly::QueryInterface(REFIID riid,
+ void **ppv)
+ {
+ HRESULT hr = S_OK;
+
+ if (ppv == NULL)
+ {
+ hr = E_POINTER;
+ }
+ else
+ {
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = static_cast<IUnknown *>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ }
+ }
+
+ return hr;
+ }
+
+ STDMETHODIMP_(ULONG) Assembly::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ STDMETHODIMP_(ULONG) Assembly::Release()
+ {
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+ }
+
+ Assembly::Assembly()
+ {
+ m_cRef = 1;
+ m_pPEImage = NULL;
+ m_pNativePEImage = NULL;
+ m_pAssemblyName = NULL;
+ m_pMDImport = NULL;
+ m_pAssemblyRefTokens = NULL;
+ m_dwCAssemblyRefTokens = static_cast<DWORD>(-1);
+ m_dwAssemblyFlags = FLAG_NONE;
+ m_pBinder = NULL;
+ }
+
+ Assembly::~Assembly()
+ {
+ BINDER_LOG_ASSEMBLY_NAME(L"destructing assembly", m_pAssemblyName);
+
+ if (m_pPEImage != NULL)
+ {
+ BinderReleasePEImage(m_pPEImage);
+ m_pPEImage = NULL;
+ }
+
+#ifdef FEATURE_PREJIT
+ if (m_pNativePEImage != NULL)
+ {
+ BinderReleasePEImage(m_pNativePEImage);
+ m_pNativePEImage = NULL;
+ }
+#endif
+
+ SAFE_RELEASE(m_pAssemblyName);
+ SAFE_RELEASE(m_pMDImport);
+ SAFE_DELETE_ARRAY(m_pAssemblyRefTokens);
+ }
+
+ HRESULT Assembly::Init(
+ IMDInternalImport *pIMetaDataAssemblyImport,
+ PEKIND PeKind,
+ PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ SString &assemblyPath,
+ BOOL fInspectionOnly,
+ BOOL fIsInGAC)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"Assembly::Init");
+
+ ReleaseHolder<AssemblyName> pAssemblyName;
+ SAFE_NEW(pAssemblyName, AssemblyName);
+
+ // Get assembly name def from meta data import and store it for later refs access
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+ SetMDImport(pIMetaDataAssemblyImport);
+ if (!fIsInGAC)
+ {
+ GetPath().Set(assemblyPath);
+ }
+
+ BINDER_LOG_ASSEMBLY_NAME(L"AssemblyNameDef", pAssemblyName);
+ BINDER_LOG_STRING(L"System Architecture",
+ AssemblyName::ArchitectureToString(GetSystemArchitecture()));
+
+ // Safe architecture for validation
+ PEKIND kAssemblyArchitecture;
+ kAssemblyArchitecture = pAssemblyName->GetArchitecture();
+ SetInspectionOnly(fInspectionOnly);
+ SetIsInGAC(fIsInGAC);
+ SetPEImage(pPEImage);
+ SetNativePEImage(pNativePEImage);
+ pAssemblyName->SetIsDefinition(TRUE);
+
+ // Now take ownership of assembly names
+ SetAssemblyName(pAssemblyName.Extract(), FALSE /* fAddRef */);
+
+ // Finally validate architecture
+ if (!fInspectionOnly && !IsValidArchitecture(kAssemblyArchitecture))
+ {
+ // Assembly image can't be executed on this platform
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"Assembly::Init", hr);
+ return hr;
+ }
+
+ HRESULT Assembly::GetMVID(GUID *pMVID)
+ {
+ // Zero init the GUID incase we fail
+ ZeroMemory(pMVID, sizeof(GUID));
+
+ return m_pMDImport->GetScopeProps(NULL, pMVID);
+ }
+
+ HRESULT Assembly::GetNextAssemblyNameRef(DWORD nIndex,
+ AssemblyName **ppAssemblyName)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"Assembly::GetNextAssemblyNameRef");
+
+ if (ppAssemblyName == NULL)
+ {
+ IF_FAIL_GO(E_INVALIDARG);
+ }
+ else if (GetNbAssemblyRefTokens() == static_cast<DWORD>(-1))
+ {
+ mdAssembly *pAssemblyRefTokens = NULL;
+ DWORD dwCAssemblyRefTokens = 0;
+
+ IF_FAIL_GO(BINDER_SPACE::GetAssemblyRefTokens(GetMDImport(),
+ &pAssemblyRefTokens,
+ &dwCAssemblyRefTokens));
+
+ if (InterlockedCompareExchangeT(&m_pAssemblyRefTokens,
+ pAssemblyRefTokens,
+ NULL))
+ {
+ SAFE_DELETE_ARRAY(pAssemblyRefTokens);
+ }
+ SetNbAsssemblyRefTokens(dwCAssemblyRefTokens);
+ }
+
+ _ASSERTE(GetNbAssemblyRefTokens() != static_cast<DWORD>(-1));
+
+ // Verify input index
+ if (nIndex >= GetNbAssemblyRefTokens())
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_NO_MORE_ITEMS));
+ }
+ else
+ {
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(GetMDImport(),
+ peNone,
+ GetAssemblyRefTokens()[nIndex],
+ FALSE /* fIsDefinition */));
+
+ *ppAssemblyName = pAssemblyName.Extract();
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"Assembly::GetNextAssemblyNameRef", hr);
+ return hr;
+ }
+
+ /* static */
+ PEKIND Assembly::GetSystemArchitecture()
+ {
+#if defined(_TARGET_X86_)
+ return peI386;
+#elif defined(_TARGET_AMD64_)
+ return peAMD64;
+#elif defined(_TARGET_ARM_)
+ return peARM;
+#elif defined(_TARGET_ARM64_)
+ return peARM64;
+#else
+ PORTABILITY_ASSERT("Assembly::GetSystemArchitecture");
+#endif
+ }
+
+ /* static */
+ BOOL Assembly::IsValidArchitecture(PEKIND kArchitecture)
+ {
+ if (!IsPlatformArchicture(kArchitecture))
+ return TRUE;
+
+ return (kArchitecture == GetSystemArchitecture());
+ }
+
+ // --------------------------------------------------------------------
+ // ICLRPrivAssembly methods
+ // --------------------------------------------------------------------
+ LPCWSTR Assembly::GetSimpleName()
+ {
+ AssemblyName *pAsmName = GetAssemblyName();
+ return (pAsmName == nullptr ? nullptr : pAsmName->GetSimpleName());
+ }
+
+ HRESULT Assembly::BindAssemblyByName(IAssemblyName * pIAssemblyName, ICLRPrivAssembly ** ppAssembly)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->BindAssemblyByName(pIAssemblyName, ppAssembly);
+ }
+
+ HRESULT Assembly::FindAssemblyBySpec(
+ LPVOID pvAppDomain,
+ LPVOID pvAssemblySpec,
+ HRESULT * pResult,
+ ICLRPrivAssembly ** ppAssembly)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->FindAssemblyBySpec(pvAppDomain, pvAssemblySpec, pResult, ppAssembly);
+ }
+
+ HRESULT Assembly::VerifyBind (
+ IAssemblyName * pIAssemblyName,
+ ICLRPrivAssembly *pAssembly,
+ ICLRPrivAssemblyInfo *pAssemblyInfo)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->VerifyBind(pIAssemblyName, pAssembly, pAssemblyInfo);
+ }
+
+ HRESULT Assembly::GetBinderID(UINT_PTR *pBinderId)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->GetBinderID(pBinderId);
+ }
+
+ HRESULT Assembly::GetBinderFlags(DWORD *pBinderFlags)
+ {
+ return (m_pBinder == NULL) ? E_FAIL : m_pBinder->GetBinderFlags(pBinderFlags);
+ }
+
+ HRESULT Assembly::IsShareable(
+ BOOL * pbIsShareable)
+ {
+ if(pbIsShareable == nullptr)
+ return E_INVALIDARG;
+
+ *pbIsShareable = GetIsSharable();
+ return S_OK;
+ }
+
+ HRESULT Assembly::GetAvailableImageTypes(
+ LPDWORD pdwImageTypes)
+ {
+ HRESULT hr = E_FAIL;
+
+ if(pdwImageTypes == nullptr)
+ return E_INVALIDARG;
+
+ *pdwImageTypes = ASSEMBLY_IMAGE_TYPE_ASSEMBLY;
+
+ return S_OK;
+ }
+
+ HRESULT Assembly::GetImageResource(
+ DWORD dwImageType,
+ DWORD * pdwImageType,
+ ICLRPrivResource ** ppIResource)
+ {
+ HRESULT hr = S_OK;
+ if(ppIResource == nullptr)
+ return E_INVALIDARG;
+
+ if ((dwImageType & ASSEMBLY_IMAGE_TYPE_ASSEMBLY) == ASSEMBLY_IMAGE_TYPE_ASSEMBLY)
+ {
+ *ppIResource = clr::SafeAddRef(&m_clrPrivRes);
+ if (pdwImageType != nullptr)
+ *pdwImageType = ASSEMBLY_IMAGE_TYPE_ASSEMBLY;
+ }
+ else
+ {
+ hr = CLR_E_BIND_IMAGE_UNAVAILABLE;
+ }
+
+ return hr;
+ }
+
+ // get parent pointer from nested type
+ #define GetPThis() ((BINDER_SPACE::Assembly*)(((PBYTE)this) - offsetof(BINDER_SPACE::Assembly, m_clrPrivRes)))
+
+ HRESULT Assembly::CLRPrivResourceAssembly::QueryInterface(REFIID riid, void ** ppv)
+ {
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppv != NULL);
+
+ if (IsEqualIID(riid, IID_IUnknown))
+ {
+ AddRef();
+ *ppv = this;
+ }
+ else if (IsEqualIID(riid, __uuidof(ICLRPrivResource)))
+ {
+ AddRef();
+ // upcasting is safe
+ *ppv = static_cast<ICLRPrivResource *>(this);
+ }
+ else if (IsEqualIID(riid, __uuidof(ICLRPrivResourceAssembly)))
+ {
+ AddRef();
+ *ppv = static_cast<ICLRPrivResourceAssembly *>(this);
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ }
+
+ return hr;
+ }
+
+ ULONG Assembly::CLRPrivResourceAssembly::AddRef()
+ {
+ return GetPThis()->AddRef();
+ }
+
+ ULONG Assembly::CLRPrivResourceAssembly::Release()
+ {
+ return GetPThis()->Release();
+ }
+
+ HRESULT Assembly::CLRPrivResourceAssembly::GetResourceType(IID *pIID)
+ {
+ VALIDATE_ARG_RET(pIID != nullptr);
+ *pIID = __uuidof(ICLRPrivResourceAssembly);
+ return S_OK;
+ }
+
+ HRESULT Assembly::CLRPrivResourceAssembly::GetAssembly(LPVOID *ppAssembly)
+ {
+ VALIDATE_ARG_RET(ppAssembly != nullptr);
+ AddRef();
+ *ppAssembly = GetPThis();
+ return S_OK;
+ }
+
+}
+
diff --git a/src/binder/assemblybinder.cpp b/src/binder/assemblybinder.cpp
new file mode 100644
index 0000000000..517eac99d6
--- /dev/null
+++ b/src/binder/assemblybinder.cpp
@@ -0,0 +1,1953 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyBinder.cpp
+//
+
+
+//
+// Implements the AssemblyBinder class
+//
+// ============================================================
+
+#include "assemblybinder.hpp"
+#include "assemblyname.hpp"
+
+#include "assembly.hpp"
+#include "applicationcontext.hpp"
+#include "loadcontext.hpp"
+#include "bindresult.inl"
+#include "failurecache.hpp"
+#ifdef FEATURE_VERSIONING_LOG
+#include "bindinglog.hpp"
+#endif // FEATURE_VERSIONING_LOG
+#include "utils.hpp"
+#include "variables.hpp"
+#include "stringarraylist.h"
+
+#include "strongname.h"
+#ifdef FEATURE_VERSIONING_LOG
+#include "../dlls/mscorrc/fusres.h"
+#endif // FEATURE_VERSIONING_LOG
+
+#define APP_DOMAIN_LOCKED_INSPECTION_ONLY 0x01
+#define APP_DOMAIN_LOCKED_UNLOCKED 0x02
+#define APP_DOMAIN_LOCKED_CONTEXT 0x04
+
+#define BIND_BEHAVIOR_STATIC 0
+#define BIND_BEHAVIOR_ORDER_INDEPENDENT 1
+#define BIND_BEHAVIOR_BEST_MATCH 2
+
+#ifndef IMAGE_FILE_MACHINE_ARM64
+#define IMAGE_FILE_MACHINE_ARM64 0xAA64 // ARM64 Little-Endian
+#endif
+
+BOOL IsCompilationProcess();
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+#include "clrprivbindercoreclr.h"
+#include "clrprivbinderassemblyloadcontext.h"
+// Helper function in the VM, invoked by the Binder, to invoke the host assembly resolver
+extern HRESULT RuntimeInvokeHostAssemblyResolver(INT_PTR pManagedAssemblyLoadContextToBindWithin,
+ IAssemblyName *pIAssemblyName, CLRPrivBinderCoreCLR *pTPABinder,
+ BINDER_SPACE::AssemblyName *pAssemblyName, ICLRPrivAssembly **ppLoadedAssembly);
+
+// Helper to check if we have a host assembly resolver set
+extern BOOL RuntimeCanUseAppPathAssemblyResolver(DWORD adid);
+
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+namespace BINDER_SPACE
+{
+ typedef enum
+ {
+ kVersionIgnore,
+ kVersionExact,
+ kVersionServiceRollForward,
+ kVersionFeatureRollForward,
+ kVersionFeatureExact,
+ kVersionFeatureHighest,
+ kVersionFeatureLowestHigher,
+ kVersionFeatureHighestLower
+ } VersionMatchMode;
+
+ namespace
+ {
+ BOOL fAssemblyBinderInitialized = FALSE;
+
+ //
+ // This defines the assembly equivalence relation
+ //
+ HRESULT IsValidAssemblyVersion(/* in */ AssemblyName *pRequestedName,
+ /* in */ AssemblyName *pFoundName,
+ /* in */ ApplicationContext *pApplicationContext)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("IsValidAssemblyVersion"));
+ AssemblyVersion *pRequestedVersion = pRequestedName->GetVersion();
+ AssemblyVersion *pFoundVersion = pFoundName->GetVersion();
+
+ //
+ // If the AssemblyRef has no version, we can treat it as requesting the most accommodating version (0.0.0.0). In
+ // that case, skip version checking and allow the bind.
+ //
+ if (!pRequestedName->HaveAssemblyVersion())
+ {
+ return hr;
+ }
+
+ //
+ // This if condition is paired with the one above that checks for pRequestedName
+ // not having an assembly version. If we didn't exit in the above if condition,
+ // and satisfy this one's requirements, we're in a situation where the assembly
+ // Ref has a version, but the Def doesn't, which cannot succeed a bind
+ //
+ _ASSERTE(pRequestedName->HaveAssemblyVersion());
+ if (!pFoundName->HaveAssemblyVersion())
+ {
+ hr = FUSION_E_APP_DOMAIN_LOCKED;
+ }
+ else if (pRequestedVersion->IsEqualFeatureVersion(pFoundVersion))
+ {
+ // Now service version matters
+ if (pRequestedVersion->IsLargerServiceVersion(pFoundVersion))
+ {
+ hr = FUSION_E_APP_DOMAIN_LOCKED;
+ }
+ }
+ else if (pRequestedVersion->IsLargerFeatureVersion(pFoundVersion))
+ {
+ hr = FUSION_E_APP_DOMAIN_LOCKED;
+ }
+
+ if (pApplicationContext->IsTpaListProvided() && hr == FUSION_E_APP_DOMAIN_LOCKED)
+ {
+ // For our new binding models, use a more descriptive error code than APP_DOMAIN_LOCKED for bind
+ // failures.
+ hr = FUSION_E_REF_DEF_MISMATCH;
+ }
+
+ BINDER_LOG_LEAVE_HR(W("IsValidAssemblyVersion"), hr)
+ return hr;
+ }
+
+ HRESULT URLToFullPath(PathString &assemblyPath)
+ {
+ HRESULT hr = S_OK;
+
+ SString::Iterator pos = assemblyPath.Begin();
+ if (assemblyPath.MatchCaseInsensitive(pos, g_BinderVariables->httpURLPrefix))
+ {
+ // HTTP downloads are unsupported
+ hr = FUSION_E_CODE_DOWNLOAD_DISABLED;
+ }
+ else
+ {
+ SString fullAssemblyPath;
+ WCHAR *pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(MAX_LONGPATH);
+ DWORD dwCCFullAssemblyPath = MAX_LONGPATH + 1; // SString allocates extra byte for null.
+
+ MutateUrlToPath(assemblyPath);
+
+ dwCCFullAssemblyPath = WszGetFullPathName(assemblyPath.GetUnicode(),
+ dwCCFullAssemblyPath,
+ pwzFullAssemblyPath,
+ NULL);
+ if (dwCCFullAssemblyPath > MAX_LONGPATH)
+ {
+ fullAssemblyPath.CloseBuffer();
+ pwzFullAssemblyPath = fullAssemblyPath.OpenUnicodeBuffer(dwCCFullAssemblyPath - 1);
+ dwCCFullAssemblyPath = WszGetFullPathName(assemblyPath.GetUnicode(),
+ dwCCFullAssemblyPath,
+ pwzFullAssemblyPath,
+ NULL);
+ }
+ fullAssemblyPath.CloseBuffer(dwCCFullAssemblyPath);
+
+ if (dwCCFullAssemblyPath == 0)
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+ else
+ {
+ assemblyPath.Set(fullAssemblyPath);
+ }
+ }
+
+ return hr;
+ }
+
+
+#ifdef FEATURE_VERSIONING_LOG
+ //
+ // This function outputs the current binding result
+ // and flushes the bind log.
+ //
+ HRESULT LogBindResult(ApplicationContext *pApplicationContext,
+ HRESULT hrLog,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ if (!pBindingLog->CanLog())
+ {
+ // For non-logging, return the bind result
+ hr = hrLog;
+ goto Exit;
+ }
+
+ IF_FAIL_GO(pBindingLog->LogHR(hrLog));
+
+ if ((hrLog == S_OK) && pBindResult->HaveResult())
+ {
+ IF_FAIL_GO(pBindingLog->LogResult(pBindResult));
+ }
+
+ IF_FAIL_GO(pBindingLog->Flush());
+
+ // For failure-free logging, return the bind result
+ hr = hrLog;
+
+ Exit:
+ // SilverLight does not propagate binding log; therefore kill the information here.
+ pApplicationContext->ClearBindingLog();
+ return hr;
+ }
+
+ inline UINT GetLockedContextEntry(BOOL fInspectionOnly)
+ {
+ if (fInspectionOnly)
+ return ID_FUSLOG_BINDING_LOCKED_ASSEMBLY_INS_CONTEXT;
+ else
+ return ID_FUSLOG_BINDING_LOCKED_ASSEMBLY_EXE_CONTEXT;
+ }
+
+ inline UINT GetLockedEntry(BOOL fInspectionOnly)
+ {
+ if (fInspectionOnly)
+ return ID_FUSLOG_BINDING_LOCKED_MT_INS_LOCKED_ENTRY;
+ else
+ return ID_FUSLOG_BINDING_LOCKED_MT_EXE_LOCKED_ENTRY;
+ }
+
+ inline UINT GetLocalizedEntry(BOOL fInspectionOnly)
+ {
+ if (fInspectionOnly)
+ return ID_FUSLOG_BINDING_LOCKED_MT_INS_LOCALI_ENTRY;
+ else
+ return ID_FUSLOG_BINDING_LOCKED_MT_EXE_LOCALI_ENTRY;
+ }
+
+ inline UINT GetCBaseEntry(BOOL fInspectionOnly)
+ {
+ if (fInspectionOnly)
+ return ID_FUSLOG_BINDING_LOCKED_MT_INS_CBASE_ENTRY;
+ else
+ return ID_FUSLOG_BINDING_LOCKED_MT_EXE_CBASE_ENTRY;
+ }
+
+ HRESULT LogAppDomainLocked(ApplicationContext *pApplicationContext,
+ DWORD dwLockedReason,
+ AssemblyName *pAssemblyName = NULL)
+ {
+ HRESULT hr = S_OK;
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ if (pBindingLog->CanLog())
+ {
+ PathString info;
+ PathString format;
+ BOOL fInspectionOnly = FALSE;
+
+ if ((dwLockedReason & APP_DOMAIN_LOCKED_INSPECTION_ONLY) != 0)
+ {
+ dwLockedReason &= ~APP_DOMAIN_LOCKED_INSPECTION_ONLY;
+ fInspectionOnly = TRUE;
+ }
+
+ switch (dwLockedReason)
+ {
+ case APP_DOMAIN_LOCKED_UNLOCKED:
+ {
+ IF_FAIL_GO(info.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_LOCKED_UNLOCKED));
+ }
+ break;
+ case APP_DOMAIN_LOCKED_CONTEXT:
+ {
+ PathString displayName;
+
+ _ASSERTE(pAssemblyName != NULL);
+
+ IF_FAIL_GO(format.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ GetLockedContextEntry(fInspectionOnly)));
+
+ pAssemblyName->GetDisplayName(displayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE);
+
+ info.Printf(format.GetUnicode(), displayName.GetUnicode());
+ }
+ break;
+ default:
+ _ASSERTE(0);
+ IF_FAIL_GO(E_INVALIDARG);
+ break;
+ }
+
+ IF_FAIL_GO(pBindingLog->Log(info));
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT LogBindBehavior(ApplicationContext *pApplicationContext,
+ DWORD dwBindBehavior)
+ {
+ HRESULT hr = S_OK;
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ if (pBindingLog->CanLog())
+ {
+ PathString bindBehavior;
+ UINT uiBindBehavior = 0;
+
+ switch (dwBindBehavior)
+ {
+ case BIND_BEHAVIOR_STATIC:
+ uiBindBehavior = ID_FUSLOG_BINDING_BEHAVIOR_STATIC;
+ break;
+ case BIND_BEHAVIOR_ORDER_INDEPENDENT:
+ uiBindBehavior = ID_FUSLOG_BINDING_BEHAVIOR_ORDER_INDEPENDENT;
+ break;
+ case BIND_BEHAVIOR_BEST_MATCH:
+ uiBindBehavior = ID_FUSLOG_BINDING_BEHAVIOR_BEST_MATCH;
+ break;
+ default:
+ _ASSERTE(0);
+ IF_FAIL_GO(E_INVALIDARG);
+ break;
+ }
+
+ IF_FAIL_GO(bindBehavior.LoadResourceAndReturnHR(CCompRC::Debugging, uiBindBehavior));
+ IF_FAIL_GO(pBindingLog->Log(bindBehavior.GetUnicode()));
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT LogAssemblyNameWhereRef(ApplicationContext *pApplicationContext,
+ Assembly *pAssembly)
+ {
+ HRESULT hr = S_OK;
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ if (pBindingLog->CanLog())
+ {
+ PathString info;
+
+ IF_FAIL_GO(info.
+ LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_LOG_WHERE_REF_NAME));
+ IF_FAIL_GO(pBindingLog->LogAssemblyName(info.GetUnicode(),
+ pAssembly->GetAssemblyName()));
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT LogConfigurationError(ApplicationContext *pApplicationContext,
+ AssemblyName *pCulturedManifestName,
+ AssemblyName *pLocalPathAssemblyName)
+ {
+ HRESULT hr = S_OK;
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ if (pBindingLog->CanLog())
+ {
+ PathString tmp;
+ PathString culturedManifestDisplayName;
+ PathString localPathDisplayName;
+ PathString info;
+
+ IF_FAIL_GO(tmp.
+ LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_LOG_ERRONOUS_MANIFEST_ENTRY));
+
+ pCulturedManifestName->GetDisplayName(culturedManifestDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE);
+ pLocalPathAssemblyName->GetDisplayName(localPathDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE);
+
+ info.Printf(tmp.GetUnicode(),
+ culturedManifestDisplayName.GetUnicode(),
+ localPathDisplayName.GetUnicode());
+ IF_FAIL_GO(pBindingLog->Log(info.GetUnicode()));
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT LogPathAttempt(ApplicationContext *pApplicationContext,
+ PathString &assemblyPath)
+ {
+ HRESULT hr = S_OK;
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ if (pBindingLog->CanLog())
+ {
+ PathString tmp;
+ PathString info;
+
+ IF_FAIL_GO(tmp.LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_LOG_PATH_ATTEMPT));
+ info.Printf(tmp.GetUnicode(), assemblyPath.GetUnicode());
+
+ IF_FAIL_GO(pBindingLog->Log(info));
+ }
+
+ Exit:
+ return hr;
+ }
+#endif // FEATURE_VERSIONING_LOG
+
+#ifndef CROSSGEN_COMPILE
+ HRESULT CreateImageAssembly(IMDInternalImport *pIMetaDataAssemblyImport,
+ PEKIND PeKind,
+ PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ BOOL fInspectionOnly,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ ReleaseHolder<Assembly> pAssembly;
+ PathString asesmblyPath;
+
+ SAFE_NEW(pAssembly, Assembly);
+ IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
+ PeKind,
+ pPEImage,
+ pNativePEImage,
+ asesmblyPath,
+ fInspectionOnly,
+ FALSE /* fIsInGAC */));
+
+ pBindResult->SetResult(pAssembly);
+ pBindResult->SetIsFirstRequest(TRUE);
+
+ Exit:
+ return hr;
+ }
+#endif // !CROSSGEN_COMPILE
+ };
+
+ /* static */
+ HRESULT AssemblyBinder::Startup()
+ {
+ HRESULT hr = S_OK;
+
+ if (!BINDER_SPACE::fAssemblyBinderInitialized)
+ {
+ g_BinderVariables = new Variables();
+ IF_FAIL_GO(g_BinderVariables->Init());
+
+ // Setup Debug log
+ BINDER_LOG_STARTUP();
+
+ // We're done
+ BINDER_SPACE::fAssemblyBinderInitialized = TRUE;
+ }
+
+ Exit:
+ return hr;
+ }
+
+
+ HRESULT AssemblyBinder::TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("TranslatePEToArchitectureType"))
+
+ _ASSERTE(pdwPAFlags != NULL);
+ _ASSERTE(PeKind != NULL);
+
+ CorPEKind CLRPeKind = (CorPEKind) pdwPAFlags[0];
+ DWORD dwImageType = pdwPAFlags[1];
+
+ *PeKind = peNone;
+
+ if(CLRPeKind == peNot)
+ {
+ // Not a PE. Shouldn't ever get here.
+ BINDER_LOG(W("Not a PE!"));
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+ else
+ {
+ if ((CLRPeKind & peILonly) && !(CLRPeKind & pe32Plus) &&
+ !(CLRPeKind & pe32BitRequired) && dwImageType == IMAGE_FILE_MACHINE_I386)
+ {
+ // Processor-agnostic (MSIL)
+ BINDER_LOG(W("Processor-agnostic (MSIL)"));
+ *PeKind = peMSIL;
+ }
+ else if (CLRPeKind & pe32Plus)
+ {
+ // 64-bit
+ if (CLRPeKind & pe32BitRequired)
+ {
+ // Invalid
+ BINDER_LOG(W("CLRPeKind & pe32BitRequired is true"));
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Regardless of whether ILONLY is set or not, the architecture
+ // is the machine type.
+ if(dwImageType == IMAGE_FILE_MACHINE_ARM64)
+ *PeKind = peARM64;
+ else if (dwImageType == IMAGE_FILE_MACHINE_AMD64)
+ *PeKind = peAMD64;
+ else
+ {
+ // We don't support other architectures
+ BINDER_LOG(W("Unknown architecture"));
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+ }
+ else
+ {
+ // 32-bit, non-agnostic
+ if(dwImageType == IMAGE_FILE_MACHINE_I386)
+ *PeKind = peI386;
+ else if(dwImageType == IMAGE_FILE_MACHINE_ARMNT)
+ *PeKind = peARM;
+ else
+ {
+ // Not supported
+ BINDER_LOG(W("32-bit, non-agnostic"));
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+ }
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("TranslatePEToArchitectureType"), hr);
+ return hr;
+ }
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ HRESULT AssemblyBinder::BindAssembly(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ LPCWSTR szCodeBase,
+ /* in */ PEAssembly *pParentAssembly,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* in */ bool excludeAppPaths,
+ /* out */ Assembly **ppAssembly)
+ {
+ HRESULT hr = S_OK;
+ LONG kContextVersion = 0;
+ BindResult bindResult;
+
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindAssembly"));
+
+#ifndef CROSSGEN_COMPILE
+ Retry:
+ {
+ // Lock the binding application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+#endif
+
+ if (szCodeBase == NULL)
+ {
+#ifdef FEATURE_VERSIONING_LOG
+ // Log bind
+ IF_FAIL_GO(BindingLog::CreateInContext(pApplicationContext,
+ pAssemblyName,
+ pParentAssembly));
+#endif // FEATURE_VERSIONING_LOG
+
+
+ hr = BindByName(pApplicationContext,
+ pAssemblyName,
+ BIND_CACHE_FAILURES,
+ excludeAppPaths,
+ &bindResult);
+ IF_FAIL_GO(hr);
+ }
+ else
+ {
+ PathString assemblyPath(szCodeBase);
+
+#ifdef FEATURE_VERSIONING_LOG
+ // Log bind
+ IF_FAIL_GO(BindingLog::CreateInContext(pApplicationContext,
+ assemblyPath,
+ pParentAssembly));
+#endif // FEATURE_VERSIONING_LOG
+
+ // Convert URL to full path and block HTTP downloads
+ IF_FAIL_GO(URLToFullPath(assemblyPath));
+ BOOL fDoNgenExplicitBind = fNgenExplicitBind;
+
+ // Only use explicit ngen binding in the new coreclr path-based binding model
+ if(!pApplicationContext->IsTpaListProvided())
+ {
+ fDoNgenExplicitBind = FALSE;
+ }
+
+ IF_FAIL_GO(BindWhereRef(pApplicationContext,
+ assemblyPath,
+ fDoNgenExplicitBind,
+ fExplicitBindToNativeImage,
+ excludeAppPaths,
+ &bindResult));
+ }
+
+ // Remember the post-bind version
+ kContextVersion = pApplicationContext->GetVersion();
+
+ Exit:
+#ifdef FEATURE_VERSIONING_LOG
+ hr = LogBindResult(pApplicationContext, hr, &bindResult);
+#else // FEATURE_VERSIONING_LOG
+ ;
+#endif // FEATURE_VERSIONING_LOG
+
+#ifndef CROSSGEN_COMPILE
+ } // lock(pApplicationContext)
+#endif
+
+ if (bindResult.HaveResult())
+ {
+
+#ifndef CROSSGEN_COMPILE
+ BindResult hostBindResult;
+
+ hr = RegisterAndGetHostChosen(pApplicationContext,
+ kContextVersion,
+ &bindResult,
+ &hostBindResult);
+
+ if (hr == S_FALSE)
+ {
+ // Another bind interfered. We need to retry the entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult.Reset();
+ goto Retry;
+ }
+ else if (hr == S_OK)
+ {
+ *ppAssembly = hostBindResult.GetAsAssembly(TRUE /* fAddRef */);
+ }
+#else // CROSSGEN_COMPILE
+
+ *ppAssembly = bindResult.GetAsAssembly(TRUE /* fAddRef */);
+
+#endif // CROSSGEN_COMPILE
+ }
+
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindAssembly"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::BindToSystem(SString &systemDirectory,
+ Assembly **ppSystemAssembly,
+ bool fBindToNativeImage)
+ {
+ _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
+
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder:BindToSystem"));
+
+ _ASSERTE(ppSystemAssembly != NULL);
+
+ StackSString sCoreLibDir(systemDirectory);
+ ReleaseHolder<Assembly> pSystemAssembly;
+
+ if(!sCoreLibDir.EndsWith(DIRECTORY_SEPARATOR_CHAR_W))
+ {
+ sCoreLibDir.Append(DIRECTORY_SEPARATOR_CHAR_W);
+ }
+
+ StackSString sCoreLib;
+
+ // At run-time, System.Private.CoreLib.ni.dll is typically always available, and
+ // System.Private.CoreLib.dll is typically not. So check for the NI first.
+ sCoreLib = sCoreLibDir;
+ sCoreLib.Append(CoreLibName_NI_W);
+ if (!fBindToNativeImage || FAILED(AssemblyBinder::GetAssembly(sCoreLib,
+ FALSE /* fInspectionOnly */,
+ TRUE /* fIsInGAC */,
+ TRUE /* fExplicitBindToNativeImage */,
+ &pSystemAssembly)))
+ {
+ // If System.Private.CoreLib.ni.dll is unavailable, look for System.Private.CoreLib.dll instead
+ sCoreLib = sCoreLibDir;
+ sCoreLib.Append(CoreLibName_IL_W);
+ IF_FAIL_GO(AssemblyBinder::GetAssembly(sCoreLib,
+ FALSE /* fInspectionOnly */,
+ TRUE /* fIsInGAC */,
+ FALSE /* fExplicitBindToNativeImage */,
+ &pSystemAssembly));
+ }
+
+ *ppSystemAssembly = pSystemAssembly.Extract();
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindToSystem"), hr);
+ return hr;
+ }
+
+
+ /* static */
+ HRESULT AssemblyBinder::BindToSystemSatellite(SString &systemDirectory,
+ SString &simpleName,
+ SString &cultureName,
+ Assembly **ppSystemAssembly)
+ {
+ _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
+
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder:BindToSystemSatellite"));
+
+ _ASSERTE(ppSystemAssembly != NULL);
+
+ StackSString sMscorlibSatellite(systemDirectory);
+ ReleaseHolder<Assembly> pSystemAssembly;
+
+ // append culture name
+ if (!cultureName.IsEmpty())
+ {
+ CombinePath(sMscorlibSatellite, cultureName, sMscorlibSatellite);
+ }
+
+ // append satellite assembly's simple name
+ CombinePath(sMscorlibSatellite, simpleName, sMscorlibSatellite);
+
+ // append extension
+ sMscorlibSatellite.Append(W(".dll"));
+
+ IF_FAIL_GO(AssemblyBinder::GetAssembly(sMscorlibSatellite,
+ FALSE /* fInspectionOnly */,
+ TRUE /* fIsInGAC */,
+ FALSE /* fExplicitBindToNativeImage */,
+ &pSystemAssembly));
+
+ *ppSystemAssembly = pSystemAssembly.Extract();
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindToSystemSatellite"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::GetAssemblyFromImage(PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ Assembly **ppAssembly)
+ {
+ _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
+
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::GetAssemblyFromImage"));
+
+ _ASSERTE(pPEImage != NULL);
+ _ASSERTE(ppAssembly != NULL);
+
+ ReleaseHolder<Assembly> pAssembly;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+ DWORD dwPAFlags[2];
+ PEKIND PeKind = peNone;
+
+ SAFE_NEW(pAssembly, Assembly);
+ if(pNativePEImage)
+ {
+ IF_FAIL_GO(BinderAcquireImport(pNativePEImage, &pIMetaDataAssemblyImport, dwPAFlags, TRUE));
+ }
+ else
+ {
+ IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE));
+ }
+ IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+ IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
+ PeKind,
+ pPEImage,
+ pNativePEImage,
+ g_BinderVariables->emptyString,
+ FALSE /* fInspectionOnly */,
+ FALSE /* fIsInGAC */));
+
+ // TODO: Is this correct?
+ pAssembly->SetIsByteArray(TRUE);
+
+ *ppAssembly = pAssembly.Extract();
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::GetAssemblyFromImage"), hr);
+ return hr;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ /* static */
+ HRESULT AssemblyBinder::PreBindByteArray(ApplicationContext *pApplicationContext,
+ PEImage *pPEImage,
+ BOOL fInspectionOnly)
+ {
+ _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
+
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::PreBindByteArray"));
+
+ ReleaseHolder<AssemblyName> pAssemblyName;
+ BOOL fNeedHostRegister = FALSE;
+ LONG kContextVersion = 0;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+ DWORD dwPAFlags[2];
+ PEKIND PeKind = peNone;
+ BindResult bindResult;
+
+ // Prepare binding data
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE));
+ IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+ pAssemblyName->SetIsDefinition(TRUE);
+
+ // Validate architecture
+ if (!fInspectionOnly && !Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Attempt the actual bind (eventually more than once)
+ Retry:
+ {
+ // Lock the application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+
+ // Attempt uncached bind and register stream if possible
+ if (!fInspectionOnly &&
+ ((hr = BindByName(pApplicationContext,
+ pAssemblyName,
+ BIND_CACHE_FAILURES | BIND_CACHE_RERUN_BIND,
+ false, // excludeAppPaths
+ &bindResult)) == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ )
+ {
+ if ((fInspectionOnly && !bindResult.HaveResult()) ||
+ (bindResult.GetRetargetedAssemblyName() == NULL))
+ {
+ IF_FAIL_GO(CreateImageAssembly(pIMetaDataAssemblyImport,
+ PeKind,
+ pPEImage,
+ NULL,
+ fInspectionOnly,
+ &bindResult));
+ if (fInspectionOnly)
+ {
+ // For inspection-only, we do not share the map.
+ IF_FAIL_GO(Register(pApplicationContext, fInspectionOnly, &bindResult));
+ }
+ else
+ {
+ // Remember the post-bind version of the context
+ kContextVersion = pApplicationContext->GetVersion();
+ fNeedHostRegister = TRUE;
+ }
+ }
+ }
+ } // lock(pApplicationContext)
+
+ if (fNeedHostRegister)
+ {
+ BindResult hostBindResult;
+
+ // This has to happen outside the binder lock as it can cause new binds
+ IF_FAIL_GO(RegisterAndGetHostChosen(pApplicationContext,
+ kContextVersion,
+ &bindResult,
+ &hostBindResult));
+
+ if (hr == S_FALSE)
+ {
+ // Another bind interfered. We need to retry entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult.Reset();
+ goto Retry;
+ }
+ }
+
+ // Ignore bind errors here because we need to attempt by-name load to get log entry.
+ GO_WITH_HRESULT(S_OK);
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::PreBindByteArray"), hr);
+ return hr;
+ }
+
+#endif //CROSSGEN_COMPILE
+
+ /* static */
+ HRESULT AssemblyBinder::BindByName(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ DWORD dwBindFlags,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindByName"));
+ PathString assemblyDisplayName;
+
+ // Look for already cached binding failure (ignore PA, every PA will lock the context)
+ pAssemblyName->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION);
+
+ hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
+ if (FAILED(hr))
+ {
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) && RerunBind(dwBindFlags))
+ {
+ // Ignore pre-existing transient bind error (re-bind will succeed)
+ pApplicationContext->GetFailureCache()->Remove(assemblyDisplayName);
+ }
+
+ goto LogExit;
+ }
+ else if (hr == S_FALSE)
+ {
+ // workaround: Special case for byte arrays. Rerun the bind to create binding log.
+ pAssemblyName->SetIsDefinition(TRUE);
+ hr = S_OK;
+ }
+
+ if (!Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ // Assembly reference contains wrong architecture
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+
+ IF_FAIL_GO(BindLocked(pApplicationContext,
+ pAssemblyName,
+ dwBindFlags,
+ excludeAppPaths,
+ pBindResult));
+
+ if (!pBindResult->HaveResult())
+ {
+ // Behavior rules are clueless now
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ Exit:
+ if (FAILED(hr) && CacheBindFailures(dwBindFlags))
+ {
+ if (RerunBind(dwBindFlags))
+ {
+ if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ // Cache non-transient bind error for byte-array
+ hr = S_FALSE;
+ }
+ else
+ {
+ // Ignore transient bind error (re-bind will succeed)
+ goto LogExit;
+ }
+ }
+ hr = pApplicationContext->AddToFailureCache(assemblyDisplayName, hr);
+ }
+ LogExit:
+
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindByName"), hr);
+ return hr;
+ }
+
+ /* static */
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ HRESULT AssemblyBinder::BindWhereRef(ApplicationContext *pApplicationContext,
+ PathString &assemblyPath,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindWhereRef"));
+
+ ReleaseHolder<Assembly> pAssembly;
+ BindResult lockedBindResult;
+
+ // Look for already cached binding failure
+ hr = pApplicationContext->GetFailureCache()->Lookup(assemblyPath);
+ if (FAILED(hr))
+ {
+ goto LogExit;
+ }
+
+ // If we return this assembly, then it is guaranteed to be not in GAC
+ // Design decision. For now, keep the V2 model of Fusion being oblivious of the strong name.
+ // Security team did not see any security concern with interpreting the version information.
+ IF_FAIL_GO(GetAssembly(assemblyPath,
+ FALSE /* fInspectionOnly */,
+ FALSE /* fIsInGAC */,
+
+ // Pass through caller's intent of whether to bind to the
+ // NI using an explicit path to the NI that was
+ // specified. Generally only NGEN PDB generation has
+ // this TRUE.
+ fExplicitBindToNativeImage,
+ &pAssembly));
+#ifdef FEATURE_VERSIONING_LOG
+ IF_FAIL_GO(LogAssemblyNameWhereRef(pApplicationContext, pAssembly));
+#endif // FEATURE_VERSIONING_LOG
+
+ AssemblyName *pAssemblyName;
+ pAssemblyName = pAssembly->GetAssemblyName();
+
+ if (!fNgenExplicitBind)
+ {
+ IF_FAIL_GO(BindLockedOrService(pApplicationContext,
+ pAssemblyName,
+ excludeAppPaths,
+ &lockedBindResult));
+ if (lockedBindResult.HaveResult())
+ {
+ pBindResult->SetResult(&lockedBindResult);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+
+ hr = S_OK;
+ pAssembly->SetIsDynamicBind(TRUE);
+ pBindResult->SetResult(pAssembly);
+
+ Exit:
+
+ if (FAILED(hr))
+ {
+ // Always cache binding failures
+ hr = pApplicationContext->AddToFailureCache(assemblyPath, hr);
+ }
+
+ LogExit:
+
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindWhereRef"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::BindLocked(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ DWORD dwBindFlags,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindLocked"));
+
+ BOOL fIgnoreDynamicBinds = IgnoreDynamicBinds(dwBindFlags);
+
+#ifndef CROSSGEN_COMPILE
+ ContextEntry *pContextEntry = NULL;
+ IF_FAIL_GO(FindInExecutionContext(pApplicationContext, pAssemblyName, &pContextEntry));
+ if (pContextEntry != NULL)
+ {
+ if (fIgnoreDynamicBinds && pContextEntry->GetIsDynamicBind())
+ {
+ // Dynamic binds need to be always considered a failure for binding closures
+ IF_FAIL_GO(FUSION_E_APP_DOMAIN_LOCKED);
+ }
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ else if (IgnoreRefDefMatch(dwBindFlags))
+ {
+ // Skip RefDef matching if we have been asked to.
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ else
+ {
+ // Can't give higher serciving than already bound
+ IF_FAIL_GO(IsValidAssemblyVersion(pAssemblyName, pContextEntry->GetAssemblyName(), pApplicationContext));
+ }
+
+ pBindResult->SetResult(pContextEntry);
+ }
+ else
+#endif // !CROSSGEN_COMPILE
+ if (pApplicationContext->IsTpaListProvided())
+ {
+ IF_FAIL_GO(BindByTpaList(pApplicationContext,
+ pAssemblyName,
+ FALSE /*fInspectionOnly*/,
+ excludeAppPaths,
+ pBindResult));
+ if (pBindResult->HaveResult())
+ {
+ hr = IsValidAssemblyVersion(pAssemblyName, pBindResult->GetAssemblyName(), pApplicationContext);
+ if (FAILED(hr))
+ {
+ pBindResult->SetNoResult();
+ }
+ }
+ }
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindLocked"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::BindLockedOrService(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindLockedOrService"));
+
+ BindResult lockedBindResult;
+
+ IF_FAIL_GO(BindLocked(pApplicationContext,
+ pAssemblyName,
+ 0 /* Do not IgnoreDynamicBinds */,
+ excludeAppPaths,
+ &lockedBindResult));
+
+ if (lockedBindResult.HaveResult())
+ {
+ // Locked Bind succeeded
+ pBindResult->SetResult(&lockedBindResult);
+ }
+ else
+ {
+ pBindResult->SetNoResult();
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindLockedOrService"), hr);
+ return hr;
+ }
+
+#ifndef CROSSGEN_COMPILE
+ /* static */
+ HRESULT AssemblyBinder::FindInExecutionContext(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ ContextEntry **ppContextEntry)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::FindInExecutionContext"));
+
+ _ASSERTE(pApplicationContext != NULL);
+ _ASSERTE(pAssemblyName != NULL);
+ _ASSERTE(ppContextEntry != NULL);
+
+ ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
+ ContextEntry *pContextEntry = pExecutionContext->Lookup(pAssemblyName);
+
+ if (pContextEntry != NULL)
+ {
+ AssemblyName *pContextName = pContextEntry->GetAssemblyName();
+
+#ifdef FEATURE_VERSIONING_LOG
+ // First-time requests are considered unlocked, everything else is locked
+ DWORD dwLockedReason = (pContextEntry->GetIsFirstRequest() ?
+ APP_DOMAIN_LOCKED_UNLOCKED : APP_DOMAIN_LOCKED_CONTEXT);
+
+ IF_FAIL_GO(LogAppDomainLocked(pApplicationContext, dwLockedReason, pContextName));
+ pContextEntry->SetIsFirstRequest(FALSE);
+#endif // FEATURE_VERSIONING_LOG
+
+ if (pAssemblyName->GetIsDefinition() &&
+ (pContextName->GetArchitecture() != pAssemblyName->GetArchitecture()))
+ {
+ IF_FAIL_GO(FUSION_E_APP_DOMAIN_LOCKED);
+ }
+ }
+
+ *ppContextEntry = pContextEntry;
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::FindInExecutionContext"), hr);
+ return hr;
+ }
+
+#endif //CROSSGEN_COMPILE
+
+ //
+ // Tests whether a candidate assembly's name matches the requested.
+ // This does not do a version check. The binder applies version policy
+ // further up the stack once it gets a successful bind.
+ //
+ BOOL TestCandidateRefMatchesDef(ApplicationContext *pApplicationContext,
+ AssemblyName *pRequestedAssemblyName,
+ AssemblyName *pBoundAssemblyName,
+ BOOL tpaListAssembly)
+ {
+ DWORD dwIncludeFlags = AssemblyName::INCLUDE_DEFAULT;
+
+ if (!tpaListAssembly)
+ {
+ SString &culture = pRequestedAssemblyName->GetCulture();
+ if (culture.IsEmpty() || culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
+ {
+ dwIncludeFlags |= AssemblyName::EXCLUDE_CULTURE;
+ }
+ }
+
+ if (pRequestedAssemblyName->GetArchitecture() != peNone)
+ {
+ dwIncludeFlags |= AssemblyName::INCLUDE_ARCHITECTURE;
+ }
+
+ BINDER_LOG_ASSEMBLY_NAME(W("pBoundAssemblyName"), pBoundAssemblyName);
+
+ return pBoundAssemblyName->Equals(pRequestedAssemblyName, dwIncludeFlags);
+ }
+
+ HRESULT BindSatelliteResourceByResourceRoots(ApplicationContext *pApplicationContext,
+ StringArrayList *pResourceRoots,
+ AssemblyName *pRequestedAssemblyName,
+ BOOL fInspectionOnly,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+
+ SString &simpleNameRef = pRequestedAssemblyName->GetSimpleName();
+ SString &cultureRef = pRequestedAssemblyName->GetCulture();
+
+ _ASSERTE(!cultureRef.IsEmpty() && !cultureRef.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral));
+
+ for (UINT i = 0; i < pResourceRoots->GetCount(); i++)
+ {
+ ReleaseHolder<Assembly> pAssembly;
+ SString &wszBindingPath = (*pResourceRoots)[i];
+ SString fileName(wszBindingPath);
+
+ CombinePath(fileName, cultureRef, fileName);
+ CombinePath(fileName, simpleNameRef, fileName);
+ fileName.Append(W(".dll"));
+
+ hr = AssemblyBinder::GetAssembly(fileName,
+ fInspectionOnly,
+ FALSE /* fIsInGAC */,
+ FALSE /* fExplicitBindToNativeImage */,
+ &pAssembly);
+
+ // Missing files are okay and expected when probing
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ continue;
+ }
+
+ IF_FAIL_GO(hr);
+
+ AssemblyName *pBoundAssemblyName = pAssembly->GetAssemblyName();
+ if (TestCandidateRefMatchesDef(pApplicationContext, pRequestedAssemblyName, pBoundAssemblyName, false /*tpaListAssembly*/))
+ {
+ pBindResult->SetResult(pAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+
+#ifdef FEATURE_VERSIONING_LOG
+ // Log the candidates we throw out for diagnostics
+ IF_FAIL_GO(LogConfigurationError(pApplicationContext,
+ pRequestedAssemblyName,
+ pBoundAssemblyName));
+#endif // FEATURE_VERSIONING_LOG
+
+ IF_FAIL_GO(FUSION_E_REF_DEF_MISMATCH);
+ }
+
+ // Up-stack expects S_OK when we don't find any candidate assemblies and no fatal error occurred (ie, no S_FALSE)
+ hr = S_OK;
+ Exit:
+ return hr;
+ }
+
+ /*
+ * BindByTpaList is the entry-point for the custom binding algorithm on the Phone.
+ * Platform assemblies are specified as a list of files. This list is the only set of
+ * assemblies that we will load as platform. They can be specified as IL or NIs.
+ *
+ * Resources for platform assemblies are located by probing starting at the Platform Resource Roots,
+ * a set of folders configured by the host.
+ *
+ * If a requested assembly identity cannot be found in the TPA list or the resource roots,
+ * it is considered an application assembly. We probe for application assemblies in one of two
+ * sets of paths: the AppNiPaths, a list of paths containing native images, and the AppPaths, a
+ * list of paths containing IL files and satellite resource folders.
+ *
+ */
+ /* static */
+ HRESULT AssemblyBinder::BindByTpaList(ApplicationContext *pApplicationContext,
+ AssemblyName *pRequestedAssemblyName,
+ BOOL fInspectionOnly,
+ bool excludeAppPaths,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindByTpaList"));
+
+ SString &culture = pRequestedAssemblyName->GetCulture();
+ bool fPartialMatchOnTpa = false;
+
+ if (!culture.IsEmpty() && !culture.EqualsCaseInsensitive(g_BinderVariables->cultureNeutral))
+ {
+ //
+ // Satellite resource probing strategy is to look under each of the Platform Resource Roots
+ // followed by App Paths.
+ //
+
+ hr = BindSatelliteResourceByResourceRoots(pApplicationContext,
+ pApplicationContext->GetPlatformResourceRoots(),
+ pRequestedAssemblyName,
+ fInspectionOnly,
+ pBindResult);
+
+ // We found a platform resource file with matching file name, but whose ref-def didn't match. Fall
+ // back to application resource lookup to handle case where a user creates resources with the same
+ // names as platform ones.
+ if (hr != FUSION_E_CONFIGURATION_ERROR)
+ {
+ IF_FAIL_GO(hr);
+ }
+
+ if (!pBindResult->HaveResult())
+ {
+ IF_FAIL_GO(BindSatelliteResourceByResourceRoots(pApplicationContext,
+ pApplicationContext->GetAppPaths(),
+ pRequestedAssemblyName,
+ fInspectionOnly,
+ pBindResult));
+ }
+ }
+ else
+ {
+ // Is assembly on TPA list?
+ SString &simpleName = pRequestedAssemblyName->GetSimpleName();
+ SimpleNameToFileNameMap * tpaMap = pApplicationContext->GetTpaList();
+ const SimpleNameToFileNameMapEntry *pTpaEntry = tpaMap->LookupPtr(simpleName.GetUnicode());
+ ReleaseHolder<Assembly> pTPAAssembly;
+ if (pTpaEntry != nullptr)
+ {
+ if (pTpaEntry->m_wszNIFileName != nullptr)
+ {
+ SString fileName(pTpaEntry->m_wszNIFileName);
+
+ // A GetAssembly overload perhaps, or just another parameter to the existing method
+ hr = GetAssembly(fileName,
+ fInspectionOnly,
+ TRUE, /* fIsInGAC */
+ TRUE /* fExplicitBindToNativeImage */,
+ &pTPAAssembly
+ );
+ }
+ else
+ {
+ _ASSERTE(pTpaEntry->m_wszILFileName != nullptr);
+ SString fileName(pTpaEntry->m_wszILFileName);
+
+ hr = GetAssembly(fileName,
+ fInspectionOnly,
+ TRUE, /* fIsInGAC */
+ FALSE /* fExplicitBindToNativeImage */,
+ &pTPAAssembly);
+ }
+
+ // On file not found, simply fall back to app path probing
+ if (hr != HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ // Any other error is fatal
+ IF_FAIL_GO(hr);
+
+ if (TestCandidateRefMatchesDef(pApplicationContext, pRequestedAssemblyName, pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
+ {
+ // We have found the requested assembly match on TPA with validation of the full-qualified name. Bind to it.
+ pBindResult->SetResult(pTPAAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ else
+ {
+ // We found the assembly on TPA but it didnt match the RequestedAssembly assembly-name. In this case, lets proceed to see if we find the requested
+ // assembly in the App paths.
+ fPartialMatchOnTpa = true;
+ }
+ }
+
+ // We either didn't find a candidate, or the ref-def failed. Either way; fall back to app path probing.
+ }
+
+ bool fUseAppPathsBasedResolver = !excludeAppPaths;
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ // If Host Assembly Resolver is specified, then we will use that as the override for the default resolution mechanism (that uses AppPath probing).
+ if (fUseAppPathsBasedResolver && !RuntimeCanUseAppPathAssemblyResolver(pApplicationContext->GetAppDomainId()))
+ {
+ fUseAppPathsBasedResolver = false;
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ // This loop executes twice max. First time through we probe AppNiPaths, the second time we probe AppPaths
+ bool parseNiPaths = true;
+ while (fUseAppPathsBasedResolver)
+ {
+ StringArrayList *pBindingPaths = parseNiPaths ? pApplicationContext->GetAppNiPaths() : pApplicationContext->GetAppPaths();
+
+ // Loop through the binding paths looking for a matching assembly
+ for (DWORD i = 0; i < pBindingPaths->GetCount(); i++)
+ {
+ ReleaseHolder<Assembly> pAssembly;
+ LPCWSTR wszBindingPath = (*pBindingPaths)[i];
+
+ SString &simpleName = pRequestedAssemblyName->GetSimpleName();
+
+ // Look for a matching dll first
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+
+ {
+ SString fileName(wszBindingPath);
+ CombinePath(fileName, simpleName, fileName);
+ if (parseNiPaths)
+ {
+ fileName.Append(W(".ni.dll"));
+ hr = GetAssembly(fileName,
+ fInspectionOnly,
+ FALSE, /* fIsInGAC */
+ TRUE /* fExplicitBindToNativeImage */,
+ &pAssembly);
+ }
+ else
+ {
+ if (FAILED(hr))
+ {
+ fileName.Append(W(".dll"));
+
+ hr = GetAssembly(fileName,
+ fInspectionOnly,
+ FALSE, /* fIsInGAC */
+ FALSE /* fExplicitBindToNativeImage */,
+ &pAssembly);
+ }
+ }
+ }
+
+ if (FAILED(hr))
+ {
+ SString fileName(wszBindingPath);
+ CombinePath(fileName, simpleName, fileName);
+
+ if (parseNiPaths)
+ {
+ fileName.Append(W(".ni.exe"));
+ hr = GetAssembly(fileName,
+ fInspectionOnly,
+ FALSE, /* fIsInGAC */
+ TRUE /* fExplicitBindToNativeImage */,
+ &pAssembly);
+ }
+ else
+ {
+ if (FAILED(hr))
+ {
+ fileName.Append(W(".exe"));
+
+ hr = GetAssembly(fileName,
+ fInspectionOnly,
+ FALSE, /* fIsInGAC */
+ FALSE /* fExplicitBindToNativeImage */,
+ &pAssembly);
+ }
+ }
+ }
+
+ // Since we're probing, file not founds are ok and we should just try another
+ // probing path
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ continue;
+ }
+ IF_FAIL_GO(hr);
+
+ // We found a candidate.
+ //
+ // Below this point, we either establish that the ref-def matches, or
+ // we fail the bind.
+
+ // Compare requested AssemblyName with that from the candidate assembly
+ if (TestCandidateRefMatchesDef(pApplicationContext, pRequestedAssemblyName, pAssembly->GetAssemblyName(), false /*tpaListAssembly*/))
+ {
+ // At this point, we have found an assembly with the expected name in the App paths. If this was also found on TPA,
+ // make sure that the app assembly has the same fullname (excluding version) as the TPA version. If it does, then
+ // we should bind to the TPA assembly. If it does not, then bind to the app assembly since it has a different fullname than the
+ // TPA assembly.
+ if (fPartialMatchOnTpa)
+ {
+ if (TestCandidateRefMatchesDef(pApplicationContext, pAssembly->GetAssemblyName(), pTPAAssembly->GetAssemblyName(), true /*tpaListAssembly*/))
+ {
+ // Fullname (SimpleName+Culture+PKT) matched for TPA and app assembly - so bind to TPA instance.
+ pBindResult->SetResult(pTPAAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ else
+ {
+ // Fullname (SimpleName+Culture+PKT) did not match for TPA and app assembly - so bind to app instance.
+ pBindResult->SetResult(pAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+ else
+ {
+ // We didnt see this assembly on TPA - so simply bind to the app instance.
+ pBindResult->SetResult(pAssembly);
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+
+ #ifdef FEATURE_VERSIONING_LOG
+ // Log the candidates we throw out for diagnostics
+ IF_FAIL_GO(LogConfigurationError(pApplicationContext,
+ pRequestedAssemblyName,
+ pAssembly->GetAssemblyName()));
+ #endif // FEATURE_VERSIONING_LOG
+
+ IF_FAIL_GO(FUSION_E_REF_DEF_MISMATCH);
+
+ }
+
+ if (!parseNiPaths)
+ {
+ break;
+ }
+
+ parseNiPaths = false;
+ }
+ }
+
+ // Couldn't find a matching assembly in any of the probing paths
+ // Return S_OK here. BindByName will interpret a lack of BindResult
+ // as a failure to find a matching assembly. Other callers of this
+ // function, such as BindLockedOrService will interpret as deciding
+ // not to override an explicit bind with a probed assembly
+ hr = S_OK;
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindByTpaList"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::GetAssembly(SString &assemblyPath,
+ BOOL fInspectionOnly,
+ BOOL fIsInGAC,
+
+ // When binding to the native image, should we
+ // assume assemblyPath explicitly specifies that
+ // NI? (If not, infer the path to the NI
+ // implicitly.)
+ BOOL fExplicitBindToNativeImage,
+
+ Assembly **ppAssembly,
+
+ // If assemblyPath refers to a native image without metadata,
+ // szMDAssemblyPath gives the alternative file to get metadata.
+ LPCTSTR szMDAssemblyPath)
+ {
+ HRESULT hr = S_OK;
+
+ BINDER_LOG_ENTER(W("Assembly::GetAssembly"));
+ BINDER_LOG_STRING(W("assemblyPath"), assemblyPath);
+
+ _ASSERTE(ppAssembly != NULL);
+
+ ReleaseHolder<Assembly> pAssembly;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+ DWORD dwPAFlags[2];
+ PEKIND PeKind = peNone;
+ PEImage *pPEImage = NULL;
+ PEImage *pNativePEImage = NULL;
+
+ // Allocate assembly object
+ SAFE_NEW(pAssembly, Assembly);
+
+ // Obtain assembly meta data
+ {
+ LPCTSTR szAssemblyPath = const_cast<LPCTSTR>(assemblyPath.GetUnicode());
+
+ BINDER_LOG_ENTER(W("BinderAcquirePEImage"));
+ hr = BinderAcquirePEImage(szAssemblyPath, &pPEImage, &pNativePEImage, fExplicitBindToNativeImage);
+ BINDER_LOG_LEAVE_HR(W("BinderAcquirePEImage"), hr);
+ IF_FAIL_GO(hr);
+
+ // If we found a native image, it might be an MSIL assembly masquerading as an native image
+ // as a fallback mechanism for when the Triton tool chain wasn't able to generate a native image.
+ // In that case it will not have a native header, so just treat it like the MSIL assembly it is.
+ if (pNativePEImage)
+ {
+ BOOL hasHeader = TRUE;
+ IF_FAIL_GO(BinderHasNativeHeader(pNativePEImage, &hasHeader));
+ if (!hasHeader)
+ {
+ pPEImage = pNativePEImage;
+ pNativePEImage = NULL;
+ }
+ }
+
+ BINDER_LOG_ENTER(W("BinderAcquireImport"));
+ if(pNativePEImage)
+ hr = BinderAcquireImport(pNativePEImage, &pIMetaDataAssemblyImport, dwPAFlags, TRUE);
+ else
+ hr = BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE);
+
+ BINDER_LOG_LEAVE_HR(W("BinderAcquireImport"), hr);
+ IF_FAIL_GO(hr);
+
+ if (pIMetaDataAssemblyImport == NULL && pNativePEImage != NULL)
+ {
+ // The native image doesn't contain metadata. Currently this is only supported for Windows.ni.winmd.
+ // While loading Windows.winmd, CLRPrivBinderWinRT::GetAssemblyAndTryFindNativeImage should have passed
+ // in a non-NULL szMDAssemblyPath, where we can load metadata from. If szMDAssemblyPath is NULL,
+ // it indicates that the app is trying to load a non-WinMD assembly named Windows (it's possible
+ // that the app happens to contain an assembly Windows.dll). To handle this case properly, we
+ // return a file-not-found error, so the caller can continues it's search.
+ if (szMDAssemblyPath == NULL)
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+ else
+ {
+ BINDER_LOG_ENTER(W("BinderAcquirePEImage"));
+ hr = BinderAcquirePEImage(szMDAssemblyPath, &pPEImage, NULL, FALSE);
+ BINDER_LOG_LEAVE_HR(W("BinderAcquirePEImage"), hr);
+ IF_FAIL_GO(hr);
+
+ BINDER_LOG_ENTER(W("BinderAcquireImport"));
+ hr = BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, FALSE);
+ BINDER_LOG_LEAVE_HR(W("BinderAcquireImport"), hr);
+ IF_FAIL_GO(hr);
+ }
+ }
+
+ IF_FAIL_GO(TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+ }
+
+ // Initialize assembly object
+ IF_FAIL_GO(pAssembly->Init(pIMetaDataAssemblyImport,
+ PeKind,
+ pPEImage,
+ pNativePEImage,
+ assemblyPath,
+ fInspectionOnly,
+ fIsInGAC));
+
+ // We're done
+ *ppAssembly = pAssembly.Extract();
+
+ Exit:
+
+ BinderReleasePEImage(pPEImage);
+ BinderReleasePEImage(pNativePEImage);
+
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::GetAssembly"), hr);
+
+ // Normalize file not found
+ if ((FAILED(hr)) && IsFileNotFound(hr))
+ {
+ hr = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
+ }
+
+ return hr;
+ }
+
+#ifndef CROSSGEN_COMPILE
+
+ /* static */
+ HRESULT AssemblyBinder::Register(ApplicationContext *pApplicationContext,
+ BOOL fInspectionOnly,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::Register"));
+
+ if (!pBindResult->GetIsContextBound())
+ {
+ pApplicationContext->IncrementVersion();
+
+ if (fInspectionOnly)
+ {
+ InspectionContext *pInspectionContext = pApplicationContext->GetInspectionContext();
+ IF_FAIL_GO(pInspectionContext->Register(pBindResult));
+ }
+ else
+ {
+ // Register the bindResult in the ExecutionContext only if we dont have it already.
+ // This method is invoked under a lock (by its caller), so we are thread safe.
+ ContextEntry *pContextEntry = NULL;
+ hr = FindInExecutionContext(pApplicationContext, pBindResult->GetAssemblyName(), &pContextEntry);
+ if (hr == S_OK)
+ {
+ if (pContextEntry == NULL)
+ {
+ ExecutionContext *pExecutionContext = pApplicationContext->GetExecutionContext();
+ IF_FAIL_GO(pExecutionContext->Register(pBindResult));
+ }
+ else
+ {
+ // The dynamic binds are compiled in CoreCLR, but they are not supported. They are only reachable by internal API Assembly.Load(byte[]) that nobody should be calling.
+ // This code path does not handle dynamic binds correctly (and is not expected to). We do not expect to come here for dynamic binds.
+
+ _ASSERTE(!pContextEntry->GetIsDynamicBind());
+
+ // Update the BindResult with the contents of the ContextEntry we found
+ pBindResult->SetResult(pContextEntry);
+ }
+ }
+ }
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::Register"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::RegisterAndGetHostChosen(ApplicationContext *pApplicationContext,
+ LONG kContextVersion,
+ BindResult *pBindResult,
+ BindResult *pHostBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("AssemblyBinder::RegisterHostChosen"));
+
+ _ASSERTE(pBindResult != NULL);
+ _ASSERTE(pBindResult->HaveResult());
+ _ASSERTE(pHostBindResult != NULL);
+
+ if (!pBindResult->GetIsContextBound())
+ {
+ pHostBindResult->SetResult(pBindResult);
+
+ {
+ // Lock the application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+
+ // Only perform costly validation if other binds succeded before us
+ if (kContextVersion != pApplicationContext->GetVersion())
+ {
+ IF_FAIL_GO(AssemblyBinder::OtherBindInterfered(pApplicationContext,
+ pBindResult));
+
+ if (hr == S_FALSE)
+ {
+ // Another bind interfered
+ GO_WITH_HRESULT(hr);
+ }
+ }
+
+ // No bind interfered, we can now register
+ IF_FAIL_GO(Register(pApplicationContext,
+ FALSE /* fInspectionOnly */,
+ pHostBindResult));
+ }
+ }
+ else
+ {
+ // No work required. Return the input
+ pHostBindResult->SetResult(pBindResult);
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::RegisterHostChosen"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT AssemblyBinder::OtherBindInterfered(ApplicationContext *pApplicationContext,
+ BindResult *pBindResult)
+ {
+ HRESULT hr = S_FALSE;
+ BINDER_LOG_ENTER(W("AssemblyBinder::OtherBindInterfered"));
+ AssemblyName *pAssemblyName = pBindResult->GetAssemblyName();
+ PathString assemblyDisplayName;
+
+ _ASSERTE(pAssemblyName != NULL);
+
+ // Look for already cached binding failure (ignore PA, every PA will lock the context)
+ pAssemblyName->GetDisplayName(assemblyDisplayName, AssemblyName::INCLUDE_VERSION);
+ hr = pApplicationContext->GetFailureCache()->Lookup(assemblyDisplayName);
+
+ if (hr == S_OK)
+ {
+ ContextEntry *pContextEntry = NULL;
+
+ hr = FindInExecutionContext(pApplicationContext, pAssemblyName, &pContextEntry);
+
+ if ((hr == S_OK) && (pContextEntry == NULL))
+ {
+ // We can accept this bind in the domain
+ GO_WITH_HRESULT(S_OK);
+ }
+ }
+
+ // Some other bind interfered
+ GO_WITH_HRESULT(S_FALSE);
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::OtherBindInterfered"), hr);
+ return hr;
+ }
+
+#endif //CROSSGEN_COMPILE
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+HRESULT AssemblyBinder::BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ IAssemblyName *pIAssemblyName,
+ /* in */ CLRPrivBinderCoreCLR *pTPABinder,
+ /* out */ Assembly **ppAssembly)
+{
+ HRESULT hr = E_FAIL;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindUsingHostAssemblyResolver"));
+
+ _ASSERTE(pManagedAssemblyLoadContextToBindWithin != NULL);
+
+ // RuntimeInvokeHostAssemblyResolver will perform steps 2-4 of CLRPrivBinderAssemblyLoadContext::BindAssemblyByName.
+ ICLRPrivAssembly *pLoadedAssembly = NULL;
+ hr = RuntimeInvokeHostAssemblyResolver(pManagedAssemblyLoadContextToBindWithin, pIAssemblyName,
+ pTPABinder, pAssemblyName, &pLoadedAssembly);
+ if (SUCCEEDED(hr))
+ {
+ _ASSERTE(pLoadedAssembly != NULL);
+ *ppAssembly = static_cast<Assembly *>(pLoadedAssembly);
+ }
+
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindUsingHostAssemblyResolver"), hr);
+ return hr;
+}
+
+/* static */
+HRESULT AssemblyBinder::BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
+ /* in */ PEImage *pPEImage,
+ /* in */ PEKIND peKind,
+ /* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* [retval] [out] */ Assembly **ppAssembly)
+{
+ HRESULT hr = E_FAIL;
+ BINDER_LOG_ENTER(W("AssemblyBinder::BindUsingPEImage"));
+
+ _ASSERTE(BINDER_SPACE::fAssemblyBinderInitialized == TRUE);
+
+ LONG kContextVersion = 0;
+ BindResult bindResult;
+
+ // Prepare binding data
+ *ppAssembly = NULL;
+
+ // Attempt the actual bind (eventually more than once)
+Retry:
+ {
+ // Lock the application context
+ CRITSEC_Holder contextLock(pApplicationContext->GetCriticalSectionCookie());
+
+ // Attempt uncached bind and register stream if possible
+ hr = BindByName(pApplicationContext,
+ pAssemblyName,
+ BIND_CACHE_FAILURES|BIND_CACHE_RERUN_BIND|BIND_IGNORE_REFDEF_MATCH,
+ false, // excludeAppPaths
+ &bindResult);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND))
+ {
+ IF_FAIL_GO(CreateImageAssembly(pIMetaDataAssemblyImport,
+ peKind,
+ pPEImage,
+ NULL,
+ FALSE,
+ &bindResult));
+
+ }
+ else if (hr == S_OK)
+ {
+ if (bindResult.HaveResult())
+ {
+ // Attempt was made to load an assembly that has the same name as a previously loaded one. Since same name
+ // does not imply the same assembly, we will need to check the MVID to confirm it is the same assembly as being
+ // requested.
+ //
+ GUID incomingMVID;
+ ZeroMemory(&incomingMVID, sizeof(GUID));
+
+ // If we cannot get MVID, then err on side of caution and fail the
+ // load.
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetScopeProps(NULL, &incomingMVID));
+
+ GUID boundMVID;
+ ZeroMemory(&boundMVID, sizeof(GUID));
+
+ // If we cannot get MVID, then err on side of caution and fail the
+ // load.
+ IF_FAIL_GO(bindResult.GetAsAssembly()->GetMVID(&boundMVID));
+
+ if (incomingMVID != boundMVID)
+ {
+ // MVIDs do not match, so fail the load.
+ IF_FAIL_GO(COR_E_FILELOAD);
+ }
+
+ // MVIDs match - request came in for the same assembly that was previously loaded.
+ // Let is through...
+ }
+ }
+
+ // Remember the post-bind version of the context
+ kContextVersion = pApplicationContext->GetVersion();
+
+ } // lock(pApplicationContext)
+
+ if (bindResult.HaveResult())
+ {
+ BindResult hostBindResult;
+
+ // This has to happen outside the binder lock as it can cause new binds
+ IF_FAIL_GO(RegisterAndGetHostChosen(pApplicationContext,
+ kContextVersion,
+ &bindResult,
+ &hostBindResult));
+
+ if (hr == S_FALSE)
+ {
+ // Another bind interfered. We need to retry entire bind.
+ // This by design loops as long as needed because by construction we eventually
+ // will succeed or fail the bind.
+ bindResult.Reset();
+ goto Retry;
+ }
+ else if (hr == S_OK)
+ {
+ *ppAssembly = hostBindResult.GetAsAssembly(TRUE /* fAddRef */);
+ }
+ }
+
+Exit:
+
+ BINDER_LOG_LEAVE_HR(W("AssemblyBinder::BindUsingPEImage"), hr);
+ return hr;
+}
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+};
+
+
diff --git a/src/binder/assemblyidentitycache.cpp b/src/binder/assemblyidentitycache.cpp
new file mode 100644
index 0000000000..dc2c7205b8
--- /dev/null
+++ b/src/binder/assemblyidentitycache.cpp
@@ -0,0 +1,72 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyIdentityCache.cpp
+//
+
+
+//
+// Implements the AssemblyIdentityCache class
+//
+// ============================================================
+
+#define DISABLE_BINDER_DEBUG_LOGGING
+
+#include "assemblyidentitycache.hpp"
+
+namespace BINDER_SPACE
+{
+ AssemblyIdentityCache::AssemblyIdentityCache() : SHash<AssemblyIdentityHashTraits>::SHash()
+ {
+ // Nothing to do here
+ }
+
+ AssemblyIdentityCache::~AssemblyIdentityCache()
+ {
+ // Delete entries and contents array
+ for (Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
+ {
+ const AssemblyIdentityCacheEntry *pAssemblyIdentityCacheEntry = *i;
+ delete pAssemblyIdentityCacheEntry;
+ }
+ RemoveAll();
+ }
+
+ HRESULT AssemblyIdentityCache::Add(LPCSTR szTextualIdentity,
+ AssemblyIdentityUTF8 *pAssemblyIdentity)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"AssemblyIdentityCache::Add");
+
+ NewHolder<AssemblyIdentityCacheEntry> pAssemblyIdentityCacheEntry;
+ SAFE_NEW(pAssemblyIdentityCacheEntry, AssemblyIdentityCacheEntry);
+
+ pAssemblyIdentityCacheEntry->SetTextualIdentity(szTextualIdentity);
+ pAssemblyIdentityCacheEntry->SetAssemblyIdentity(pAssemblyIdentity);
+
+ Hash::Add(pAssemblyIdentityCacheEntry);
+ pAssemblyIdentityCacheEntry.SuppressRelease();
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"AssemblyIdentityCache::Add", hr);
+ return hr;
+ }
+
+ AssemblyIdentityUTF8 *AssemblyIdentityCache::Lookup(LPCSTR szTextualIdentity)
+ {
+ BINDER_LOG_ENTER(L"AssemblyIdentityCache::Lookup");
+ AssemblyIdentityUTF8 *pAssemblyIdentity = NULL;
+ AssemblyIdentityCacheEntry *pAssemblyIdentityCacheEntry = Hash::Lookup(szTextualIdentity);
+
+ if (pAssemblyIdentityCacheEntry != NULL)
+ {
+ BINDER_LOG(L"Found cached identity");
+ pAssemblyIdentity = pAssemblyIdentityCacheEntry->GetAssemblyIdentity();
+ }
+
+ BINDER_LOG_LEAVE(L"AssemblyIdentityCache::Lookup");
+ return pAssemblyIdentity;
+ }
+};
diff --git a/src/binder/assemblyname.cpp b/src/binder/assemblyname.cpp
new file mode 100644
index 0000000000..616869b3f9
--- /dev/null
+++ b/src/binder/assemblyname.cpp
@@ -0,0 +1,704 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyName.cpp
+//
+
+
+//
+// Implements the AssemblyName class
+//
+// ============================================================
+
+#define DISABLE_BINDER_DEBUG_LOGGING
+
+#include "assemblyname.hpp"
+#include "assembly.hpp"
+#include "utils.hpp"
+#include "variables.hpp"
+
+#include "fusionassemblyname.hpp"
+
+#include "textualidentityparser.hpp"
+
+#include "corpriv.h"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ AssemblyName::AssemblyName()
+ {
+ m_cRef = 1;
+ m_dwNameFlags = NAME_FLAG_NONE;
+ // Default values present in every assembly name
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE |
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+
+ AssemblyName::~AssemblyName()
+ {
+ // Nothing to do here
+ }
+
+ HRESULT AssemblyName::Init(IMDInternalImport *pIMetaDataAssemblyImport,
+ PEKIND PeKind,
+ mdAssemblyRef mdar /* = 0 */,
+ BOOL fIsDefinition /* = TRUE */)
+ {
+ HRESULT hr = S_OK;
+ mdAssembly mda = 0;
+ AssemblyMetaDataInternal amd = {0};
+ CONST VOID *pvPublicKeyToken = NULL;
+ DWORD dwPublicKeyToken = 0;
+ LPCSTR pAssemblyName = NULL;
+ DWORD dwRefOrDefFlags = 0;
+ DWORD dwHashAlgId = 0;
+
+ BINDER_LOG_ENTER(L"AssemblyName::Init(IMetaDataAssemblyImport)");
+
+ if (fIsDefinition)
+ {
+ // Get the assembly token
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyFromScope(&mda));
+ }
+
+ BINDER_LOG(L"Have mda scope!");
+
+ // Get name and metadata
+ if (fIsDefinition)
+ {
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyProps(
+ mda, // [IN] The Assembly for which to get the properties.
+ &pvPublicKeyToken, // [OUT] Pointer to the PublicKeyToken blob.
+ &dwPublicKeyToken, // [OUT] Count of bytes in the PublicKeyToken Blob.
+ &dwHashAlgId, // [OUT] Hash Algorithm.
+ &pAssemblyName, // [OUT] Name.
+ &amd, // [OUT] Assembly MetaData.
+ &dwRefOrDefFlags // [OUT] Flags.
+ ));
+ }
+ else
+ {
+ IF_FAIL_GO(pIMetaDataAssemblyImport->GetAssemblyRefProps(
+ mdar, // [IN] The Assembly for which to get the properties.
+ &pvPublicKeyToken, // [OUT] Pointer to the PublicKeyToken blob.
+ &dwPublicKeyToken, // [OUT] Count of bytes in the PublicKeyToken Blob.
+ &pAssemblyName, // [OUT] Name.
+ &amd, // [OUT] Assembly MetaData.
+ NULL, // [OUT] Hash blob.
+ NULL, // [OUT] Count of bytes in hash blob.
+ &dwRefOrDefFlags // [OUT] Flags.
+ ));
+ }
+
+ BINDER_LOG(L"Have props!");
+
+ {
+ StackSString culture;
+ culture.SetUTF8(amd.szLocale);
+ culture.Normalize();
+
+ SString::CIterator itr = culture.Begin();
+ if (culture.Find(itr, L';'))
+ {
+ culture = SString(culture, culture.Begin(), itr-1);
+ }
+
+ SetCulture(culture);
+ }
+
+ {
+ StackSString assemblyName;
+ assemblyName.SetUTF8(pAssemblyName);
+ assemblyName.Normalize();
+
+ COUNT_T assemblyNameLength = assemblyName.GetCount();
+ if (assemblyNameLength == 0 || assemblyNameLength >= MAX_PATH_FNAME)
+ {
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+
+ SetSimpleName(assemblyName);
+ }
+
+ // See if the assembly[def] is retargetable (ie, for a generic assembly).
+ if (IsAfRetargetable(dwRefOrDefFlags))
+ {
+ SetIsRetargetable(TRUE);
+ }
+
+ // Set ContentType
+ if (IsAfContentType_Default(dwRefOrDefFlags))
+ {
+ SetContentType(AssemblyContentType_Default);
+ }
+ else if (IsAfContentType_WindowsRuntime(dwRefOrDefFlags))
+ {
+ SetContentType(AssemblyContentType_WindowsRuntime);
+ }
+ else
+ {
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+
+ // Set the assembly version
+ {
+ AssemblyVersion *pAssemblyVersion = GetVersion();
+
+ pAssemblyVersion->SetFeatureVersion(amd.usMajorVersion, amd.usMinorVersion);
+ pAssemblyVersion->SetServiceVersion(amd.usBuildNumber, amd.usRevisionNumber);
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+
+ // Set public key and/or public key token (if we have it)
+ if (pvPublicKeyToken && dwPublicKeyToken)
+ {
+ SBuffer publicKeyOrTokenBLOB((const BYTE *) pvPublicKeyToken, dwPublicKeyToken);
+
+ if (IsAfPublicKey(dwRefOrDefFlags))
+ {
+ SBuffer publicKeyTokenBLOB;
+
+ IF_FAIL_GO(GetTokenFromPublicKey(publicKeyOrTokenBLOB, publicKeyTokenBLOB));
+ GetPublicKeyTokenBLOB().Set(publicKeyTokenBLOB);
+ }
+ else
+ {
+ GetPublicKeyTokenBLOB().Set(publicKeyOrTokenBLOB);
+ }
+
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ }
+
+ SetArchitecture(PeKind);
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"AssemblyName::Init(IMetaDataAssemblyImport)", hr);
+ return hr;
+ }
+
+ HRESULT AssemblyName::Init(SString &assemblyDisplayName)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"AssemblyName::Init(assemblyDisplayName)");
+
+ BINDER_LOG_STRING(L"assemblyDisplayName", assemblyDisplayName);
+
+ IF_FAIL_GO(TextualIdentityParser::Parse(assemblyDisplayName, this));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"AssemblyName::Init(assemblyDisplayName)", hr);
+ return hr;
+ }
+
+ HRESULT AssemblyName::Init(IAssemblyName *pIAssemblyName)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pIAssemblyName != NULL);
+
+ EX_TRY
+ {
+ {
+ // Set the simpleName
+ StackSString simpleName;
+ hr = fusion::util::GetSimpleName(pIAssemblyName, simpleName);
+ IF_FAIL_GO(hr);
+ SetSimpleName(simpleName);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+ }
+
+ // Display version
+ DWORD dwVersionParts[4] = {0,0,0,0};
+ DWORD cbVersionSize = sizeof(dwVersionParts[0]);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_MAJOR_VERSION, static_cast<PVOID>(&dwVersionParts[0]), &cbVersionSize);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbVersionSize != 0))
+ {
+ // Property is present - loop to get the individual version details
+ for(DWORD i = 0; i < 4; i++)
+ {
+ cbVersionSize = sizeof(dwVersionParts[i]);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_MAJOR_VERSION+i, static_cast<PVOID>(&dwVersionParts[i]), &cbVersionSize);
+ IF_FAIL_GO(hr);
+ }
+
+ m_version.SetFeatureVersion(dwVersionParts[0], dwVersionParts[1]);
+ m_version.SetServiceVersion(dwVersionParts[2], dwVersionParts[3]);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+
+ {
+ // Display culture
+ StackSString culture;
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CULTURE, culture);
+ IF_FAIL_GO(hr);
+ if (hr == S_OK)
+ {
+ SetCulture(culture);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ }
+ }
+
+ {
+ // Display public key token
+ NewArrayHolder<BYTE> pPublicKeyToken;
+ DWORD cbPublicKeyToken = 0;
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_PUBLIC_KEY_TOKEN, static_cast<PBYTE*>(&pPublicKeyToken), &cbPublicKeyToken);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbPublicKeyToken != 0))
+ {
+ m_publicKeyOrTokenBLOB.Set(pPublicKeyToken, cbPublicKeyToken);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ }
+ else
+ {
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+ }
+
+ // Display processor architecture
+ DWORD peKind = 0;
+ DWORD cbPeKind = sizeof(peKind);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_ARCHITECTURE, static_cast<PVOID>(&peKind), &cbPeKind);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbPeKind != 0))
+ {
+ PEKIND PeKind = (PEKIND)peKind;
+ if (PeKind != peNone)
+ {
+ SetArchitecture(PeKind);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ }
+
+ // Display retarget flag
+ BOOL fRetarget = FALSE;
+ DWORD cbRetarget = sizeof(fRetarget);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_RETARGET, static_cast<PVOID>(&fRetarget), &cbRetarget);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbRetarget != 0))
+ {
+ if (fRetarget)
+ {
+ SetIsRetargetable(fRetarget);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ }
+
+ // Display content type
+ DWORD dwContentType = AssemblyContentType_Default;
+ DWORD cbContentType = sizeof(dwContentType);
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CONTENT_TYPE, static_cast<PVOID>(&dwContentType), &cbContentType);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbContentType != 0))
+ {
+ if (dwContentType != AssemblyContentType_Default)
+ {
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ SetContentType((AssemblyContentType)dwContentType);
+ }
+ }
+
+ {
+ // Display custom flag. Dont set it if it is not present since that will end up adding the "Custom=null" attribute
+ // in the displayname of the assembly that maybe generated using this AssemblyName instance. This could create conflict when
+ // the displayname is generated from the assembly directly as that will not have a "Custom" field set.
+ NewArrayHolder<BYTE> pCustomBLOB;
+ DWORD cbCustomBLOB = 0;
+ hr = fusion::util::GetProperty(pIAssemblyName, ASM_NAME_CUSTOM, static_cast<PBYTE*>(&pCustomBLOB), &cbCustomBLOB);
+ IF_FAIL_GO(hr);
+ if ((hr == S_OK) && (cbCustomBLOB != 0))
+ {
+ m_customBLOB.Set(pCustomBLOB, cbCustomBLOB);
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+Exit:
+ return hr;
+ }
+
+ HRESULT AssemblyName::CreateFusionName(IAssemblyName **ppIAssemblyName)
+ {
+ HRESULT hr = S_OK;
+ ReleaseHolder<IAssemblyName> pIAssemblyName;
+
+ IF_FAIL_GO(CreateAssemblyNameObject(&pIAssemblyName, NULL, 0, NULL));
+
+ IF_FAIL_GO(LegacyFusion::SetStringProperty(pIAssemblyName, ASM_NAME_NAME, GetSimpleName()));
+
+ if (Have(AssemblyIdentity::IDENTITY_FLAG_VERSION))
+ {
+ AssemblyVersion *pAssemblyVersion = GetVersion();
+
+ IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
+ ASM_NAME_MAJOR_VERSION,
+ pAssemblyVersion->GetMajor()));
+ IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
+ ASM_NAME_MINOR_VERSION,
+ pAssemblyVersion->GetMinor()));
+ IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
+ ASM_NAME_BUILD_NUMBER,
+ pAssemblyVersion->GetBuild()));
+ IF_FAIL_GO(LegacyFusion::SetWordProperty(pIAssemblyName,
+ ASM_NAME_REVISION_NUMBER,
+ pAssemblyVersion->GetRevision()));
+ }
+
+ if (Have(AssemblyIdentity::IDENTITY_FLAG_CULTURE))
+ {
+ IF_FAIL_GO(LegacyFusion::SetStringProperty(pIAssemblyName, ASM_NAME_CULTURE, GetCulture()));
+ }
+
+ if (Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
+ {
+ // GetPublicKeyTokenBLOB contains either PK or PKT.
+ IF_FAIL_GO(LegacyFusion::SetBufferProperty(pIAssemblyName,
+ ASM_NAME_PUBLIC_KEY,
+ GetPublicKeyTokenBLOB()));
+ }
+ else if (Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
+ {
+ // GetPublicKeyTokenBLOB contains either PK or PKT.
+ IF_FAIL_GO(LegacyFusion::SetBufferProperty(pIAssemblyName,
+ ASM_NAME_PUBLIC_KEY_TOKEN,
+ GetPublicKeyTokenBLOB()));
+ }
+
+ if (Have(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
+ {
+ IF_FAIL_GO(LegacyFusion::SetDwordProperty(pIAssemblyName,
+ ASM_NAME_ARCHITECTURE,
+ static_cast<DWORD>(GetArchitecture())));
+ }
+
+ if (Have(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
+ {
+ IF_FAIL_GO(LegacyFusion::SetDwordProperty(pIAssemblyName,
+ ASM_NAME_CONTENT_TYPE,
+ GetContentType()));
+ }
+
+ *ppIAssemblyName = pIAssemblyName.Extract();
+
+ Exit:
+ return hr;
+ }
+
+ ULONG AssemblyName::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ ULONG AssemblyName::Release()
+ {
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+ return ulRef;
+ }
+
+ SString &AssemblyName::GetDeNormalizedCulture()
+ {
+ SString &culture = GetCulture();
+
+ if (EqualsCaseInsensitive(culture, g_BinderVariables->cultureNeutral))
+ {
+ culture = g_BinderVariables->emptyString;
+ }
+
+ return culture;
+ }
+
+ BOOL AssemblyName::IsStronglyNamed()
+ {
+ return Have(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ }
+
+ BOOL AssemblyName::IsMscorlib()
+ {
+ // TODO: Is this simple comparison enough?
+ return EqualsCaseInsensitive(GetSimpleName(), g_BinderVariables->mscorlib);
+ }
+
+ HRESULT AssemblyName::SetArchitecture(SString &architecture)
+ {
+ HRESULT hr = S_OK;
+
+ if (architecture.IsEmpty())
+ {
+ SetArchitecture(peNone);
+ }
+ else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureMSIL))
+ {
+ SetArchitecture(peMSIL);
+ }
+ else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureX86))
+ {
+ SetArchitecture(peI386);
+ }
+ else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureAMD64))
+ {
+ SetArchitecture(peAMD64);
+ }
+ else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureARM))
+ {
+ SetArchitecture(peARM);
+ }
+ else if (EqualsCaseInsensitive(architecture, g_BinderVariables->architectureARM64))
+ {
+ SetArchitecture(peARM64);
+ }
+ else
+ {
+ hr = FUSION_E_MANIFEST_PARSE_ERROR;
+ }
+
+ return hr;
+ }
+
+ ULONG AssemblyName::Hash(DWORD dwIncludeFlags)
+ {
+ DWORD dwHash = 0;
+ DWORD dwUseIdentityFlags = m_dwIdentityFlags;
+
+ // Prune unwanted name parts
+ if ((dwIncludeFlags & INCLUDE_VERSION) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_VERSION;
+ }
+ if ((dwIncludeFlags & INCLUDE_ARCHITECTURE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
+ }
+ if ((dwIncludeFlags & INCLUDE_RETARGETABLE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
+ }
+ if ((dwIncludeFlags & INCLUDE_CONTENT_TYPE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE;
+ }
+
+ dwHash ^= static_cast<DWORD>(HashCaseInsensitive(GetSimpleName()));
+ dwHash = _rotl(dwHash, 4);
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY) ||
+ AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
+ {
+ const BYTE *pbPublicKeyOrToken = GetPublicKeyTokenBLOB();
+ DWORD dwcbPublicKeyOrToken = GetPublicKeyTokenBLOB().GetSize();
+
+ _ASSERTE(pbPublicKeyOrToken != NULL);
+
+ dwHash ^= HashBytes(pbPublicKeyOrToken, dwcbPublicKeyOrToken);
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_VERSION))
+ {
+ AssemblyVersion *pAssemblyVersion = GetVersion();
+
+ dwHash ^= pAssemblyVersion->GetMajor();
+ dwHash = _rotl(dwHash, 8);
+ dwHash ^= pAssemblyVersion->GetMinor();
+ dwHash = _rotl(dwHash, 8);
+ dwHash ^= pAssemblyVersion->GetBuild();
+ dwHash = _rotl(dwHash, 8);
+ dwHash ^= pAssemblyVersion->GetRevision();
+ dwHash = _rotl(dwHash, 8);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CULTURE))
+ {
+ dwHash ^= static_cast<DWORD>(HashCaseInsensitive(GetNormalizedCulture()));
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
+ {
+ dwHash ^= 1;
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
+ {
+ dwHash ^= static_cast<DWORD>(GetArchitecture());
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ if (AssemblyIdentity::Have(dwUseIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
+ {
+ dwHash ^= static_cast<DWORD>(GetContentType());
+ dwHash = _rotl(dwHash, 4);
+ }
+
+ return static_cast<ULONG>(dwHash);
+ }
+
+ BOOL AssemblyName::Equals(AssemblyName *pAssemblyName,
+ DWORD dwIncludeFlags)
+ {
+ BOOL fEquals = FALSE;
+
+ if (GetContentType() == AssemblyContentType_WindowsRuntime)
+ { // Assembly is meaningless for WinRT, all assemblies form one joint type namespace
+ return (GetContentType() == pAssemblyName->GetContentType());
+ }
+
+ if (EqualsCaseInsensitive(GetSimpleName(), pAssemblyName->GetSimpleName()) &&
+ (GetContentType() == pAssemblyName->GetContentType()))
+ {
+ fEquals = TRUE;
+
+ if ((dwIncludeFlags & EXCLUDE_CULTURE) == 0)
+ {
+ fEquals = EqualsCaseInsensitive(GetNormalizedCulture(), pAssemblyName->GetNormalizedCulture());
+ }
+
+ if (fEquals && (dwIncludeFlags & INCLUDE_PUBLIC_KEY_TOKEN) != 0)
+ {
+ fEquals = (GetPublicKeyTokenBLOB().Equals(pAssemblyName->GetPublicKeyTokenBLOB()));
+ }
+
+ if (fEquals && ((dwIncludeFlags & INCLUDE_ARCHITECTURE) != 0))
+ {
+ fEquals = (GetArchitecture() == pAssemblyName->GetArchitecture());
+ }
+
+ if (fEquals && ((dwIncludeFlags & INCLUDE_VERSION) != 0))
+ {
+ fEquals = GetVersion()->Equals(pAssemblyName->GetVersion());
+ }
+
+ if (fEquals && ((dwIncludeFlags & INCLUDE_RETARGETABLE) != 0))
+ {
+ fEquals = (GetIsRetargetable() == pAssemblyName->GetIsRetargetable());
+ }
+ }
+
+ return fEquals;
+ }
+
+ BOOL AssemblyName::RefEqualsDef(AssemblyName *pAssemblyNameDef,
+ BOOL fInspectionOnly)
+ {
+ BOOL fEquals = FALSE;
+
+ if (GetContentType() == AssemblyContentType_WindowsRuntime)
+ { // Assembly is meaningless for WinRT, all assemblies form one joint type namespace
+ return (GetContentType() == pAssemblyNameDef->GetContentType());
+ }
+
+ if (EqualsCaseInsensitive(GetSimpleName(), pAssemblyNameDef->GetSimpleName()) &&
+ EqualsCaseInsensitive(GetNormalizedCulture(),
+ pAssemblyNameDef->GetNormalizedCulture()) &&
+ GetPublicKeyTokenBLOB().Equals(pAssemblyNameDef->GetPublicKeyTokenBLOB()) &&
+ (GetContentType() == pAssemblyNameDef->GetContentType()))
+ {
+ PEKIND kRefArchitecture = GetArchitecture();
+ PEKIND kDefArchitecture = pAssemblyNameDef->GetArchitecture();
+
+ if (kRefArchitecture == peNone)
+ {
+ fEquals = (fInspectionOnly ||
+ (kDefArchitecture == peNone) ||
+ (kDefArchitecture == peMSIL) ||
+ (kDefArchitecture == Assembly::GetSystemArchitecture()));
+ }
+ else
+ {
+ fEquals = (kRefArchitecture == kDefArchitecture);
+ }
+ }
+
+ return fEquals;
+ }
+
+ HRESULT AssemblyName::Clone(AssemblyName **ppAssemblyName)
+ {
+ HRESULT hr = S_OK;
+ AssemblyName *pClonedAssemblyName = NULL;
+
+ SAFE_NEW(pClonedAssemblyName, AssemblyName);
+ CloneInto(pClonedAssemblyName);
+ pClonedAssemblyName->m_dwNameFlags = m_dwNameFlags;
+
+ *ppAssemblyName = pClonedAssemblyName;
+
+ Exit:
+ return hr;
+ }
+
+ void AssemblyName::GetDisplayName(PathString &displayName,
+ DWORD dwIncludeFlags)
+ {
+ DWORD dwUseIdentityFlags = m_dwIdentityFlags;
+
+ // Prune unwanted name parts
+ if ((dwIncludeFlags & INCLUDE_VERSION) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_VERSION;
+ }
+ if ((dwIncludeFlags & INCLUDE_ARCHITECTURE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE;
+ }
+ if ((dwIncludeFlags & INCLUDE_RETARGETABLE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
+ }
+ if ((dwIncludeFlags & INCLUDE_CONTENT_TYPE) == 0)
+ {
+ dwUseIdentityFlags &= ~AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE;
+ }
+
+ TextualIdentityParser::ToString(this, dwUseIdentityFlags, displayName);
+ }
+
+ SString &AssemblyName::ArchitectureToString(PEKIND kArchitecture)
+ {
+ switch (kArchitecture)
+ {
+ case peNone:
+ return g_BinderVariables->emptyString;
+ case peMSIL:
+ return g_BinderVariables->architectureMSIL;
+ case peI386:
+ return g_BinderVariables->architectureX86;
+ case peAMD64:
+ return g_BinderVariables->architectureAMD64;
+ case peARM:
+ return g_BinderVariables->architectureARM;
+ case peARM64:
+ return g_BinderVariables->architectureARM64;
+ default:
+ _ASSERTE(0);
+ return g_BinderVariables->emptyString;
+ }
+ }
+
+ SString &AssemblyName::GetNormalizedCulture()
+ {
+ SString &culture = GetCulture();
+
+ if (culture.IsEmpty())
+ {
+ culture = g_BinderVariables->cultureNeutral;
+ }
+
+ return culture;
+ }
+}; // namespace BINDER_SPACE
diff --git a/src/binder/binder.targets b/src/binder/binder.targets
new file mode 100644
index 0000000000..01b35e2315
--- /dev/null
+++ b/src/binder/binder.targets
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <PropertyGroup Label="Globals">
+ <SccProjectName>SAK</SccProjectName>
+ <SccAuxPath>SAK</SccAuxPath>
+ <SccLocalPath>SAK</SccLocalPath>
+ <SccProvider>SAK</SccProvider>
+ </PropertyGroup>
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <TargetType>LIBRARY</TargetType>
+ <OutputPath>$(ClrLibDest)</OutputPath>
+ <ClAdditionalOptions>$(ClAdditionalOptions) -DUNICODE -D_UNICODE </ClAdditionalOptions>
+ <LinkAdditionalOptions>$(LinkAdditionalOptions) /VERBOSE</LinkAdditionalOptions>
+ <BinderPath>$(Clrbase)\src\binder</BinderPath>
+ <UserIncludes>
+ $(UserIncludes);
+ $(BinderPath);
+ $(BinderPath)\inc;
+ $(Clrbase)\src\inc;
+ $(Clrbase)\src\vm;
+ $(Clrbase)\src\vm\$(TargetCpu);
+ $(Clrbase)\src\strongname\inc;
+ $(SdkIncPath);
+ </UserIncludes>
+ </PropertyGroup>
+ <!--Leaf Project Items-->
+ <ItemGroup>
+ <CppCompile Include="..\Variables.cpp" />
+ <CppCompile Include="..\Utils.cpp" />
+ <CppCompile Include="..\AssemblyName.cpp" />
+ <CppCompile Include="..\PropertyMap.cpp" />
+ <CppCompile Include="..\ApplicationContext.cpp" />
+ <CppCompile Include="..\Assembly.cpp" />
+ <CppCompile Include="..\FailureCache.cpp" />
+ <CppCompile Include="..\AssemblyBinder.cpp" />
+ <CppCompile Include="..\StringLexer.cpp" />
+ <CppCompile Include="..\CLRPrivBinderCoreCLR.cpp" />
+ <CppCompile Include="..\BinderInterface.cpp" />
+ <CppCompile Include="..\DebugLog.cpp" />
+ <CppCompile Include="..\BindingLog.cpp" />
+ <CppCompile Include="..\CDebugLog.cpp" />
+ <CppCompile Include="..\TextualIdentityParser.cpp" />
+ <CppCompile Include="..\AssemblyIdentityCache.cpp" />
+ <CppCompile Include="..\CLRPrivBinderAssemblyLoadContext.cpp" Condition="'$(FeatureHostAssemblyResolver)' == 'true'"/>
+ <CppCompile Include="..\CoreCLRBinderCommon.cpp"/>
+ <CppCompile Include="..\FusionAssemblyName.cpp"/>
+ <CppCompile Include="..\FusionHelpers.cpp"/>
+ </ItemGroup>
+</Project>
diff --git a/src/binder/binderinterface.cpp b/src/binder/binderinterface.cpp
new file mode 100644
index 0000000000..4e5f9b42b3
--- /dev/null
+++ b/src/binder/binderinterface.cpp
@@ -0,0 +1,191 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BinderInterface.cpp
+//
+
+
+//
+// Implements the public AssemblyBinder interface
+//
+// ============================================================
+
+#include "assemblybinder.hpp"
+#include "assemblyname.hpp"
+#include "applicationcontext.hpp"
+#include "binderinterface.hpp"
+#include "bindresult.inl"
+#include "utils.hpp"
+
+#include "ex.h"
+
+using namespace BINDER_SPACE;
+
+namespace BinderInterface
+{
+
+ HRESULT Init()
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ hr = AssemblyBinder::Startup();
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+
+ HRESULT SetupContext(LPCWSTR wszApplicationBase,
+ DWORD dwAppDomainId,
+ IUnknown **ppIApplicationContext)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ BINDER_LOG_LOCK();
+ BINDER_LOG_ENTER(L"BinderInterface::SetupContext");
+
+ // Verify input arguments
+ IF_FALSE_GO(ppIApplicationContext != NULL);
+
+ {
+ ReleaseHolder<ApplicationContext> pApplicationContext;
+
+ SAFE_NEW(pApplicationContext, ApplicationContext);
+ IF_FAIL_GO(pApplicationContext->Init());
+ pApplicationContext->SetAppDomainId(dwAppDomainId);
+ *ppIApplicationContext = static_cast<IUnknown *>(pApplicationContext.Extract());
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BinderInterface::SetupContext", hr);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ HRESULT Bind(IUnknown *pIApplicationContext,
+ SString &assemblyDisplayName,
+ LPCWSTR wszCodeBase,
+ PEAssembly *pParentAssembly,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ BINDER_SPACE::Assembly **ppAssembly)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ BINDER_LOG_LOCK();
+ BINDER_LOG_ENTER(L"BinderInterface::Bind");
+
+ // Verify input arguments
+ IF_FALSE_GO(pIApplicationContext != NULL);
+ IF_FALSE_GO(ppAssembly != NULL);
+
+ {
+ ApplicationContext *pApplicationContext =
+ static_cast<ApplicationContext *>(pIApplicationContext);
+
+ ReleaseHolder<AssemblyName> pAssemblyName;
+ if (!assemblyDisplayName.IsEmpty())
+ {
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(assemblyDisplayName));
+ }
+
+ IF_FAIL_GO(AssemblyBinder::BindAssembly(pApplicationContext,
+ pAssemblyName,
+ wszCodeBase,
+ pParentAssembly,
+ fNgenExplicitBind,
+ fExplicitBindToNativeImage,
+ false, // excludeAppPaths
+ ppAssembly));
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BinderInterface::Bind", hr);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+
+ HRESULT BindToSystem(SString &sSystemDirectory,
+ BINDER_SPACE::Assembly **ppSystemAssembly,
+ bool fBindToNativeImage)
+ {
+ HRESULT hr = S_OK;
+
+ IF_FALSE_GO(ppSystemAssembly != NULL);
+
+ EX_TRY
+ {
+ BINDER_LOG_LOCK();
+
+ IF_FAIL_GO(AssemblyBinder::BindToSystem(sSystemDirectory, ppSystemAssembly, fBindToNativeImage));
+ }
+ EX_CATCH_HRESULT(hr);
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT SetupBindingPaths(IUnknown *pIApplicationContext,
+ SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ BINDER_LOG_LOCK();
+ BINDER_LOG_ENTER(L"BinderInterface::SetupBindingPaths");
+
+ // Verify input arguments
+ IF_FALSE_GO(pIApplicationContext != NULL);
+
+ {
+ ApplicationContext *pApplicationContext =
+ static_cast<ApplicationContext *>(pIApplicationContext);
+ _ASSERTE(pApplicationContext != NULL);
+
+ IF_FAIL_GO(pApplicationContext->SetupBindingPaths(sTrustedPlatformAssemblies, sPlatformResourceRoots, sAppPaths, sAppNiPaths, TRUE /* fAcquireLock */));
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BinderInterface::SetupBindingPaths", hr);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+
+#ifdef BINDER_DEBUG_LOG
+ HRESULT Log(LPCWSTR wszMessage)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ BINDER_LOG_LOCK();
+ BINDER_LOG((WCHAR *) wszMessage);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+#endif // BINDER_DEBUG_LOG
+};
diff --git a/src/binder/bindinglog.cpp b/src/binder/bindinglog.cpp
new file mode 100644
index 0000000000..4466fcea28
--- /dev/null
+++ b/src/binder/bindinglog.cpp
@@ -0,0 +1,332 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BindingLog.cpp
+//
+
+
+//
+// Implements the fusion-like BindingLog class
+//
+// ============================================================
+
+#ifdef FEATURE_VERSIONING_LOG
+
+#define DISABLE_BINDER_DEBUG_LOGGING
+
+#include "bindinglog.hpp"
+#include "assemblyname.hpp"
+#include "assembly.hpp"
+#include "applicationcontext.hpp"
+#include "bindresult.hpp"
+#include "cdebuglog.hpp"
+#include "variables.hpp"
+#include "bindresult.inl"
+
+#include "strsafe.h"
+
+#define SIZE_OF_TOKEN_INFORMATION \
+ sizeof( TOKEN_USER ) \
+ + sizeof( SID ) \
+ + sizeof( ULONG ) * SID_MAX_SUB_AUTHORITIES
+
+#include "../dlls/mscorrc/fusres.h"
+
+STDAPI BinderGetDisplayName(PEAssembly *pAssembly,
+ SString &displayName);
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ // Ripped from Fusion
+
+ inline UINT GetPreBindStateName(AssemblyName *pAssemblyName)
+ {
+ if (pAssemblyName->HaveAssemblyVersion())
+ {
+ return ID_FUSLOG_BINDING_PRE_BIND_STATE_BY_NAME;
+ }
+ else
+ {
+ return ID_FUSLOG_BINDING_PRE_BIND_STATE_BY_NAME_PARTIAL;
+ }
+ }
+ };
+
+ BindingLog::BindingLog()
+ {
+ m_pCDebugLog = NULL;
+ }
+
+ BindingLog::~BindingLog()
+ {
+ SAFE_RELEASE(m_pCDebugLog);
+ }
+
+ /* static */
+ HRESULT BindingLog::CreateInContext(ApplicationContext *pApplicationContext,
+ SString &assemblyPath,
+ PEAssembly *pParentAssembly)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::CreateInContext (assemblyPath)");
+
+ if (IsLoggingNeeded())
+ {
+ IF_FAIL_GO(CreateInContext(pApplicationContext, NULL, assemblyPath, pParentAssembly));
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::CreateInContext (assemblyPath)", hr);
+ return hr;
+ }
+
+ /* static */
+ BOOL BindingLog::IsLoggingNeeded()
+ {
+#ifdef FEATURE_VERSIONING_LOG
+ return g_BinderVariables->fLoggingNeeded;
+#else // FEATURE_VERSIONING_LOG
+ return FALSE;
+#endif // FEATURE_VERSIONING_LOG
+ }
+
+ /* static */
+ HRESULT BindingLog::CreateInContext(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ PEAssembly *pParentAssembly)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::CreateInContext (pAssemblyName)");
+
+ if (IsLoggingNeeded())
+ {
+ SmallStackSString emptyString;
+
+ IF_FALSE_GO(pAssemblyName != NULL);
+ IF_FAIL_GO(CreateInContext(pApplicationContext,
+ pAssemblyName,
+ emptyString,
+ pParentAssembly));
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::CreateInContext (pAssemblyName)", hr);
+ return hr;
+ }
+
+ HRESULT BindingLog::Log(SString &info)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::Log");
+
+ IF_FAIL_GO(GetDebugLog()->LogMessage(0, FUSION_BIND_LOG_CATEGORY_DEFAULT, info));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::Log", hr);
+ return hr;
+ }
+
+ HRESULT BindingLog::LogAssemblyName(LPCWSTR pwzPrefix,
+ AssemblyName *pAssemblyName)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::LogAssemblyName");
+ PathString assemblyDisplayName;
+
+ // Verify input arguments
+ IF_FALSE_GO(pwzPrefix != NULL);
+ IF_FALSE_GO(pAssemblyName != NULL);
+
+ pAssemblyName->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE);
+ IF_FAIL_GO(Log(pwzPrefix, assemblyDisplayName));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::LogAssemblyName", hr);
+ return hr;
+ }
+
+ HRESULT BindingLog::LogHR(HRESULT logHR)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::LogHR");
+
+ IF_FAIL_GO(GetDebugLog()->SetResultCode(0, logHR));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::LogHR", hr);
+ return hr;
+ }
+
+ HRESULT BindingLog::LogResult(BindResult *pBindResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::LogResult");
+ PathString assemblyDisplayName;
+ PathString format;
+ PathString info;
+
+ pBindResult->GetAssemblyName()->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE);
+
+ IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_ASSEMBLY_STATUS_BOUND_TO_ID));
+ info.Printf(format.GetUnicode(), assemblyDisplayName.GetUnicode());
+ IF_FAIL_GO(Log(info));
+
+ IUnknown *pIUnknownAssembly;
+ pIUnknownAssembly = pBindResult->GetAssembly(FALSE /* fAddRef */);
+ Assembly *pAssembly;
+ pAssembly = static_cast<Assembly *>(static_cast<void *>(pIUnknownAssembly));
+ _ASSERTE(pAssembly != NULL);
+
+ if (pAssembly->GetIsInGAC())
+ {
+ IF_FAIL_GO(info.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_ASSEMBLY_STATUS_BOUND_GAC));
+ }
+ else if (pAssembly->GetIsByteArray())
+ {
+ IF_FAIL_GO(info.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_ASSEMBLY_STATUS_BOUND_BYTE_ARRAY));
+ }
+ else
+ {
+ PathString assemblyPath;
+
+ BinderGetImagePath(pAssembly->GetPEImage(), assemblyPath);
+ IF_FAIL_GO(format.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_ASSEMBLY_STATUS_BOUND_TO_LOCATION));
+ info.Printf(format.GetUnicode(), assemblyPath.GetUnicode());
+ }
+ IF_FAIL_GO(Log(info));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::LogResult", hr);
+ return hr;
+ }
+
+ HRESULT BindingLog::Flush()
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::Flush");
+
+ hr = GetDebugLog()->Flush(0, FUSION_BIND_LOG_CATEGORY_DEFAULT);
+ if (hr == E_ACCESSDENIED)
+ {
+ // We've been impersonated differently and have a old log entry
+ BINDER_LOG(L"Impersonated: E_ACCESSDENIED");
+ hr = S_OK;
+ }
+
+ BINDER_LOG_LEAVE_HR(L"BindingLog::Flush", hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT BindingLog::CreateInContext(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ SString &assemblyPath,
+ PEAssembly *pParentAssembly)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::CreateInContext");
+
+ BindingLog *pBindingLog = pApplicationContext->GetBindingLog();
+
+ // Invalidate existing debug log
+ pBindingLog->SetDebugLog(NULL);
+
+ IF_FAIL_GO(CDebugLog::Create(pApplicationContext,
+ pAssemblyName,
+ assemblyPath,
+ &pBindingLog->m_pCDebugLog));
+
+ IF_FAIL_GO(pBindingLog->LogPreBindState(pApplicationContext,
+ pAssemblyName,
+ assemblyPath,
+ pParentAssembly));
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::CreateInContext", hr);
+ return hr;
+ }
+
+ HRESULT BindingLog::LogPreBindState(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ SString &assemblyPath,
+ PEAssembly *pParentAssembly)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"BindingLog::LogPreBindState");
+ PathString format;
+ PathString info;
+
+ IF_FAIL_GO(info.LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_PRE_BIND_STATE_BEGIN));
+ IF_FAIL_GO(Log(info));
+
+ if (pAssemblyName != NULL)
+ {
+ PathString assemblyDisplayName;
+
+ pAssemblyName->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE |
+ AssemblyName::INCLUDE_RETARGETABLE);
+
+ IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging,
+ GetPreBindStateName(pAssemblyName)));
+ info.Printf(format.GetUnicode(), assemblyDisplayName.GetUnicode());
+ }
+ else
+ {
+ IF_FAIL_GO(format.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_PRE_BIND_STATE_WHERE_REF));
+ info.Printf(format.GetUnicode(), assemblyPath.GetUnicode());
+ }
+ IF_FAIL_GO(Log(info));
+
+ if (pParentAssembly != NULL)
+ {
+ PathString parentAssemblyDisplayName;
+
+ IF_FAIL_GO(BinderGetDisplayName(pParentAssembly, parentAssemblyDisplayName));
+ IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_PRE_BIND_STATE_CALLER));
+ info.Printf(format.GetUnicode(), parentAssemblyDisplayName.GetUnicode());
+ }
+ else
+ {
+ IF_FAIL_GO(info.
+ LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_PRE_BIND_STATE_CALLER_UNKNOWN));
+ }
+ IF_FAIL_GO(Log(info));
+
+ IF_FAIL_GO(info.LoadResourceAndReturnHR(CCompRC::Debugging,
+ ID_FUSLOG_BINDING_PRE_BIND_STATE_END));
+ IF_FAIL_GO(Log(info));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"BindingLog::LogPreBindState", hr);
+ return hr;
+ }
+
+ void BindingLog::SetDebugLog(CDebugLog *pCDebugLog)
+ {
+ SAFE_RELEASE(m_pCDebugLog);
+ m_pCDebugLog = pCDebugLog;
+ }
+};
+
+#endif // FEATURE_VERSIONING_LOG
diff --git a/src/binder/cdebuglog.cpp b/src/binder/cdebuglog.cpp
new file mode 100644
index 0000000000..3724f9ec8e
--- /dev/null
+++ b/src/binder/cdebuglog.cpp
@@ -0,0 +1,482 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// CDebugLog.cpp
+//
+
+
+//
+// Implements the fusion-derived CDebugLog class
+//
+// ============================================================
+
+#ifdef FEATURE_VERSIONING_LOG
+
+#include "cdebuglog.hpp"
+#include "applicationcontext.hpp"
+#include "assemblyname.hpp"
+#include "variables.hpp"
+#include "utils.hpp"
+
+#include "shlwapi.h"
+#include "strsafe.h"
+
+#include "../dlls/mscorrc/fusres.h"
+
+#define MAX_DBG_STR_LEN 1024
+#define MAX_DATE_LEN 128
+
+#define DEBUG_LOG_HTML_START L"<html><pre>\r\n"
+#define DEBUG_LOG_HTML_META_LANGUAGE L"<meta http-equiv=\"Content-Type\" content=\"charset=unicode-1-1-utf-8\">"
+#define DEBUG_LOG_MARK_OF_THE_WEB L"<!-- saved from url=(0015)assemblybinder: -->"
+#define DEBUG_LOG_HTML_END L"\r\n</pre></html>"
+#define DEBUG_LOG_NEW_LINE L"\r\n"
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ inline LPCWSTR LogCategoryToString(DWORD dwLogCategory)
+ {
+ switch (dwLogCategory)
+ {
+ case FUSION_BIND_LOG_CATEGORY_DEFAULT:
+ return L"default";
+ case FUSION_BIND_LOG_CATEGORY_NGEN:
+ return L"Native";
+ default:
+ return L"Unknown";
+ }
+ }
+
+ HRESULT CreateFilePathHierarchy(LPCOLESTR pszName)
+ {
+ HRESULT hr=S_OK;
+ LPTSTR pszFileName;
+ PathString szPathString;
+ DWORD dw = 0;
+
+ size_t pszNameLen = wcslen(pszName);
+ WCHAR * szPath = szPathString.OpenUnicodeBuffer(static_cast<COUNT_T>(pszNameLen));
+ size_t cbSzPath = (sizeof(WCHAR)) * (pszNameLen + 1); // SString allocates extra byte for null
+ IF_FAIL_GO(StringCbCopy(szPath, cbSzPath, pszName));
+ szPathString.CloseBuffer(static_cast<COUNT_T>(pszNameLen));
+
+ pszFileName = PathFindFileName(szPath);
+
+ if (pszFileName <= szPath)
+ {
+ IF_FAIL_GO(E_INVALIDARG);
+ }
+
+ *(pszFileName-1) = 0;
+
+ dw = WszGetFileAttributes(szPath);
+ if (dw != INVALID_FILE_ATTRIBUTES)
+ {
+ return S_OK;
+ }
+
+ hr = HRESULT_FROM_GetLastError();
+
+ switch (hr)
+ {
+ case __HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND):
+ {
+ hr = CreateFilePathHierarchy(szPath);
+ if (hr != S_OK)
+ return hr;
+ }
+
+ case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
+ {
+ if (WszCreateDirectory(szPath, NULL))
+ return S_OK;
+ else
+ {
+ hr = HRESULT_FROM_WIN32(GetLastError());
+ if(hr == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS))
+ hr = S_OK;
+ else
+ return hr;
+ }
+ }
+
+ default:
+ break;
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT WriteLog(HANDLE hLogFile,
+ LPCWSTR pwzInfo)
+ {
+ HRESULT hr = S_OK;
+ DWORD dwLen = 0;
+ DWORD dwWritten = 0;
+ CHAR szBuf[MAX_DBG_STR_LEN];
+
+ dwLen = WszWideCharToMultiByte(CP_UTF8,
+ 0,
+ pwzInfo,
+ -1,
+ szBuf,
+ MAX_DBG_STR_LEN,
+ NULL,
+ NULL);
+
+ if (!dwLen)
+ {
+ IF_FAIL_GO(HRESULT_FROM_GetLastError());
+ }
+
+ // dwLen includes NULL terminator. We don't want to write this out.
+ if (dwLen > 1) {
+ dwLen--;
+
+ if (!WriteFile(hLogFile, szBuf, dwLen, &dwWritten, NULL)) {
+ IF_FAIL_GO(HRESULT_FROM_GetLastError());
+ }
+ }
+
+ Exit:
+ return hr;
+ }
+
+ HRESULT GetBindTimeInfo(PathString &info)
+ {
+ HRESULT hr = S_OK;
+ SYSTEMTIME systime;
+
+ {
+ WCHAR wzDateBuffer[MAX_DATE_LEN];
+ WCHAR wzTimeBuffer[MAX_DATE_LEN];
+
+ GetLocalTime(&systime);
+
+ if (!WszGetDateFormat(LOCALE_USER_DEFAULT,
+ 0,
+ &systime,
+ NULL,
+ wzDateBuffer,
+ MAX_DATE_LEN))
+ {
+ return HRESULT_FROM_GetLastError();
+ }
+
+ if (!WszGetTimeFormat(LOCALE_USER_DEFAULT,
+ 0,
+ &systime,
+ NULL,
+ wzTimeBuffer,
+ MAX_DATE_LEN))
+ {
+ return HRESULT_FROM_GetLastError();
+ }
+
+ info.Printf(L"(%s @ %s)", wzDateBuffer, wzTimeBuffer);
+ }
+ return hr;
+ }
+
+ HRESULT GetHrResultInfo(PathString &info, HRESULT hrResult)
+ {
+ HRESULT hr = S_OK;
+
+ // TODO: Get the result information in here.
+ info.Printf(L"%p.", hrResult);
+
+ return hr;
+ }
+
+ inline BOOL IsInvalidCharacter(WCHAR wcChar)
+ {
+ switch (wcChar)
+ {
+ case L':':
+ case L'/':
+ case L'\\':
+ case L'*':
+ case L'<':
+ case L'>':
+ case L'?':
+ case L'|':
+ case L'"':
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ }
+
+ inline void ReplaceInvalidFileCharacters(SString &assemblyName)
+ {
+ SString::Iterator pos = assemblyName.Begin();
+ SString::Iterator end = assemblyName.End();
+
+ while (pos < end)
+ {
+ if (IsInvalidCharacter(pos[0]))
+ {
+ assemblyName.Replace(pos, L'_');
+ }
+
+ pos++;
+ }
+ }
+ };
+
+ CDebugLog::CDebugLog()
+ {
+ m_cRef = 1;
+ }
+
+ CDebugLog::~CDebugLog()
+ {
+ // Nothing to do here
+ }
+
+ /* static */
+ HRESULT CDebugLog::Create(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ SString &sCodeBase,
+ CDebugLog **ppCDebugLog)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::Create");
+ ReleaseHolder<CDebugLog> pDebugLog;
+
+ // Validate input arguments
+ IF_FALSE_GO(pApplicationContext != NULL);
+ IF_FALSE_GO(ppCDebugLog != NULL);
+
+ SAFE_NEW(pDebugLog, CDebugLog);
+ IF_FAIL_GO(pDebugLog->Init(pApplicationContext, pAssemblyName, sCodeBase));
+
+ *ppCDebugLog = pDebugLog.Extract();
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::Create", hr);
+ return hr;
+ }
+
+ ULONG CDebugLog::AddRef()
+ {
+ return InterlockedIncrement(&m_cRef);
+ }
+
+ ULONG CDebugLog::Release()
+ {
+ ULONG ulRef;
+
+ ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+ }
+
+ HRESULT CDebugLog::SetResultCode(DWORD dwLogCategory,
+ HRESULT hrResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::SetResultCode");
+
+ IF_FALSE_GO(dwLogCategory < FUSION_BIND_LOG_CATEGORY_MAX);
+
+ m_HrResult[dwLogCategory] = hrResult;
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::SetResultCode", hr);
+ return hr;
+ }
+
+ HRESULT CDebugLog::LogMessage(DWORD,
+ DWORD dwLogCategory,
+ SString &sDebugString)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::LogMessage");
+
+ IF_FALSE_GO(dwLogCategory < FUSION_BIND_LOG_CATEGORY_MAX);
+
+ m_content[dwLogCategory].AddTail(const_cast<const SString &>(sDebugString));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::LogMessage", hr);
+ return hr;
+ }
+
+ HRESULT CDebugLog::Flush(DWORD,
+ DWORD dwLogCategory)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::Flush");
+ SmallStackSString sCategory(LogCategoryToString(dwLogCategory));
+ PathString logFilePath;
+ ListNode<SString> *pListNode = NULL;
+
+ IF_FALSE_GO(dwLogCategory < FUSION_BIND_LOG_CATEGORY_MAX);
+
+ CombinePath(g_BinderVariables->logPath, sCategory, logFilePath);
+ CombinePath(logFilePath, m_applicationName, logFilePath);
+ CombinePath(logFilePath, m_logFileName, logFilePath);
+
+ BINDER_LOG_STRING(L"logFilePath", logFilePath);
+
+ IF_FAIL_GO(CreateFilePathHierarchy(logFilePath.GetUnicode()));
+
+ m_hLogFile = WszCreateFile(logFilePath.GetUnicode(),
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (m_hLogFile == INVALID_HANDLE_VALUE)
+ {
+ // Silently ignore unability to log.
+ BINDER_LOG(L"Unable to open binding log");
+ GO_WITH_HRESULT(S_OK);
+ }
+
+ LogHeader(dwLogCategory);
+
+ pListNode = static_cast<ListNode<SString> *>(m_content[dwLogCategory].GetHeadPosition());
+ while (pListNode != NULL)
+ {
+ SString item = pListNode->GetItem();
+
+ IF_FAIL_GO(WriteLog(m_hLogFile, item.GetUnicode()));
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE));
+
+ pListNode = pListNode->GetNext();
+ }
+
+ LogFooter(dwLogCategory);
+
+ // Ignore failure
+ CloseHandle(m_hLogFile.Extract());
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::Flush", hr);
+ return hr;
+ }
+
+ HRESULT CDebugLog::Init(ApplicationContext *pApplicationContext,
+ AssemblyName *pAssemblyName,
+ SString &sCodeBase)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::Init");
+
+ m_applicationName.Set(pApplicationContext->GetApplicationName());
+ ReplaceInvalidFileCharacters(m_applicationName);
+
+ if (m_applicationName.IsEmpty())
+ {
+ BINDER_LOG(L"empty application name");
+ m_applicationName.Set(L"unknown");
+ }
+
+ if (pAssemblyName == NULL)
+ {
+ m_logFileName.Set(L"WhereRefBind!Host=(LocalMachine)!FileName=(");
+
+ LPCWSTR pwzFileName = PathFindFileNameW(sCodeBase.GetUnicode());
+ if (pwzFileName != NULL)
+ {
+ m_logFileName.Append(pwzFileName);
+ }
+ m_logFileName.Append(L").HTM");
+ }
+ else
+ {
+ PathString assemblyDisplayName;
+
+ pAssemblyName->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE |
+ AssemblyName::INCLUDE_RETARGETABLE);
+
+ ReplaceInvalidFileCharacters(assemblyDisplayName);
+
+ m_logFileName.Set(assemblyDisplayName);
+ m_logFileName.Append(L".HTM");
+ }
+
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::Init", hr);
+ return hr;
+ }
+
+ HRESULT CDebugLog::LogHeader(DWORD dwLogCategory)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::LogHeader");
+ PathString info;
+ PathString temp;
+ PathString format;
+
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_HTML_META_LANGUAGE));
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_MARK_OF_THE_WEB));
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_HTML_START));
+
+ IF_FAIL_GO(GetBindTimeInfo(temp));
+ IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BEGIN));
+ info.Printf(format.GetUnicode(), temp.GetUnicode());
+ IF_FAIL_GO(WriteLog(m_hLogFile, info.GetUnicode()));
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE DEBUG_LOG_NEW_LINE));
+
+ if (SUCCEEDED(m_HrResult[dwLogCategory]))
+ {
+ IF_FAIL_GO(temp.
+ LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BIND_RESULT_SUCCESS));
+ IF_FAIL_GO(WriteLog(m_hLogFile, temp.GetUnicode()));
+ }
+ else
+ {
+ IF_FAIL_GO(temp.
+ LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BIND_RESULT_ERROR));
+ IF_FAIL_GO(WriteLog(m_hLogFile, temp.GetUnicode()));
+ }
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE));
+
+ GetHrResultInfo(temp, m_HrResult[dwLogCategory]);
+
+ IF_FAIL_GO(format.LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_BIND_RESULT));
+ info.Printf(format.GetUnicode(), temp.GetUnicode());
+ IF_FAIL_GO(WriteLog(m_hLogFile, info.GetUnicode()));
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE DEBUG_LOG_NEW_LINE));
+
+ // TODO: Assembly Manager info + Executable info.
+
+ IF_FAIL_GO(info.LoadResourceAndReturnHR(CCompRC::Debugging, ID_FUSLOG_BINDING_HEADER_END));
+ IF_FAIL_GO(WriteLog(m_hLogFile, info.GetUnicode()));
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_NEW_LINE DEBUG_LOG_NEW_LINE));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::LogHeader", hr);
+ return hr;
+ }
+
+ HRESULT CDebugLog::LogFooter(DWORD)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"CDebugLog::LogFooter");
+
+ IF_FAIL_GO(WriteLog(m_hLogFile, DEBUG_LOG_HTML_END));
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"CDebugLog::LogFooter", hr);
+ return hr;
+ }
+};
+
+#endif // FEATURE_VERSIONING_LOG
diff --git a/src/binder/clrprivbinderassemblyloadcontext.cpp b/src/binder/clrprivbinderassemblyloadcontext.cpp
new file mode 100644
index 0000000000..8f3a3eef49
--- /dev/null
+++ b/src/binder/clrprivbinderassemblyloadcontext.cpp
@@ -0,0 +1,259 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "assemblybinder.hpp"
+#include "clrprivbindercoreclr.h"
+#include "clrprivbinderassemblyloadcontext.h"
+#include "clrprivbinderutil.h"
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+using namespace BINDER_SPACE;
+
+// ============================================================================
+// CLRPrivBinderAssemblyLoadContext implementation
+// ============================================================================
+HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
+ BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly)
+{
+ VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
+ HRESULT hr = S_OK;
+
+#ifdef _DEBUG
+ // MSCORLIB should be bound using BindToSystem
+ _ASSERTE(!pAssemblyName->IsMscorlib());
+#endif
+
+ // Do we have the assembly already loaded in the context of the current binder?
+ hr = AssemblyBinder::BindAssembly(&m_appContext,
+ pAssemblyName,
+ NULL,
+ NULL,
+ FALSE, //fNgenExplicitBind,
+ FALSE, //fExplicitBindToNativeImage,
+ false, //excludeAppPaths,
+ ppCoreCLRFoundAssembly);
+ if (!FAILED(hr))
+ {
+ _ASSERTE(*ppCoreCLRFoundAssembly != NULL);
+ (*ppCoreCLRFoundAssembly)->SetBinder(this);
+ }
+
+ return hr;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::BindAssemblyByName(IAssemblyName *pIAssemblyName,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(pIAssemblyName != nullptr && ppAssembly != nullptr);
+
+ // DevDiv #933506: Exceptions thrown during AssemblyLoadContext.Load should propagate
+ // EX_TRY
+ {
+ _ASSERTE(m_pTPABinder != NULL);
+
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
+
+ // When LoadContext needs to resolve an assembly reference, it will go through the following lookup order:
+ //
+ // 1) Lookup the assembly within the LoadContext itself. If assembly is found, use it.
+ // 2) Invoke the LoadContext's Load method implementation. If assembly is found, use it.
+ // 3) Lookup the assembly within TPABinder. If assembly is found, use it.
+ // 4) Invoke the LoadContext's Resolving event. If assembly is found, use it.
+ // 5) Raise exception.
+ //
+ // This approach enables a LoadContext to override assemblies that have been loaded in TPA context by loading
+ // a different (or even the same!) version.
+
+ {
+ // Step 1 - Try to find the assembly within the LoadContext.
+ hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly);
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
+ // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
+ // that has been loaded.
+ //
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(GetManagedAssemblyLoadContext(), pAssemblyName, pIAssemblyName, m_pTPABinder, &pCoreCLRFoundAssembly);
+ if (SUCCEEDED(hr))
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
+ // In such a case, we will not overwrite the binding context (which would be wrong since it would not
+ // be present in the cache of the current binding context).
+ if (pCoreCLRFoundAssembly->GetBinder() == NULL)
+ {
+ pCoreCLRFoundAssembly->SetBinder(this);
+ }
+ }
+ }
+ }
+
+ IF_FAIL_GO(hr);
+
+ // Extract the assembly reference.
+ //
+ // For TPA assemblies that were bound, TPABinder
+ // would have already set the binder reference for the assembly, so we just need to
+ // extract the reference now.
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+Exit:;
+ }
+ // EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<BINDER_SPACE::AssemblyName> pAssemblyName;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+
+ PEKIND PeKind = peNone;
+
+ // Get the Metadata interface
+ DWORD dwPAFlags[2];
+ IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, fIsNativeImage));
+ IF_FAIL_GO(AssemblyBinder::TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+
+ _ASSERTE(pIMetaDataAssemblyImport != NULL);
+
+ // Using the information we just got, initialize the assemblyname
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+
+ // Validate architecture
+ if (!BINDER_SPACE::Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Disallow attempt to bind to the core library. Aside from that,
+ // the LoadContext can load any assembly (even if it was in a different LoadContext like TPA).
+ if (pAssemblyName->IsMscorlib())
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly);
+ if (hr == S_OK)
+ {
+ _ASSERTE(pCoreCLRFoundAssembly != NULL);
+ pCoreCLRFoundAssembly->SetBinder(this);
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+ }
+Exit:;
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::VerifyBind(IAssemblyName *AssemblyName,
+ ICLRPrivAssembly *pAssembly,
+ ICLRPrivAssemblyInfo *pAssemblyInfo)
+{
+ return E_FAIL;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::GetBinderFlags(DWORD *pBinderFlags)
+{
+ if (pBinderFlags == NULL)
+ return E_INVALIDARG;
+ *pBinderFlags = BINDER_NONE;
+ return S_OK;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::GetBinderID(
+ UINT_PTR *pBinderId)
+{
+ *pBinderId = reinterpret_cast<UINT_PTR>(this);
+ return S_OK;
+}
+
+HRESULT CLRPrivBinderAssemblyLoadContext::FindAssemblyBySpec(
+ LPVOID pvAppDomain,
+ LPVOID pvAssemblySpec,
+ HRESULT *pResult,
+ ICLRPrivAssembly **ppAssembly)
+{
+ // We are not using a cache at this level
+ // However, assemblies bound by the CoreCLR binder is already cached in the
+ // AppDomain and will be resolved from there if required
+ return E_FAIL;
+}
+
+//=============================================================================
+// Creates an instance of the AssemblyLoadContext Binder
+//
+// This method does not take a lock since it is invoked from the ctor of the
+// managed AssemblyLoadContext type.
+//=============================================================================
+/* static */
+HRESULT CLRPrivBinderAssemblyLoadContext::SetupContext(DWORD dwAppDomainId,
+ CLRPrivBinderCoreCLR *pTPABinder,
+ UINT_PTR ptrAssemblyLoadContext,
+ CLRPrivBinderAssemblyLoadContext **ppBindContext)
+{
+ HRESULT hr = E_FAIL;
+ EX_TRY
+ {
+ if(ppBindContext != NULL)
+ {
+ ReleaseHolder<CLRPrivBinderAssemblyLoadContext> pBinder;
+
+ SAFE_NEW(pBinder, CLRPrivBinderAssemblyLoadContext);
+ hr = pBinder->m_appContext.Init();
+ if(SUCCEEDED(hr))
+ {
+ // Save the reference to the AppDomain in which the binder lives
+ pBinder->m_appContext.SetAppDomainId(dwAppDomainId);
+
+ // Mark that this binder can explicitly bind to native images
+ pBinder->m_appContext.SetExplicitBindToNativeImages(true);
+
+ // Save reference to the TPABinder that is required to be present.
+ _ASSERTE(pTPABinder != NULL);
+ pBinder->m_pTPABinder = pTPABinder;
+
+ // Save the reference to the IntPtr for GCHandle for the managed
+ // AssemblyLoadContext instance
+ pBinder->m_ptrManagedAssemblyLoadContext = ptrAssemblyLoadContext;
+
+ // Return reference to the allocated Binder instance
+ *ppBindContext = clr::SafeAddRef(pBinder.Extract());
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+Exit:
+ return hr;
+}
+
+CLRPrivBinderAssemblyLoadContext::CLRPrivBinderAssemblyLoadContext()
+{
+ m_pTPABinder = NULL;
+}
+
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
diff --git a/src/binder/clrprivbindercoreclr.cpp b/src/binder/clrprivbindercoreclr.cpp
new file mode 100644
index 0000000000..d62af867ef
--- /dev/null
+++ b/src/binder/clrprivbindercoreclr.cpp
@@ -0,0 +1,309 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+#include "common.h"
+#include "assemblybinder.hpp"
+#include "clrprivbindercoreclr.h"
+#include "clrprivbinderutil.h"
+
+using namespace BINDER_SPACE;
+
+//=============================================================================
+// Helper functions
+//-----------------------------------------------------------------------------
+
+HRESULT CLRPrivBinderCoreCLR::BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName,
+ BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
+ bool excludeAppPaths)
+{
+ VALIDATE_ARG_RET(pAssemblyName != nullptr && ppCoreCLRFoundAssembly != nullptr);
+ HRESULT hr = S_OK;
+
+#ifdef _DEBUG
+ // MSCORLIB should be bound using BindToSystem
+ _ASSERTE(!pAssemblyName->IsMscorlib());
+#endif
+
+ hr = AssemblyBinder::BindAssembly(&m_appContext,
+ pAssemblyName,
+ NULL,
+ NULL,
+ FALSE, //fNgenExplicitBind,
+ FALSE, //fExplicitBindToNativeImage,
+ excludeAppPaths,
+ ppCoreCLRFoundAssembly);
+ if (!FAILED(hr))
+ {
+ (*ppCoreCLRFoundAssembly)->SetBinder(this);
+ }
+
+ return hr;
+}
+
+// ============================================================================
+// CLRPrivBinderCoreCLR implementation
+// ============================================================================
+HRESULT CLRPrivBinderCoreCLR::BindAssemblyByName(IAssemblyName *pIAssemblyName,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(pIAssemblyName != nullptr && ppAssembly != nullptr);
+
+ EX_TRY
+ {
+ *ppAssembly = nullptr;
+
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIAssemblyName));
+
+ hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, false /* excludeAppPaths */);
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == FUSION_E_APP_DOMAIN_LOCKED) || (hr == FUSION_E_REF_DEF_MISMATCH))
+ {
+ // If we are here, one of the following is possible:
+ //
+ // 1) The assembly has not been found in the current binder's application context (i.e. it has not already been loaded), OR
+ // 2) An assembly with the same simple name was already loaded in the context of the current binder but we ran into a Ref/Def
+ // mismatch (either due to version difference or strong-name difference).
+ //
+ // Thus, if default binder has been overridden, then invoke it in an attempt to perform the binding for it make the call
+ // of what to do next. The host-overridden binder can either fail the bind or return reference to an existing assembly
+ // that has been loaded.
+
+ // Attempt to resolve the assembly via managed TPA ALC instance if one exists
+ INT_PTR pManagedAssemblyLoadContext = GetManagedAssemblyLoadContext();
+ if (pManagedAssemblyLoadContext != NULL)
+ {
+ hr = AssemblyBinder::BindUsingHostAssemblyResolver(pManagedAssemblyLoadContext, pAssemblyName, pIAssemblyName,
+ NULL, &pCoreCLRFoundAssembly);
+ if (SUCCEEDED(hr))
+ {
+ // We maybe returned an assembly that was bound to a different AssemblyLoadContext instance.
+ // In such a case, we will not overwrite the binding context (which would be wrong since it would not
+ // be present in the cache of the current binding context).
+ if (pCoreCLRFoundAssembly->GetBinder() == NULL)
+ {
+ pCoreCLRFoundAssembly->SetBinder(this);
+ }
+ }
+ }
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ IF_FAIL_GO(hr);
+
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+
+Exit:;
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+HRESULT CLRPrivBinderCoreCLR::BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pCoreCLRFoundAssembly;
+ ReleaseHolder<BINDER_SPACE::AssemblyName> pAssemblyName;
+ ReleaseHolder<IMDInternalImport> pIMetaDataAssemblyImport;
+
+ PEKIND PeKind = peNone;
+
+ // Get the Metadata interface
+ DWORD dwPAFlags[2];
+ IF_FAIL_GO(BinderAcquireImport(pPEImage, &pIMetaDataAssemblyImport, dwPAFlags, fIsNativeImage));
+ IF_FAIL_GO(AssemblyBinder::TranslatePEToArchitectureType(dwPAFlags, &PeKind));
+
+ _ASSERTE(pIMetaDataAssemblyImport != NULL);
+
+ // Using the information we just got, initialize the assemblyname
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(pIMetaDataAssemblyImport, PeKind));
+
+ // Validate architecture
+ if (!BINDER_SPACE::Assembly::IsValidArchitecture(pAssemblyName->GetArchitecture()))
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_BAD_FORMAT));
+ }
+
+ // Ensure we are not being asked to bind to a TPA assembly
+ //
+ // Easy out for mscorlib
+ if (pAssemblyName->IsMscorlib())
+ {
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+
+ {
+ SString& simpleName = pAssemblyName->GetSimpleName();
+ SimpleNameToFileNameMap * tpaMap = GetAppContext()->GetTpaList();
+ if (tpaMap->LookupPtr(simpleName.GetUnicode()) != NULL)
+ {
+ // The simple name of the assembly being requested to be bound was found in the TPA list.
+ // Now, perform the actual bind to see if the assembly was really in the TPA assembly list or not.
+ hr = BindAssemblyByNameWorker(pAssemblyName, &pCoreCLRFoundAssembly, true /* excludeAppPaths */);
+ if (SUCCEEDED(hr))
+ {
+ if (pCoreCLRFoundAssembly->GetIsInGAC())
+ {
+ // If we were able to bind to a TPA assembly, then fail the load
+ IF_FAIL_GO(HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND));
+ }
+ }
+ }
+
+ hr = AssemblyBinder::BindUsingPEImage(&m_appContext, pAssemblyName, pPEImage, PeKind, pIMetaDataAssemblyImport, &pCoreCLRFoundAssembly);
+ if (hr == S_OK)
+ {
+ _ASSERTE(pCoreCLRFoundAssembly != NULL);
+ pCoreCLRFoundAssembly->SetBinder(this);
+ *ppAssembly = pCoreCLRFoundAssembly.Extract();
+ }
+ }
+Exit:;
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+HRESULT CLRPrivBinderCoreCLR::VerifyBind(IAssemblyName *AssemblyName,
+ ICLRPrivAssembly *pAssembly,
+ ICLRPrivAssemblyInfo *pAssemblyInfo)
+{
+ return E_FAIL;
+}
+
+HRESULT CLRPrivBinderCoreCLR::GetBinderFlags(DWORD *pBinderFlags)
+{
+ if (pBinderFlags == NULL)
+ return E_INVALIDARG;
+ *pBinderFlags = BINDER_NONE;
+ return S_OK;
+}
+
+HRESULT CLRPrivBinderCoreCLR::GetBinderID(
+ UINT_PTR *pBinderId)
+{
+ *pBinderId = reinterpret_cast<UINT_PTR>(this);
+ return S_OK;
+}
+
+HRESULT CLRPrivBinderCoreCLR::FindAssemblyBySpec(
+ LPVOID pvAppDomain,
+ LPVOID pvAssemblySpec,
+ HRESULT *pResult,
+ ICLRPrivAssembly **ppAssembly)
+{
+ // We are not using a cache at this level
+ // However, assemblies bound by the CoreCLR binder is already cached in the
+ // AppDomain and will be resolved from there if required
+ return E_FAIL;
+}
+
+HRESULT CLRPrivBinderCoreCLR::SetupBindingPaths(SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths)
+{
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ hr = m_appContext.SetupBindingPaths(sTrustedPlatformAssemblies, sPlatformResourceRoots, sAppPaths, sAppNiPaths, TRUE /* fAcquireLock */);
+ }
+ EX_CATCH_HRESULT(hr);
+ return hr;
+}
+
+bool CLRPrivBinderCoreCLR::IsInTpaList(const SString &sFileName)
+{
+ bool fIsFileOnTpaList = false;
+
+ TpaFileNameHash * tpaFileNameMap = m_appContext.GetTpaFileNameList();
+ if (tpaFileNameMap != nullptr)
+ {
+ const FileNameMapEntry *pTpaEntry = tpaFileNameMap->LookupPtr(sFileName.GetUnicode());
+ fIsFileOnTpaList = (pTpaEntry != nullptr);
+ }
+
+ return fIsFileOnTpaList;
+}
+
+// See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+// and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+// for an example of how they're used.
+HRESULT CLRPrivBinderCoreCLR::Bind(SString &assemblyDisplayName,
+ LPCWSTR wszCodeBase,
+ PEAssembly *pParentAssembly,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppAssembly != NULL);
+
+ AssemblyName assemblyName;
+
+ ReleaseHolder<AssemblyName> pAssemblyName;
+
+ if (!assemblyDisplayName.IsEmpty())
+ {
+ // AssemblyDisplayName can be empty if wszCodeBase is specified.
+ SAFE_NEW(pAssemblyName, AssemblyName);
+ IF_FAIL_GO(pAssemblyName->Init(assemblyDisplayName));
+ }
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+ hr = AssemblyBinder::BindAssembly(&m_appContext,
+ pAssemblyName,
+ wszCodeBase,
+ pParentAssembly,
+ fNgenExplicitBind,
+ fExplicitBindToNativeImage,
+ false, // excludeAppPaths
+ &pAsm);
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != NULL);
+ pAsm->SetBinder(this);
+ *ppAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+Exit:
+ return hr;
+}
+
+#ifndef CROSSGEN_COMPILE
+HRESULT CLRPrivBinderCoreCLR::PreBindByteArray(PEImage *pPEImage, BOOL fInspectionOnly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(pPEImage != NULL);
+
+ EX_TRY
+ {
+ hr = AssemblyBinder::PreBindByteArray(&m_appContext, pPEImage, fInspectionOnly);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+#endif // CROSSGEN_COMPILE
diff --git a/src/binder/coreclrbindercommon.cpp b/src/binder/coreclrbindercommon.cpp
new file mode 100644
index 0000000000..86540fcfd5
--- /dev/null
+++ b/src/binder/coreclrbindercommon.cpp
@@ -0,0 +1,188 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+#include "common.h"
+#include "assemblybinder.hpp"
+#include "coreclrbindercommon.h"
+#include "clrprivbindercoreclr.h"
+#include "clrprivbinderutil.h"
+
+using namespace BINDER_SPACE;
+
+//=============================================================================
+// Init code
+//-----------------------------------------------------------------------------
+/* static */
+HRESULT CCoreCLRBinderHelper::Init()
+{
+ STANDARD_VM_CONTRACT;
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ hr = AssemblyBinder::Startup();
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CCoreCLRBinderHelper::DefaultBinderSetupContext(DWORD dwAppDomainId,CLRPrivBinderCoreCLR **ppTPABinder)
+{
+ HRESULT hr = S_OK;
+ EX_TRY
+ {
+ if(ppTPABinder != NULL)
+ {
+ ReleaseHolder<CLRPrivBinderCoreCLR> pBinder;
+ SAFE_NEW(pBinder, CLRPrivBinderCoreCLR);
+
+ BINDER_SPACE::ApplicationContext *pApplicationContext = pBinder->GetAppContext();
+ hr = pApplicationContext->Init();
+ if(SUCCEEDED(hr))
+ {
+ pApplicationContext->SetAppDomainId(dwAppDomainId);
+ pBinder->SetManagedAssemblyLoadContext(NULL);
+ *ppTPABinder = clr::SafeAddRef(pBinder.Extract());
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+Exit:
+ return hr;
+}
+
+HRESULT CCoreCLRBinderHelper::GetAssemblyIdentity(LPCSTR szTextualIdentity,
+ BINDER_SPACE::ApplicationContext *pApplicationContext,
+ NewHolder<AssemblyIdentityUTF8> &assemblyIdentityHolder)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(szTextualIdentity != NULL);
+
+ EX_TRY
+ {
+ AssemblyIdentityUTF8 *pAssemblyIdentity = NULL;
+ if (pApplicationContext != NULL)
+ {
+ // This returns a cached copy owned by application context
+ hr = pApplicationContext->GetAssemblyIdentity(szTextualIdentity, &pAssemblyIdentity);
+ if(SUCCEEDED(hr))
+ {
+ assemblyIdentityHolder = pAssemblyIdentity;
+ assemblyIdentityHolder.SuppressRelease();
+ }
+ }
+ else
+ {
+ SString sTextualIdentity;
+
+ sTextualIdentity.SetUTF8(szTextualIdentity);
+
+ // This is a private copy
+ pAssemblyIdentity = new AssemblyIdentityUTF8();
+ hr = TextualIdentityParser::Parse(sTextualIdentity, pAssemblyIdentity);
+ if(SUCCEEDED(hr))
+ {
+ pAssemblyIdentity->PopulateUTF8Fields();
+ assemblyIdentityHolder = pAssemblyIdentity;
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+//=============================================================================
+// Functions that provides binding services beyond the ICLRPrivInterface
+//-----------------------------------------------------------------------------
+
+HRESULT CCoreCLRBinderHelper::BindToSystem(ICLRPrivAssembly **ppSystemAssembly, bool fBindToNativeImage)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppSystemAssembly != NULL);
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+#ifdef FEATURE_CORECLR
+ StackSString systemPath(SystemDomain::System()->SystemDirectory());
+ hr = AssemblyBinder::BindToSystem(systemPath, &pAsm, fBindToNativeImage);
+#else
+ AssemblySpec::BindToSystem(&pAsm);
+#endif
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != NULL);
+ *ppSystemAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CCoreCLRBinderHelper::BindToSystemSatellite(SString &systemPath,
+ SString &sSimpleName,
+ SString &sCultureName,
+ ICLRPrivAssembly **ppSystemAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(ppSystemAssembly != NULL && !systemPath.IsEmpty());
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+ hr = AssemblyBinder::BindToSystemSatellite(systemPath, sSimpleName, sCultureName, &pAsm);
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != NULL);
+ *ppSystemAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+HRESULT CCoreCLRBinderHelper::GetAssemblyFromImage(PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ ICLRPrivAssembly **ppAssembly)
+{
+ HRESULT hr = S_OK;
+ VALIDATE_ARG_RET(pPEImage != NULL && ppAssembly != NULL);
+
+ EX_TRY
+ {
+ ReleaseHolder<BINDER_SPACE::Assembly> pAsm;
+ hr = AssemblyBinder::GetAssemblyFromImage(pPEImage, pNativePEImage, &pAsm);
+ if(SUCCEEDED(hr))
+ {
+ _ASSERTE(pAsm != nullptr);
+ *ppAssembly = pAsm.Extract();
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+}
+
+//=============================================================================
+// Explicitly bind to an assembly by filepath
+//=============================================================================
+/* static */
+HRESULT CCoreCLRBinderHelper::GetAssembly(/* in */ SString &assemblyPath,
+ /* in */ BOOL fInspectionOnly,
+ /* in */ BOOL fIsInGAC,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* out */ BINDER_SPACE::Assembly **ppAssembly)
+{
+ return AssemblyBinder::GetAssembly(assemblyPath,
+ fInspectionOnly,
+ fIsInGAC,
+ fExplicitBindToNativeImage,
+ ppAssembly
+ );
+}
diff --git a/src/binder/debuglog.cpp b/src/binder/debuglog.cpp
new file mode 100644
index 0000000000..1170c0eb8c
--- /dev/null
+++ b/src/binder/debuglog.cpp
@@ -0,0 +1,416 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// DebugLog.cpp
+//
+
+
+//
+// Implements the DebugLog class
+//
+// ============================================================
+
+#if defined(BINDER_DEBUG_LOG)
+
+#include "debuglog.hpp"
+#include "assemblyname.hpp"
+#include "utils.hpp"
+#include "variables.hpp"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ void GetStringFromHR(HRESULT hr,
+ SString &info)
+ {
+ switch(hr)
+ {
+ case S_OK:
+ info.Append(L"S_OK");
+ break;
+ case S_FALSE:
+ info.Append(L"S_FALSE");
+ break;
+ case E_FAIL:
+ info.Append(L"E_FAIL");
+ break;
+ case __HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND):
+ info.Append(L"HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)");
+ break;
+ case __HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER):
+ info.Append(L"HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)");
+ break;
+ case FUSION_E_REF_DEF_MISMATCH:
+ info.Append(L"FUSION_E_REF_DEF_MISMATCH");
+ break;
+ case FUSION_E_CODE_DOWNLOAD_DISABLED:
+ info.Append(L"FUSION_E_CODE_DOWNLOAD_DISABLED");
+ break;
+ default:
+ info.AppendPrintf(L"%p", hr);
+ break;
+ }
+ }
+
+ HRESULT GetLogFilePath(PathString &logFileDir,
+ PathString &logFilePath)
+ {
+ HRESULT hr = S_OK;
+
+ BOOL fFileExists = TRUE;
+
+ do
+ {
+ LARGE_INTEGER kCount1;
+ LARGE_INTEGER kCount2;
+
+ logFilePath.Clear();
+
+ if (!QueryPerformanceCounter(&kCount1))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+ else if(!QueryPerformanceCounter(&kCount2))
+ {
+ hr = HRESULT_FROM_GetLastError();
+ }
+ else
+ {
+ logFilePath.Printf(L"%s\\Log_%u%u_%u%u.tmp",
+ logFileDir.GetUnicode(),
+ static_cast<UINT32>(kCount1.u.LowPart),
+ kCount1.u.HighPart,
+ static_cast<UINT32>(kCount2.u.LowPart),
+ kCount2.u.HighPart);
+
+ PlatformPath(logFilePath);
+ }
+
+ fFileExists = (FileOrDirectoryExists(logFilePath) == S_OK);
+ }
+ while (fFileExists == TRUE);
+
+ return hr;
+ }
+
+ HRESULT WriteToFile(HANDLE hFile,
+ const BYTE *pbBuffer,
+ DWORD dwcbBuffer)
+ {
+ HRESULT hr = S_OK;
+ DWORD dwNumberOfBytesWritten = 0;
+
+ while ((dwcbBuffer != 0) && (dwNumberOfBytesWritten < dwcbBuffer))
+ {
+ if (WriteFile(hFile, pbBuffer, dwcbBuffer, &dwNumberOfBytesWritten, NULL))
+ {
+ dwcbBuffer -= dwNumberOfBytesWritten;
+ pbBuffer += dwNumberOfBytesWritten;
+ }
+ else
+ {
+ hr = HRESULT_FROM_GetLastError();
+ goto Exit;
+ }
+ }
+
+ Exit:
+ return hr;
+ }
+ };
+
+ /* static */
+ HRESULT DebugLog::Startup()
+ {
+ HRESULT hr = S_OK;
+
+ PathString logFileDir;
+ PathString logFilePath;
+
+ REGUTIL::CORConfigLevel kCorConfigLevel =
+ static_cast<REGUTIL::CORConfigLevel>(REGUTIL::COR_CONFIG_ENV |
+ REGUTIL::COR_CONFIG_FUSION);
+ NewArrayHolder<WCHAR> pwzLogDirectory = CLRConfig::GetConfigValue(CLRConfig::INTERNAL_CoreClrBinderLog);
+
+
+ g_BinderVariables->m_logCS = ClrCreateCriticalSection(CrstCoreCLRBinderLog, CRST_REENTRANCY);
+ if (!g_BinderVariables->m_logCS)
+ {
+ IF_FAIL_GO(E_OUTOFMEMORY);
+ }
+
+
+ if (pwzLogDirectory == NULL)
+ {
+ goto Exit;
+ }
+
+ logFileDir.Set(pwzLogDirectory);
+
+ if (WszCreateDirectory(logFileDir.GetUnicode(), NULL) ||
+ ((hr = HRESULT_FROM_GetLastError()) == HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS)))
+ {
+ hr = S_OK;
+ }
+
+ IF_FAIL_GO(GetLogFilePath(logFileDir, logFilePath));
+
+ g_BinderVariables->m_hDebugLogFile = WszCreateFile(logFilePath.GetUnicode(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+
+ if (g_BinderVariables->m_hDebugLogFile == INVALID_HANDLE_VALUE)
+ {
+ IF_FAIL_GO(E_FAIL);
+ }
+ Exit:
+ return hr;
+ }
+
+ // This is not multi-thread aware by any means. That said, neither is any of this logging mechanism.
+ static int s_scopeLevel = 0;
+ static const ANSI s_szScopeIndent[3] = " ";
+
+ /* static */
+ void DebugLog::Enter(WCHAR *pwzScope)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzScope);
+ info.Append(L": Enter");
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+
+ s_scopeLevel++;
+ }
+
+ /* static */
+ void DebugLog::Leave(WCHAR *pwzScope)
+ {
+ HRESULT hr = S_OK;
+
+ s_scopeLevel--;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzScope);
+ info.Append(L": Leave(void)");
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::LeaveHR(WCHAR *pwzScope,
+ HRESULT hrLog)
+ {
+ HRESULT hr = S_OK;
+
+ s_scopeLevel--;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzScope);
+ info.Append(L": Leave(hr=");
+ GetStringFromHR(hrLog, info);
+ info.Append(L")");
+
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::LeaveBool(WCHAR *pwzScope,
+ BOOL fResult)
+ {
+ HRESULT hr = S_OK;
+
+ s_scopeLevel--;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzScope);
+ info.Append(L": Leave(fResult=");
+ info.Append(fResult ? L"TRUE)" : L"FALSE)");
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::Log(WCHAR *pwzComment)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzComment);
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::Log(WCHAR *pwzComment,
+ SString &value)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzComment);
+ info.Append(L" = '");
+ info.Append(value);
+ info.Append(L"'");
+
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::Log(WCHAR *pwzComment,
+ const WCHAR *value)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzComment);
+ info.Append(L" = '");
+ info.Append(value);
+ info.Append(L"'");
+
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr)
+ }
+
+ /* static */
+ void DebugLog::Log(WCHAR *pwzComment,
+ HRESULT hrLog)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzComment);
+ info.Append(L" = ");
+ GetStringFromHR(hrLog, info);
+
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::Log(WCHAR *pwzComment,
+ AssemblyName *pAssemblyName)
+ {
+ EX_TRY
+ {
+ PathString assemblyDisplayName;
+ PathString info;
+
+ if (pAssemblyName != NULL)
+ {
+ pAssemblyName->GetDisplayName(assemblyDisplayName,
+ AssemblyName::INCLUDE_VERSION |
+ AssemblyName::INCLUDE_ARCHITECTURE |
+ AssemblyName::INCLUDE_RETARGETABLE);
+ }
+ else
+ {
+ assemblyDisplayName.Set(L"<NULL>");
+ }
+
+ info.Printf(L"(%d):", static_cast<INT32>(assemblyDisplayName.GetCount()));
+ info.Append(assemblyDisplayName);
+
+ Log(pwzComment, info);
+ }
+ EX_CATCH
+ {
+ Log(L"<AssemblyDisplayName: Failure>");
+ }
+ EX_END_CATCH(SwallowAllExceptions);
+ }
+
+ /* static */
+ void DebugLog::Log(WCHAR *pwzComment,
+ void *pData)
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ PathString info;
+
+ info.Append(pwzComment);
+ info.AppendPrintf(L" = %p", pData);
+ Log(info);
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ /* static */
+ void DebugLog::Log(SString &info)
+ {
+ HRESULT hr = S_OK;
+
+ StackScratchBuffer scratchBuffer;
+ const BYTE *pbRawBuffer = reinterpret_cast<const BYTE *>(info.GetANSI(scratchBuffer));
+ DWORD dwcbRawBuffer = static_cast<DWORD>(info.GetCount());
+ // Work around SString issue
+ const ANSI ansiCRLF[] = { 0x0d, 0x0a };
+ DWORD dwcbAnsiCRLF = 2 * sizeof(ANSI);
+ s_scopeLevel;
+ for (int iScope = 0; iScope < s_scopeLevel; iScope++)
+ {
+ IF_FAIL_GO(WriteToFile(g_BinderVariables->m_hDebugLogFile, reinterpret_cast<const BYTE *>(&s_szScopeIndent[0]), sizeof(s_szScopeIndent)));
+ }
+ IF_FAIL_GO(WriteToFile(g_BinderVariables->m_hDebugLogFile, pbRawBuffer, dwcbRawBuffer));
+ IF_FAIL_GO(WriteToFile(g_BinderVariables->m_hDebugLogFile,
+ reinterpret_cast<const BYTE *>(ansiCRLF),
+ dwcbAnsiCRLF));
+ // Don't cache anything
+ if (!FlushFileBuffers(g_BinderVariables->m_hDebugLogFile))
+ {
+ WszOutputDebugString(L"DebugLog::Log(info): FlushFileBuffers failed!\n");
+ }
+
+ Exit:
+ return;
+ }
+};
+
+#endif
diff --git a/src/binder/dirs.proj b/src/binder/dirs.proj
new file mode 100644
index 0000000000..cb7c0b4d02
--- /dev/null
+++ b/src/binder/dirs.proj
@@ -0,0 +1,20 @@
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <PropertyGroup>
+ <BuildInPhase1>true</BuildInPhase1>
+ <BuildInPhaseDefault>false</BuildInPhaseDefault>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ </PropertyGroup>
+
+ <!--The following projects will build during PHASE 1 of the Desktop build -->
+ <ItemGroup Condition="'$(BuildExePhase)' == '1'">
+ <ProjectFile Include="assemblyname\assemblyname.nativeproj" />
+ </ItemGroup>
+
+ <ItemGroup Condition="'$(BuildExePhase)' == '1' and '$(FeatureCoreclr)' == 'true'">
+ <ProjectFile Include="v3binder\v3binder.nativeproj" />
+ </ItemGroup>
+
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\tools\Microsoft.DevDiv.Traversal.targets" />
+</Project>
diff --git a/src/binder/failurecache.cpp b/src/binder/failurecache.cpp
new file mode 100644
index 0000000000..c7f17a69f6
--- /dev/null
+++ b/src/binder/failurecache.cpp
@@ -0,0 +1,85 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FailureCache.cpp
+//
+
+
+//
+// Implements the FailureCache class
+//
+// ============================================================
+
+#include "failurecache.hpp"
+
+namespace BINDER_SPACE
+{
+ FailureCache::FailureCache() : SHash<FailureCacheHashTraits>::SHash()
+ {
+ // Nothing to do here
+ }
+
+ FailureCache::~FailureCache()
+ {
+ // Delete entries and contents array
+ for (Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
+ {
+ const FailureCacheEntry *pFailureCacheEntry = *i;
+ delete pFailureCacheEntry;
+ }
+ RemoveAll();
+ }
+
+ HRESULT FailureCache::Add(SString &assemblyNameorPath,
+ HRESULT hrBindingResult)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"FailureCache::Add");
+
+ NewHolder<FailureCacheEntry> pFailureCacheEntry;
+ SAFE_NEW(pFailureCacheEntry, FailureCacheEntry);
+
+ // No error occurred; report the original error
+ hr = hrBindingResult;
+
+ pFailureCacheEntry->GetAssemblyNameOrPath().Set(assemblyNameorPath);
+ pFailureCacheEntry->SetBindingResult(hrBindingResult);
+
+ Hash::Add(pFailureCacheEntry);
+ pFailureCacheEntry.SuppressRelease();
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(L"FailureCache::Add", hr);
+ return hr;
+ }
+
+ HRESULT FailureCache::Lookup(SString &assemblyNameorPath)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(L"FailureCache::Lookup");
+ FailureCacheEntry *pFailureCachEntry = Hash::Lookup(assemblyNameorPath);
+
+ if (pFailureCachEntry != NULL)
+ {
+ hr = pFailureCachEntry->GetBindingResult();
+ }
+
+ BINDER_LOG_LEAVE_HR(L"FailureCache::Lookup", hr);
+ return hr;
+ }
+
+ void FailureCache::Remove(SString &assemblyName)
+ {
+ BINDER_LOG_ENTER(L"FailureCache::Remove");
+
+ FailureCacheEntry *pFailureCachEntry = Hash::Lookup(assemblyName);
+
+ // Hash::Remove does not clean up entries
+ Hash::Remove(assemblyName);
+ SAFE_DELETE(pFailureCachEntry);
+
+ BINDER_LOG_LEAVE(L"FailureCache::Remove");
+ }
+};
diff --git a/src/binder/fusionassemblyname.cpp b/src/binder/fusionassemblyname.cpp
new file mode 100644
index 0000000000..f370337051
--- /dev/null
+++ b/src/binder/fusionassemblyname.cpp
@@ -0,0 +1,1857 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FusionAssemblyName.cpp
+//
+// Implements the CAssemblyName class
+//
+// ============================================================
+
+#include <windows.h>
+#include <winerror.h>
+#include "strongname.h"
+
+#include "fusionhelpers.hpp"
+#include "fusionassemblyname.hpp"
+
+#include <strsafe.h>
+#include "shlwapi.h"
+
+#include "binderinterface.hpp"
+#include "assemblyidentity.hpp"
+#include "textualidentityparser.hpp"
+
+#define DISPLAY_NAME_DELIMITER W(',')
+#define DISPLAY_NAME_DELIMITER_STRING W(",")
+#define VERSION_STRING_SEGMENTS 4
+#define REMAINING_BUFFER_SIZE ((*pccDisplayName) - (pszBuf - szDisplayName))
+
+// ---------------------------------------------------------------------------
+// Private Helpers
+// ---------------------------------------------------------------------------
+namespace
+{
+ HRESULT GetPublicKeyTokenFromPKBlob(LPBYTE pbPublicKeyToken, DWORD cbPublicKeyToken,
+ LPBYTE *ppbSN, LPDWORD pcbSN)
+ {
+ HRESULT hr = S_OK;
+
+ // Generate the hash of the public key.
+ if (!StrongNameTokenFromPublicKey(pbPublicKeyToken, cbPublicKeyToken, ppbSN, pcbSN))
+ {
+ hr = StrongNameErrorInfo();
+ }
+
+ return hr;
+ }
+};
+
+// ---------------------------------------------------------------------------
+// CPropertyArray ctor
+// ---------------------------------------------------------------------------
+CPropertyArray::CPropertyArray()
+{
+ _dwSig = 0x504f5250; /* 'PORP' */
+ memset(&_rProp, 0, ASM_NAME_MAX_PARAMS * sizeof(FusionProperty));
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray dtor
+// ---------------------------------------------------------------------------
+CPropertyArray::~CPropertyArray()
+{
+ for (DWORD i = 0; i < ASM_NAME_MAX_PARAMS; i++)
+ {
+ if (_rProp[i].cb > sizeof(DWORD))
+ {
+ if (_rProp[i].pv != NULL)
+ {
+ FUSION_DELETE_ARRAY((LPBYTE) _rProp[i].pv);
+ _rProp[i].pv = NULL;
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray::Set
+// ---------------------------------------------------------------------------
+HRESULT CPropertyArray::Set(DWORD PropertyId,
+ LPCVOID pvProperty, DWORD cbProperty)
+{
+ HRESULT hr = S_OK;
+ FusionProperty *pItem = NULL;
+
+ pItem = &(_rProp[PropertyId]);
+
+ if (!cbProperty && !pvProperty)
+ {
+ if (pItem->cb > sizeof(DWORD))
+ {
+ if (pItem->pv != NULL)
+ FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
+ }
+ pItem->pv = NULL;
+ }
+ else if (cbProperty > sizeof(DWORD))
+ {
+ LPBYTE ptr = NEW(BYTE[cbProperty]);
+ if (!ptr)
+ {
+ hr = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ if (pItem->cb > sizeof(DWORD))
+ FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
+
+ memcpy(ptr, pvProperty, cbProperty);
+ pItem->pv = ptr;
+ }
+ else
+ {
+ if (pItem->cb > sizeof(DWORD))
+ FUSION_DELETE_ARRAY((LPBYTE) pItem->pv);
+
+ memcpy(&(pItem->pv), pvProperty, cbProperty);
+
+#ifdef _DEBUG
+ if (PropertyId == ASM_NAME_ARCHITECTURE) {
+ PEKIND pe = * ((PEKIND *)pvProperty);
+ _ASSERTE(pe != peInvalid);
+ }
+#endif
+ }
+ pItem->cb = cbProperty;
+
+exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray::Get
+// ---------------------------------------------------------------------------
+HRESULT CPropertyArray::Get(DWORD PropertyId,
+ LPVOID pvProperty, LPDWORD pcbProperty)
+{
+ HRESULT hr = S_OK;
+ FusionProperty *pItem;
+
+ _ASSERTE(pcbProperty);
+
+ if (PropertyId >= ASM_NAME_MAX_PARAMS
+ || (!pvProperty && *pcbProperty))
+ {
+ _ASSERTE(!"Invalid Argument! Passed in NULL buffer with size non-zero!");
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ pItem = &(_rProp[PropertyId]);
+
+ if (pItem->cb > *pcbProperty)
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+ else if (pItem->cb)
+ memcpy(pvProperty, (pItem->cb > sizeof(DWORD) ?
+ pItem->pv : (LPBYTE) &(pItem->pv)), pItem->cb);
+
+ *pcbProperty = pItem->cb;
+
+exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CPropertyArray::operator []
+// Wraps DWORD optimization test.
+// ---------------------------------------------------------------------------
+FusionProperty CPropertyArray::operator [] (DWORD PropertyId)
+{
+ FusionProperty prop;
+
+ prop.pv = _rProp[PropertyId].cb > sizeof(DWORD) ?
+ _rProp[PropertyId].pv : &(_rProp[PropertyId].pv);
+
+ prop.cb = _rProp[PropertyId].cb;
+
+ return prop;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::AddRef
+// ---------------------------------------------------------------------------
+STDMETHODIMP_(ULONG)
+CAssemblyName::AddRef()
+{
+ return InterlockedIncrement(&_cRef);
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Release
+// ---------------------------------------------------------------------------
+STDMETHODIMP_(ULONG)
+CAssemblyName::Release()
+{
+ ULONG ulRef = InterlockedDecrement(&_cRef);
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::QueryInterface
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::QueryInterface(REFIID riid, void** ppv)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ if (!ppv)
+ {
+ hr = E_POINTER;
+ goto Exit;
+ }
+
+ if ( IsEqualIID(riid, IID_IUnknown)
+ || IsEqualIID(riid, IID_IAssemblyName)
+ )
+ {
+ *ppv = static_cast<IAssemblyName*> (this);
+ AddRef();
+ hr = S_OK;
+ goto Exit;
+ }
+ else
+ {
+ *ppv = NULL;
+ hr = E_NOINTERFACE;
+ goto Exit;
+ }
+
+ Exit:
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::SetProperty
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::SetProperty(DWORD PropertyId,
+ LPCVOID pvProperty,
+ DWORD cbProperty)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ hr = SetPropertyInternal(PropertyId, pvProperty, cbProperty);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::GetProperty
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::GetProperty(DWORD PropertyId,
+ LPVOID pvProperty, LPDWORD pcbProperty)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Retrieve the property.
+ switch(PropertyId)
+ {
+ case ASM_NAME_NULL_PUBLIC_KEY_TOKEN:
+ case ASM_NAME_NULL_PUBLIC_KEY:
+ {
+ hr = (_fPublicKeyToken && !_rProp[PropertyId].cb) ? S_OK : S_FALSE;
+ break;
+ }
+ case ASM_NAME_NULL_CUSTOM:
+ {
+ hr = (_fCustom && !_rProp[PropertyId].cb) ? S_OK : S_FALSE;
+ break;
+ }
+ default:
+ {
+ hr = _rProp.Get(PropertyId, pvProperty, pcbProperty);
+ break;
+ }
+ }
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Finalize
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::Finalize()
+{
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ _fIsFinalized = TRUE;
+ END_ENTRYPOINT_NOTHROW;
+
+ return S_OK;
+}
+// ---------------------------------------------------------------------------
+// CAssemblyName::GetDisplayName
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::GetDisplayName( __out_ecount_opt(*pccDisplayName) LPOLESTR szDisplayName,
+ __inout LPDWORD pccDisplayName,
+ DWORD dwDisplayFlags)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ if (!dwDisplayFlags) {
+ dwDisplayFlags = ASM_DISPLAYF_DEFAULT;
+ }
+
+ // Validate input buffer.
+ if(!pccDisplayName || (!szDisplayName && *pccDisplayName)) {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ EX_TRY
+ {
+ NewHolder<BINDER_SPACE::AssemblyIdentity> pAssemblyIdentity = new BINDER_SPACE::AssemblyIdentity();
+ FusionProperty prop;
+ StackSString textualIdentity;
+
+ // Name required
+ prop = _rProp[ASM_NAME_NAME];
+ if (prop.cb == 0) {
+ hr = FUSION_E_INVALID_NAME;
+ goto exit;
+ }
+ else {
+ _ASSERTE(prop.cb >= sizeof(WCHAR));
+
+ pAssemblyIdentity->m_simpleName.Set((const WCHAR *) prop.pv,
+ (prop.cb - sizeof(WCHAR)) / sizeof(WCHAR));
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+ }
+
+ // Display version
+ if (dwDisplayFlags & ASM_DISPLAYF_VERSION) {
+ prop = _rProp[ASM_NAME_MAJOR_VERSION];
+
+ // Set version if we have it
+ if (prop.cb != 0) {
+ DWORD dwVersionParts[4];
+
+ for(DWORD i = 0; i < 4; i++) {
+ prop = _rProp[ASM_NAME_MAJOR_VERSION + i];
+
+ // Normalize non-existing version parts to zero
+ if (prop.cb == sizeof(WORD)) {
+ dwVersionParts[i] = (DWORD) (* ((WORD *) prop.pv));
+ }
+ else {
+ dwVersionParts[i] = 0;
+ }
+ }
+
+ pAssemblyIdentity->m_version.SetFeatureVersion(dwVersionParts[0], dwVersionParts[1]);
+ pAssemblyIdentity->m_version.SetServiceVersion(dwVersionParts[2], dwVersionParts[3]);
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+ }
+
+ // Display culture
+ if (dwDisplayFlags & ASM_DISPLAYF_CULTURE) {
+ prop = _rProp[ASM_NAME_CULTURE];
+
+ if (prop.cb != 0) {
+ _ASSERTE(prop.cb >= sizeof(WCHAR));
+
+ if (((const WCHAR *) prop.pv)[0] != 0x00) {
+ pAssemblyIdentity->m_cultureOrLanguage.
+ Set((const WCHAR *) prop.pv,
+ (prop.cb - sizeof(WCHAR)) / sizeof(WCHAR));
+ }
+
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ }
+ }
+
+ // Display public key token
+ if ((dwDisplayFlags & ASM_DISPLAYF_PUBLIC_KEY_TOKEN) && _fPublicKeyToken) {
+ prop = _rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
+
+ if (prop.cb != 0) {
+ pAssemblyIdentity->m_publicKeyOrTokenBLOB.Set((const BYTE *) prop.pv, prop.cb);
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ }
+ else {
+ pAssemblyIdentity->
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+ }
+
+ // Display processor architecture
+ if (dwDisplayFlags & ASM_DISPLAYF_PROCESSORARCHITECTURE) {
+ if (_rProp[ASM_NAME_ARCHITECTURE].cb != 0) {
+ DWORD PeKind = *((LPDWORD)_rProp[ASM_NAME_ARCHITECTURE].pv);
+
+ if (PeKind != peNone) {
+ pAssemblyIdentity->m_kProcessorArchitecture = (PEKIND) PeKind;
+ pAssemblyIdentity->
+ SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ }
+ }
+
+ // Display retarget flag
+ if (dwDisplayFlags & ASM_DISPLAYF_RETARGET) {
+ prop = _rProp[ASM_NAME_RETARGET];
+
+ if (prop.cb != 0) {
+ BOOL fRetarget = *((LPBOOL) prop.pv);
+
+ if (fRetarget)
+ {
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ }
+ }
+
+ // Display content type
+ if (dwDisplayFlags & ASM_DISPLAYF_CONTENT_TYPE)
+ {
+ prop = _rProp[ASM_NAME_CONTENT_TYPE];
+ if (prop.cb != 0)
+ {
+ DWORD dwContentType = *((LPDWORD)prop.pv);
+ if (dwContentType != AssemblyContentType_Default)
+ {
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ pAssemblyIdentity->m_kContentType = (AssemblyContentType)dwContentType;
+ }
+ }
+ }
+
+ // Display custom flag
+ if ((dwDisplayFlags & ASM_DISPLAYF_CUSTOM) && _fCustom) {
+ prop = _rProp[ASM_NAME_CUSTOM];
+
+ if (prop.cb != 0) {
+ pAssemblyIdentity->m_customBLOB.Set((const BYTE *) prop.pv, prop.cb);
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+ }
+ else {
+ pAssemblyIdentity->SetHave(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL);
+ }
+ }
+
+ // Create the textual identity
+ hr = BINDER_SPACE::TextualIdentityParser::ToString(pAssemblyIdentity,
+ pAssemblyIdentity->m_dwIdentityFlags,
+ textualIdentity);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ // Determine required buffer size
+ DWORD dwGivenSize = *pccDisplayName;
+ DWORD dwRequiredSize = textualIdentity.GetCount() + 1;
+
+ *pccDisplayName = dwRequiredSize;
+
+ if (dwRequiredSize > dwGivenSize) {
+ hr = HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER);
+
+ if (szDisplayName) {
+ szDisplayName[0] = 0x00;
+ }
+ goto exit;
+ }
+ else {
+ hr = S_OK;
+ memcpy(szDisplayName, textualIdentity.GetUnicode(), dwRequiredSize * sizeof(WCHAR));
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::GetName
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::GetName(
+ __inout LPDWORD lpcwBuffer,
+ __out_ecount_opt(*lpcwBuffer) LPOLESTR pwzBuffer)
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ DWORD cbBuffer = *lpcwBuffer * sizeof(TCHAR);
+ hr = GetProperty(ASM_NAME_NAME, pwzBuffer, &cbBuffer);
+ *lpcwBuffer = cbBuffer / sizeof(TCHAR);
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::GetVersion
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::GetVersion(
+ /* [out] */ LPDWORD pdwVersionHi,
+ /* [out] */ LPDWORD pdwVersionLow)
+{
+ HRESULT hr = S_OK;
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ // Get Assembly Version
+ hr = GetVersion( ASM_NAME_MAJOR_VERSION, pdwVersionHi, pdwVersionLow);
+
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::IsEqual
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::IsEqual(LPASSEMBLYNAME pName, DWORD dwCmpFlags)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ DWORD dwPartialCmpMask = 0;
+ BOOL fIsPartial = FALSE;
+ CAssemblyName *pCName = static_cast<CAssemblyName *>(pName);
+
+ const DWORD SIMPLE_VERSION_MASK = ASM_CMPF_VERSION;
+
+ FusionProperty propThis;
+ FusionProperty propPara;
+
+ if(!pName) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ // Get the ref partial comparison mask, if any.
+ fIsPartial = CAssemblyName::IsPartial(this, &dwPartialCmpMask);
+
+ if (dwCmpFlags == ASM_CMPF_DEFAULT) {
+ // Set all comparison flags.
+ dwCmpFlags = ASM_CMPF_IL_ALL | ASM_CMPF_ARCHITECTURE;
+
+ // don't compare architecture if ref does not have architecture.
+ if (!(dwPartialCmpMask & ASM_CMPF_ARCHITECTURE)) {
+ dwCmpFlags &= ~ASM_CMPF_ARCHITECTURE;
+ }
+
+ // Otherwise, if ref is simple (possibly partial)
+ // we mask off all version bits.
+ if (!CAssemblyName::IsStronglyNamed(this))
+ {
+ // we don't have a public key token, but we don't know
+ // it is because we are simply named assembly or we are
+ // just partial on public key token.
+ if (dwPartialCmpMask & ASM_CMPF_PUBLIC_KEY_TOKEN)
+ {
+ // now we know we are simply named assembly since we
+ // have a public key token, but it is NULL.
+ dwCmpFlags &= ~SIMPLE_VERSION_MASK;
+ }
+ // If neither of these two cases then public key token
+ // is not set in ref , but def may be simple or strong.
+ // The comparison mask is chosen based on def.
+ else
+ {
+ if (!CAssemblyName::IsStronglyNamed(pName))
+ dwCmpFlags &= ~SIMPLE_VERSION_MASK;
+ }
+ }
+ }
+
+ // Mask off flags (either passed in or generated
+ // by default flag with the comparison mask generated
+ // from the ref.
+ dwCmpFlags &= dwPartialCmpMask;
+
+
+ // The individual name fields can now be compared..
+
+ // Compare name
+
+ if (dwCmpFlags & ASM_CMPF_NAME)
+ {
+ propThis = _rProp[ASM_NAME_NAME];
+ propPara = pCName->_rProp[ASM_NAME_NAME];
+
+ if (propThis.cb != propPara.cb)
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb && FusionCompareStringI((LPWSTR)propThis.pv, (LPWSTR)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // Compare version
+
+ if (dwCmpFlags & ASM_CMPF_MAJOR_VERSION)
+ {
+ propThis = _rProp[ASM_NAME_MAJOR_VERSION];
+ propPara = pCName->_rProp[ASM_NAME_MAJOR_VERSION];
+
+ if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ if (dwCmpFlags & ASM_CMPF_MINOR_VERSION)
+ {
+ propThis = _rProp[ASM_NAME_MINOR_VERSION];
+ propPara = pCName->_rProp[ASM_NAME_MINOR_VERSION];
+
+ if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ if (dwCmpFlags & ASM_CMPF_REVISION_NUMBER)
+ {
+ propThis = _rProp[ASM_NAME_REVISION_NUMBER];
+ propPara = pCName->_rProp[ASM_NAME_REVISION_NUMBER];
+
+ if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ if (dwCmpFlags & ASM_CMPF_BUILD_NUMBER)
+ {
+ propThis = _rProp[ASM_NAME_BUILD_NUMBER];
+ propPara = pCName->_rProp[ASM_NAME_BUILD_NUMBER];
+
+ if (*((LPWORD) propThis.pv) != *((LPWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // Compare public key token
+
+ if (dwCmpFlags & ASM_CMPF_PUBLIC_KEY_TOKEN)
+ {
+ // compare public key if both of them have public key set.
+ propThis = _rProp[ASM_NAME_PUBLIC_KEY];
+ propPara = pCName->_rProp[ASM_NAME_PUBLIC_KEY];
+ if (!propThis.cb || !propPara.cb) {
+ // otherwise, compare public key token
+ propThis = _rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
+ propPara = pCName->_rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
+ }
+
+ if (propThis.cb != propPara.cb) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // Compare Culture
+
+ if (dwCmpFlags & ASM_CMPF_CULTURE)
+ {
+ propThis = _rProp[ASM_NAME_CULTURE];
+ propPara = pCName->_rProp[ASM_NAME_CULTURE];
+
+ if (propThis.cb != propPara.cb)
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb && FusionCompareStringI((LPWSTR)propThis.pv, (LPWSTR)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // Compare Custom attribute.
+
+ if (dwCmpFlags & ASM_CMPF_CUSTOM)
+ {
+ propThis = _rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
+ propPara = pCName->_rProp[ASM_NAME_PUBLIC_KEY_TOKEN];
+
+ if (propThis.cb != propPara.cb) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // Compare Retarget flag
+ if (dwCmpFlags & ASM_CMPF_RETARGET)
+ {
+ propThis = _rProp[ASM_NAME_RETARGET];
+ propPara = pCName->_rProp[ASM_NAME_RETARGET];
+
+ if (*((LPDWORD) propThis.pv) != *((LPDWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // compare config mask
+ if (dwCmpFlags & ASM_CMPF_CONFIG_MASK)
+ {
+ propThis = _rProp[ASM_NAME_CONFIG_MASK];
+ propPara = pCName->_rProp[ASM_NAME_CONFIG_MASK];
+
+ if (*((LPDWORD) propThis.pv) != *((LPDWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ }
+
+ // compare architecture
+ if (dwCmpFlags & ASM_CMPF_ARCHITECTURE)
+ {
+ propThis = _rProp[ASM_NAME_ARCHITECTURE];
+ propPara = pCName->_rProp[ASM_NAME_ARCHITECTURE];
+
+ if (propThis.cb != propPara.cb) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb) {
+ if (*((LPDWORD) propThis.pv) != *((LPDWORD)propPara.pv)) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+ }
+
+ // Compare content type
+ if (dwCmpFlags & ASM_CMPF_CONTENT_TYPE)
+ {
+ propThis = _rProp[ASM_NAME_CONTENT_TYPE];
+ propPara = pCName->_rProp[ASM_NAME_CONTENT_TYPE];
+
+ if (*((LPDWORD)propThis.pv) != *((LPDWORD)propPara.pv))
+ {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // compare MVID
+ if (dwCmpFlags & ASM_CMPF_MVID)
+ {
+ propThis = _rProp[ASM_NAME_MVID];
+ propPara = pCName->_rProp[ASM_NAME_MVID];
+
+ if (propThis.cb != propPara.cb) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ // compare Signature
+ if (dwCmpFlags & ASM_CMPF_SIGNATURE)
+ {
+ propThis = _rProp[ASM_NAME_SIGNATURE_BLOB];
+ propPara = pCName->_rProp[ASM_NAME_SIGNATURE_BLOB];
+
+ if (propThis.cb != propPara.cb) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+
+ if (propThis.cb && memcmp(propThis.pv, propPara.pv, propThis.cb)) {
+ hr = S_FALSE;
+ goto Exit;
+ }
+ }
+
+ hr = S_OK;
+Exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Reserved
+// ---------------------------------------------------------------------------
+STDMETHODIMP
+CAssemblyName::Reserved(
+ /* in */ REFIID refIID,
+ /* in */ IUnknown *pUnkBindSink,
+ /* in */ IUnknown *pUnkAppCtx,
+ /* in */ LPCOLESTR szCodebaseIn,
+ /* in */ LONGLONG llFlags,
+ /* in */ LPVOID pvReserved,
+ /* in */ DWORD cbReserved,
+ /* out */ VOID **ppv)
+{
+ return E_NOTIMPL;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Clone
+// ---------------------------------------------------------------------------
+HRESULT CAssemblyName::Clone(IAssemblyName **ppName)
+{
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CAssemblyName *pClone = NULL;
+
+ if (!ppName) {
+ hr = E_INVALIDARG;
+ goto Exit;
+ }
+
+ *ppName = NULL;
+
+ pClone = NEW(CAssemblyName);
+ if( !pClone ) {
+ hr = E_OUTOFMEMORY;
+ goto Exit;
+ }
+
+ hr = CopyProperties(this, pClone, NULL, 0);
+ if (FAILED(hr)) {
+ goto Exit;
+ }
+
+ *ppName = pClone;
+ (*ppName)->AddRef();
+
+Exit:
+ SAFERELEASE(pClone);
+
+ END_ENTRYPOINT_NOTHROW;
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::SetPropertyInternal
+// ---------------------------------------------------------------------------
+HRESULT CAssemblyName::SetPropertyInternal(DWORD PropertyId,
+ LPCVOID pvProperty,
+ DWORD cbProperty)
+{
+ HRESULT hr = S_OK;
+ LPBYTE pbSN = NULL;
+ DWORD cbSN = 0;
+
+ // Fail if finalized.
+ if (_fIsFinalized)
+ {
+ _ASSERTE(!"SetProperty on a IAssemblyName while the name is finalized!");
+ hr = E_UNEXPECTED;
+ goto exit;
+ }
+
+ if (PropertyId >= ASM_NAME_MAX_PARAMS
+ || (!pvProperty && cbProperty))
+ {
+ _ASSERTE(!"Invalid Argument! Passed in NULL buffer with size non-zero!");
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ // <REVISIT_TODO> - make this a switch statement.</REVISIT_TODO>
+ if (PropertyId == ASM_NAME_MAJOR_VERSION ||
+ PropertyId == ASM_NAME_MINOR_VERSION ||
+ PropertyId == ASM_NAME_BUILD_NUMBER ||
+ PropertyId == ASM_NAME_REVISION_NUMBER)
+ {
+ if (cbProperty > sizeof(WORD)) {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+ }
+
+ // Check if public key is being set and if so,
+ // set the public key token if not already set.
+ if (PropertyId == ASM_NAME_PUBLIC_KEY)
+ {
+ // If setting true public key, generate hash.
+ if (pvProperty && cbProperty)
+ {
+ // Generate the public key token from the pk.
+ if (FAILED(hr = GetPublicKeyTokenFromPKBlob((LPBYTE) pvProperty, cbProperty, &pbSN, &cbSN)))
+ goto exit;
+
+ // Set the public key token property.
+ if (FAILED(hr = SetPropertyInternal(ASM_NAME_PUBLIC_KEY_TOKEN, pbSN, cbSN)))
+ goto exit;
+ }
+ // Otherwise expect call to reset property.
+ else if (!cbProperty)
+ {
+ if (FAILED(hr = SetPropertyInternal(ASM_NAME_PUBLIC_KEY_TOKEN, pvProperty, cbProperty)))
+ goto exit;
+ }
+
+ }
+ // Setting NULL public key clears values in public key,
+ // public key token and sets public key token flag.
+ else if (PropertyId == ASM_NAME_NULL_PUBLIC_KEY)
+ {
+ pvProperty = NULL;
+ cbProperty = 0;
+ hr = SetPropertyInternal(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, pvProperty, cbProperty);
+ goto exit;
+ }
+ // Setting or clearing public key token.
+ else if (PropertyId == ASM_NAME_PUBLIC_KEY_TOKEN)
+ {
+ // Defensive: invalid sized public key tokens should be avoided.
+ if (cbProperty > PUBLIC_KEY_TOKEN_LEN)
+ {
+ hr = SetPropertyInternal(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0);
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ if (pvProperty && cbProperty)
+ _fPublicKeyToken = TRUE;
+ else if (!cbProperty)
+ _fPublicKeyToken = FALSE;
+ }
+ // Setting NULL public key token clears public key token and
+ // sets public key token flag.
+ else if (PropertyId == ASM_NAME_NULL_PUBLIC_KEY_TOKEN)
+ {
+ _fPublicKeyToken = TRUE;
+ pvProperty = NULL;
+ cbProperty = 0;
+ PropertyId = ASM_NAME_PUBLIC_KEY_TOKEN;
+ }
+ else if (PropertyId == ASM_NAME_CUSTOM)
+ {
+ if (pvProperty && cbProperty)
+ _fCustom = TRUE;
+ else if (!cbProperty)
+ _fCustom = FALSE;
+ }
+ else if (PropertyId == ASM_NAME_NULL_CUSTOM)
+ {
+ _fCustom = TRUE;
+ pvProperty = NULL;
+ cbProperty = 0;
+ PropertyId = ASM_NAME_CUSTOM;
+ }
+
+ // Setting "neutral" as the culture is the same as "" culture (meaning
+ // culture-invariant).
+ else if (PropertyId == ASM_NAME_CULTURE) {
+ if (pvProperty && !FusionCompareStringI((LPWSTR)pvProperty, W("neutral"))) {
+ pvProperty = (void *)W("");
+ cbProperty = sizeof(W(""));
+ }
+ }
+
+ // Set property on array.
+ hr = _rProp.Set(PropertyId, pvProperty, cbProperty);
+
+exit:
+ if (SUCCEEDED(hr)) {
+ LPWSTR pwzOld;
+
+ // Clear cache
+
+ pwzOld = InterlockedExchangeT(&_pwzTextualIdentity, NULL);
+ SAFEDELETEARRAY(pwzOld);
+ pwzOld = InterlockedExchangeT(&_pwzTextualIdentityILFull, NULL);
+ SAFEDELETEARRAY(pwzOld);
+ }
+
+ // Free memory allocated by crypto wrapper.
+ if (pbSN) {
+ StrongNameFreeBuffer(pbSN);
+ }
+
+ return hr;
+}
+
+
+
+// ---------------------------------------------------------------------------
+// CheckFieldsForFriendAssembly
+// ---------------------------------------------------------------------------
+STDAPI
+CheckFieldsForFriendAssembly(
+ LPASSEMBLYNAME pAssemblyName)
+{
+ HRESULT hr = S_OK;
+ DWORD dwSize=0;
+
+ // Let's look at the information they gave us in the friends declaration.
+ // If they put in a Processor Architecture, Culture, or Version, then we'll return an error.
+
+ if (FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_MAJOR_VERSION, NULL, &dwSize)) ||
+ FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_MINOR_VERSION, NULL, &dwSize)) ||
+ FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_BUILD_NUMBER, NULL, &dwSize)) ||
+ FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_REVISION_NUMBER, NULL, &dwSize)) ||
+ FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_CULTURE, NULL, &dwSize)) ||
+ FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_ARCHITECTURE, NULL, &dwSize)))
+ {
+ // If any of these calls failed due to an insufficient buffer, then that means
+ // the assembly name contained them
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ hr = META_E_CA_BAD_FRIENDS_ARGS;
+ } else {
+ if (FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_PUBLIC_KEY_TOKEN, NULL, &dwSize))) {
+
+ //
+ // Public Key token should not be passed to InternalsVisibleTo
+ // attribute. This translates to the ASM_NAME_PUBLIC_KEY_TOKEN
+ // property being set, while the full public key is not.
+ //
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)) {
+
+ dwSize = 0;
+
+ if (FAILED(hr = pAssemblyName->GetProperty(ASM_NAME_PUBLIC_KEY, NULL, &dwSize))) {
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ hr = S_OK;
+ } else {
+ hr = META_E_CA_BAD_FRIENDS_ARGS;
+ }
+
+ }
+ } else {
+ hr = S_OK;
+ }
+ }
+
+
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CreateAssemblyNameObject
+// ---------------------------------------------------------------------------
+
+// This is not external for CoreCLR
+STDAPI
+CreateAssemblyNameObject(
+ LPASSEMBLYNAME *ppAssemblyName,
+ LPCOLESTR szAssemblyName,
+ DWORD dwFlags,
+ LPVOID pvReserved)
+{
+
+ HRESULT hr = S_OK;
+
+ BEGIN_ENTRYPOINT_NOTHROW;
+
+ CAssemblyName *pName = NULL;
+
+ if (!ppAssemblyName)
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ pName = NEW(CAssemblyName);
+ if (!pName)
+ {
+ hr = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ if (dwFlags & CANOF_PARSE_DISPLAY_NAME)
+ {
+ hr = pName->Init(NULL, NULL);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ hr = pName->Parse((LPWSTR)szAssemblyName);
+ }
+ else
+ {
+ hr = pName->Init(szAssemblyName, NULL);
+ }
+
+
+ if (SUCCEEDED(hr) && ((dwFlags & CANOF_VERIFY_FRIEND_ASSEMBLYNAME)))
+ {
+ hr = CheckFieldsForFriendAssembly(pName);
+ }
+
+
+ if (FAILED(hr))
+ {
+ SAFERELEASE(pName);
+ goto exit;
+ }
+
+ *ppAssemblyName = pName;
+
+exit:
+ END_ENTRYPOINT_NOTHROW;
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CreateAssemblyNameObjectFromMetaData
+// ---------------------------------------------------------------------------
+STDAPI
+CreateAssemblyNameObjectFromMetaData(
+ LPASSEMBLYNAME *ppAssemblyName,
+ LPCOLESTR szAssemblyName,
+ ASSEMBLYMETADATA *pamd,
+ LPVOID pvReserved)
+{
+
+ HRESULT hr = S_OK;
+ CAssemblyName *pName = NULL;
+
+ pName = NEW(CAssemblyName);
+ if (!pName)
+ {
+ hr = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ hr = pName->Init(szAssemblyName, pamd);
+
+ if (FAILED(hr))
+ {
+ SAFERELEASE(pName);
+ goto exit;
+ }
+
+ *ppAssemblyName = pName;
+
+exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName constructor
+// ---------------------------------------------------------------------------
+CAssemblyName::CAssemblyName()
+{
+ _dwSig = 0x454d414e; /* 'EMAN' */
+ _fIsFinalized = FALSE;
+ _fPublicKeyToken = FALSE;
+ _fCustom = TRUE;
+ _cRef = 1;
+ _pwzPathModifier = NULL;
+ _pwzTextualIdentity = NULL;
+ _pwzTextualIdentityILFull = NULL;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName destructor
+// ---------------------------------------------------------------------------
+CAssemblyName::~CAssemblyName()
+{
+ SAFEDELETEARRAY(_pwzPathModifier);
+ SAFEDELETEARRAY(_pwzTextualIdentity);
+ SAFEDELETEARRAY(_pwzTextualIdentityILFull);
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::IsStronglyNamed
+// ---------------------------------------------------------------------------
+BOOL CAssemblyName::IsStronglyNamed(IAssemblyName *pName)
+{
+ CAssemblyName *pCName = static_cast<CAssemblyName *> (pName);
+ _ASSERTE(pCName);
+
+ return (pCName->_rProp[ASM_NAME_PUBLIC_KEY_TOKEN].cb != 0);
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::IsPartial
+// ---------------------------------------------------------------------------
+BOOL CAssemblyName::IsPartial(IAssemblyName *pIName,
+ LPDWORD pdwCmpMask)
+{
+ DWORD dwCmpMask = 0;
+ BOOL fPartial = FALSE;
+
+ static const ASM_NAME rNameFlags[] ={ASM_NAME_NAME,
+ ASM_NAME_CULTURE,
+ ASM_NAME_PUBLIC_KEY_TOKEN,
+ ASM_NAME_MAJOR_VERSION,
+ ASM_NAME_MINOR_VERSION,
+ ASM_NAME_BUILD_NUMBER,
+ ASM_NAME_REVISION_NUMBER,
+ ASM_NAME_CUSTOM
+ };
+
+ static const ASM_CMP_FLAGS rCmpFlags[] = {ASM_CMPF_NAME,
+ ASM_CMPF_CULTURE,
+ ASM_CMPF_PUBLIC_KEY_TOKEN,
+ ASM_CMPF_MAJOR_VERSION,
+ ASM_CMPF_MINOR_VERSION,
+ ASM_CMPF_BUILD_NUMBER,
+ ASM_CMPF_REVISION_NUMBER,
+ ASM_CMPF_CUSTOM
+ };
+
+ CAssemblyName *pName = static_cast<CAssemblyName*> (pIName); // dynamic_cast
+ _ASSERTE(pName);
+
+ DWORD iNumOfComparison = sizeof(rNameFlags) / sizeof(rNameFlags[0]);
+
+ for (DWORD i = 0; i < iNumOfComparison; i++)
+ {
+ if (pName->_rProp[rNameFlags[i]].cb
+ || (rNameFlags[i] == ASM_NAME_PUBLIC_KEY_TOKEN
+ && pName->_fPublicKeyToken)
+ || (rNameFlags[i] == ASM_NAME_CUSTOM
+ && pName->_fCustom))
+ {
+ dwCmpMask |= rCmpFlags[i];
+ }
+ else {
+ fPartial = TRUE;
+ }
+ }
+
+ if(pName->_rProp[ASM_NAME_ARCHITECTURE].cb) {
+ dwCmpMask |= ASM_CMPF_ARCHITECTURE;
+ }
+
+ if (pName->_rProp[ASM_NAME_RETARGET].cb) {
+ dwCmpMask |= ASM_CMPF_RETARGET;
+ }
+
+ if (pName->_rProp[ASM_NAME_CONTENT_TYPE].cb != 0)
+ {
+ dwCmpMask |= ASM_CMPF_CONTENT_TYPE;
+ }
+
+ if (pName->_rProp[ASM_NAME_CONFIG_MASK].cb) {
+ dwCmpMask |= ASM_CMPF_CONFIG_MASK;
+ }
+
+ if (pName->_rProp[ASM_NAME_MVID].cb) {
+ dwCmpMask |= ASM_CMPF_MVID;
+ }
+
+ if (pName->_rProp[ASM_NAME_SIGNATURE_BLOB].cb) {
+ dwCmpMask |= ASM_CMPF_SIGNATURE;
+ }
+
+ if (pdwCmpMask)
+ *pdwCmpMask = dwCmpMask;
+
+ return fPartial;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Init
+// ---------------------------------------------------------------------------
+HRESULT
+CAssemblyName::Init(LPCTSTR pszAssemblyName, ASSEMBLYMETADATA *pamd)
+{
+ HRESULT hr = S_OK;
+
+ // Name
+ if (pszAssemblyName)
+ {
+ hr = SetProperty(ASM_NAME_NAME, (LPTSTR) pszAssemblyName,
+ (lstrlenW(pszAssemblyName)+1) * sizeof(TCHAR));
+ if (FAILED(hr))
+ goto exit;
+ }
+
+ if (pamd) {
+ // Major version
+ if (FAILED(hr = SetProperty(ASM_NAME_MAJOR_VERSION,
+ &pamd->usMajorVersion, sizeof(WORD)))
+
+ // Minor version
+ || FAILED(hr = SetProperty(ASM_NAME_MINOR_VERSION,
+ &pamd->usMinorVersion, sizeof(WORD)))
+
+ // Revision number
+ || FAILED(hr = SetProperty(ASM_NAME_REVISION_NUMBER,
+ &pamd->usRevisionNumber, sizeof(WORD)))
+
+ // Build number
+ || FAILED(hr = SetProperty(ASM_NAME_BUILD_NUMBER,
+ &pamd->usBuildNumber, sizeof(WORD)))
+
+ // Culture
+ || FAILED(hr = SetProperty(ASM_NAME_CULTURE,
+ pamd->szLocale, pamd->cbLocale * sizeof(WCHAR)))
+ )
+ {
+ goto exit;
+ }
+ }
+
+exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::Parse
+// ---------------------------------------------------------------------------
+HRESULT CAssemblyName::Parse(__in_z LPCWSTR szDisplayName)
+{
+ HRESULT hr = S_OK;
+
+ if (!(szDisplayName && *szDisplayName))
+ {
+ hr = E_INVALIDARG;
+ goto exit;
+ }
+
+ EX_TRY {
+ BINDER_SPACE::AssemblyIdentity assemblyIdentity;
+ SString displayName(szDisplayName);
+
+ // Parse the textual identity
+ hr = BINDER_SPACE::TextualIdentityParser::Parse(displayName, &assemblyIdentity);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ // Set name.
+ hr = SetProperty(ASM_NAME_NAME,
+ (LPVOID) assemblyIdentity.m_simpleName.GetUnicode(),
+ (assemblyIdentity.m_simpleName.GetCount() + 1) * sizeof(WCHAR));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ // Set version.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_VERSION)) {
+ WORD wVersionPart = 0;
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetMajor();
+ hr = SetProperty(ASM_NAME_MAJOR_VERSION, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetMinor();
+ hr = SetProperty(ASM_NAME_MINOR_VERSION, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetBuild();
+ hr = SetProperty(ASM_NAME_BUILD_NUMBER, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+
+ wVersionPart = (WORD) assemblyIdentity.m_version.GetRevision();
+ hr = SetProperty(ASM_NAME_REVISION_NUMBER, &wVersionPart, sizeof(WORD));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set culture.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CULTURE)) {
+ hr = SetProperty(ASM_NAME_CULTURE,
+ (LPVOID) assemblyIdentity.m_cultureOrLanguage.GetUnicode(),
+ (assemblyIdentity.m_cultureOrLanguage.GetCount()+1) * sizeof(WCHAR));
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set public key (token) or NULL flag.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY)) {
+ SBuffer &publicKeyBuffer = assemblyIdentity.m_publicKeyOrTokenBLOB;
+ const void *pBytes = publicKeyBuffer;
+
+ // This also computes and sets the public key token.
+ hr = SetProperty(ASM_NAME_PUBLIC_KEY, (void *) pBytes, publicKeyBuffer.GetSize());
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ else if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN)) {
+ SBuffer &publicKeyTokenBuffer = assemblyIdentity.m_publicKeyOrTokenBLOB;
+ const void *pBytes = publicKeyTokenBuffer;
+
+ hr = SetProperty(ASM_NAME_PUBLIC_KEY_TOKEN,
+ (LPVOID) pBytes,
+ publicKeyTokenBuffer.GetSize());
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ else if (assemblyIdentity.
+ Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL)) {
+ hr = SetProperty(ASM_NAME_NULL_PUBLIC_KEY_TOKEN, NULL, 0);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set architecture.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE)) {
+ PEKIND peKind = assemblyIdentity.m_kProcessorArchitecture;
+
+ hr = SetProperty(ASM_NAME_ARCHITECTURE, (LPVOID) &peKind, sizeof(PEKIND));
+ if(FAILED(hr)) {
+ goto exit;
+ }
+ }
+
+ // Set retargetable flag.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE)) {
+ BOOL fRetarget = TRUE;
+
+ if (FAILED(hr = SetProperty(ASM_NAME_RETARGET, &fRetarget, sizeof(BOOL)))) {
+ goto exit;
+ }
+ }
+
+ // Set content type.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE)) {
+ DWORD dwContentType = assemblyIdentity.m_kContentType;
+
+ hr = SetProperty(ASM_NAME_CONTENT_TYPE, &dwContentType, sizeof(dwContentType));
+ IfFailGoto(hr, exit);
+ }
+
+ // Set custom or NULL flag.
+ if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM)) {
+ SBuffer &customBuffer = assemblyIdentity.m_customBLOB;
+ const void *pBytes = customBuffer;
+
+ hr = SetProperty(ASM_NAME_CUSTOM, (void *) pBytes, customBuffer.GetSize());
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ else if (assemblyIdentity.Have(BINDER_SPACE::AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL)) {
+ hr = SetProperty(ASM_NAME_NULL_CUSTOM, NULL, 0);
+ if (FAILED(hr)) {
+ goto exit;
+ }
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::GetVersion
+// ---------------------------------------------------------------------------
+HRESULT
+CAssemblyName::GetVersion(
+ /* [in] */ DWORD dwMajorVersionEnumValue,
+ /* [out] */ LPDWORD pdwVersionHi,
+ /* [out] */ LPDWORD pdwVersionLow)
+{
+ HRESULT hr = S_OK;
+ DWORD cb = sizeof(WORD);
+ WORD wVerMajor = 0, wVerMinor = 0, wRevNo = 0, wBldNo = 0;
+
+ if(!pdwVersionHi || !pdwVersionLow) {
+ hr = E_INVALIDARG;
+ goto Exit;
+ }
+
+ *pdwVersionHi = *pdwVersionLow = 0;
+
+ if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue, &wVerMajor, &(cb = sizeof(WORD))))))
+ goto Exit;
+ if (cb == 0) {
+ hr = FUSION_E_INVALID_NAME;
+ goto Exit;
+ }
+
+ if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue+1, &wVerMinor, &(cb = sizeof(WORD))))))
+ goto Exit;
+
+ if (cb == 0) {
+ hr = FUSION_E_INVALID_NAME;
+ goto Exit;
+ }
+
+ if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue+2, &wBldNo, &(cb = sizeof(WORD))))))
+ goto Exit;
+ if (cb == 0) {
+ hr = FUSION_E_INVALID_NAME;
+ goto Exit;
+ }
+
+ if(FAILED( (hr = GetProperty(dwMajorVersionEnumValue+3, &wRevNo, &(cb = sizeof(WORD))))))
+ goto Exit;
+
+ if (cb == 0) {
+ hr = FUSION_E_INVALID_NAME;
+ goto Exit;
+ }
+
+ *pdwVersionHi = MAKELONG(wVerMinor, wVerMajor);
+ *pdwVersionLow = MAKELONG(wRevNo, wBldNo);
+
+Exit:
+ return hr;
+}
+
+// ---------------------------------------------------------------------------
+// CAssemblyName::CopyProperties
+// ---------------------------------------------------------------------------
+HRESULT
+CAssemblyName::CopyProperties(CAssemblyName *pSource,
+ CAssemblyName *pTarget,
+ const DWORD properties[],
+ DWORD dwSize)
+{
+ HRESULT hr = S_OK;
+ DWORD i = 0;
+ FusionProperty prop;
+
+ _ASSERTE(pSource && pTarget);
+
+ if (!dwSize) {
+ for( i = 0; i < ASM_NAME_MAX_PARAMS; i ++) {
+ prop = pSource->_rProp[i];
+
+ if (prop.cb) {
+ if (FAILED(hr = pTarget->SetProperty(i, prop.pv, prop.cb))) {
+ goto Exit;
+ }
+ }
+ }
+ }
+ else {
+ for (i = 0; i<dwSize; i++) {
+ _ASSERTE(properties[i] < ASM_NAME_MAX_PARAMS);
+ prop = pSource->_rProp[properties[i]];
+ if (prop.cb) {
+ if (FAILED(hr = pTarget->SetProperty(properties[i], prop.pv, prop.cb))) {
+ goto Exit;
+ }
+ }
+ }
+ }
+
+ pTarget->_fPublicKeyToken = pSource->_fPublicKeyToken;
+ pTarget->_fCustom = pSource->_fCustom;
+
+ if (pSource->_pwzPathModifier) {
+ pTarget->_pwzPathModifier = WSTRDupDynamic(pSource->_pwzPathModifier);
+ if(!pTarget->_pwzPathModifier) {
+ hr = E_OUTOFMEMORY;
+ goto Exit;
+ }
+ }
+
+Exit:
+ return hr;
+}
+
+namespace LegacyFusion
+{
+ HRESULT SetStringProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ SString &value)
+ {
+ CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
+ const WCHAR *pValue = value.GetUnicode();
+ DWORD dwCBValue = (value.GetCount() + 1) * sizeof(WCHAR);
+
+ return pAssemblyName->SetPropertyInternal(dwPropertyId,
+ const_cast<WCHAR *>(pValue),
+ dwCBValue);
+ }
+
+ HRESULT SetBufferProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ SBuffer &value)
+ {
+ CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
+ const BYTE *pValue = value; // special operator
+ DWORD dwCBValue = value.GetSize() * sizeof(BYTE);
+
+ return pAssemblyName->SetPropertyInternal(dwPropertyId,
+ const_cast<BYTE *>(pValue),
+ dwCBValue);
+ }
+
+ HRESULT SetWordProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ DWORD dwValue)
+ {
+ CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
+ WORD wValue = static_cast<WORD>(dwValue);
+ DWORD wCBValue = sizeof(WORD);
+
+ // This file-internal function is and must be only used to set version fields
+ PREFIX_ASSUME((dwPropertyId == ASM_NAME_MAJOR_VERSION) ||
+ (dwPropertyId == ASM_NAME_MINOR_VERSION) ||
+ (dwPropertyId == ASM_NAME_BUILD_NUMBER) ||
+ (dwPropertyId == ASM_NAME_REVISION_NUMBER));
+
+ return pAssemblyName->SetPropertyInternal(dwPropertyId, &wValue, wCBValue);
+ }
+
+ HRESULT SetDwordProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ DWORD dwValue)
+ {
+ CAssemblyName *pAssemblyName = static_cast<CAssemblyName *>(pIAssemblyName);
+ DWORD dwCBValue = sizeof(DWORD);
+
+ return pAssemblyName->SetPropertyInternal(dwPropertyId, &dwValue, dwCBValue);
+ }
+};
+namespace fusion
+{
+ namespace util
+ {
+ namespace priv
+ {
+ inline bool IsNullProperty(DWORD dwProperty)
+ {
+ LIMITED_METHOD_CONTRACT;
+ return dwProperty == ASM_NAME_NULL_PUBLIC_KEY_TOKEN ||
+ dwProperty == ASM_NAME_NULL_PUBLIC_KEY ||
+ dwProperty == ASM_NAME_NULL_CUSTOM;
+ }
+
+ HRESULT ConvertToUtf8(PCWSTR wzStr, __deref_out UTF8** pszStr)
+ {
+ HRESULT hr = S_OK;
+
+ _ASSERTE(wzStr != nullptr && pszStr != nullptr);
+ if (wzStr == nullptr || pszStr == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ DWORD cbSize = WszWideCharToMultiByte(CP_UTF8, 0, wzStr, -1, NULL, 0, NULL, NULL);
+ if(cbSize == 0)
+ {
+ return SUCCEEDED(hr = HRESULT_FROM_GetLastError()) ? E_UNEXPECTED : hr;
+ }
+
+ NewArrayHolder<UTF8> szStr = new (nothrow) UTF8[cbSize];
+ IfNullRet(szStr);
+
+ cbSize = WszWideCharToMultiByte(CP_UTF8, 0, wzStr, -1, static_cast<LPSTR>(szStr), cbSize, NULL, NULL);
+ if(cbSize == 0)
+ {
+ return SUCCEEDED(hr = HRESULT_FROM_GetLastError()) ? E_UNEXPECTED : hr;
+ }
+
+ *pszStr = szStr.Extract();
+ return S_OK;
+ }
+ }
+
+ // Non-allocating helper.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PVOID pBuf, DWORD *pcbBuf)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pName != nullptr && pcbBuf != nullptr);
+ if (pName == nullptr || pcbBuf == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ hr = pName->GetProperty(dwProperty, pBuf, pcbBuf);
+ IfFailRet(hr);
+
+ // Zero-length non-null property means there is no value.
+ if (hr == S_OK && *pcbBuf == 0 && !priv::IsNullProperty(dwProperty))
+ {
+ hr = S_FALSE;
+ }
+
+ return hr;
+ }
+
+ // Allocating helper.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PBYTE * ppBuf, DWORD *pcbBuf)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(ppBuf != nullptr && (*ppBuf == nullptr || pcbBuf != nullptr));
+ if (ppBuf == nullptr || (*ppBuf != nullptr && pcbBuf == nullptr))
+ {
+ return E_INVALIDARG;
+ }
+
+ DWORD cbBuf = 0;
+ if (pcbBuf == nullptr)
+ pcbBuf = &cbBuf;
+
+ hr = GetProperty(pName, dwProperty, *ppBuf, pcbBuf);
+
+ // No provided buffer constitutes a request for one to be allocated.
+ if (*ppBuf == nullptr)
+ {
+ // If it's a null property, allocate a single-byte array to provide consistency.
+ if (hr == S_OK && priv::IsNullProperty(dwProperty))
+ {
+ *ppBuf = new (nothrow) BYTE[1];
+ IfNullRet(*ppBuf);
+ }
+ // Great, get the value.
+ else if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ {
+ NewArrayHolder<BYTE> pBuf = new (nothrow) BYTE[*pcbBuf];
+ IfNullRet(pBuf);
+ hr = pName->GetProperty(dwProperty, pBuf, pcbBuf);
+ IfFailRet(hr);
+ *ppBuf = pBuf.Extract();
+ hr = S_OK;
+ }
+ }
+
+ return hr;
+ }
+
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, SString & ssVal)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pName != nullptr);
+ if (pName == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ DWORD cbSize = 0;
+ hr = GetProperty(pName, dwProperty, static_cast<PBYTE>(nullptr), &cbSize);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ {
+ EX_TRY
+ {
+ PWSTR wzNameBuf = ssVal.OpenUnicodeBuffer(cbSize / sizeof(WCHAR) - 1);
+ hr = GetProperty(pName, dwProperty, reinterpret_cast<PBYTE>(wzNameBuf), &cbSize);
+ ssVal.CloseBuffer();
+ IfFailThrow(hr);
+ ssVal.Normalize();
+ }
+ EX_CATCH_HRESULT(hr);
+ IfFailRet(hr);
+ }
+
+ return hr;
+ }
+
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, __deref_out WCHAR ** pwzVal)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ _ASSERTE(pName != nullptr && pwzVal != nullptr);
+ if (pName == nullptr || pwzVal == nullptr)
+ {
+ return E_INVALIDARG;
+ }
+
+ DWORD cbSize = 0;
+ hr = pName->GetProperty(dwProperty, NULL, &cbSize);
+
+ if (hr == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ {
+ NewArrayHolder<WCHAR> wzVal = reinterpret_cast<PWSTR>(new (nothrow) BYTE[cbSize]);
+ IfNullRet(wzVal);
+ hr = pName->GetProperty(dwProperty, reinterpret_cast<PBYTE>(static_cast<PWSTR>(wzVal)), &cbSize);
+ IfFailRet(hr);
+ *pwzVal = wzVal.Extract();
+ }
+
+ return hr;
+ }
+
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, __deref_out UTF8 **pwzOut)
+ {
+ LIMITED_METHOD_CONTRACT;
+ HRESULT hr = S_OK;
+
+ if (pwzOut == nullptr)
+ return E_INVALIDARG;
+
+ SmallStackSString ssStr;
+ hr = GetProperty(pName, dwProperty, ssStr);
+ IfFailRet(hr);
+ hr = priv::ConvertToUtf8(ssStr, pwzOut);
+ IfFailRet(hr);
+ return hr;
+ }
+
+
+ }
+}
+
diff --git a/src/binder/fusionhelpers.cpp b/src/binder/fusionhelpers.cpp
new file mode 100644
index 0000000000..bb32856a52
--- /dev/null
+++ b/src/binder/fusionhelpers.cpp
@@ -0,0 +1,114 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FusionHelpers.cpp
+//
+// Implements various helper functions
+//
+// ============================================================
+
+#include "fusionhelpers.hpp"
+
+#include "shlwapi.h"
+#include "newapis.h"
+
+#define IS_UPPER_A_TO_Z(x) (((x) >= L'A') && ((x) <= L'Z'))
+#define IS_LOWER_A_TO_Z(x) (((x) >= L'a') && ((x) <= L'z'))
+#define IS_0_TO_9(x) (((x) >= L'0') && ((x) <= L'9'))
+#define CAN_SIMPLE_UPCASE(x) (((x)&~0x7f) == 0)
+#define SIMPLE_UPCASE(x) (IS_LOWER_A_TO_Z(x) ? ((x) - L'a' + L'A') : (x))
+#define CAN_SIMPLE_LOWERCASE(x) (((x)&~0x7f) == 0)
+#define SIMPLE_LOWERCASE(x) (IS_UPPER_A_TO_Z(x) ? ((x) - L'A' + L'a') : (x))
+
+// ---------------------------------------------------------------------------
+// Private Helpers
+// ---------------------------------------------------------------------------
+namespace
+{
+ WCHAR FusionMapChar(WCHAR wc)
+ {
+ WCHAR wTmp;
+
+#ifndef FEATURE_PAL
+
+#ifdef FEATURE_USE_LCID
+ int iRet = WszLCMapString(g_lcid, LCMAP_UPPERCASE, &wc, 1, &wTmp, 1);
+#else
+ int iRet = NewApis::LCMapStringEx(g_lcid, LCMAP_UPPERCASE, &wc, 1, &wTmp, 1, NULL, NULL, 0);
+#endif
+ if (!iRet) {
+ _ASSERTE(!"LCMapString failed!");
+ iRet = GetLastError();
+ wTmp = wc;
+ }
+#else // !FEATURE_PAL
+ // For PAL, no locale specific processing is done
+ wTmp = toupper(wc);
+#endif // !FEATURE_PAL
+
+ return wTmp;
+ }
+};
+
+// ---------------------------------------------------------------------------
+// FusionCompareStringN
+// ---------------------------------------------------------------------------
+// if nChar < 0, compare the whole string
+int FusionCompareStringN(LPCWSTR pwz1, LPCWSTR pwz2, int nChar, BOOL bCaseSensitive)
+{
+ int iRet = 0;
+ int nCount = 0;
+ WCHAR ch1;
+ WCHAR ch2;
+ _ASSERTE(pwz1 && pwz2);
+
+ // same point always return equal.
+ if (pwz1 == pwz2) {
+ return 0;
+ }
+
+ // Case sensitive comparison
+ if (bCaseSensitive) {
+ if (nChar >= 0)
+ return wcsncmp(pwz1, pwz2, nChar);
+ else
+ return wcscmp(pwz1, pwz2);
+ }
+
+ for (;;) {
+ ch1 = *pwz1++;
+ ch2 = *pwz2++;
+
+ if (ch1 == L'\0' || ch2 == L'\0') {
+ break;
+ }
+
+ // We use OS mapping table
+ ch1 = (CAN_SIMPLE_UPCASE(ch1)) ? (SIMPLE_UPCASE(ch1)) : (FusionMapChar(ch1));
+ ch2 = (CAN_SIMPLE_UPCASE(ch2)) ? (SIMPLE_UPCASE(ch2)) : (FusionMapChar(ch2));
+ nCount++;
+
+ if (ch1 != ch2 || (nChar >= 0 && nCount >= nChar)) {
+ break;
+ }
+ }
+
+ if (ch1 > ch2) {
+ iRet = 1;
+ }
+ else if (ch1 < ch2) {
+ iRet = -1;
+ }
+
+ return iRet;
+}
+
+// ---------------------------------------------------------------------------
+// FusionCompareStringI
+// ---------------------------------------------------------------------------
+int FusionCompareStringI(LPCWSTR pwz1, LPCWSTR pwz2)
+{
+ return FusionCompareStringN(pwz1, pwz2, -1, FALSE);
+}
diff --git a/src/binder/inc/.gitmirror b/src/binder/inc/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/binder/inc/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/binder/inc/applicationcontext.hpp b/src/binder/inc/applicationcontext.hpp
new file mode 100644
index 0000000000..4c256771eb
--- /dev/null
+++ b/src/binder/inc/applicationcontext.hpp
@@ -0,0 +1,197 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// ApplicationContext.hpp
+//
+
+
+//
+// Defines the ApplicationContext class
+//
+// ============================================================
+
+#ifndef __BINDER__APPLICATION_CONTEXT_HPP__
+#define __BINDER__APPLICATION_CONTEXT_HPP__
+
+#include "bindertypes.hpp"
+#include "failurecache.hpp"
+#include "assemblyidentitycache.hpp"
+#ifdef FEATURE_VERSIONING_LOG
+#include "bindinglog.hpp"
+#endif // FEATURE_VERSIONING_LOG
+#include "stringarraylist.h"
+
+namespace BINDER_SPACE
+{
+ //=============================================================================================
+ // Data structures for Simple Name -> File Name hash
+ struct FileNameMapEntry
+ {
+ LPWSTR m_wszFileName;
+ };
+
+ class FileNameHashTraits : public NoRemoveSHashTraits< DefaultSHashTraits< FileNameMapEntry > >
+ {
+ public:
+ typedef PCWSTR key_t;
+ static const FileNameMapEntry Null() { FileNameMapEntry e; e.m_wszFileName = nullptr; return e; }
+ static bool IsNull(const FileNameMapEntry & e) { return e.m_wszFileName == nullptr; }
+ static const key_t GetKey(const FileNameMapEntry & e)
+ {
+ key_t key;
+ key = e.m_wszFileName;
+ return key;
+ }
+ static count_t Hash(const key_t &str) { return HashiString(str); }
+ static BOOL Equals(const key_t &lhs, const key_t &rhs) { LIMITED_METHOD_CONTRACT; return (_wcsicmp(lhs, rhs) == 0); }
+ };
+
+ typedef SHash<FileNameHashTraits> TpaFileNameHash;
+
+ // Entry in SHash table that maps namespace to list of files
+ struct SimpleNameToFileNameMapEntry
+ {
+ LPWSTR m_wszSimpleName;
+ LPWSTR m_wszILFileName;
+ LPWSTR m_wszNIFileName;
+ };
+
+ // SHash traits for Namespace -> FileNameList hash
+ class SimpleNameToFileNameMapTraits : public NoRemoveSHashTraits< DefaultSHashTraits< SimpleNameToFileNameMapEntry > >
+ {
+ public:
+ typedef PCWSTR key_t;
+ static const SimpleNameToFileNameMapEntry Null() { SimpleNameToFileNameMapEntry e; e.m_wszSimpleName = nullptr; return e; }
+ static bool IsNull(const SimpleNameToFileNameMapEntry & e) { return e.m_wszSimpleName == nullptr; }
+ static const key_t GetKey(const SimpleNameToFileNameMapEntry & e)
+ {
+ key_t key;
+ key = e.m_wszSimpleName;
+ return key;
+ }
+ static count_t Hash(const key_t &str) { return HashiString(str); }
+ static BOOL Equals(const key_t &lhs, const key_t &rhs) { LIMITED_METHOD_CONTRACT; return (_wcsicmp(lhs, rhs) == 0); }
+
+ void OnDestructPerEntryCleanupAction(const SimpleNameToFileNameMapEntry & e)
+ {
+ if (e.m_wszILFileName == nullptr && e.m_wszNIFileName == nullptr)
+ {
+ // Don't delete simple name here since it's a filename only entry and will be cleaned up
+ // by the SimpleName -> FileName entry which reuses the same filename pointer.
+ return;
+ }
+
+ if (e.m_wszSimpleName != nullptr)
+ {
+ delete [] e.m_wszSimpleName;
+ }
+ if (e.m_wszILFileName != nullptr)
+ {
+ delete [] e.m_wszILFileName;
+ }
+ if (e.m_wszNIFileName != nullptr)
+ {
+ delete [] e.m_wszNIFileName;
+ }
+ }
+ static const bool s_DestructPerEntryCleanupAction = true;
+ };
+
+ typedef SHash<SimpleNameToFileNameMapTraits> SimpleNameToFileNameMap;
+
+ class ApplicationContext
+ : public IUnknown
+ {
+ public:
+ // IUnknown methods
+ STDMETHOD(QueryInterface)(REFIID riid,
+ void **ppv);
+ STDMETHOD_(ULONG, AddRef)();
+ STDMETHOD_(ULONG, Release)();
+
+ // ApplicationContext methods
+ ApplicationContext();
+ virtual ~ApplicationContext();
+ HRESULT Init();
+
+ inline SString &GetApplicationName();
+ inline DWORD GetAppDomainId();
+ inline void SetAppDomainId(DWORD dwAppDomainId);
+
+ HRESULT SetupBindingPaths(/* in */ SString &sTrustedPlatformAssemblies,
+ /* in */ SString &sPlatformResourceRoots,
+ /* in */ SString &sAppPaths,
+ /* in */ SString &sAppNiPaths,
+ /* in */ BOOL fAcquireLock);
+
+ HRESULT GetAssemblyIdentity(/* in */ LPCSTR szTextualIdentity,
+ /* in */ AssemblyIdentityUTF8 **ppAssemblyIdentity);
+
+ // Getters/Setter
+ inline ExecutionContext *GetExecutionContext();
+ inline InspectionContext *GetInspectionContext();
+ inline FailureCache *GetFailureCache();
+ inline HRESULT AddToFailureCache(SString &assemblyNameOrPath,
+ HRESULT hrBindResult);
+ inline StringArrayList *GetAppPaths();
+ inline SimpleNameToFileNameMap *GetTpaList();
+ inline TpaFileNameHash *GetTpaFileNameList();
+ inline StringArrayList *GetPlatformResourceRoots();
+ inline StringArrayList *GetAppNiPaths();
+
+ // Using a host-configured Trusted Platform Assembly list
+ bool IsTpaListProvided();
+ inline CRITSEC_COOKIE GetCriticalSectionCookie();
+ inline LONG GetVersion();
+ inline void IncrementVersion();
+
+#ifdef FEATURE_VERSIONING_LOG
+ inline BindingLog *GetBindingLog();
+ inline void ClearBindingLog();
+#endif // FEATURE_VERSIONING_LOG
+
+ protected:
+ LONG m_cRef;
+ Volatile<LONG> m_cVersion;
+ SString m_applicationName;
+ DWORD m_dwAppDomainId;
+ ExecutionContext *m_pExecutionContext;
+ InspectionContext *m_pInspectionContext;
+ FailureCache *m_pFailureCache;
+ CRITSEC_COOKIE m_contextCS;
+#ifdef FEATURE_VERSIONING_LOG
+ BindingLog m_bindingLog;
+#endif // FEATURE_VERSIONING_LOG
+
+ AssemblyIdentityCache m_assemblyIdentityCache;
+
+ StringArrayList m_platformResourceRoots;
+ StringArrayList m_appPaths;
+ StringArrayList m_appNiPaths;
+
+ SimpleNameToFileNameMap * m_pTrustedPlatformAssemblyMap;
+ TpaFileNameHash * m_pFileNameHash;
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ bool m_fCanExplicitlyBindToNativeImages;
+public:
+ inline void SetExplicitBindToNativeImages(bool fCanExplicitlyBindToNativeImages)
+ {
+ m_fCanExplicitlyBindToNativeImages = fCanExplicitlyBindToNativeImages;
+ }
+
+ inline bool CanExplicitlyBindToNativeImages()
+ {
+ return m_fCanExplicitlyBindToNativeImages;
+ }
+protected:
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER)
+ };
+
+#include "applicationcontext.inl"
+
+};
+
+#endif
diff --git a/src/binder/inc/applicationcontext.inl b/src/binder/inc/applicationcontext.inl
new file mode 100644
index 0000000000..b57562f4d5
--- /dev/null
+++ b/src/binder/inc/applicationcontext.inl
@@ -0,0 +1,110 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// ApplicationContext.inl
+//
+
+
+//
+// Implements inlined methods of ApplicationContext
+//
+// ============================================================
+
+#ifndef __BINDER__APPLICATION_CONTEXT_INL__
+#define __BINDER__APPLICATION_CONTEXT_INL__
+
+LONG ApplicationContext::GetVersion()
+{
+ return m_cVersion;
+}
+
+void ApplicationContext::IncrementVersion()
+{
+ InterlockedIncrement(&m_cVersion);
+}
+
+SString &ApplicationContext::GetApplicationName()
+{
+ return m_applicationName;
+}
+
+DWORD ApplicationContext::GetAppDomainId()
+{
+ return m_dwAppDomainId;
+}
+
+void ApplicationContext::SetAppDomainId(DWORD dwAppDomainId)
+{
+ m_dwAppDomainId = dwAppDomainId;
+}
+
+ExecutionContext *ApplicationContext::GetExecutionContext()
+{
+ return m_pExecutionContext;
+}
+
+InspectionContext *ApplicationContext::GetInspectionContext()
+{
+ return m_pInspectionContext;
+}
+
+FailureCache *ApplicationContext::GetFailureCache()
+{
+ _ASSERTE(m_pFailureCache != NULL);
+ return m_pFailureCache;
+}
+
+HRESULT ApplicationContext::AddToFailureCache(SString &assemblyNameOrPath,
+ HRESULT hrBindResult)
+{
+ HRESULT hr = GetFailureCache()->Add(assemblyNameOrPath, hrBindResult);
+ IncrementVersion();
+ return hr;
+}
+
+StringArrayList *ApplicationContext::GetAppPaths()
+{
+ return &m_appPaths;
+}
+
+SimpleNameToFileNameMap * ApplicationContext::GetTpaList()
+{
+ return m_pTrustedPlatformAssemblyMap;
+}
+
+TpaFileNameHash * ApplicationContext::GetTpaFileNameList()
+{
+ return m_pFileNameHash;
+}
+
+StringArrayList * ApplicationContext::GetPlatformResourceRoots()
+{
+ return &m_platformResourceRoots;
+}
+
+StringArrayList * ApplicationContext::GetAppNiPaths()
+{
+ return &m_appNiPaths;
+}
+
+CRITSEC_COOKIE ApplicationContext::GetCriticalSectionCookie()
+{
+ return m_contextCS;
+}
+
+#ifdef FEATURE_VERSIONING_LOG
+BindingLog *ApplicationContext::GetBindingLog()
+{
+ return &m_bindingLog;
+}
+
+void ApplicationContext::ClearBindingLog()
+{
+ m_bindingLog.SetDebugLog(NULL);
+}
+#endif // FEATURE_VERSIONING_LOG
+
+
+#endif
diff --git a/src/binder/inc/assembly.hpp b/src/binder/inc/assembly.hpp
new file mode 100644
index 0000000000..5b8425a3d1
--- /dev/null
+++ b/src/binder/inc/assembly.hpp
@@ -0,0 +1,222 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Assembly.hpp
+//
+
+
+//
+// Defines the Assembly class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_HPP__
+#define __BINDER__ASSEMBLY_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyname.hpp"
+
+#include "corpriv.h"
+#include "clrprivbinding.h"
+
+#if !defined(FEATURE_FUSION)
+#include "clrprivbindercoreclr.h"
+#endif // !defined(FEATURE_FUSION)
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+#include "clrprivbinderassemblyloadcontext.h"
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+STDAPI BinderAcquirePEImage(LPCTSTR szAssemblyPath,
+ PEImage **ppPEImage,
+ PEImage **ppNativeImage,
+ BOOL fExplicitBindToNativeImage);
+
+STDAPI BinderAcquireImport(PEImage *pPEImage,
+ IMDInternalImport **pIMetaDataAssemblyImport,
+ DWORD *pdwPAFlags,
+ BOOL bNativeImage);
+
+STDAPI BinderHasNativeHeader(PEImage *pPEImage,
+ BOOL *result);
+
+STDAPI BinderGetImagePath(PEImage *pPEImage,
+ SString &imagePath);
+
+STDAPI BinderReleasePEImage(PEImage *pPEImage);
+
+STDAPI BinderAddRefPEImage(PEImage *pPEImage);
+
+namespace BINDER_SPACE
+{
+
+ // An assembly represents a particular set of bits. However we extend this to
+ // also include whether those bits have precompiled information (NGEN). Thus
+ // and assembly knows whether it has an NGEN image or not.
+ //
+ // This allows us to preferentially use the NGEN image if it is available.
+ class Assembly
+ : public ICLRPrivAssembly
+ {
+ public:
+ // --------------------------------------------------------------------
+ // IUnknown methods
+ // --------------------------------------------------------------------
+ STDMETHOD(QueryInterface)(REFIID riid,
+ void ** ppv);
+ STDMETHOD_(ULONG, AddRef)();
+ STDMETHOD_(ULONG, Release)();
+
+ // --------------------------------------------------------------------
+ // ICLRPrivAssembly methods
+ // --------------------------------------------------------------------
+ LPCWSTR GetSimpleName();
+
+ STDMETHOD(BindAssemblyByName)(
+ IAssemblyName * pIAssemblyName,
+ ICLRPrivAssembly ** ppAssembly);
+
+ STDMETHOD(IsShareable)(BOOL * pbIsShareable);
+
+ STDMETHOD(GetAvailableImageTypes)(PDWORD pdwImageTypes);
+
+ STDMETHOD(GetImageResource)(
+ DWORD dwImageType,
+ DWORD *pdwImageType,
+ ICLRPrivResource ** ppIResource);
+
+ STDMETHOD(VerifyBind)(
+ IAssemblyName * pIAssemblyName,
+ ICLRPrivAssembly *pAssembly,
+ ICLRPrivAssemblyInfo *pAssemblyInfo);
+
+ STDMETHOD(GetBinderID)(UINT_PTR *pBinderId);
+
+ STDMETHOD(FindAssemblyBySpec)(
+ LPVOID pvAppDomain,
+ LPVOID pvAssemblySpec,
+ HRESULT * pResult,
+ ICLRPrivAssembly ** ppAssembly);
+
+ STDMETHOD(GetBinderFlags)(DWORD *pBinderFlags);
+
+ // --------------------------------------------------------------------
+ // Assembly methods
+ // --------------------------------------------------------------------
+ Assembly();
+ virtual ~Assembly();
+
+ HRESULT Init(/* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* in */ PEKIND PeKind,
+ /* in */ PEImage *pPEImage,
+ /* in */ PEImage *pPENativeImage,
+ /* in */ SString &assemblyPath,
+ /* in */ BOOL fInspectionOnly,
+ /* in */ BOOL fIsInGAC);
+
+ // Enumerates dependent assemblies
+ HRESULT GetNextAssemblyNameRef(/* in */ DWORD nIndex,
+ /* out */ AssemblyName **ppAssemblyName);
+
+ inline AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE);
+ inline BOOL GetIsInGAC();
+ inline BOOL GetIsDynamicBind();
+ inline void SetIsDynamicBind(BOOL fIsDynamicBind);
+ inline BOOL GetIsByteArray();
+ inline void SetIsByteArray(BOOL fIsByteArray);
+ inline BOOL GetIsSharable();
+ inline void SetIsSharable(BOOL fIsSharable);
+ inline SString &GetPath();
+
+ inline PEImage *GetPEImage(BOOL fAddRef = FALSE);
+ inline PEImage *GetNativePEImage(BOOL fAddRef = FALSE);
+ inline PEImage *GetNativeOrILPEImage(BOOL fAddRef = FALSE);
+
+ HRESULT GetMVID(GUID *pMVID);
+
+ static PEKIND GetSystemArchitecture();
+ static BOOL IsValidArchitecture(PEKIND kArchitecture);
+
+#ifndef CROSSGEN_COMPILE
+ protected:
+#endif
+ // Asssembly Flags
+ enum
+ {
+ FLAG_NONE = 0x00,
+ FLAG_INSPECTION_ONLY = 0x01,
+ FLAG_IS_IN_GAC = 0x02,
+ FLAG_IS_DYNAMIC_BIND = 0x04,
+ FLAG_IS_BYTE_ARRAY = 0x08,
+ FLAG_IS_SHARABLE = 0x10
+ };
+
+ inline void SetPEImage(PEImage *pPEImage);
+ inline void SetNativePEImage(PEImage *pNativePEImage);
+
+ inline void SetAssemblyName(AssemblyName *pAssemblyName,
+ BOOL fAddRef = TRUE);
+ inline BOOL GetInspectionOnly();
+ inline void SetInspectionOnly(BOOL fInspectionOnly);
+ inline void SetIsInGAC(BOOL fIsInGAC);
+
+ inline IMDInternalImport *GetMDImport();
+ inline void SetMDImport(IMDInternalImport *pMDImport);
+ inline mdAssembly *GetAssemblyRefTokens();
+
+ inline DWORD GetNbAssemblyRefTokens();
+ inline void SetNbAsssemblyRefTokens(DWORD dwCAssemblyRefTokens);
+
+ LONG m_cRef;
+ PEImage *m_pPEImage;
+ PEImage *m_pNativePEImage;
+ IMDInternalImport *m_pMDImport;
+ mdAssembly *m_pAssemblyRefTokens;
+ DWORD m_dwCAssemblyRefTokens;
+ AssemblyName *m_pAssemblyName;
+ SString m_assemblyPath;
+ DWORD m_dwAssemblyFlags;
+ ICLRPrivBinder *m_pBinder;
+
+ // Nested class used to implement ICLRPriv binder related interfaces
+ class CLRPrivResourceAssembly :
+ public ICLRPrivResource, public ICLRPrivResourceAssembly
+ {
+public:
+ STDMETHOD(QueryInterface)(REFIID riid, void ** ppv);
+ STDMETHOD_(ULONG, AddRef)();
+ STDMETHOD_(ULONG, Release)();
+ STDMETHOD(GetResourceType)(IID *pIID);
+ STDMETHOD(GetAssembly)(LPVOID *ppAssembly);
+ } m_clrPrivRes;
+
+ inline void SetBinder(ICLRPrivBinder *pBinder)
+ {
+ _ASSERTE(m_pBinder == NULL || m_pBinder == pBinder);
+ m_pBinder = pBinder;
+ }
+
+ inline ICLRPrivBinder* GetBinder()
+ {
+ return m_pBinder;
+ }
+
+#if !defined(FEATURE_FUSION)
+ friend class ::CLRPrivBinderCoreCLR;
+#endif // !defined(FEATURE_FUSION)
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ friend class ::CLRPrivBinderAssemblyLoadContext;
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ };
+
+ // This is a fast version which goes around the COM interfaces and directly
+ // casts the interfaces and does't AddRef
+ inline BINDER_SPACE::Assembly * GetAssemblyFromPrivAssemblyFast(ICLRPrivAssembly *pPrivAssembly);
+
+#include "assembly.inl"
+};
+
+#endif
diff --git a/src/binder/inc/assembly.inl b/src/binder/inc/assembly.inl
new file mode 100644
index 0000000000..92f9c72e6d
--- /dev/null
+++ b/src/binder/inc/assembly.inl
@@ -0,0 +1,218 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Assembly.inl
+//
+
+
+//
+// Implements the inline methods of Assembly
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_INL__
+#define __BINDER__ASSEMBLY_INL__
+
+PEImage *Assembly::GetPEImage(BOOL fAddRef /* = FALSE */)
+{
+ PEImage *pPEImage = m_pPEImage;
+
+ if (fAddRef)
+ {
+ BinderAddRefPEImage(pPEImage);
+ }
+
+ return pPEImage;
+}
+
+PEImage *Assembly::GetNativePEImage(BOOL fAddRef /* = FALSE */)
+{
+ PEImage *pNativePEImage = m_pNativePEImage;
+
+ if (fAddRef)
+ {
+ BinderAddRefPEImage(pNativePEImage);
+ }
+
+ return pNativePEImage;
+}
+
+PEImage *Assembly::GetNativeOrILPEImage(BOOL fAddRef /* = FALSE */)
+{
+ PEImage* pPEImage = GetNativePEImage(fAddRef);
+ if (pPEImage == NULL)
+ pPEImage = GetPEImage(fAddRef);
+ return pPEImage;
+}
+
+void Assembly::SetPEImage(PEImage *pPEImage)
+{
+ BinderAddRefPEImage(pPEImage);
+ m_pPEImage = pPEImage;
+}
+
+void Assembly::SetNativePEImage(PEImage *pNativePEImage)
+{
+ BinderAddRefPEImage(pNativePEImage);
+ m_pNativePEImage = pNativePEImage;
+}
+
+AssemblyName *Assembly::GetAssemblyName(BOOL fAddRef /* = FALSE */)
+{
+ AssemblyName *pAssemblyName = m_pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+ return pAssemblyName;
+}
+
+void Assembly::SetAssemblyName(AssemblyName *pAssemblyName,
+ BOOL fAddRef /* = TRUE */)
+{
+ SAFE_RELEASE(m_pAssemblyName);
+
+ m_pAssemblyName = pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+}
+
+BOOL Assembly::GetInspectionOnly()
+{
+ return ((m_dwAssemblyFlags & FLAG_INSPECTION_ONLY) != 0);
+}
+
+void Assembly::SetInspectionOnly(BOOL fInspectionOnly)
+{
+ if (fInspectionOnly)
+ {
+ m_dwAssemblyFlags |= FLAG_INSPECTION_ONLY;
+ }
+ else
+ {
+ m_dwAssemblyFlags &= ~FLAG_INSPECTION_ONLY;
+ }
+}
+
+BOOL Assembly::GetIsInGAC()
+{
+ return ((m_dwAssemblyFlags & FLAG_IS_IN_GAC) != 0);
+}
+
+void Assembly::SetIsInGAC(BOOL fIsInGAC)
+{
+ if (fIsInGAC)
+ {
+ m_dwAssemblyFlags |= FLAG_IS_IN_GAC;
+ }
+ else
+ {
+ m_dwAssemblyFlags &= ~FLAG_IS_IN_GAC;
+ }
+}
+
+BOOL Assembly::GetIsDynamicBind()
+{
+ return ((m_dwAssemblyFlags & FLAG_IS_DYNAMIC_BIND) != 0);
+}
+
+void Assembly::SetIsDynamicBind(BOOL fIsDynamicBind)
+{
+ if (fIsDynamicBind)
+ {
+ m_dwAssemblyFlags |= FLAG_IS_DYNAMIC_BIND;
+ }
+ else
+ {
+ m_dwAssemblyFlags &= ~FLAG_IS_DYNAMIC_BIND;
+ }
+}
+
+BOOL Assembly::GetIsByteArray()
+{
+ return ((m_dwAssemblyFlags & FLAG_IS_BYTE_ARRAY) != 0);
+}
+
+void Assembly::SetIsByteArray(BOOL fIsByteArray)
+{
+ if (fIsByteArray)
+ {
+ m_dwAssemblyFlags |= FLAG_IS_BYTE_ARRAY;
+ }
+ else
+ {
+ m_dwAssemblyFlags &= ~FLAG_IS_BYTE_ARRAY;
+ }
+}
+
+BOOL Assembly::GetIsSharable()
+{
+ return ((m_dwAssemblyFlags & FLAG_IS_SHARABLE) != 0);
+}
+
+void Assembly::SetIsSharable(BOOL fIsSharable)
+{
+ if (fIsSharable)
+ {
+ m_dwAssemblyFlags |= FLAG_IS_SHARABLE;
+ }
+ else
+ {
+ m_dwAssemblyFlags &= ~FLAG_IS_SHARABLE;
+ }
+}
+
+SString &Assembly::GetPath()
+{
+ return m_assemblyPath;
+}
+
+IMDInternalImport *Assembly::GetMDImport()
+{
+ return m_pMDImport;
+}
+
+void Assembly::SetMDImport(IMDInternalImport *pMDImport)
+{
+ SAFE_RELEASE(m_pMDImport);
+
+ m_pMDImport = pMDImport;
+ m_pMDImport->AddRef();
+}
+
+mdAssembly *Assembly::GetAssemblyRefTokens()
+{
+ return m_pAssemblyRefTokens;
+}
+
+DWORD Assembly::GetNbAssemblyRefTokens()
+{
+ return m_dwCAssemblyRefTokens;
+}
+
+void Assembly::SetNbAsssemblyRefTokens(DWORD dwCAssemblyRefTokens)
+{
+ m_dwCAssemblyRefTokens = dwCAssemblyRefTokens;
+}
+
+BINDER_SPACE::Assembly* GetAssemblyFromPrivAssemblyFast(ICLRPrivAssembly *pPrivAssembly)
+{
+#ifdef _DEBUG
+ if(pPrivAssembly != nullptr)
+ {
+ // Ensure the pPrivAssembly we are about to cast is indeed a valid Assembly
+ DWORD dwImageType = 0;
+ pPrivAssembly->GetAvailableImageTypes(&dwImageType);
+ _ASSERTE((dwImageType & ASSEMBLY_IMAGE_TYPE_ASSEMBLY) == ASSEMBLY_IMAGE_TYPE_ASSEMBLY);
+ }
+#endif
+ return (BINDER_SPACE::Assembly *)pPrivAssembly;
+}
+
+#endif
diff --git a/src/binder/inc/assemblybinder.hpp b/src/binder/inc/assemblybinder.hpp
new file mode 100644
index 0000000000..3a1f1e45fd
--- /dev/null
+++ b/src/binder/inc/assemblybinder.hpp
@@ -0,0 +1,178 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyBinder.hpp
+//
+
+
+//
+// Defines the AssemblyBinder class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_BINDER_HPP__
+#define __BINDER__ASSEMBLY_BINDER_HPP__
+
+#include "bindertypes.hpp"
+#include "bindresult.hpp"
+#include "coreclrbindercommon.h"
+
+class CLRPrivBinderAssemblyLoadContext;
+class CLRPrivBinderCoreCLR;
+
+namespace BINDER_SPACE
+{
+ typedef enum
+ {
+ kBindingStoreGAC = 0x01,
+ kBindingStoreManifest = 0x02,
+ kBindingStoreHost = 0x04,
+ kBindingStoreContext = 0x08
+ } BindingStore;
+
+ class AssemblyBinder
+ {
+ public:
+ static HRESULT Startup();
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ static HRESULT BindAssembly(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ LPCWSTR szCodeBase,
+ /* in */ PEAssembly *pParentAssembly,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* in */ bool excludeAppPaths,
+ /* out */ Assembly **ppAssembly);
+
+ static HRESULT BindToSystem(/* in */ SString &systemDirectory,
+ /* out */ Assembly **ppSystemAssembly,
+ /* in */ bool fBindToNativeImage);
+
+ static HRESULT BindToSystemSatellite(/* in */ SString &systemDirectory,
+ /* in */ SString &simpleName,
+ /* in */ SString &cultureName,
+ /* out */ Assembly **ppSystemAssembly);
+
+ static HRESULT GetAssemblyFromImage(/* in */ PEImage *pPEImage,
+ /* in */ PEImage *pNativePEImage,
+ /* out */ Assembly **ppAssembly);
+
+ // Special assembly binder entry point for byte arrays
+ static HRESULT PreBindByteArray(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ PEImage *pPEImage,
+ /* in */ BOOL fInspectionOnly);
+
+ static HRESULT GetAssembly(/* in */ SString &assemblyPath,
+ /* in */ BOOL fInspectionOnly,
+ /* in */ BOOL fIsInGAC,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* out */ Assembly **ppAssembly,
+ /* in */ LPCTSTR szMDAssemblyPath = NULL);
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ static HRESULT BindUsingHostAssemblyResolver (/* in */ INT_PTR pManagedAssemblyLoadContextToBindWithin,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ IAssemblyName *pIAssemblyName,
+ /* in */ CLRPrivBinderCoreCLR *pTPABinder,
+ /* out */ Assembly **ppAssembly);
+
+ static HRESULT BindUsingPEImage(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BINDER_SPACE::AssemblyName *pAssemblyName,
+ /* in */ PEImage *pPEImage,
+ /* in */ PEKIND peKind,
+ /* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* [retval] [out] */ Assembly **ppAssembly);
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ static HRESULT TranslatePEToArchitectureType(DWORD *pdwPAFlags, PEKIND *PeKind);
+
+ protected:
+ enum
+ {
+ BIND_NONE = 0x00,
+ BIND_CACHE_FAILURES = 0x01,
+ BIND_CACHE_RERUN_BIND = 0x02,
+ BIND_IGNORE_DYNAMIC_BINDS = 0x04
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ ,
+ BIND_IGNORE_REFDEF_MATCH = 0x8
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ };
+
+ static BOOL IgnoreDynamicBinds(DWORD dwBindFlags)
+ {
+ return ((dwBindFlags & BIND_IGNORE_DYNAMIC_BINDS) != 0);
+ }
+
+ static BOOL CacheBindFailures(DWORD dwBindFlags)
+ {
+ return ((dwBindFlags & BIND_CACHE_FAILURES) != 0);
+ }
+
+ static BOOL RerunBind(DWORD dwBindFlags)
+ {
+ return ((dwBindFlags & BIND_CACHE_RERUN_BIND) != 0);
+ }
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ static BOOL IgnoreRefDefMatch(DWORD dwBindFlags)
+ {
+ return ((dwBindFlags & BIND_IGNORE_REFDEF_MATCH) != 0);
+ }
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ static HRESULT BindByName(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ DWORD dwBindFlags,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ static HRESULT BindWhereRef(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ PathString &assemblyPath,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ static HRESULT BindLocked(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ DWORD dwBindFlags,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+ static HRESULT BindLockedOrService(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ static HRESULT FindInExecutionContext(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* out */ ContextEntry **ppContextEntry);
+
+ static HRESULT BindByTpaList(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pRequestedAssemblyName,
+ /* in */ BOOL fInspectionOnly,
+ /* in */ bool excludeAppPaths,
+ /* out */ BindResult *pBindResult);
+
+ static HRESULT Register(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BOOL fInspectionOnly,
+ /* in */ BindResult *pBindResult);
+ static HRESULT RegisterAndGetHostChosen(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ LONG kContextVersion,
+ /* in */ BindResult *pBindResult,
+ /* out */ BindResult *pHostBindResult);
+
+ static HRESULT OtherBindInterfered(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ BindResult *pBindResult);
+ };
+};
+
+#endif
diff --git a/src/binder/inc/assemblyentry.hpp b/src/binder/inc/assemblyentry.hpp
new file mode 100644
index 0000000000..d0bf27b2d5
--- /dev/null
+++ b/src/binder/inc/assemblyentry.hpp
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyEntry.hpp
+//
+
+
+//
+// Defines the AssemblyEntry class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_ENTRY_HPP__
+#define __BINDER__ASSEMBLY_ENTRY_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyname.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyEntry
+ {
+ public:
+ AssemblyEntry()
+ {
+ m_pAssemblyName = NULL;
+ }
+ virtual ~AssemblyEntry()
+ {
+ SAFE_RELEASE(m_pAssemblyName);
+ }
+
+ AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE)
+ {
+ AssemblyName *pAssemblyName = m_pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+ return pAssemblyName;
+ }
+
+ void SetAssemblyName(AssemblyName *pAssemblyName, BOOL fAddRef = TRUE)
+ {
+ SAFE_RELEASE(m_pAssemblyName);
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+
+ m_pAssemblyName = pAssemblyName;
+ }
+ protected:
+ AssemblyName *m_pAssemblyName;
+ };
+};
+
+#endif
diff --git a/src/binder/inc/assemblyhashtraits.hpp b/src/binder/inc/assemblyhashtraits.hpp
new file mode 100644
index 0000000000..285368f687
--- /dev/null
+++ b/src/binder/inc/assemblyhashtraits.hpp
@@ -0,0 +1,59 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyHashTraits.hpp
+//
+
+
+//
+// Defines the AssemblyHashTraits template class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_HASH_TRAITS_HPP__
+#define __BINDER__ASSEMBLY_HASH_TRAITS_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyentry.hpp"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ template<typename HashEntry, DWORD dwAssemblyNameFlags>
+ class AssemblyHashTraits : public NoRemoveSHashTraits<DefaultSHashTraits<HashEntry> >
+ {
+ public:
+ typedef typename NoRemoveSHashTraits<DefaultSHashTraits<HashEntry> >::element_t element_t;
+ typedef typename NoRemoveSHashTraits<DefaultSHashTraits<HashEntry> >::count_t count_t;
+
+ typedef AssemblyName* key_t;
+
+ // GetKey, Equals and Hash can throw due to SString
+ static const bool s_NoThrow = false;
+
+ static key_t GetKey(element_t pAssemblyEntry)
+ {
+ return pAssemblyEntry->GetAssemblyName();
+ }
+ static BOOL Equals(key_t pAssemblyName1, key_t pAssemblyName2)
+ {
+ return pAssemblyName1->Equals(pAssemblyName2, dwAssemblyNameFlags);
+ }
+ static count_t Hash(key_t pAssemblyName)
+ {
+ return pAssemblyName->Hash(dwAssemblyNameFlags);
+ }
+ static const element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &assemblyEntry)
+ {
+ return (assemblyEntry == NULL);
+ }
+ };
+};
+
+#endif
diff --git a/src/binder/inc/assemblyidentity.hpp b/src/binder/inc/assemblyidentity.hpp
new file mode 100644
index 0000000000..4d7c7f1bac
--- /dev/null
+++ b/src/binder/inc/assemblyidentity.hpp
@@ -0,0 +1,149 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyIdentity.hpp
+//
+
+
+//
+// Defines the AssemblyIdentity class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_IDENTITY_HPP__
+#define __BINDER__ASSEMBLY_IDENTITY_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyversion.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentity
+ {
+ public:
+ enum
+ {
+ IDENTITY_FLAG_EMPTY = 0x000,
+ IDENTITY_FLAG_SIMPLE_NAME = 0x001,
+ IDENTITY_FLAG_VERSION = 0x002,
+ IDENTITY_FLAG_PUBLIC_KEY_TOKEN = 0x004,
+ IDENTITY_FLAG_PUBLIC_KEY = 0x008,
+ IDENTITY_FLAG_CULTURE = 0x010,
+ IDENTITY_FLAG_LANGUAGE = 0x020,
+ IDENTITY_FLAG_PROCESSOR_ARCHITECTURE = 0x040,
+ IDENTITY_FLAG_RETARGETABLE = 0x080,
+ IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL = 0x100,
+ IDENTITY_FLAG_CUSTOM = 0x200,
+ IDENTITY_FLAG_CUSTOM_NULL = 0x400,
+ IDENTITY_FLAG_CONTENT_TYPE = 0x800,
+ IDENTITY_FLAG_FULL_NAME = (IDENTITY_FLAG_SIMPLE_NAME |
+ IDENTITY_FLAG_VERSION)
+ } IdentityFlags;
+
+ AssemblyIdentity()
+ {
+ m_dwIdentityFlags = IDENTITY_FLAG_EMPTY;
+ m_kProcessorArchitecture = peNone;
+ m_kContentType = AssemblyContentType_Default;
+
+ // Need to pre-populate SBuffers because of bogus asserts
+ static const BYTE byteArr[] = { 0 };
+ m_publicKeyOrTokenBLOB.SetImmutable(byteArr, sizeof(byteArr));
+ m_customBLOB.SetImmutable(byteArr, sizeof(byteArr));
+ }
+ ~AssemblyIdentity()
+ {
+ // Nothing to do here
+ }
+
+ static BOOL Have(DWORD dwUseIdentityFlags, DWORD dwIdentityFlags)
+ {
+ return ((dwUseIdentityFlags & dwIdentityFlags) != 0);
+ }
+
+ BOOL Have(DWORD dwIdentityFlags)
+ {
+ return Have(m_dwIdentityFlags, dwIdentityFlags);
+ }
+
+ void SetHave(DWORD dwIdentityFlags)
+ {
+ m_dwIdentityFlags |= dwIdentityFlags;
+ }
+
+ void SetClear(DWORD dwIdentityFlags)
+ {
+ m_dwIdentityFlags &= ~dwIdentityFlags;
+ }
+
+ void CloneInto(AssemblyIdentity *pAssemblyIdentity)
+ {
+ pAssemblyIdentity->m_simpleName.Set(m_simpleName);
+ pAssemblyIdentity->m_simpleName.Normalize();
+ pAssemblyIdentity->m_version.SetVersion(&m_version);
+ pAssemblyIdentity->m_cultureOrLanguage.Set(m_cultureOrLanguage);
+ pAssemblyIdentity->m_cultureOrLanguage.Normalize();
+ pAssemblyIdentity->m_publicKeyOrTokenBLOB.Set(m_publicKeyOrTokenBLOB);
+ pAssemblyIdentity->m_kProcessorArchitecture = m_kProcessorArchitecture;
+ pAssemblyIdentity->m_kContentType = m_kContentType;
+ pAssemblyIdentity->m_customBLOB.Set(m_customBLOB);
+ pAssemblyIdentity->m_dwIdentityFlags = m_dwIdentityFlags;
+ }
+
+ SString m_simpleName;
+ AssemblyVersion m_version;
+ SString m_cultureOrLanguage;
+ SBuffer m_publicKeyOrTokenBLOB;
+ PEKIND m_kProcessorArchitecture;
+ AssemblyContentType m_kContentType;
+ SBuffer m_customBLOB;
+ DWORD m_dwIdentityFlags;
+ };
+
+ class AssemblyIdentityUTF8 : public AssemblyIdentity
+ {
+ public:
+ AssemblyIdentityUTF8()
+ {
+ m_szSimpleNameUTF8 = NULL;
+ m_szCultureOrLanguageUTF8 = NULL;
+ }
+
+ void PopulateUTF8Fields()
+ {
+ m_szSimpleNameUTF8 = m_simpleName.GetUTF8(sSimpleNameBuffer);
+
+ if (Have(IDENTITY_FLAG_CULTURE) && !m_cultureOrLanguage.IsEmpty())
+ {
+ m_szCultureOrLanguageUTF8 = m_cultureOrLanguage.GetUTF8(sCultureBuffer);
+ }
+ }
+
+ inline LPCSTR GetSimpleNameUTF8()
+ {
+ return m_szSimpleNameUTF8;
+ }
+
+ inline LPCSTR GetCultureOrLanguageUTF8()
+ {
+ return m_szCultureOrLanguageUTF8;
+ }
+
+ inline const BYTE *GetPublicKeyOrTokenArray()
+ {
+ const BYTE *pPublicKeyOrToken = m_publicKeyOrTokenBLOB;
+
+ return pPublicKeyOrToken;
+ }
+
+ protected:
+ StackScratchBuffer sSimpleNameBuffer;
+ StackScratchBuffer sCultureBuffer;
+ LPCSTR m_szSimpleNameUTF8;
+ LPCSTR m_szCultureOrLanguageUTF8;
+ };
+};
+
+#endif
diff --git a/src/binder/inc/assemblyidentitycache.hpp b/src/binder/inc/assemblyidentitycache.hpp
new file mode 100644
index 0000000000..39ad283175
--- /dev/null
+++ b/src/binder/inc/assemblyidentitycache.hpp
@@ -0,0 +1,116 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyIdentityCache.hpp
+//
+
+
+//
+// Defines the AssemblyIdentityCache class and its helpers
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_IDENTITY_CACHE_HPP__
+#define __BINDER__ASSEMBLY_IDENTITY_CACHE_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyidentity.hpp"
+#include "utils.hpp"
+#include "sstring.h"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityCacheEntry
+ {
+ public:
+ inline AssemblyIdentityCacheEntry()
+ {
+ m_szTextualIdentity = NULL;
+ m_pAssemblyIdentity = NULL;
+ }
+ inline ~AssemblyIdentityCacheEntry()
+ {
+ SAFE_DELETE_ARRAY(m_szTextualIdentity);
+ SAFE_DELETE(m_pAssemblyIdentity);
+ }
+
+ // Getters/Setters
+ inline LPCSTR GetTextualIdentity()
+ {
+ return m_szTextualIdentity;
+ }
+ inline void SetTextualIdentity(LPCSTR szTextualIdentity)
+ {
+ size_t len = strlen(szTextualIdentity) + 1;
+
+ m_szTextualIdentity = new char[len];
+ strcpy_s((LPSTR) m_szTextualIdentity, len, szTextualIdentity);
+ }
+ inline AssemblyIdentityUTF8 *GetAssemblyIdentity()
+ {
+ return m_pAssemblyIdentity;
+ }
+ inline void SetAssemblyIdentity(AssemblyIdentityUTF8 *pAssemblyIdentity)
+ {
+ m_pAssemblyIdentity = pAssemblyIdentity;
+ }
+
+ protected:
+ LPCSTR m_szTextualIdentity;
+ AssemblyIdentityUTF8 *m_pAssemblyIdentity;
+ };
+
+ class AssemblyIdentityHashTraits : public DefaultSHashTraits<AssemblyIdentityCacheEntry *>
+ {
+ public:
+ typedef LPCSTR key_t;
+
+ static key_t GetKey(element_t pAssemblyIdentityCacheEntry)
+ {
+ return pAssemblyIdentityCacheEntry->GetTextualIdentity();
+ }
+ static BOOL Equals(key_t textualIdentity1, key_t textualIdentity2)
+ {
+ if ((textualIdentity1 == NULL) && (textualIdentity2 == NULL))
+ return TRUE;
+ if ((textualIdentity1 == NULL) || (textualIdentity2 == NULL))
+ return FALSE;
+
+ return (strcmp(textualIdentity1, textualIdentity2) == 0);
+ }
+ static count_t Hash(key_t textualIdentity)
+ {
+ if (textualIdentity == NULL)
+ return 0;
+ else
+ return HashStringA(textualIdentity);
+ }
+ static const element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &assemblyIdentityCacheEntry)
+ {
+ return (assemblyIdentityCacheEntry == NULL);
+ }
+
+ };
+
+ class AssemblyIdentityCache : protected SHash<AssemblyIdentityHashTraits>
+ {
+ private:
+ typedef SHash<AssemblyIdentityHashTraits> Hash;
+ public:
+ AssemblyIdentityCache();
+ ~AssemblyIdentityCache();
+
+ HRESULT Add(/* in */ LPCSTR szTextualIdentity,
+ /* in */ AssemblyIdentityUTF8 *pAssemblyIdentity);
+ AssemblyIdentityUTF8 *Lookup(/* in */ LPCSTR szTextualIdentity);
+ };
+};
+
+#endif
diff --git a/src/binder/inc/assemblyname.hpp b/src/binder/inc/assemblyname.hpp
new file mode 100644
index 0000000000..1ce84d1902
--- /dev/null
+++ b/src/binder/inc/assemblyname.hpp
@@ -0,0 +1,112 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyName.hpp
+//
+
+
+//
+// Defines the AssemblyName class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_NAME_HPP__
+#define __BINDER__ASSEMBLY_NAME_HPP__
+
+#include "bindertypes.hpp"
+#include "assemblyidentity.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyName : protected AssemblyIdentity
+ {
+ public:
+ typedef enum
+ {
+ INCLUDE_DEFAULT = 0x00,
+ INCLUDE_VERSION = 0x01,
+ INCLUDE_ARCHITECTURE = 0x02,
+ INCLUDE_RETARGETABLE = 0x04,
+ INCLUDE_CONTENT_TYPE = 0x08,
+ INCLUDE_PUBLIC_KEY_TOKEN = 0x10,
+ EXCLUDE_CULTURE = 0x20
+ } INCLUDE_FLAGS;
+
+ AssemblyName();
+ ~AssemblyName();
+
+ HRESULT Init(/* in */ IMDInternalImport *pIMetaDataAssemblyImport,
+ /* in */ PEKIND PeKind,
+ /* in */ mdAssemblyRef mda = 0,
+ /* in */ BOOL fIsDefinition = TRUE);
+ HRESULT Init(/* in */ SString &assemblyDisplayName);
+ HRESULT Init(/* in */ IAssemblyName *pIAssemblyName);
+ HRESULT CreateFusionName(/* out */ IAssemblyName **ppIAssemblyName);
+
+ ULONG AddRef();
+ ULONG Release();
+
+ // Getters/Setters
+ inline SString &GetSimpleName();
+ inline void SetSimpleName(SString &simpleName);
+ inline AssemblyVersion *GetVersion();
+ inline void SetVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline SString &GetCulture();
+ inline void SetCulture(SString &culture);
+ inline SBuffer &GetPublicKeyTokenBLOB();
+ inline PEKIND GetArchitecture();
+ inline void SetArchitecture(PEKIND kArchitecture);
+ inline AssemblyContentType GetContentType();
+ inline void SetContentType(AssemblyContentType kContentType);
+ inline BOOL GetIsRetargetable();
+ inline void SetIsRetargetable(BOOL fIsRetargetable);
+ inline BOOL GetIsDefinition();
+ inline void SetIsDefinition(BOOL fIsDefinition);
+
+ inline void SetHave(DWORD dwIdentityFlags);
+
+ inline BOOL HaveAssemblyVersion();
+ inline BOOL HaveNeutralCulture();
+
+ SString &GetDeNormalizedCulture();
+ BOOL IsStronglyNamed();
+
+ BOOL IsMscorlib();
+
+ // Translate textual identity into appropriate PEKIND
+ HRESULT SetArchitecture(SString &architecture);
+
+ ULONG Hash(/* in */ DWORD dwIncludeFlags);
+ BOOL Equals(/* in */ AssemblyName *pAssemblyName,
+ /* in */ DWORD dwIncludeFlags);
+
+ // Compare assembly ref with assembly def ignoring assembly version
+ BOOL RefEqualsDef(/* in */ AssemblyName *pAssemblyNameDef,
+ /* in */ BOOL fInspectionOnly);
+
+ HRESULT Clone(/* out */ AssemblyName **ppAssemblyName);
+
+ void GetDisplayName(/* out */ PathString &displayName,
+ /* in */ DWORD dwIncludeFlags);
+
+ static SString &ArchitectureToString(PEKIND kArchitecture);
+ protected:
+ enum
+ {
+ NAME_FLAG_NONE = 0x00,
+ NAME_FLAG_RETARGETABLE = 0x01,
+ NAME_FLAG_DEFINITION = 0x02,
+ };
+
+ SString &GetNormalizedCulture();
+
+ LONG m_cRef;
+ DWORD m_dwNameFlags;
+ };
+
+#include "assemblyname.inl"
+};
+
+#endif
diff --git a/src/binder/inc/assemblyname.inl b/src/binder/inc/assemblyname.inl
new file mode 100644
index 0000000000..3acd39ce0a
--- /dev/null
+++ b/src/binder/inc/assemblyname.inl
@@ -0,0 +1,144 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyName.inl
+//
+
+
+//
+// Implements the inlined methods of AssemblyName class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_NAME_INL__
+#define __BINDER__ASSEMBLY_NAME_INL__
+
+SString &AssemblyName::GetSimpleName()
+{
+ return m_simpleName;
+}
+
+void AssemblyName::SetSimpleName(SString &simpleName)
+{
+ m_simpleName.Set(simpleName);
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+}
+
+AssemblyVersion *AssemblyName::GetVersion()
+{
+ return &m_version;
+}
+
+void AssemblyName::SetVersion(AssemblyVersion *pAssemblyVersion)
+{
+ m_version.SetVersion(pAssemblyVersion);
+}
+
+SString &AssemblyName::GetCulture()
+{
+ return m_cultureOrLanguage;
+}
+
+void AssemblyName::SetCulture(SString &culture)
+{
+ m_cultureOrLanguage.Set(culture);
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+}
+
+SBuffer &AssemblyName::GetPublicKeyTokenBLOB()
+{
+ return m_publicKeyOrTokenBLOB;
+}
+
+PEKIND AssemblyName::GetArchitecture()
+{
+ return m_kProcessorArchitecture;
+}
+
+void AssemblyName::SetArchitecture(PEKIND kArchitecture)
+{
+ m_kProcessorArchitecture = kArchitecture;
+
+ if (kArchitecture != peNone)
+ {
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ else
+ {
+ SetClear(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+}
+
+AssemblyContentType AssemblyName::GetContentType()
+{
+ return m_kContentType;
+}
+
+void AssemblyName::SetContentType(AssemblyContentType kContentType)
+{
+ m_kContentType = kContentType;
+
+ if (kContentType != AssemblyContentType_Default)
+ {
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ }
+ else
+ {
+ SetClear(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ }
+}
+
+BOOL AssemblyName::GetIsRetargetable()
+{
+ return m_dwIdentityFlags & AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE;
+}
+
+void AssemblyName::SetIsRetargetable(BOOL fIsRetargetable)
+{
+ if (fIsRetargetable)
+ {
+ m_dwNameFlags |= NAME_FLAG_RETARGETABLE;
+ SetHave(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ else
+ {
+ m_dwNameFlags &= ~NAME_FLAG_RETARGETABLE;
+ SetClear(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+}
+
+BOOL AssemblyName::GetIsDefinition()
+{
+ return ((m_dwNameFlags & NAME_FLAG_DEFINITION) != 0);
+}
+
+void AssemblyName::SetIsDefinition(BOOL fIsDefinition)
+{
+ if (fIsDefinition)
+ {
+ m_dwNameFlags |= NAME_FLAG_DEFINITION;
+ }
+ else
+ {
+ m_dwNameFlags &= ~NAME_FLAG_DEFINITION;
+ }
+}
+
+void AssemblyName::SetHave(DWORD dwIdentityFlags)
+{
+ AssemblyIdentity::SetHave(dwIdentityFlags);
+}
+
+BOOL AssemblyName::HaveAssemblyVersion()
+{
+ return (m_version.GetMajor() != static_cast<DWORD>(-1));
+}
+
+BOOL AssemblyName::HaveNeutralCulture()
+{
+ return GetDeNormalizedCulture().IsEmpty();
+}
+
+#endif
diff --git a/src/binder/inc/assemblyversion.hpp b/src/binder/inc/assemblyversion.hpp
new file mode 100644
index 0000000000..20ef4ee48c
--- /dev/null
+++ b/src/binder/inc/assemblyversion.hpp
@@ -0,0 +1,60 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyVersion.hpp
+//
+
+
+//
+// Defines the AssemblyVersion class
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_VERSION_HPP__
+#define __BINDER__ASSEMBLY_VERSION_HPP__
+
+#include "bindertypes.hpp"
+#include "textualidentityparser.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyVersion
+ {
+ public:
+ inline AssemblyVersion();
+ inline ~AssemblyVersion();
+
+ inline DWORD GetMajor();
+ inline DWORD GetMinor();
+ inline DWORD GetBuild();
+ inline DWORD GetRevision();
+
+ inline void SetFeatureVersion(/* in */ DWORD dwMajor,
+ /* in */ DWORD dwMinor);
+ inline void SetServiceVersion(/* in */ DWORD dwBuild,
+ /* in */ DWORD dwRevision);
+ inline BOOL SetServiceVersion(/* in */ LPCWSTR pwzVersionStr);
+ inline BOOL SetVersion(/* in */ LPCWSTR pwzVersionStr);
+ inline void SetVersion(AssemblyVersion *pAssemblyVersion);
+
+ inline BOOL IsLargerFeatureVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline BOOL IsEqualFeatureVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline BOOL IsSmallerFeatureVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline BOOL IsEqualServiceVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline BOOL IsLargerServiceVersion(/* in */ AssemblyVersion *pAssemblyVersion);
+ inline BOOL Equals(AssemblyVersion *pAssemblyVersion);
+ inline BOOL IsSmallerOrEqual(AssemblyVersion *pAssemblyVersion);
+ inline BOOL IsLargerOrEqual(AssemblyVersion *pAssemblyVersion);
+ protected:
+ DWORD m_dwMajor;
+ DWORD m_dwMinor;
+ DWORD m_dwBuild;
+ DWORD m_dwRevision;
+ };
+
+#include "assemblyversion.inl"
+};
+
+#endif
diff --git a/src/binder/inc/assemblyversion.inl b/src/binder/inc/assemblyversion.inl
new file mode 100644
index 0000000000..795f8c1765
--- /dev/null
+++ b/src/binder/inc/assemblyversion.inl
@@ -0,0 +1,183 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// AssemblyVersion.inl
+//
+
+
+//
+// Implements the inline methods of AssemblyVersion
+//
+// ============================================================
+
+#ifndef __BINDER__ASSEMBLY_VERSION_INL__
+#define __BINDER__ASSEMBLY_VERSION_INL__
+
+AssemblyVersion::AssemblyVersion()
+{
+ m_dwMajor = m_dwMinor = m_dwBuild = m_dwRevision = static_cast<DWORD>(-1);
+}
+
+AssemblyVersion::~AssemblyVersion()
+{
+ // Noting to do here
+}
+
+DWORD AssemblyVersion::GetMajor()
+{
+ return m_dwMajor;
+}
+
+DWORD AssemblyVersion::GetMinor()
+{
+ return m_dwMinor;
+}
+
+DWORD AssemblyVersion::GetBuild()
+{
+ return m_dwBuild;
+}
+
+DWORD AssemblyVersion::GetRevision()
+{
+ return m_dwRevision;
+}
+
+void AssemblyVersion::SetFeatureVersion(DWORD dwMajor,
+ DWORD dwMinor)
+{
+ m_dwMajor = dwMajor;
+ m_dwMinor = dwMinor;
+}
+
+void AssemblyVersion::SetServiceVersion(DWORD dwBuild,
+ DWORD dwRevision)
+{
+ m_dwBuild = dwBuild;
+ m_dwRevision = dwRevision;
+}
+
+BOOL AssemblyVersion::SetVersion(LPCWSTR pwzVersionStr)
+{
+ SmallStackSString versionString(pwzVersionStr);
+
+ return TextualIdentityParser::ParseVersion(versionString, this);
+}
+
+void AssemblyVersion::SetVersion(AssemblyVersion *pAssemblyVersion)
+{
+ m_dwMajor = pAssemblyVersion->GetMajor();
+ m_dwMinor = pAssemblyVersion->GetMinor();
+ m_dwBuild = pAssemblyVersion->GetBuild();
+ m_dwRevision = pAssemblyVersion->GetRevision();
+}
+
+BOOL AssemblyVersion::IsLargerFeatureVersion(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+
+ if (GetMajor() > pAssemblyVersion->GetMajor())
+ {
+ result = TRUE;
+ }
+ else if ((GetMajor() == pAssemblyVersion->GetMajor()) &&
+ (GetMinor() > pAssemblyVersion->GetMinor()))
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL AssemblyVersion::IsEqualFeatureVersion(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+
+ if ((GetMajor() == pAssemblyVersion->GetMajor()) &&
+ (GetMinor() == pAssemblyVersion->GetMinor()))
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL AssemblyVersion::IsSmallerFeatureVersion(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+
+ if (GetMajor() < pAssemblyVersion->GetMajor())
+ {
+ result = TRUE;
+ }
+ else if ((GetMajor() == pAssemblyVersion->GetMajor()) &&
+ (GetMinor() < pAssemblyVersion->GetMinor()))
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL AssemblyVersion::IsEqualServiceVersion(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+
+ if ((GetBuild() == pAssemblyVersion->GetBuild()) &&
+ (GetRevision() == pAssemblyVersion->GetRevision()))
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL AssemblyVersion::IsLargerServiceVersion(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+
+ if (GetBuild() > pAssemblyVersion->GetBuild())
+ {
+ result = TRUE;
+ }
+ else if ((GetBuild() == pAssemblyVersion->GetBuild()) &&
+ (GetRevision() > pAssemblyVersion->GetRevision()))
+ {
+ result = TRUE;
+ }
+
+ return result;
+}
+
+BOOL AssemblyVersion::Equals(AssemblyVersion *pAssemblyVersion)
+{
+ BOOL result = FALSE;
+ if ((GetMajor() == pAssemblyVersion->GetMajor()) &&
+ (GetMinor() == pAssemblyVersion->GetMinor()) &&
+ (GetBuild() == pAssemblyVersion->GetBuild()) &&
+ (GetRevision() == pAssemblyVersion->GetRevision()))
+ {
+ result = TRUE;
+ }
+ return result;
+}
+
+BOOL AssemblyVersion::IsSmallerOrEqual(AssemblyVersion *pAssemblyVersion)
+{
+ return (Equals(pAssemblyVersion) ||
+ IsSmallerFeatureVersion(pAssemblyVersion) ||
+ (IsEqualFeatureVersion(pAssemblyVersion) &&
+ !IsLargerServiceVersion(pAssemblyVersion)));
+}
+
+BOOL AssemblyVersion::IsLargerOrEqual(AssemblyVersion *pAssemblyVersion)
+{
+ return (Equals(pAssemblyVersion) ||
+ IsLargerFeatureVersion(pAssemblyVersion) ||
+ (IsEqualFeatureVersion(pAssemblyVersion) &&
+ IsLargerServiceVersion(pAssemblyVersion)));
+}
+
+#endif
diff --git a/src/binder/inc/binderinterface.hpp b/src/binder/inc/binderinterface.hpp
new file mode 100644
index 0000000000..a9f0c210ff
--- /dev/null
+++ b/src/binder/inc/binderinterface.hpp
@@ -0,0 +1,69 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BinderInterface.hpp
+//
+
+
+//
+// Defines the public AssemblyBinder interface
+//
+// ============================================================
+
+#ifndef __BINDER_INTERFACE_HPP__
+#define __BINDER_INTERFACE_HPP__
+
+class PEImage;
+class PEAssembly;
+class StringArrayList;
+
+namespace BINDER_SPACE
+{
+ class Assembly;
+ class AssemblyIdentityUTF8;
+};
+
+namespace BinderInterface
+{
+ HRESULT Init();
+
+ HRESULT SetupContext(/* in */ LPCWSTR wszApplicationBase,
+ /* in */ DWORD dwAppDomainId,
+ /* out */ IUnknown **ppIApplicationContext);
+
+ // See code:BINDER_SPACE::AssemblyBinder::GetAssembly for info on fNgenExplicitBind
+ // and fExplicitBindToNativeImage, and see code:CEECompileInfo::LoadAssemblyByPath
+ // for an example of how they're used.
+ HRESULT Bind(/* in */ IUnknown *pIApplicationContext,
+ /* in */ SString &assemblyDisplayName,
+ /* in */ LPCWSTR wszCodeBase,
+ /* in */ PEAssembly *pParentAssembly,
+ /* in */ BOOL fNgenExplicitBind,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /*out */ BINDER_SPACE::Assembly **ppAssembly);
+
+ //
+ // Called via managed AppDomain.ExecuteAssembly variants and during binding host setup
+ //
+ HRESULT SetupBindingPaths(/* in */ IUnknown *pIApplicationContext,
+ /* in */ SString &sTrustedPlatformAssemblies,
+ /* in */ SString &sPlatformResourceRoots,
+ /* in */ SString &sAppPaths,
+ /* in */ SString &sAppNiPaths);
+
+ //
+ // Called via CoreAssemblySpec::BindToSystem
+ //
+ HRESULT BindToSystem(/* in */ SString &sSystemDirectory,
+ /* out */ BINDER_SPACE::Assembly **ppSystemAssembly,
+ /* in */ bool fBindToNativeImage);
+
+#ifdef BINDER_DEBUG_LOG
+ HRESULT Log(/* in */ LPCWSTR wszMessage);
+#endif // BINDER_DEBUG_LOG
+
+};
+
+#endif
diff --git a/src/binder/inc/bindertypes.hpp b/src/binder/inc/bindertypes.hpp
new file mode 100644
index 0000000000..7d7e822871
--- /dev/null
+++ b/src/binder/inc/bindertypes.hpp
@@ -0,0 +1,132 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BinderTypes.hpp
+//
+
+
+//
+// Declares a bunch of binder classes, types and macros
+//
+// ============================================================
+
+#ifndef __BINDER_TYPES_HPP__
+#define __BINDER_TYPES_HPP__
+
+#include "clrtypes.h"
+#include "sstring.h"
+
+#include "fusionhelpers.hpp"
+
+extern void DECLSPEC_NORETURN ThrowOutOfMemory();
+
+#ifndef S_TRUE
+#define S_TRUE S_OK
+#endif
+
+class PEImage;
+class PEAssembly;
+
+namespace BINDER_SPACE
+{
+ class AssemblyVersion;
+ class AssemblyName;
+ class Assembly;
+
+ class GACEntry;
+ class GACVersionIterator;
+ class GAC;
+
+ class ContextEntry;
+ class ExecutionContext;
+ class InspectionContext;
+
+ class PropertyMap;
+ class ApplicationContext;
+
+ class BindResult;
+ class FailureCache;
+ class AssemblyBinder;
+
+#if defined(BINDER_DEBUG_LOG)
+ class DebugLog;
+#endif
+
+#if defined(FEATURE_VERSIONING_LOG)
+ class BindingLog;
+ class CDebugLog;
+#endif // FEATURE_VERSIONING_LOG
+
+ namespace Tests
+ {
+ HRESULT Run();
+ };
+};
+
+#define IF_FAIL_GO(expr) \
+ hr = (expr); \
+ if (FAILED(hr)) \
+ { \
+ goto Exit; \
+ }
+
+#define IF_FALSE_GO(expr) \
+ if (!(expr)) { \
+ hr = E_FAIL; \
+ goto Exit; \
+ }
+
+#define GO_WITH_HRESULT(hrValue) \
+ hr = hrValue; \
+ goto Exit;
+
+#define IF_WIN32_ERROR_GO(expr) \
+ if (!(expr)) \
+ { \
+ hr = HRESULT_FROM_GetLastError(); \
+ goto Exit; \
+ }
+
+#define NEW_CONSTR(Object, Constr) \
+ (Object) = new (nothrow) Constr;
+
+#define SAFE_NEW_CONSTR(Object, Constr) \
+ (Object) = new (nothrow) Constr; \
+ if ((Object) == NULL) \
+ { \
+ hr = E_OUTOFMEMORY; \
+ goto Exit; \
+ }
+
+#define SAFE_NEW(Object, Class) \
+ SAFE_NEW_CONSTR(Object, Class());
+
+#define SAFE_RELEASE(objectPtr) \
+ if ((objectPtr) != NULL) \
+ { \
+ (objectPtr)->Release(); \
+ (objectPtr) = NULL; \
+ }
+
+#define SAFE_DELETE(objectPtr) \
+ if ((objectPtr) != NULL) \
+ { \
+ delete (objectPtr); \
+ (objectPtr) = NULL; \
+ }
+
+#define SAFE_DELETE_ARRAY(objectPtr) \
+ if ((objectPtr) != NULL) \
+ { \
+ delete[] (objectPtr); \
+ (objectPtr) = NULL; \
+ }
+
+#define LENGTH_OF(x) \
+ (sizeof(x) / sizeof(x[0]))
+
+#include "debuglog.hpp"
+
+#endif
diff --git a/src/binder/inc/bindinglog.hpp b/src/binder/inc/bindinglog.hpp
new file mode 100644
index 0000000000..d1467ed5c4
--- /dev/null
+++ b/src/binder/inc/bindinglog.hpp
@@ -0,0 +1,82 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BindingLog.hpp
+//
+
+
+//
+// Defines the BindingLog class
+//
+// ============================================================
+
+#ifndef __BINDER__BINDING_LOG_HPP__
+#define __BINDER__BINDING_LOG_HPP__
+
+#include "bindertypes.hpp"
+
+namespace BINDER_SPACE
+{
+ class BindingLog
+ {
+ public:
+ BindingLog();
+ ~BindingLog();
+
+ //
+ // These functions will create a new log together with pre-bind state
+ // information if needed and store it into the application context.
+ // This is to avoid endlessly passing around the debug log.
+ //
+ static HRESULT CreateInContext(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ SString &assemblyPath,
+ /* in */ PEAssembly *pParentAssembly);
+ static HRESULT CreateInContext(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ PEAssembly *pParentAssembly);
+
+ HRESULT Log(SString &info);
+
+ inline HRESULT Log(LPCWSTR pwzInfo);
+ inline HRESULT Log(/* in */ LPCWSTR pwzPrefix,
+ /* in */ SString &info);
+
+ HRESULT LogAssemblyName(/* in */ LPCWSTR pwzPrefix,
+ /* in */ AssemblyName *pAssemblyName);
+
+ HRESULT LogHR(/* in */ HRESULT logHR);
+ HRESULT LogResult(/* in */ BindResult *pBindResult);
+
+ HRESULT Flush();
+
+ inline BOOL CanLog();
+
+ void SetDebugLog(CDebugLog *pCDebugLog);
+
+ protected:
+ static BOOL IsLoggingNeeded();
+
+ static HRESULT CreateInContext(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ SString &assemblyPath,
+ /* in */ PEAssembly *pParentAssembly);
+
+ HRESULT LogPreBindState(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ SString &assemblyPath,
+ /* in */ PEAssembly *pParentAssembly);
+
+
+ inline CDebugLog *GetDebugLog();
+
+ HRESULT LogUser();
+
+ CDebugLog *m_pCDebugLog;
+ };
+
+#include "bindinglog.inl"
+};
+
+#endif
diff --git a/src/binder/inc/bindinglog.inl b/src/binder/inc/bindinglog.inl
new file mode 100644
index 0000000000..f342f618ea
--- /dev/null
+++ b/src/binder/inc/bindinglog.inl
@@ -0,0 +1,46 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BindingLog.inl
+//
+
+
+//
+// Implements inlined methods of BindingLog
+//
+// ============================================================
+
+#ifndef __BINDER__BINDING_LOG_INL__
+#define __BINDER__BINDING_LOG_INL__
+
+BOOL BindingLog::CanLog()
+{
+ return (m_pCDebugLog != NULL);
+}
+
+CDebugLog *BindingLog::GetDebugLog()
+{
+ _ASSERTE(m_pCDebugLog != NULL);
+ return m_pCDebugLog;
+}
+
+HRESULT BindingLog::Log(LPCWSTR pwzInfo)
+{
+ PathString info(pwzInfo);
+ return BindingLog::Log(info);
+}
+
+HRESULT BindingLog::Log(LPCWSTR pwzPrefix,
+ SString &info)
+{
+ PathString message;
+
+ message.Append(pwzPrefix);
+ message.Append(info);
+
+ return Log(message);
+}
+
+#endif
diff --git a/src/binder/inc/bindresult.hpp b/src/binder/inc/bindresult.hpp
new file mode 100644
index 0000000000..54d154a009
--- /dev/null
+++ b/src/binder/inc/bindresult.hpp
@@ -0,0 +1,64 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BindResult.hpp
+//
+
+
+//
+// Defines the BindResult class
+//
+// ============================================================
+
+#ifndef __BINDER__BIND_RESULT_HPP__
+#define __BINDER__BIND_RESULT_HPP__
+
+#include "bindertypes.hpp"
+
+namespace BINDER_SPACE
+{
+ class BindResult
+ {
+ public:
+ inline BindResult();
+ inline ~BindResult();
+
+ inline AssemblyName *GetAssemblyName(BOOL fAddRef = FALSE);
+ inline IUnknown *GetAssembly(BOOL fAddRef = FALSE);
+ inline Assembly *GetAsAssembly(BOOL fAddRef = FALSE);
+
+ inline AssemblyName *GetRetargetedAssemblyName();
+ inline void SetRetargetedAssemblyName(AssemblyName *pRetargetedAssemblyName);
+
+ inline BOOL GetIsDynamicBind();
+ inline void SetIsDynamicBind(BOOL fIsDynamicBind);
+ inline BOOL GetIsInGAC();
+ inline void SetIsInGAC(BOOL fIsInGAC);
+ inline BOOL GetIsContextBound();
+ inline void SetIsContextBound(BOOL fIsContextBound);
+ inline BOOL GetIsFirstRequest();
+ inline void SetIsFirstRequest(BOOL fIsFirstRequest);
+ inline BOOL GetIsSharable();
+ inline void SetIsSharable(BOOL fIsSharable);
+
+ inline void SetResult(ContextEntry *pContextEntry, BOOL fIsContextBound = TRUE);
+ inline void SetResult(Assembly *pAssembly);
+ inline void SetResult(BindResult *pBindResult);
+
+ inline void SetNoResult();
+ inline BOOL HaveResult();
+
+ inline IUnknown *ExtractAssembly();
+ inline void Reset();
+
+ protected:
+ DWORD m_dwResultFlags;
+ AssemblyName *m_pAssemblyName;
+ AssemblyName *m_pRetargetedAssemblyName;
+ ReleaseHolder<IUnknown> m_pIUnknownAssembly;
+ };
+};
+
+#endif
diff --git a/src/binder/inc/bindresult.inl b/src/binder/inc/bindresult.inl
new file mode 100644
index 0000000000..8e94e85c4f
--- /dev/null
+++ b/src/binder/inc/bindresult.inl
@@ -0,0 +1,229 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// BindResult.inl
+//
+
+
+//
+// Implements the inline methods of BindResult
+//
+// ============================================================
+
+#ifndef __BINDER__BIND_RESULT_INL__
+#define __BINDER__BIND_RESULT_INL__
+
+#include "contextentry.hpp"
+#include "assembly.hpp"
+
+namespace BINDER_SPACE
+{
+BindResult::BindResult()
+{
+ m_dwResultFlags = ContextEntry::RESULT_FLAG_NONE;
+ m_pAssemblyName = NULL;
+ m_pRetargetedAssemblyName = NULL;
+ m_pIUnknownAssembly = NULL;
+}
+
+BindResult::~BindResult()
+{
+ SAFE_RELEASE(m_pAssemblyName);
+ SAFE_RELEASE(m_pRetargetedAssemblyName);
+}
+
+AssemblyName *BindResult::GetAssemblyName(BOOL fAddRef /* = FALSE */)
+{
+ AssemblyName *pAssemblyName = m_pAssemblyName;
+
+ if (fAddRef && (pAssemblyName != NULL))
+ {
+ pAssemblyName->AddRef();
+ }
+
+ return pAssemblyName;
+}
+
+AssemblyName *BindResult::GetRetargetedAssemblyName()
+{
+ return m_pRetargetedAssemblyName;
+}
+
+void BindResult::SetRetargetedAssemblyName(AssemblyName *pRetargetedAssemblyName)
+{
+ SAFE_RELEASE(m_pRetargetedAssemblyName);
+
+ if (pRetargetedAssemblyName)
+ {
+ pRetargetedAssemblyName->AddRef();
+ }
+
+ m_pRetargetedAssemblyName = pRetargetedAssemblyName;
+}
+
+IUnknown *BindResult::GetAssembly(BOOL fAddRef /* = FALSE */)
+{
+ IUnknown *pIUnknownAssembly = m_pIUnknownAssembly;
+
+ if (fAddRef && (pIUnknownAssembly != NULL))
+ {
+ pIUnknownAssembly->AddRef();
+ }
+
+ return pIUnknownAssembly;
+}
+
+Assembly *BindResult::GetAsAssembly(BOOL fAddRef /* = FALSE */)
+{
+ return static_cast<Assembly *>(GetAssembly(fAddRef));
+}
+
+BOOL BindResult::GetIsDynamicBind()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_IS_DYNAMIC_BIND) != 0);
+}
+
+void BindResult::SetIsDynamicBind(BOOL fIsDynamicBind)
+{
+ if (fIsDynamicBind)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_IS_DYNAMIC_BIND;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_IS_DYNAMIC_BIND;
+ }
+}
+
+BOOL BindResult::GetIsInGAC()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_IS_IN_GAC) != 0);
+}
+
+void BindResult::SetIsInGAC(BOOL fIsInGAC)
+{
+ if (fIsInGAC)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_IS_IN_GAC;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_IS_IN_GAC;
+ }
+}
+
+BOOL BindResult::GetIsContextBound()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_CONTEXT_BOUND) != 0);
+}
+
+void BindResult::SetIsContextBound(BOOL fIsContextBound)
+{
+ if (fIsContextBound)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_CONTEXT_BOUND;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_CONTEXT_BOUND;
+ }
+}
+
+BOOL BindResult::GetIsFirstRequest()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_FIRST_REQUEST) != 0);
+}
+
+void BindResult::SetIsFirstRequest(BOOL fIsFirstRequest)
+{
+ if (fIsFirstRequest)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_FIRST_REQUEST;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_FIRST_REQUEST;
+ }
+}
+
+BOOL BindResult::GetIsSharable()
+{
+ return ((m_dwResultFlags & ContextEntry::RESULT_FLAG_IS_SHARABLE) != 0);
+}
+
+void BindResult::SetIsSharable(BOOL fIsSharable)
+{
+ if (fIsSharable)
+ {
+ m_dwResultFlags |= ContextEntry::RESULT_FLAG_IS_SHARABLE;
+ }
+ else
+ {
+ m_dwResultFlags &= ~ContextEntry::RESULT_FLAG_IS_SHARABLE;
+ }
+}
+
+void BindResult::SetResult(ContextEntry *pContextEntry, BOOL fIsContextBound /* = TRUE */)
+{
+ _ASSERTE(pContextEntry != NULL);
+
+ SetIsDynamicBind(pContextEntry->GetIsDynamicBind());
+ SetIsInGAC(pContextEntry->GetIsInGAC());
+ SetIsContextBound(fIsContextBound);
+ SetIsSharable(pContextEntry->GetIsSharable());
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pAssemblyName = pContextEntry->GetAssemblyName(TRUE /* fAddRef */);
+ m_pIUnknownAssembly = pContextEntry->GetAssembly(TRUE /* fAddRef */);
+}
+
+void BindResult::SetResult(Assembly *pAssembly)
+{
+ _ASSERTE(pAssembly != NULL);
+
+ SetIsDynamicBind(pAssembly->GetIsDynamicBind());
+ SetIsInGAC(pAssembly->GetIsInGAC());
+ SetIsSharable(pAssembly->GetIsSharable());
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pAssemblyName = pAssembly->GetAssemblyName(TRUE /* fAddRef */);
+ pAssembly->AddRef();
+ m_pIUnknownAssembly = static_cast<IUnknown *>(pAssembly);
+}
+
+void BindResult::SetResult(BindResult *pBindResult)
+{
+ _ASSERTE(pBindResult != NULL);
+
+ m_dwResultFlags = pBindResult->m_dwResultFlags;
+ SAFE_RELEASE(m_pAssemblyName);
+ m_pAssemblyName = pBindResult->GetAssemblyName(TRUE /* fAddRef */);
+ m_pIUnknownAssembly = pBindResult->GetAssembly(TRUE /* fAddRef */);
+}
+
+void BindResult::SetNoResult()
+{
+ m_pAssemblyName = NULL;
+}
+
+BOOL BindResult::HaveResult()
+{
+ return (GetAssemblyName() != NULL);
+}
+
+IUnknown *BindResult::ExtractAssembly()
+{
+ return m_pIUnknownAssembly.Extract();
+}
+
+void BindResult::Reset()
+{
+ SAFE_RELEASE(m_pAssemblyName);
+ SAFE_RELEASE(m_pRetargetedAssemblyName);
+ m_pIUnknownAssembly = NULL;
+ m_dwResultFlags = ContextEntry::RESULT_FLAG_NONE;
+}
+
+}
+
+#endif
diff --git a/src/binder/inc/cdebuglog.hpp b/src/binder/inc/cdebuglog.hpp
new file mode 100644
index 0000000000..37e1bc65b9
--- /dev/null
+++ b/src/binder/inc/cdebuglog.hpp
@@ -0,0 +1,67 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// CDebugLog.hpp
+//
+
+
+//
+// Defines the CDebugLog class
+//
+// ============================================================
+
+#ifndef __BINDER__C_DEBUG_LOG_HPP__
+#define __BINDER__C_DEBUG_LOG_HPP__
+
+#include "bindertypes.hpp"
+#include "list.hpp"
+
+#define FUSION_BIND_LOG_CATEGORY_DEFAULT 0
+#define FUSION_BIND_LOG_CATEGORY_NGEN 1
+#define FUSION_BIND_LOG_CATEGORY_MAX 2
+
+namespace BINDER_SPACE
+{
+ class CDebugLog
+ {
+ public:
+ CDebugLog();
+ ~CDebugLog();
+
+ static HRESULT Create(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ SString &sCodeBase,
+ /* out */ CDebugLog **ppCDebugLog);
+
+ ULONG AddRef();
+ ULONG Release();
+
+ HRESULT SetResultCode(/* in */ DWORD dwLogCategory,
+ /* in */ HRESULT hrResult);
+
+ HRESULT LogMessage(/* in */ DWORD dwDetailLevel,
+ /* in */ DWORD dwLogCategory,
+ /* in */ SString &sDebugString);
+
+ HRESULT Flush(/* in */ DWORD dwDetailLevel,
+ /* in */ DWORD dwLogCategory);
+ protected:
+ HRESULT Init(/* in */ ApplicationContext *pApplicationContext,
+ /* in */ AssemblyName *pAssemblyName,
+ /* in */ SString &sCodeBase);
+
+ HRESULT LogHeader(/* in */ DWORD dwLogCategory);
+ HRESULT LogFooter(/* in */ DWORD dwLogCategory);
+
+ LONG m_cRef;
+ FileHandleHolder m_hLogFile;
+ List<SString> m_content[FUSION_BIND_LOG_CATEGORY_MAX];
+ SString m_applicationName;
+ SString m_logFileName;
+ HRESULT m_HrResult[FUSION_BIND_LOG_CATEGORY_MAX];
+ };
+};
+
+#endif
diff --git a/src/binder/inc/clrprivbinderassemblyloadcontext.h b/src/binder/inc/clrprivbinderassemblyloadcontext.h
new file mode 100644
index 0000000000..83113f4633
--- /dev/null
+++ b/src/binder/inc/clrprivbinderassemblyloadcontext.h
@@ -0,0 +1,86 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+#ifndef __CLRPRIVBINDERASSEMBLYLOADCONTEXT_H__
+#define __CLRPRIVBINDERASSEMBLYLOADCONTEXT_H__
+
+#include "coreclrbindercommon.h"
+#include "applicationcontext.hpp"
+#include "clrprivbindercoreclr.h"
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityUTF8;
+};
+
+class CLRPrivBinderAssemblyLoadContext : public IUnknownCommon<ICLRPrivBinder>
+{
+public:
+
+ //=========================================================================
+ // ICLRPrivBinder functions
+ //-------------------------------------------------------------------------
+ STDMETHOD(BindAssemblyByName)(
+ /* [in] */ IAssemblyName *pIAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ STDMETHOD(VerifyBind)(
+ /* [in] */ IAssemblyName *pIAssemblyName,
+ /* [in] */ ICLRPrivAssembly *pAssembly,
+ /* [in] */ ICLRPrivAssemblyInfo *pAssemblyInfo);
+
+ STDMETHOD(GetBinderFlags)(
+ /* [retval][out] */ DWORD *pBinderFlags);
+
+ STDMETHOD(GetBinderID)(
+ /* [retval][out] */ UINT_PTR *pBinderId);
+
+ STDMETHOD(FindAssemblyBySpec)(
+ /* [in] */ LPVOID pvAppDomain,
+ /* [in] */ LPVOID pvAssemblySpec,
+ /* [out] */ HRESULT *pResult,
+ /* [out] */ ICLRPrivAssembly **ppAssembly);
+
+public:
+ //=========================================================================
+ // Class functions
+ //-------------------------------------------------------------------------
+
+ static HRESULT SetupContext(DWORD dwAppDomainId, CLRPrivBinderCoreCLR *pTPABinder,
+ UINT_PTR ptrAssemblyLoadContext, CLRPrivBinderAssemblyLoadContext **ppBindContext);
+
+ CLRPrivBinderAssemblyLoadContext();
+
+ inline BINDER_SPACE::ApplicationContext *GetAppContext()
+ {
+ return &m_appContext;
+ }
+
+ inline INT_PTR GetManagedAssemblyLoadContext()
+ {
+ return m_ptrManagedAssemblyLoadContext;
+ }
+
+ HRESULT BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ //=========================================================================
+ // Internal implementation details
+ //-------------------------------------------------------------------------
+private:
+ HRESULT BindAssemblyByNameWorker(BINDER_SPACE::AssemblyName *pAssemblyName, BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly);
+
+ BINDER_SPACE::ApplicationContext m_appContext;
+
+ CLRPrivBinderCoreCLR *m_pTPABinder;
+
+ INT_PTR m_ptrManagedAssemblyLoadContext;
+};
+
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+#endif // __CLRPRIVBINDERASSEMBLYLOADCONTEXT_H__
diff --git a/src/binder/inc/clrprivbindercoreclr.h b/src/binder/inc/clrprivbindercoreclr.h
new file mode 100644
index 0000000000..e906e01b12
--- /dev/null
+++ b/src/binder/inc/clrprivbindercoreclr.h
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+#ifndef __CLR_PRIV_BINDER_CORECLR_H__
+#define __CLR_PRIV_BINDER_CORECLR_H__
+
+#include "coreclrbindercommon.h"
+#include "applicationcontext.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityUTF8;
+};
+
+class CLRPrivBinderCoreCLR : public IUnknownCommon<ICLRPrivBinder>
+{
+public:
+
+ //=========================================================================
+ // ICLRPrivBinder functions
+ //-------------------------------------------------------------------------
+ STDMETHOD(BindAssemblyByName)(
+ /* [in] */ IAssemblyName *pIAssemblyName,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+
+ STDMETHOD(VerifyBind)(
+ /* [in] */ IAssemblyName *pIAssemblyName,
+ /* [in] */ ICLRPrivAssembly *pAssembly,
+ /* [in] */ ICLRPrivAssemblyInfo *pAssemblyInfo);
+
+ STDMETHOD(GetBinderFlags)(
+ /* [retval][out] */ DWORD *pBinderFlags);
+
+ STDMETHOD(GetBinderID)(
+ /* [retval][out] */ UINT_PTR *pBinderId);
+
+ STDMETHOD(FindAssemblyBySpec)(
+ /* [in] */ LPVOID pvAppDomain,
+ /* [in] */ LPVOID pvAssemblySpec,
+ /* [out] */ HRESULT *pResult,
+ /* [out] */ ICLRPrivAssembly **ppAssembly);
+
+public:
+
+ HRESULT SetupBindingPaths(SString &sTrustedPlatformAssemblies,
+ SString &sPlatformResourceRoots,
+ SString &sAppPaths,
+ SString &sAppNiPaths);
+
+ bool IsInTpaList(const SString &sFileName);
+
+ inline BINDER_SPACE::ApplicationContext *GetAppContext()
+ {
+ return &m_appContext;
+ }
+
+ HRESULT Bind(SString &assemblyDisplayName,
+ LPCWSTR wszCodeBase,
+ PEAssembly *pParentAssembly,
+ BOOL fNgenExplicitBind,
+ BOOL fExplicitBindToNativeImage,
+ ICLRPrivAssembly **ppAssembly);
+
+#ifndef CROSSGEN_COMPILE
+ HRESULT PreBindByteArray(PEImage *pPEImage, BOOL fInspectionOnly);
+#endif // CROSSGEN_COMPILE
+
+#if defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+ HRESULT BindUsingPEImage( /* in */ PEImage *pPEImage,
+ /* in */ BOOL fIsNativeImage,
+ /* [retval][out] */ ICLRPrivAssembly **ppAssembly);
+#endif // defined(FEATURE_HOST_ASSEMBLY_RESOLVER) && !defined(DACCESS_COMPILE) && !defined(CROSSGEN_COMPILE)
+
+ HRESULT BindAssemblyByNameWorker(
+ BINDER_SPACE::AssemblyName *pAssemblyName,
+ BINDER_SPACE::Assembly **ppCoreCLRFoundAssembly,
+ bool excludeAppPaths);
+
+ INT_PTR GetManagedAssemblyLoadContext()
+ {
+ return m_ptrManagedAssemblyLoadContext;
+ }
+
+ void SetManagedAssemblyLoadContext(INT_PTR ptrManagedTPABinderInstance)
+ {
+ m_ptrManagedAssemblyLoadContext = ptrManagedTPABinderInstance;
+ }
+
+ //=========================================================================
+ // Internal implementation details
+ //-------------------------------------------------------------------------
+private:
+ BINDER_SPACE::ApplicationContext m_appContext;
+
+ INT_PTR m_ptrManagedAssemblyLoadContext;
+};
+
+#endif // __CLR_PRIV_BINDER_CORECLR_H__
diff --git a/src/binder/inc/contextentry.hpp b/src/binder/inc/contextentry.hpp
new file mode 100644
index 0000000000..d35f57b0ca
--- /dev/null
+++ b/src/binder/inc/contextentry.hpp
@@ -0,0 +1,146 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// ContextEntry.hpp
+//
+
+
+//
+// Defines the ContextEntry class
+//
+// ============================================================
+
+#ifndef __BINDER__CONTEXT_ENTRY_HPP__
+#define __BINDER__CONTEXT_ENTRY_HPP__
+
+#include "assemblyentry.hpp"
+#include "assembly.hpp"
+
+namespace BINDER_SPACE
+{
+ class ContextEntry : public AssemblyEntry
+ {
+ public:
+ typedef enum
+ {
+ RESULT_FLAG_NONE = 0x00,
+ RESULT_FLAG_IS_DYNAMIC_BIND = 0x01,
+ RESULT_FLAG_IS_IN_GAC = 0x02,
+ //RESULT_FLAG_FROM_MANIFEST = 0x04,
+ RESULT_FLAG_CONTEXT_BOUND = 0x08,
+ RESULT_FLAG_FIRST_REQUEST = 0x10,
+ RESULT_FLAG_IS_SHARABLE = 0x20
+ } ResultFlags;
+
+ ContextEntry() : AssemblyEntry()
+ {
+ m_dwResultFlags = RESULT_FLAG_NONE;
+ m_pIUnknownAssembly = NULL;
+ }
+
+ ~ContextEntry()
+ {
+ SAFE_RELEASE(m_pIUnknownAssembly);
+ }
+
+ BOOL GetIsDynamicBind()
+ {
+ return ((m_dwResultFlags & RESULT_FLAG_IS_DYNAMIC_BIND) != 0);
+ }
+
+ void SetIsDynamicBind(BOOL fIsDynamicBind)
+ {
+ if (fIsDynamicBind)
+ {
+ m_dwResultFlags |= RESULT_FLAG_IS_DYNAMIC_BIND;
+ }
+ else
+ {
+ m_dwResultFlags &= ~RESULT_FLAG_IS_DYNAMIC_BIND;
+ }
+ }
+
+ BOOL GetIsInGAC()
+ {
+ return ((m_dwResultFlags & RESULT_FLAG_IS_IN_GAC) != 0);
+ }
+
+ void SetIsInGAC(BOOL fIsInGAC)
+ {
+ if (fIsInGAC)
+ {
+ m_dwResultFlags |= RESULT_FLAG_IS_IN_GAC;
+ }
+ else
+ {
+ m_dwResultFlags &= ~RESULT_FLAG_IS_IN_GAC;
+ }
+ }
+
+ BOOL GetIsFirstRequest()
+ {
+ return ((m_dwResultFlags & RESULT_FLAG_FIRST_REQUEST) != 0);
+ }
+
+ void SetIsFirstRequest(BOOL fIsFirstRequest)
+ {
+ if (fIsFirstRequest)
+ {
+ m_dwResultFlags |= RESULT_FLAG_FIRST_REQUEST;
+ }
+ else
+ {
+ m_dwResultFlags &= ~RESULT_FLAG_FIRST_REQUEST;
+ }
+ }
+
+ BOOL GetIsSharable()
+ {
+ return ((m_dwResultFlags & RESULT_FLAG_IS_SHARABLE) != 0);
+ }
+
+ void SetIsSharable(BOOL fIsSharable)
+ {
+ if (fIsSharable)
+ {
+ m_dwResultFlags |= RESULT_FLAG_IS_SHARABLE;
+ }
+ else
+ {
+ m_dwResultFlags &= ~RESULT_FLAG_IS_SHARABLE;
+ }
+ }
+
+ IUnknown *GetAssembly(BOOL fAddRef = FALSE)
+ {
+ IUnknown *pIUnknownAssembly = m_pIUnknownAssembly;
+
+ if (fAddRef && (pIUnknownAssembly != NULL))
+ {
+ pIUnknownAssembly->AddRef();
+ }
+
+ return pIUnknownAssembly;
+ }
+
+ void SetAssembly(IUnknown *pIUnknownAssembly)
+ {
+ SAFE_RELEASE(m_pIUnknownAssembly);
+
+ if (pIUnknownAssembly != NULL)
+ {
+ pIUnknownAssembly->AddRef();
+ }
+
+ m_pIUnknownAssembly = pIUnknownAssembly;
+ }
+
+ protected:
+ DWORD m_dwResultFlags;
+ IUnknown *m_pIUnknownAssembly;
+ };
+};
+
+#endif
diff --git a/src/binder/inc/coreclrbindercommon.h b/src/binder/inc/coreclrbindercommon.h
new file mode 100644
index 0000000000..66166d6fd2
--- /dev/null
+++ b/src/binder/inc/coreclrbindercommon.h
@@ -0,0 +1,58 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+
+#ifndef __CORECLR_BINDER_COMMON_H__
+#define __CORECLR_BINDER_COMMON_H__
+
+#include "clrprivbinding.h"
+#include "internalunknownimpl.h"
+#include "applicationcontext.hpp"
+
+
+namespace BINDER_SPACE
+{
+ class AssemblyIdentityUTF8;
+};
+
+class CLRPrivBinderCoreCLR;
+
+// General purpose AssemblyBinder helper class
+class CCoreCLRBinderHelper
+{
+public:
+ static HRESULT Init();
+
+ static HRESULT DefaultBinderSetupContext(DWORD dwAppDomainId,
+ CLRPrivBinderCoreCLR **ppTPABinder);
+
+ // ABHI-TODO: The call indicates that this can come from a case where
+ // pDomain->GetFusionContext() is null, hence this is static function
+ // which handles a null binder. See if this actually happens
+ static HRESULT GetAssemblyIdentity(LPCSTR szTextualIdentity,
+ BINDER_SPACE::ApplicationContext *pApplicationContext,
+ NewHolder<BINDER_SPACE::AssemblyIdentityUTF8> &assemblyIdentityHolder);
+
+ //=============================================================================
+ // Class functions that provides binding services beyond the ICLRPrivInterface
+ //-----------------------------------------------------------------------------
+ static HRESULT BindToSystem(ICLRPrivAssembly **ppSystemAssembly, bool fBindToNativeImage);
+
+ static HRESULT BindToSystemSatellite(SString &systemPath,
+ SString &sSimpleName,
+ SString &sCultureName,
+ ICLRPrivAssembly **ppSystemAssembly);
+
+ static HRESULT GetAssemblyFromImage(PEImage *pPEImage,
+ PEImage *pNativePEImage,
+ ICLRPrivAssembly **ppAssembly);
+
+ static HRESULT GetAssembly(/* in */ SString &assemblyPath,
+ /* in */ BOOL fInspectionOnly,
+ /* in */ BOOL fIsInGAC,
+ /* in */ BOOL fExplicitBindToNativeImage,
+ /* out */ BINDER_SPACE::Assembly **ppAssembly);
+};
+
+#endif // __CORECLR_BINDER_COMMON_H__
diff --git a/src/binder/inc/debuglog.hpp b/src/binder/inc/debuglog.hpp
new file mode 100644
index 0000000000..28de7f3267
--- /dev/null
+++ b/src/binder/inc/debuglog.hpp
@@ -0,0 +1,118 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// DebugLog.hpp
+//
+
+
+//
+// Defines the DebugLog class
+//
+// ============================================================
+
+#ifndef __BINDER__DEBUG_LOG_HPP__
+#define __BINDER__DEBUG_LOG_HPP__
+
+#include "bindertypes.hpp"
+#include "variables.hpp"
+
+namespace BINDER_SPACE
+{
+
+// When defined at the top of a source file, DISABLE_BINDER_DEBUG_LOGGING will cause
+// binder debug logging to be disabled only in the scope of that file by defining all the
+// binder logging macros as NOPs.
+
+#if defined(BINDER_DEBUG_LOG) && !defined(DISABLE_BINDER_DEBUG_LOGGING)
+
+#define BINDER_LOG_STARTUP() \
+ IF_FAIL_GO(DebugLog::Startup());
+
+#define BINDER_LOG_LOCK() \
+ CRITSEC_Holder logLock(g_BinderVariables->m_logCS);
+
+#define BINDER_LOG_ENTER(scope) \
+ DebugLog::Enter(scope);
+
+#define BINDER_LOG_LEAVE(scope) \
+ DebugLog::Leave(scope);
+
+#define BINDER_LOG_LEAVE_HR(scope, hr) \
+ DebugLog::LeaveHR(scope, hr);
+
+#define BINDER_LOG_LEAVE_BOOL(scope, fResult) \
+ DebugLog::LeaveBool(scope, fResult);
+
+#define BINDER_LOG(comment) \
+ DebugLog::Log(comment);
+
+#define BINDER_LOG_STRING(comment, value) \
+ DebugLog::Log(comment, value);
+
+#define BINDER_LOG_HRESULT(comment, hr) \
+ DebugLog::Log(comment, hr);
+
+#define BINDER_LOG_ASSEMBLY_NAME(comment, assemblyName) \
+ DebugLog::Log(comment, assemblyName);
+
+#define BINDER_LOG_I_ASSEMBLY_NAME(comment, assemblyName) \
+ DebugLog::Log(comment, assemblyName);
+
+#define BINDER_LOG_POINTER(comment, pData) \
+ DebugLog::Log(comment, (void *) (pData));
+
+ class DebugLog
+ {
+ public:
+ static HRESULT Startup();
+
+ static void Enter(/* in */ WCHAR *pwzScope);
+ static void Leave(/* in */ WCHAR *pwzScope);
+ static void LeaveHR(/* in */ WCHAR *pwzScope,
+ /* in */ HRESULT hrLog);
+ static void LeaveBool(/* in */ WCHAR *pwzScope,
+ /* in */ BOOL fResult);
+
+ static void Log(/* in */ WCHAR *pwzComment);
+ static void Log(/* in */ WCHAR *pwzComment,
+ /* in */ SString &value);
+ static void Log(/* in */ WCHAR *pwzComment,
+ /* in */ const WCHAR *value);
+ static void Log(/* in */ WCHAR *pwzComment,
+ /* in */ HRESULT hrLog);
+ static void Log(/* in */ WCHAR *pwzComment,
+ /* in */ AssemblyName *pAssemblyName);
+ static void Log(/* in */ WCHAR *pwzComment,
+ /* in */ void *pData);
+ protected:
+ static void Log(/* in */ SString &info);
+ };
+#else
+ class DebugLog
+ {
+ public:
+ static void Empty() {};
+ };
+
+#define BINDER_LOG_STARTUP() DebugLog::Empty();
+
+#define BINDER_LOG_LOCK() DebugLog::Empty();
+
+#define BINDER_LOG_ENTER(scope) DebugLog::Empty();
+#define BINDER_LOG_LEAVE(scope) DebugLog::Empty();
+#define BINDER_LOG_LEAVE_HR(scope, hr) DebugLog::Empty();
+#define BINDER_LOG_LEAVE_BOOL(scope, fResult) DebugLog::Empty();
+
+#define BINDER_LOG(comment) DebugLog::Empty();
+#define BINDER_LOG_STRING(comment, value) DebugLog::Empty();
+#define BINDER_LOG_HRESULT(comment, hr) DebugLog::Empty();
+#define BINDER_LOG_ASSEMBLY_NAME(comment, assemblyName) DebugLog::Empty();
+#define BINDER_LOG_I_ASSEMBLY_NAME(comment, assemblyName) DebugLog::Empty();
+#define BINDER_LOG_POINTER(comment, pData) DebugLog::Empty();
+
+#endif
+};
+
+#endif
diff --git a/src/binder/inc/failurecache.hpp b/src/binder/inc/failurecache.hpp
new file mode 100644
index 0000000000..3dbc3f611e
--- /dev/null
+++ b/src/binder/inc/failurecache.hpp
@@ -0,0 +1,38 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FailureCache.hpp
+//
+
+
+//
+// Defines the FailureCache class
+//
+// ============================================================
+
+
+#ifndef __BINDER__FAILURE_CACHE_HPP__
+#define __BINDER__FAILURE_CACHE_HPP__
+
+#include "failurecachehashtraits.hpp"
+
+namespace BINDER_SPACE
+{
+ class FailureCache : protected SHash<FailureCacheHashTraits>
+ {
+ private:
+ typedef SHash<FailureCacheHashTraits> Hash;
+ public:
+ FailureCache();
+ ~FailureCache();
+
+ HRESULT Add(/* in */ SString &assemblyNameorPath,
+ /* in */ HRESULT hrBindResult);
+ HRESULT Lookup(/* in */ SString &assemblyNameorPath);
+ void Remove(/* in */ SString &assemblyName);
+ };
+};
+
+#endif
diff --git a/src/binder/inc/failurecachehashtraits.hpp b/src/binder/inc/failurecachehashtraits.hpp
new file mode 100644
index 0000000000..7d65544ecc
--- /dev/null
+++ b/src/binder/inc/failurecachehashtraits.hpp
@@ -0,0 +1,88 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FailureCache.hpp
+//
+
+
+//
+// Defines the FailureCache class
+//
+// ============================================================
+
+#ifndef __BINDER__FAILURE_CACHE_HASH_TRAITS_HPP__
+#define __BINDER__FAILURE_CACHE_HASH_TRAITS_HPP__
+
+#include "bindertypes.hpp"
+#include "utils.hpp"
+#include "sstring.h"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ class FailureCacheEntry
+ {
+ public:
+ inline FailureCacheEntry()
+ {
+ m_hrBindingResult = S_OK;
+ }
+ inline ~FailureCacheEntry()
+ {
+ // Nothing to do here
+ }
+
+ // Getters/Setters
+ inline SString &GetAssemblyNameOrPath()
+ {
+ return m_assemblyNameOrPath;
+ }
+ inline HRESULT GetBindingResult()
+ {
+ return m_hrBindingResult;
+ }
+ inline void SetBindingResult(HRESULT hrBindingResult)
+ {
+ m_hrBindingResult = hrBindingResult;
+ }
+
+ protected:
+ SString m_assemblyNameOrPath;
+ HRESULT m_hrBindingResult;
+ };
+
+ class FailureCacheHashTraits : public DefaultSHashTraits<FailureCacheEntry *>
+ {
+ public:
+ typedef SString& key_t;
+
+ // GetKey, Equals, and Hash can throw due to SString
+ static const bool s_NoThrow = false;
+
+ static key_t GetKey(element_t pFailureCacheEntry)
+ {
+ return pFailureCacheEntry->GetAssemblyNameOrPath();
+ }
+ static BOOL Equals(key_t pAssemblyNameOrPath1, key_t pAssemblyNameOrPath2)
+ {
+ return EqualsCaseInsensitive(pAssemblyNameOrPath1, pAssemblyNameOrPath2);
+ }
+ static count_t Hash(key_t pAssemblyNameOrPath)
+ {
+ return HashCaseInsensitive(pAssemblyNameOrPath);
+ }
+ static const element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &propertyEntry)
+ {
+ return (propertyEntry == NULL);
+ }
+
+ };
+};
+
+#endif
diff --git a/src/binder/inc/fusionassemblyname.hpp b/src/binder/inc/fusionassemblyname.hpp
new file mode 100644
index 0000000000..f0f69d3274
--- /dev/null
+++ b/src/binder/inc/fusionassemblyname.hpp
@@ -0,0 +1,217 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FusionAssemblyName.hpp
+//
+// Defines the CAssemblyName class
+//
+// ============================================================
+
+#ifndef __FUSION_ASSEMBLY_NAME_HPP__
+#define __FUSION_ASSEMBLY_NAME_HPP__
+
+#include "fusionhelpers.hpp"
+
+struct FusionProperty
+{
+ union {
+ LPVOID pv;
+ wchar_t* asStr; // For debugging.
+ };
+ DWORD cb;
+};
+
+class CPropertyArray
+{
+ friend class CAssemblyName;
+private:
+ DWORD _dwSig;
+ FusionProperty _rProp[ASM_NAME_MAX_PARAMS];
+
+public:
+ CPropertyArray();
+ ~CPropertyArray();
+
+ inline HRESULT Set(DWORD PropertyId, LPCVOID pvProperty, DWORD cbProperty);
+ inline HRESULT Get(DWORD PropertyId, LPVOID pvProperty, LPDWORD pcbProperty);
+ inline FusionProperty operator [] (DWORD dwPropId);
+};
+
+class CAssemblyName : public IAssemblyName
+{
+private:
+ DWORD _dwSig;
+ Volatile<LONG> _cRef;
+ CPropertyArray _rProp;
+ BOOL _fIsFinalized;
+ BOOL _fPublicKeyToken;
+ BOOL _fCustom;
+ LPWSTR _pwzPathModifier;
+ LPWSTR _pwzTextualIdentity;
+ LPWSTR _pwzTextualIdentityILFull;
+
+ DWORD _dw;
+
+public:
+ // IUnknown methods
+ STDMETHODIMP QueryInterface(REFIID riid,void ** ppv);
+ STDMETHODIMP_(ULONG) AddRef();
+ STDMETHODIMP_(ULONG) Release();
+
+ // IAssemblyName methods
+ STDMETHOD(SetProperty)(
+ /* in */ DWORD PropertyId,
+ /* in */ LPCVOID pvProperty,
+ /* in */ DWORD cbProperty);
+
+ STDMETHOD(GetProperty)(
+ /* in */ DWORD PropertyId,
+ /* out */ LPVOID pvProperty,
+ /* in out */ LPDWORD pcbProperty);
+
+ STDMETHOD(Finalize)();
+
+ STDMETHOD(GetDisplayName)(
+ __out_ecount_opt(*pccDisplayName) LPOLESTR szDisplayName,
+ __inout LPDWORD pccDisplayName,
+ __in DWORD dwDisplayFlags);
+
+ STDMETHOD(GetName)(
+ __inout LPDWORD lpcwBuffer,
+ __out_ecount_opt(*lpcwBuffer) LPOLESTR pwzBuffer);
+
+ STDMETHOD(GetVersion)(
+ /* [out] */ LPDWORD pwVersionHi,
+ /* [out] */ LPDWORD pwVersionLow);
+
+ STDMETHOD (IsEqual)(
+ /* [in] */ LPASSEMBLYNAME pName,
+ /* [in] */ DWORD dwCmpFlags);
+
+ STDMETHOD(Reserved)(
+ /* in */ REFIID refIID,
+ /* in */ IUnknown *pUnkBindSink,
+ /* in */ IUnknown *pUnkAppCtx,
+ /* in */ LPCOLESTR szCodebase,
+ /* in */ LONGLONG llFlags,
+ /* in */ LPVOID pvReserved,
+ /* in */ DWORD cbReserved,
+ /* out */ VOID **ppv);
+
+ STDMETHODIMP Clone(IAssemblyName **ppName);
+
+ HRESULT SetPropertyInternal(/* in */ DWORD PropertyId,
+ /* in */ LPCVOID pvProperty,
+ /* in */ DWORD cbProperty);
+
+ CAssemblyName();
+ virtual ~CAssemblyName();
+
+ HRESULT Init(LPCTSTR pszAssemblyName, ASSEMBLYMETADATA *pamd);
+ HRESULT Parse(LPCWSTR szDisplayName);
+
+ static BOOL IsStronglyNamed(IAssemblyName *pName);
+ static BOOL IsPartial(IAssemblyName *pName,
+ LPDWORD pdwCmpMask = NULL);
+
+protected:
+ HRESULT GetVersion(DWORD dwMajorVersionEnumValue,
+ LPDWORD pwVersionHi,
+ LPDWORD pwVersionLow);
+
+ HRESULT CopyProperties(CAssemblyName *pSource,
+ CAssemblyName *pTarget,
+ const DWORD properties[],
+ DWORD dwSize);
+};
+
+STDAPI
+CreateAssemblyNameObject(
+ LPASSEMBLYNAME *ppAssemblyName,
+ LPCOLESTR szAssemblyName,
+ DWORD dwFlags,
+ LPVOID pvReserved);
+
+STDAPI
+CreateAssemblyNameObjectFromMetaData(
+ LPASSEMBLYNAME *ppAssemblyName,
+ LPCOLESTR szAssemblyName,
+ ASSEMBLYMETADATA *pamd,
+ LPVOID pvReserved);
+
+namespace LegacyFusion
+{
+ HRESULT SetStringProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ SString &value);
+ HRESULT SetBufferProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ SBuffer &value);
+ HRESULT SetWordProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ DWORD dwValue);
+ HRESULT SetDwordProperty(IAssemblyName *pIAssemblyName,
+ DWORD dwPropertyId,
+ DWORD dwValue);
+};
+
+namespace fusion
+{
+ namespace util
+ {
+ // Fills the provided buffer with the contents of the property. pcbBuf is
+ // set to be either the required buffer space when insufficient buffer is
+ // provided, or the number of bytes written.
+ //
+ // Returns S_FALSE if the property has not been set, regardless of the values of pBuf and pcbBuf.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PVOID pBuf, DWORD *pcbBuf);
+
+ // Fills the provided buffer with the contents of the property. If no buffer is provided
+ // (*ppBuf == nullptr), then a buffer is allocated for the caller and ppBuf is set to point
+ // at the allocated buffer on return. pcbBuf is set to be either the required buffer space
+ // when insufficient buffer is provided, or the number of bytes written.
+ //
+ // Returns S_FALSE if the property has not been set, regardless of the values of pBuf and pcbBuf.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, PBYTE * ppBuf, DWORD *pcbBuf);
+
+ // Fills the provided SString with the contents of the property.
+ //
+ // Returns S_FALSE if the property has not been set.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, SString & ssVal);
+
+ // Returns an allocated buffer with the contents of the property.
+ //
+ // Returns S_FALSE if the property has not been set.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, __deref_out LPWSTR * pwzVal);
+
+ inline HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, LPCWSTR *pwzOut)
+ { return GetProperty(pName, dwProperty, const_cast<LPWSTR*>(pwzOut)); }
+
+ // Returns an allocated buffer with the contents of the property.
+ //
+ // Returns S_FALSE if the property has not been set.
+ HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, __deref_out LPSTR *pwzOut);
+
+ inline HRESULT GetProperty(IAssemblyName * pName, DWORD dwProperty, LPCSTR *pwzOut)
+ { return GetProperty(pName, dwProperty, const_cast<LPSTR*>(pwzOut)); }
+
+ template <typename T> inline
+ typename std::enable_if<!std::is_pointer< typename std::remove_cv< T >::type >::value, HRESULT>::type
+ GetProperty(IAssemblyName * pName, DWORD dwProperty, T * pVal)
+ {
+ DWORD cbBuf = sizeof(T);
+ HRESULT hr = GetProperty(pName, dwProperty, pVal, &cbBuf);
+ if (hr == S_OK && cbBuf != sizeof(T))
+ hr = E_UNEXPECTED;
+ return hr;
+ }
+
+ inline HRESULT GetSimpleName(IAssemblyName * pName, SString & ssName)
+ { return GetProperty(pName, ASM_NAME_NAME, ssName); }
+ } // namespace fusion.util
+} // namespace fusion
+
+
+#endif
diff --git a/src/binder/inc/fusionhelpers.hpp b/src/binder/inc/fusionhelpers.hpp
new file mode 100644
index 0000000000..229ebe6c4e
--- /dev/null
+++ b/src/binder/inc/fusionhelpers.hpp
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// FusionHelpers.hpp
+//
+// Defines various legacy fusion types
+//
+// ============================================================
+
+#ifndef __FUSION_HELPERS_HPP__
+#define __FUSION_HELPERS_HPP__
+
+#include "clrtypes.h"
+#include "sstring.h"
+
+#include "clrhost.h"
+#include "shlwapi.h"
+#include "winwrap.h"
+#include "ex.h"
+#include "fusion.h"
+
+#ifndef FEATURE_VERSIONING
+// Rename the fusion bind result to avoid collision with core bind result
+#define IBindResult IBindResult_Fusion
+#include "binderngen.h"
+#undef IBindResult
+#endif
+
+#include "peinformation.h"
+
+#define FUSION_NEW_SINGLETON(_type) new (nothrow) _type
+#define FUSION_NEW_ARRAY(_type, _n) new (nothrow) _type[_n]
+#define FUSION_DELETE_ARRAY(_ptr) if((_ptr)) delete [] (_ptr)
+#define FUSION_DELETE_SINGLETON(_ptr) if((_ptr)) delete (_ptr)
+
+#define SAFEDELETE(p) if ((p) != NULL) { FUSION_DELETE_SINGLETON((p)); (p) = NULL; };
+#define SAFEDELETEARRAY(p) if ((p) != NULL) { FUSION_DELETE_ARRAY((p)); (p) = NULL; };
+#define SAFERELEASE(p) if ((p) != NULL) { (p)->Release(); (p) = NULL; };
+
+#ifndef NEW
+#define NEW(_type) FUSION_NEW_SINGLETON(_type)
+#endif // !NEW
+
+#ifndef ARRAYSIZE
+#define ARRAYSIZE(a) (sizeof(a)/sizeof(a[0]))
+#endif // !ARRAYSIZE
+
+#define MAX_VERSION_DISPLAY_SIZE sizeof("65535.65535.65535.65535")
+
+#define ASM_DISPLAYF_DEFAULT (ASM_DISPLAYF_VERSION \
+ |ASM_DISPLAYF_CULTURE \
+ |ASM_DISPLAYF_PUBLIC_KEY_TOKEN \
+ |ASM_DISPLAYF_RETARGET)
+
+#define SIGNATURE_BLOB_LENGTH 0x80
+#define SIGNATURE_BLOB_LENGTH_HASH 0x14
+#define MVID_LENGTH sizeof(GUID)
+
+#define PUBLIC_KEY_TOKEN_LEN 8
+
+inline
+WCHAR*
+WSTRDupDynamic(LPCWSTR pwszSrc)
+{
+ LPWSTR pwszDest = NULL;
+ if (pwszSrc != NULL)
+ {
+ const size_t dwLen = wcslen(pwszSrc) + 1;
+ pwszDest = FUSION_NEW_ARRAY(WCHAR, dwLen);
+
+ if( pwszDest )
+ memcpy(pwszDest, pwszSrc, dwLen * sizeof(WCHAR));
+ }
+
+ return pwszDest;
+}
+
+#define MAX_URL_LENGTH 2084 // same as INTERNET_MAX_URL_LENGTH
+
+// bit mask macro helpers
+#define MAX_ID_FROM_MASK(size) ((size) << 3)
+#define MASK_SIZE_FROM_ID(id) ((id) >> 3)
+#define IS_IN_RANGE(id, size) ((id) <= ((size) << 3))
+#define IS_BIT_SET(id, mask) (mask[((id)-1)>>3] & (0x1 << (((id)-1)&0x7)))
+#define SET_BIT(id, mask) (mask[((id)-1)>>3] |= (0x1<< (((id)-1)&0x7)))
+#define UNSET_BIT(id, mask) (mask[((id)-1)>>3] &= (0xFF - (0x1<<(((id)-1)&0x7))))
+
+int FusionCompareStringI(LPCWSTR pwz1, LPCWSTR pwz2);
+
+// CLR lobal culture ID
+extern LocaleID g_lcid;
+
+#endif
diff --git a/src/binder/inc/list.hpp b/src/binder/inc/list.hpp
new file mode 100644
index 0000000000..91ecd1752b
--- /dev/null
+++ b/src/binder/inc/list.hpp
@@ -0,0 +1,358 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// List.hpp
+//
+
+
+//
+// Defines the List class
+//
+// ============================================================
+
+#ifndef __BINDER__LIST_HPP__
+#define __BINDER__LIST_HPP__
+
+#include "bindertypes.hpp"
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ // Ripped from Fusion
+
+ //
+ // ListNode
+ //
+
+ typedef void *LISTNODE;
+
+ template <class Type> class ListNode
+ {
+ public:
+ ListNode(Type item);
+ virtual ~ListNode();
+
+ void SetNext(ListNode *pNode);
+ void SetPrev(ListNode *pNode);
+ Type GetItem();
+ ListNode *GetNext();
+ ListNode *GetPrev();
+
+ private:
+ Type _type;
+ ListNode *_pNext;
+ ListNode *_pPrev;
+ };
+
+ //
+ // List
+ //
+
+ template <class Type> class List
+ {
+ public:
+ List();
+ ~List();
+
+ LISTNODE AddHead(const Type &item);
+ LISTNODE AddTail(const Type &item);
+
+ LISTNODE GetHeadPosition();
+ LISTNODE GetTailPosition();
+ void RemoveAt(LISTNODE pNode);
+ void RemoveAll();
+ LISTNODE Find(const Type &item);
+ int GetCount();
+ Type GetNext(LISTNODE &pNode);
+ Type GetAt(LISTNODE pNode);
+ LISTNODE AddSorted(const Type &item, LPVOID pfn);
+
+ public:
+ DWORD _dwSig;
+
+ private:
+ ListNode<Type> *_pHead;
+ ListNode<Type> *_pTail;
+ int _iCount;
+ };
+
+ //
+ // ListNode Implementation
+ //
+
+ template <class Type> ListNode<Type>::ListNode(Type item)
+ : _type(item)
+ , _pNext(NULL)
+ , _pPrev(NULL)
+ {
+ }
+
+ template <class Type> ListNode<Type>::~ListNode()
+ {
+ }
+
+ template <class Type> void ListNode<Type>::SetNext(ListNode *pNode)
+ {
+ _pNext = pNode;
+ }
+
+ template <class Type> void ListNode<Type>::SetPrev(ListNode *pNode)
+ {
+ _pPrev = pNode;
+ }
+
+ template <class Type> Type ListNode<Type>::GetItem()
+ {
+ return _type;
+ }
+
+ template <class Type> ListNode<Type> *ListNode<Type>::GetNext()
+ {
+ return _pNext;
+ }
+
+ template <class Type> ListNode<Type> *ListNode<Type>::GetPrev()
+ {
+ return _pPrev;
+ }
+
+
+ //
+ // List Implementation
+ //
+
+ template <class Type> List<Type>::List()
+ : _pHead(NULL)
+ , _pTail(NULL)
+ , _iCount(0)
+ {
+ _dwSig = 0x5453494c; /* 'TSIL' */
+ }
+
+ template <class Type> List<Type>::~List()
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ RemoveAll();
+ }
+ EX_CATCH_HRESULT(hr);
+ }
+
+ template <class Type> LISTNODE List<Type>::AddHead(const Type &item)
+ {
+ ListNode<Type> *pNode = NULL;
+
+ NEW_CONSTR(pNode, ListNode<Type>(item));
+ if (pNode) {
+ _iCount++;
+ pNode->SetNext(_pHead);
+ pNode->SetPrev(NULL);
+ if (_pHead == NULL) {
+ _pTail = pNode;
+ }
+ else {
+ _pHead->SetPrev(pNode);
+ }
+ _pHead = pNode;
+ }
+
+ return (LISTNODE)pNode;
+ }
+
+ template <class Type> LISTNODE List<Type>::AddSorted(const Type &item,
+ LPVOID pfn)
+ {
+ ListNode<Type> *pNode = NULL;
+ LISTNODE pCurrNode = NULL;
+ LISTNODE pPrevNode = NULL;
+ int i;
+ Type curItem;
+
+ LONG (*pFN) (const Type item1, const Type item2);
+
+ pFN = (LONG (*) (const Type item1, const Type item2))pfn;
+
+ if(_pHead == NULL) {
+ return AddHead(item);
+ }
+ else {
+ pCurrNode = GetHeadPosition();
+ curItem = ((ListNode<Type> *) pCurrNode)->GetItem();
+ for (i = 0; i < _iCount; i++) {
+ if (pFN(item, curItem) < 1) {
+ NEW_CONSTR(pNode, ListNode<Type>(item));
+ if (pNode) {
+ pNode->SetPrev((ListNode<Type> *)pPrevNode);
+ pNode->SetNext((ListNode<Type> *)pCurrNode);
+ // update pPrevNode
+ if(pPrevNode) {
+ ((ListNode<Type> *)pPrevNode)->SetNext(pNode);
+ }
+ else {
+ _pHead = pNode;
+ }
+ // update pCurrNode
+ ((ListNode<Type> *)pCurrNode)->SetPrev(pNode);
+ _iCount++;
+ }
+ break;
+ }
+ pPrevNode = pCurrNode;
+ GetNext(pCurrNode);
+ if(i+1 == _iCount) {
+ return AddTail(item);
+ }
+ else {
+ _ASSERTE(pCurrNode);
+ curItem = GetAt(pCurrNode);
+ }
+ }
+ }
+
+ return (LISTNODE)pNode;
+ }
+
+ template <class Type> LISTNODE List<Type>::AddTail(const Type &item)
+ {
+ ListNode<Type> *pNode = NULL;
+
+ NEW_CONSTR(pNode, ListNode<Type>(item));
+ if (pNode) {
+ _iCount++;
+ if (_pTail) {
+ pNode->SetPrev(_pTail);
+ _pTail->SetNext(pNode);
+ _pTail = pNode;
+ }
+ else {
+ _pHead = _pTail = pNode;
+ }
+ }
+
+ return (LISTNODE)pNode;
+ }
+
+ template <class Type> int List<Type>::GetCount()
+ {
+ return _iCount;
+ }
+
+ template <class Type> LISTNODE List<Type>::GetHeadPosition()
+ {
+ return (LISTNODE)_pHead;
+ }
+
+ template <class Type> LISTNODE List<Type>::GetTailPosition()
+ {
+ return (LISTNODE)_pTail;
+ }
+
+ template <class Type> Type List<Type>::GetNext(LISTNODE &pNode)
+ {
+ ListNode<Type> *pListNode = (ListNode<Type> *)pNode;
+
+ // Faults if you pass NULL
+ _ASSERTE(pNode);
+
+ Type item = pListNode->GetItem();
+ pNode = (LISTNODE)(pListNode->GetNext());
+
+ return item;
+ }
+
+ template <class Type> void List<Type>::RemoveAll()
+ {
+ int i;
+ LISTNODE listNode = NULL;
+ ListNode<Type> *pDelNode = NULL;
+
+ listNode = GetHeadPosition();
+
+ for (i = 0; i < _iCount; i++) {
+ pDelNode = (ListNode<Type> *)listNode;
+ GetNext(listNode);
+ SAFE_DELETE(pDelNode);
+ }
+
+ _iCount = 0;
+ _pHead = NULL;
+ _pTail = NULL;
+ }
+
+ template <class Type> void List<Type>::RemoveAt(LISTNODE pNode)
+ {
+ ListNode<Type> *pListNode = (ListNode<Type> *)pNode;
+ ListNode<Type> *pPrevNode = NULL;
+ ListNode<Type> *pNextNode = NULL;
+
+ if (pNode) {
+ pPrevNode = pListNode->GetPrev();
+ pNextNode = pListNode->GetNext();
+
+ if (pPrevNode) {
+ pPrevNode->SetNext(pNextNode);
+ if (pNextNode) {
+ pNextNode->SetPrev(pPrevNode);
+ }
+ else {
+ // We're removing the last node, so we have a new tail
+ _pTail = pPrevNode;
+ }
+ SAFE_DELETE(pListNode);
+ }
+ else {
+ // No previous, so we are the head of the list
+ _pHead = pNextNode;
+ if (pNextNode) {
+ pNextNode->SetPrev(NULL);
+ }
+ else {
+ // No previous, or next. There was only one node.
+ _pHead = NULL;
+ _pTail = NULL;
+ }
+ SAFE_DELETE(pListNode);
+ }
+
+ _iCount--;
+ }
+ }
+
+
+ template <class Type> LISTNODE List<Type>::Find(const Type &item)
+ {
+ int i;
+ Type curItem;
+ LISTNODE pNode = NULL;
+ LISTNODE pMatchNode = NULL;
+ ListNode<Type> * pListNode = NULL;
+
+ pNode = GetHeadPosition();
+ for (i = 0; i < _iCount; i++) {
+ pListNode = (ListNode<Type> *)pNode;
+ curItem = GetNext(pNode);
+ if (curItem == item) {
+ pMatchNode = (LISTNODE)pListNode;
+ break;
+ }
+ }
+
+ return pMatchNode;
+ }
+
+ template <class Type> Type List<Type>::GetAt(LISTNODE pNode)
+ {
+ ListNode<Type> *pListNode = (ListNode<Type> *)pNode;
+
+ // Faults if you pass NULL
+ _ASSERTE(pNode);
+
+ return pListNode->GetItem();
+ }
+};
+
+#endif
diff --git a/src/binder/inc/loadcontext.hpp b/src/binder/inc/loadcontext.hpp
new file mode 100644
index 0000000000..5a403a7542
--- /dev/null
+++ b/src/binder/inc/loadcontext.hpp
@@ -0,0 +1,49 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// LoadContext.hpp
+//
+
+
+//
+// Defines the LoadContext template class
+//
+// ============================================================
+
+#ifndef __BINDER__LOAD_CONTEXT_HPP__
+#define __BINDER__LOAD_CONTEXT_HPP__
+
+#include "assemblyhashtraits.hpp"
+#include "contextentry.hpp"
+#include "bindresult.hpp"
+
+namespace BINDER_SPACE
+{
+ template <DWORD dwIncludeFlags>
+ class LoadContext : protected SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >
+ {
+ private:
+ typedef SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> > Hash;
+ public:
+ LoadContext();
+ ~LoadContext();
+
+ ULONG AddRef();
+ ULONG Release();
+ ContextEntry *Lookup(/* in */ AssemblyName *pAssemblyName);
+ HRESULT Register(BindResult *pBindResult);
+
+ protected:
+ LONG m_cRef;
+ };
+
+#include "loadcontext.inl"
+
+ class InspectionContext :
+ public LoadContext<AssemblyName::INCLUDE_VERSION | AssemblyName::INCLUDE_ARCHITECTURE> {};
+ class ExecutionContext : public LoadContext<AssemblyName::INCLUDE_DEFAULT> {};
+};
+
+#endif
diff --git a/src/binder/inc/loadcontext.inl b/src/binder/inc/loadcontext.inl
new file mode 100644
index 0000000000..c584f8d6ef
--- /dev/null
+++ b/src/binder/inc/loadcontext.inl
@@ -0,0 +1,90 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// LoadContext.inl
+//
+
+
+//
+// Implements the inlined methods of LoadContext template class
+//
+// ============================================================
+
+#ifndef __BINDER__LOAD_CONTEXT_INL__
+#define __BINDER__LOAD_CONTEXT_INL__
+
+template <DWORD dwIncludeFlags>
+LoadContext<dwIncludeFlags>::LoadContext() :
+ SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >::SHash()
+{
+ m_cRef = 1;
+}
+
+template <DWORD dwIncludeFlags>
+LoadContext<dwIncludeFlags>::~LoadContext()
+{
+ // Delete context entries and contents array
+ for (typename Hash::Iterator i = Hash::Begin(), end = Hash::End(); i != end; i++)
+ {
+ const ContextEntry *pContextEntry = *i;
+ delete pContextEntry;
+ }
+ this->RemoveAll();
+}
+
+template <DWORD dwIncludeFlags>
+ULONG LoadContext<dwIncludeFlags>::AddRef()
+{
+ return InterlockedIncrement(&m_cRef);
+}
+
+template <DWORD dwIncludeFlags>
+ULONG LoadContext<dwIncludeFlags>::Release()
+{
+ ULONG ulRef = InterlockedDecrement(&m_cRef);
+
+ if (ulRef == 0)
+ {
+ delete this;
+ }
+
+ return ulRef;
+}
+
+template <DWORD dwIncludeFlags>
+ContextEntry *LoadContext<dwIncludeFlags>::Lookup(AssemblyName *pAssemblyName)
+{
+ ContextEntry *pContextEntry =
+ SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >::Lookup(pAssemblyName);
+
+ return pContextEntry;
+}
+
+template <DWORD dwIncludeFlags>
+HRESULT LoadContext<dwIncludeFlags>::Register(BindResult *pBindResult)
+{
+ HRESULT hr = S_OK;
+ ContextEntry *pContextEntry = NULL;
+
+ SAFE_NEW(pContextEntry, ContextEntry);
+
+ pContextEntry->SetIsDynamicBind(pBindResult->GetIsDynamicBind());
+ pContextEntry->SetIsInGAC(pBindResult->GetIsInGAC());
+ pContextEntry->SetIsSharable(pBindResult->GetIsSharable());
+ pContextEntry->SetAssemblyName(pBindResult->GetAssemblyName(), TRUE /* fAddRef */);
+ pContextEntry->SetAssembly(pBindResult->GetAssembly());
+
+ if (pBindResult->GetIsFirstRequest())
+ {
+ pContextEntry->SetIsFirstRequest(TRUE);
+ }
+
+ SHash<AssemblyHashTraits<ContextEntry *, dwIncludeFlags> >::Add(pContextEntry);
+
+ Exit:
+ return hr;
+}
+
+#endif
diff --git a/src/binder/inc/propertyhashtraits.hpp b/src/binder/inc/propertyhashtraits.hpp
new file mode 100644
index 0000000000..c35d5f0dfe
--- /dev/null
+++ b/src/binder/inc/propertyhashtraits.hpp
@@ -0,0 +1,95 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// PropertyMap.hpp
+//
+
+
+//
+// Defines the PropertyMap class
+//
+// ============================================================
+
+#ifndef __BINDER__PROPERTY_HASH_TRAITS_HPP__
+#define __BINDER__PROPERTY_HASH_TRAITS_HPP__
+
+#include "bindertypes.hpp"
+#include "sstring.h"
+#include "shash.h"
+
+namespace BINDER_SPACE
+{
+ class PropertyEntry
+ {
+ public:
+ inline PropertyEntry()
+ {
+ m_pPropertyName = NULL;
+ m_pPropertyValue = NULL;
+ }
+ inline ~PropertyEntry()
+ {
+ SAFE_DELETE(m_pPropertyName);
+ SAFE_DELETE(m_pPropertyValue);
+ }
+
+ // Getters/Setters
+ inline SString *GetPropertyName()
+ {
+ return m_pPropertyName;
+ }
+ inline void SetPropertyName(SString *pPropertyName)
+ {
+ SAFE_DELETE(m_pPropertyName);
+ m_pPropertyName = pPropertyName;
+ }
+ inline SBuffer *GetPropertyValue()
+ {
+ return m_pPropertyValue;
+ }
+ inline void SetPropertyValue(SBuffer *pPropertyValue)
+ {
+ SAFE_DELETE(m_pPropertyValue);
+ m_pPropertyValue = pPropertyValue;
+ }
+
+ protected:
+ SString *m_pPropertyName;
+ SBuffer *m_pPropertyValue;
+ };
+
+ class PropertyHashTraits : public DefaultSHashTraits<PropertyEntry *>
+ {
+ public:
+ typedef SString* key_t;
+
+ // GetKey, Equals, and Hash can throw due to SString
+ static const bool s_NoThrow = false;
+
+ static key_t GetKey(element_t pPropertyEntry)
+ {
+ return pPropertyEntry->GetPropertyName();
+ }
+ static BOOL Equals(key_t pPropertyName1, key_t pPropertyName2)
+ {
+ return pPropertyName1->Equals(*pPropertyName2);
+ }
+ static count_t Hash(key_t pPropertyName)
+ {
+ return pPropertyName->Hash();
+ }
+ static const element_t Null()
+ {
+ return NULL;
+ }
+ static bool IsNull(const element_t &propertyEntry)
+ {
+ return (propertyEntry == NULL);
+ }
+
+ };
+};
+
+#endif
diff --git a/src/binder/inc/propertymap.hpp b/src/binder/inc/propertymap.hpp
new file mode 100644
index 0000000000..38a8890dcc
--- /dev/null
+++ b/src/binder/inc/propertymap.hpp
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// PropertyMap.hpp
+//
+
+
+//
+// Defines the PropertyMap class
+//
+// ============================================================
+
+
+#ifndef __BINDER__PROPERTY_MAP_HPP__
+#define __BINDER__PROPERTY_MAP_HPP__
+
+#include "propertyhashtraits.hpp"
+
+namespace BINDER_SPACE
+{
+ class PropertyMap : protected SHash<PropertyHashTraits>
+ {
+ public:
+ PropertyMap();
+ ~PropertyMap();
+
+ HRESULT Add(/* in */ SString *pPropertyName,
+ /* in */ SBuffer *pPropertyValue);
+ SBuffer *Lookup(/* in */ SString *pPropertyName);
+ };
+};
+
+#endif
diff --git a/src/binder/inc/stringlexer.hpp b/src/binder/inc/stringlexer.hpp
new file mode 100644
index 0000000000..257b883c51
--- /dev/null
+++ b/src/binder/inc/stringlexer.hpp
@@ -0,0 +1,100 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// StringLexer.hpp
+//
+
+
+//
+// Defines the StringLexer class
+//
+// ============================================================
+
+#ifndef __BINDER__STRING_LEXER_HPP__
+#define __BINDER__STRING_LEXER_HPP__
+
+#include "bindertypes.hpp"
+
+#define GO_IF_NOT_EXPECTED(expr, kRequiredLexemeType) \
+ if ((expr) != kRequiredLexemeType) \
+ { \
+ fIsValid = FALSE; \
+ goto Exit; \
+ }
+
+#define GO_IF_END_OR_NOT_EXPECTED(expr, kRequiredLexemeType) \
+ { \
+ LEXEME_TYPE kGotLexemeType = (expr); \
+ if (kGotLexemeType == LEXEME_TYPE_END_OF_STREAM) \
+ { \
+ goto Exit; \
+ } \
+ else \
+ { \
+ GO_IF_NOT_EXPECTED(kGotLexemeType, kRequiredLexemeType); \
+ } \
+ }
+
+namespace BINDER_SPACE
+{
+ class StringLexer
+ {
+ public:
+ typedef enum
+ {
+ LEXEME_TYPE_INVALID,
+ LEXEME_TYPE_EQUALS,
+ LEXEME_TYPE_COMMA,
+ LEXEME_TYPE_COLON,
+ LEXEME_TYPE_SEMICOLON,
+ LEXEME_TYPE_STRING,
+ LEXEME_TYPE_END_OF_STREAM
+ } LEXEME_TYPE;
+
+ inline StringLexer();
+ inline ~StringLexer();
+
+ inline void Init(SString &inputString, BOOL fSupportEscaping);
+
+ static inline BOOL IsWhitespace(WCHAR wcChar);
+ static inline BOOL IsEOS(WCHAR wcChar);
+ static inline BOOL IsQuoteCharacter(WCHAR wcChar);
+
+ virtual BOOL IsSeparatorChar(WCHAR wcChar) = NULL;
+ virtual LEXEME_TYPE GetLexemeType(WCHAR wcChar) = NULL;
+
+ protected:
+ static const WCHAR INVALID_CHARACTER = -1;
+
+ LEXEME_TYPE GetNextLexeme(SString &currentString, BOOL fPermitUnescapedQuotes = FALSE);
+
+ inline WCHAR PopCharacter(BOOL *pfIsEscaped);
+ inline void PushCharacter(WCHAR wcCurrentChar,
+ BOOL fIsEscaped);
+
+ inline WCHAR GetRawCharacter();
+ inline void PushRawCharacter();
+ inline WCHAR DecodeUTF16Character();
+ inline WCHAR GetNextCharacter(BOOL *pfIsEscaped);
+
+ inline WCHAR ParseUnicode();
+ LEXEME_TYPE ParseString(SString &currentString,
+ BOOL fPermitUnescapeQuotes);
+
+ void TrimTrailingWhiteSpaces(SString &currentString);
+
+ SString::Iterator m_cursor;
+ SString::Iterator m_end;
+
+ WCHAR m_wcCurrentChar;
+ BOOL m_fCurrentCharIsEscaped;
+ BOOL m_fSupportEscaping;
+ BOOL m_fReadRawCharacter;
+ };
+
+#include "stringlexer.inl"
+};
+
+#endif
diff --git a/src/binder/inc/stringlexer.inl b/src/binder/inc/stringlexer.inl
new file mode 100644
index 0000000000..f8bc3816a4
--- /dev/null
+++ b/src/binder/inc/stringlexer.inl
@@ -0,0 +1,266 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// StringLexer.inl
+//
+
+
+//
+// Implements the inlined methods of StringLexer class
+//
+// ============================================================
+
+#ifndef __BINDER__STRING_LEXER_INL__
+#define __BINDER__STRING_LEXER_INL__
+
+StringLexer::StringLexer()
+{
+ m_wcCurrentChar = INVALID_CHARACTER;
+ m_fCurrentCharIsEscaped = FALSE;
+}
+
+StringLexer::~StringLexer()
+{
+ // Nothing to do here
+}
+
+void StringLexer::Init(SString &inputString, BOOL fSupportEscaping)
+{
+ m_cursor = inputString.Begin();
+ m_end = inputString.End();
+ m_fSupportEscaping = fSupportEscaping;
+ m_fReadRawCharacter = FALSE;
+}
+
+BOOL StringLexer::IsWhitespace(WCHAR wcChar)
+{
+ return ((wcChar == L'\n') || (wcChar == L'\r') || (wcChar == L' ') || (wcChar == L'\t'));
+}
+
+BOOL StringLexer::IsEOS(WCHAR wcChar)
+{
+ return (wcChar == 0);
+}
+
+BOOL StringLexer::IsQuoteCharacter(WCHAR wcChar)
+{
+ return ((wcChar == L'\'') || (wcChar == L'"'));
+}
+
+WCHAR StringLexer::PopCharacter(BOOL *pfIsEscaped)
+{
+ WCHAR wcCurrentChar = m_wcCurrentChar;
+ BINDER_LOG_ENTER(L"StringLexer::PopCharacter");
+
+ if (wcCurrentChar != INVALID_CHARACTER)
+ {
+ BINDER_LOG(L"HAVE wcCurrentChar");
+ m_wcCurrentChar = INVALID_CHARACTER;
+ *pfIsEscaped = m_fCurrentCharIsEscaped;
+ }
+ else
+ {
+ BINDER_LOG(L"GET wcCurrentChar");
+ wcCurrentChar = GetNextCharacter(pfIsEscaped);
+ }
+
+#ifdef BINDER_DEBUG_LOG
+ PathString info;
+
+ info.Printf(L"wcCurrentChar=%p", (void *) wcCurrentChar);
+ BINDER_LOG((WCHAR *) info.GetUnicode());
+#endif
+
+ BINDER_LOG_LEAVE(L"StringLexer::PopCharacter");
+ return wcCurrentChar;
+}
+
+void StringLexer::PushCharacter(WCHAR wcCurrentChar,
+ BOOL fIsEscaped)
+{
+ BINDER_LOG_ENTER(L"StringLexer::PushCharacter");
+
+#ifdef BINDER_DEBUG_LOG
+ PathString info;
+
+ info.Printf(L"wcCurrentChar=%p, fIsEscaped=%d", (void *) wcCurrentChar, fIsEscaped);
+ BINDER_LOG((WCHAR *) info.GetUnicode());
+#endif
+
+ _ASSERTE(m_wcCurrentChar == INVALID_CHARACTER);
+
+ m_wcCurrentChar = wcCurrentChar;
+ m_fCurrentCharIsEscaped = fIsEscaped;
+
+ BINDER_LOG_LEAVE(L"StringLexer::PushCharacter");
+}
+
+WCHAR StringLexer::GetRawCharacter()
+{
+ WCHAR wcCurrentChar = 0;
+
+ if (m_cursor <= m_end)
+ {
+ wcCurrentChar = m_cursor[0];
+ m_fReadRawCharacter = TRUE;
+ m_cursor++;
+ }
+ else
+ {
+ m_fReadRawCharacter = FALSE;
+ }
+
+ return wcCurrentChar;
+}
+
+void StringLexer::PushRawCharacter()
+{
+ if (m_fReadRawCharacter)
+ {
+ m_cursor--;
+ m_fReadRawCharacter = FALSE;
+ }
+}
+
+WCHAR StringLexer::DecodeUTF16Character()
+{
+ // See http://www.ietf.org/rfc/rfc2781.txt for details on UTF-16 encoding.
+
+ WCHAR wcCurrentChar = 0;
+ SIZE_T nCharacters = m_end - m_cursor + 1;
+ WCHAR wcChar1 = GetRawCharacter();
+
+ if (wcChar1 < 0xd800)
+ {
+ wcCurrentChar = wcChar1;
+ }
+ else
+ {
+ // StringLexer is not designed to handle UTF-16 characters beyond the Basic Multilingual Plane,
+ // since it stores all characters in 16-bit WCHARs.
+ // However, since the vast majority of the time, we (Microsoft) produce the manifests,
+ // this is likely a non-scenario, as the other Unicode planes would never be used in practice.
+
+ if (wcChar1 <= 0xdbff) // 0xd800 - 0xdbff indicates the first WCHAR of a surrogate pair
+ {
+ if (nCharacters >= 2)
+ {
+ GetRawCharacter(); // Skip the second WCHAR of the surrogate pair
+ }
+ }
+ // Otherwise, the character is either in the 0xdc00 - 0xdfff range, indicating the second WCHAR of a surrogate pair,
+ // or in the 0xE000 - 0xFFFF range, which has within it ranges of invalid characters, and which we conservatively treat
+ // as invalid.
+
+ wcCurrentChar = INVALID_CHARACTER;
+ }
+
+ return wcCurrentChar;
+}
+
+
+WCHAR StringLexer::GetNextCharacter(BOOL *pfIsEscaped)
+{
+ *pfIsEscaped = FALSE;
+
+ WCHAR wcCurrentChar = GetRawCharacter(); // DecodeUTF16Character()
+ if (wcCurrentChar == L'\\')
+ {
+ WCHAR wcTempChar = GetRawCharacter(); // DecodeUTF16Character()
+
+ if (m_fSupportEscaping)
+ {
+ // Handle standard escapes
+ switch (wcTempChar)
+ {
+ case L'"':
+ case L'\'':
+ case L',':
+ case L'\\':
+ case L'/':
+ case L'=':
+ break;
+ case L't':
+ wcTempChar = 9;
+ break;
+ case L'n':
+ wcTempChar = 10;
+ break;
+ case L'r':
+ wcTempChar = 13;
+ break;
+ case L'u':
+ wcTempChar = ParseUnicode();
+ break;
+ default:
+ return INVALID_CHARACTER;
+ }
+
+ *pfIsEscaped = TRUE;
+ wcCurrentChar = wcTempChar;
+ }
+ else
+ {
+ // Do not handle escapes except for quotes
+ switch (wcTempChar)
+ {
+ case L'"':
+ case L'\'':
+ *pfIsEscaped = TRUE;
+ wcCurrentChar = wcTempChar;
+ break;
+ default:
+ PushRawCharacter();
+ break;
+ }
+ }
+ }
+
+ return wcCurrentChar;
+}
+
+WCHAR StringLexer::ParseUnicode()
+{
+ int nCharacters = 0;
+ WCHAR wcUnicodeChar = 0;
+
+ for(;;)
+ {
+ WCHAR wcCurrentChar = DecodeUTF16Character();
+ nCharacters++;
+
+ if (wcCurrentChar == L';')
+ {
+ break;
+ }
+ else if ((wcCurrentChar == INVALID_CHARACTER) || (nCharacters >= 9))
+ {
+ return INVALID_CHARACTER;
+ }
+
+ wcUnicodeChar <<= 4;
+
+ if ((wcCurrentChar >= L'0') && (wcCurrentChar <= L'9'))
+ {
+ wcUnicodeChar += (wcCurrentChar - L'0');
+ }
+ else if ((wcCurrentChar >= L'a') && (wcCurrentChar <= L'f'))
+ {
+ wcUnicodeChar += (wcCurrentChar - L'a') + 10;
+ }
+ else if ((wcCurrentChar >= L'A') && (wcCurrentChar <= L'F'))
+ {
+ wcUnicodeChar += (wcCurrentChar - L'A') + 10;
+ }
+ else
+ {
+ return INVALID_CHARACTER;
+ }
+ }
+
+ return wcUnicodeChar;
+}
+
+#endif
diff --git a/src/binder/inc/textualidentityparser.hpp b/src/binder/inc/textualidentityparser.hpp
new file mode 100644
index 0000000000..02af033cfb
--- /dev/null
+++ b/src/binder/inc/textualidentityparser.hpp
@@ -0,0 +1,70 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// TextualIdentityParser.hpp
+//
+
+
+//
+// Defines the TextualIdentityParser class
+//
+// ============================================================
+
+#ifndef __BINDER__TEXTUAL_IDENTITY_PARSER_HPP__
+#define __BINDER__TEXTUAL_IDENTITY_PARSER_HPP__
+
+#include "bindertypes.hpp"
+#include "stringlexer.hpp"
+
+namespace BINDER_SPACE
+{
+ class AssemblyVersion;
+ class AssemblyIdentity;
+
+ class TextualIdentityParser : public StringLexer
+ {
+ public:
+ TextualIdentityParser(AssemblyIdentity *pAssemblyIdentity);
+ ~TextualIdentityParser();
+
+ virtual BOOL IsSeparatorChar(WCHAR wcChar);
+ virtual StringLexer::LEXEME_TYPE GetLexemeType(WCHAR wcChar);
+
+ static HRESULT Parse(/* in */ SString &textualIdentity,
+ /* out */ AssemblyIdentity *pAssemblyIdentity,
+ /* in */ BOOL fPermitUnescapedQuotes = FALSE);
+ static HRESULT ToString(/* in */ AssemblyIdentity *pAssemblyIdentity,
+ /* in */ DWORD dwIdentityFlags,
+ /* out */ SString &textualIdentity);
+
+ static BOOL ParseVersion(/* in */ SString &versionString,
+ /* out */ AssemblyVersion *pAssemblyVersion);
+
+ static BOOL HexToBlob(/* in */ SString &publicKeyOrToken,
+ /* in */ BOOL fValidateHex,
+ /* in */ BOOL fIsToken,
+ /* out */ SBuffer &publicKeyOrTokenBLOB);
+ static void BlobToHex(/* in */ SBuffer &publicKeyOrTokenBLOB,
+ /* out */ SString &publicKeyOrToken);
+
+ BOOL ParseString(/* in */ SString &textualString,
+ /* out */ SString &contentString);
+
+ protected:
+ BOOL Parse(/* in */ SString &textualIdentity,
+ /* in */ BOOL fPermitUnescapedQuotes = FALSE);
+
+ BOOL PopulateAssemblyIdentity(/* in */ SString &attributeString,
+ /* in */ SString &valueString);
+
+ static void EscapeString(/* in */ SString &input,
+ /* out*/ SString &result);
+
+ AssemblyIdentity *m_pAssemblyIdentity;
+ DWORD m_dwAttributesSeen;
+ };
+};
+
+#endif
diff --git a/src/binder/inc/utils.hpp b/src/binder/inc/utils.hpp
new file mode 100644
index 0000000000..8b65fd8c12
--- /dev/null
+++ b/src/binder/inc/utils.hpp
@@ -0,0 +1,57 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Utils.hpp
+//
+
+
+//
+// Declares a bunch of binder auxilary functions
+//
+// ============================================================
+
+#ifndef __BINDER_UTILS_HPP__
+#define __BINDER_UTILS_HPP__
+
+#include "bindertypes.hpp"
+
+extern LocaleID g_lcid;
+
+namespace BINDER_SPACE
+{
+ inline BOOL EqualsCaseInsensitive(SString &a, SString &b)
+ {
+ return a.EqualsCaseInsensitive(b, g_lcid);
+ }
+
+ inline ULONG HashCaseInsensitive(SString &string)
+ {
+ return string.HashCaseInsensitive(g_lcid);
+ }
+
+ HRESULT FileOrDirectoryExists(PathString &path);
+ HRESULT FileOrDirectoryExistsLog(PathString &path);
+
+ BOOL IsURL(SString &urlOrPath);
+
+ void MutateUrlToPath(SString &urlOrPath);
+ void MutatePathToUrl(SString &pathOrUrl);
+
+ // Mutates path
+ void PlatformPath(SString &path);
+ void CanonicalizePath(SString &path, BOOL fAppendPathSeparator = FALSE);
+
+ // It is safe to use either A or B as CombinedPath.
+ void CombinePath(SString &pathA,
+ SString &pathB,
+ SString &combinedPath);
+
+ HRESULT GetTokenFromPublicKey(SBuffer &publicKeyBLOB,
+ SBuffer &publicKeyTokenBLOB);
+
+ BOOL IsFileNotFound(HRESULT hr);
+};
+
+#endif
diff --git a/src/binder/inc/variables.hpp b/src/binder/inc/variables.hpp
new file mode 100644
index 0000000000..d2cf742a23
--- /dev/null
+++ b/src/binder/inc/variables.hpp
@@ -0,0 +1,66 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Variables.hpp
+//
+
+
+//
+// Defines the Variables class
+//
+// ============================================================
+
+#ifndef __BINDER__VARIABLES_HPP__
+#define __BINDER__VARIABLES_HPP__
+
+#include "bindertypes.hpp"
+
+namespace BINDER_SPACE
+{
+ class Variables
+ {
+ public:
+ Variables();
+ ~Variables();
+
+ HRESULT Init();
+
+ // ApplicationContext string constants
+ SString AppBaseURL;
+ SString DynamicDirectory;
+ SString DynamicBaseDirectory;
+ SString AppName;
+ SString AppConfigFile;
+ SString AppDomainId;
+
+ // AssemblyBinder string constants
+ SString httpURLPrefix;
+
+ // AssemblyName string constants
+ SString architectureMSIL;
+ SString architectureX86;
+ SString architectureAMD64;
+ SString architectureARM;
+ SString architectureARM64;
+ SString cultureNeutral;
+ SString emptyString;
+ SString mscorlib;
+
+#ifdef FEATURE_VERSIONING_LOG
+ BOOL fLoggingNeeded;
+ SString logPath;
+#endif // FEATURE_VERSIONING_LOG
+#ifndef DACCESS_COMPILE
+#ifdef BINDER_DEBUG_LOG
+ CRITSEC_COOKIE m_logCS;
+ HandleHolder m_hDebugLogFile;
+#endif // BINDER_DEBUG_LOG
+#endif
+ };
+
+ extern Variables *g_BinderVariables;
+};
+
+#endif
diff --git a/src/binder/propertymap.cpp b/src/binder/propertymap.cpp
new file mode 100644
index 0000000000..b942b4b765
--- /dev/null
+++ b/src/binder/propertymap.cpp
@@ -0,0 +1,62 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// PropertyMap.cpp
+//
+
+
+//
+// Implements the PropertyMap class
+//
+// ============================================================
+
+#include "propertymap.hpp"
+
+namespace BINDER_SPACE
+{
+ PropertyMap::PropertyMap() : SHash<PropertyHashTraits>::SHash() {
+ // Nothing to do here
+ }
+
+ PropertyMap::~PropertyMap() {
+ // Nothing to do here
+ }
+
+ HRESULT PropertyMap::Add(SString *pPropertyName,
+ SBuffer *pPropertyValue)
+ {
+ _ASSERTE(pPropertyName != NULL);
+ _ASSERTE(pPropertyValue != NULL);
+
+ HRESULT hr = S_OK;
+
+ NewHolder<PropertyEntry> pPropertyEntry;
+ SAFE_NEW(pPropertyEntry, PropertyEntry);
+
+ pPropertyEntry->SetPropertyName(pPropertyName);
+ pPropertyEntry->SetPropertyValue(pPropertyValue);
+
+ SHash<PropertyHashTraits>::Add(pPropertyEntry);
+ pPropertyEntry.SuppressRelease();
+
+ Exit:
+ return hr;
+ }
+
+ SBuffer *PropertyMap::Lookup(SString *pPropertyName)
+ {
+ _ASSERTE(pPropertyName != NULL);
+
+ SBuffer *pPropertyValue = NULL;
+ PropertyEntry *pPropertyEntry = SHash<PropertyHashTraits>::Lookup(pPropertyName);
+
+ if (pPropertyEntry != NULL)
+ {
+ pPropertyValue = pPropertyEntry->GetPropertyValue();
+ }
+
+ return pPropertyValue;
+ }
+};
diff --git a/src/binder/stringlexer.cpp b/src/binder/stringlexer.cpp
new file mode 100644
index 0000000000..ebecd70058
--- /dev/null
+++ b/src/binder/stringlexer.cpp
@@ -0,0 +1,173 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// StringLexer.cpp
+//
+
+
+//
+// Implements the StringLexer class
+//
+// ============================================================
+
+#define DISABLE_BINDER_DEBUG_LOGGING
+
+#include "stringlexer.hpp"
+#include "utils.hpp"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+ StringLexer::LEXEME_TYPE
+ StringLexer::GetNextLexeme(SString &currentString, BOOL fPermitUnescapedQuotes)
+ {
+ BOOL fIsEscaped = FALSE;
+ WCHAR wcCurrentChar = INVALID_CHARACTER;
+ BINDER_LOG_ENTER(L"StringLexer::GetNextLexeme");
+
+ // Remove any white spaces
+ do
+ {
+ wcCurrentChar = PopCharacter(&fIsEscaped);
+ }
+ while (IsWhitespace(wcCurrentChar));
+
+ // Determine lexeme type
+ LEXEME_TYPE kLexemeType = LEXEME_TYPE_INVALID;
+ if (!fIsEscaped)
+ {
+ kLexemeType = GetLexemeType(wcCurrentChar);
+
+ if (kLexemeType != LEXEME_TYPE_STRING)
+ {
+ return kLexemeType;
+ }
+ }
+
+ // First character of string lexeme; push it back
+ PushCharacter(wcCurrentChar, fIsEscaped);
+ kLexemeType = ParseString(currentString, fPermitUnescapedQuotes);
+ if (kLexemeType == LEXEME_TYPE_STRING)
+ {
+ BINDER_LOG_LEAVE_HR(L"StringLexer::GetNextLexeme(LEXEME_TYPE_STRING)", S_OK);
+ }
+ else
+ {
+ BINDER_LOG_LEAVE_HR(L"StringLexer::GetNextLexeme(LEXEME_TYPE_INVALID)",
+ S_FALSE);
+ }
+
+ return kLexemeType;
+ }
+
+ StringLexer::LEXEME_TYPE
+ StringLexer::ParseString(SString &currentString, BOOL fPermitUnescapedQuotes)
+ {
+ BOOL fIsFirstCharacter = TRUE;
+ WCHAR wcCurrentChar = INVALID_CHARACTER;
+ WCHAR wcOpeningQuote = INVALID_CHARACTER;
+
+ currentString.Clear();
+
+ // Read until we find another lexeme that's not a string character
+ for (;;)
+ {
+ BOOL fIsEscaped = FALSE;
+ wcCurrentChar = PopCharacter(&fIsEscaped);
+
+ if (wcCurrentChar == INVALID_CHARACTER)
+ {
+ // Found invalid character encoding
+ BINDER_LOG(L"StringLexer::ParseString: Invalid character encoding");
+ return LEXEME_TYPE_INVALID;
+ }
+
+ if (IsEOS(wcCurrentChar))
+ {
+ if (IsQuoteCharacter(wcOpeningQuote))
+ {
+ // EOS and unclosed quotes is an error
+ BINDER_LOG(L"StringLexer::ParseString: EOS and unclosed quotes");
+ return LEXEME_TYPE_INVALID;
+ }
+ else
+ {
+ // Reached end of input and therefore of string
+ break;
+ }
+ }
+
+ if (fIsFirstCharacter)
+ {
+ fIsFirstCharacter = FALSE;
+
+ // If first character is quote, then record its quoteness
+ if (IsQuoteCharacter(wcCurrentChar))
+ {
+ wcOpeningQuote = wcCurrentChar;
+ continue;
+ }
+ }
+
+ if (wcCurrentChar == wcOpeningQuote)
+ {
+ // We've found the closing quote for a quoted string
+ break;
+ }
+
+ if (!fPermitUnescapedQuotes && !fIsEscaped && IsQuoteCharacter(wcCurrentChar) && !IsQuoteCharacter(wcOpeningQuote))
+ {
+ // Unescaped quotes in the middle of the string are an error
+ BINDER_LOG(L"StringLexer::ParseString: Quote in the middle of a string");
+ return LEXEME_TYPE_INVALID;
+ }
+
+ if (IsSeparatorChar(wcCurrentChar) && !IsQuoteCharacter(wcOpeningQuote) && !fIsEscaped)
+ {
+ // Unescaped separator char terminates the string
+ PushCharacter(wcCurrentChar, fIsEscaped);
+ break;
+ }
+
+ // Add character to current string
+ currentString.Append(wcCurrentChar);
+ }
+
+ if (!IsQuoteCharacter(wcOpeningQuote))
+ {
+ // Remove trailing white spaces from unquoted string
+ BINDER_LOG(L"StringLexer::ParseString: Trimming string");
+ TrimTrailingWhiteSpaces(currentString);
+ }
+
+ BINDER_LOG_STRING(L"string", currentString);
+
+ return LEXEME_TYPE_STRING;
+ }
+
+ void StringLexer::TrimTrailingWhiteSpaces(SString &currentString)
+ {
+ SString::Iterator begin = currentString.Begin();
+ SString::Iterator cursor = currentString.End() - 1;
+ BOOL fFoundWhiteSpace = FALSE;
+
+ for (;;)
+ {
+ if ((cursor >= begin) && IsWhitespace(cursor[0]))
+ {
+ fFoundWhiteSpace = TRUE;
+ cursor--;
+ continue;
+ }
+ break;
+ }
+
+ if (fFoundWhiteSpace)
+ {
+ currentString.Truncate(cursor + 1);
+ }
+ }
+};
diff --git a/src/binder/textualidentityparser.cpp b/src/binder/textualidentityparser.cpp
new file mode 100644
index 0000000000..eb6e371afe
--- /dev/null
+++ b/src/binder/textualidentityparser.cpp
@@ -0,0 +1,763 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// TextualIdentityParser.cpp
+//
+
+
+//
+// Implements the TextualIdentityParser class
+//
+// ============================================================
+
+#define DISABLE_BINDER_DEBUG_LOGGING
+
+#include "textualidentityparser.hpp"
+#include "assemblyidentity.hpp"
+#include "utils.hpp"
+
+#include "ex.h"
+
+#define GO_IF_SEEN(kAssemblyIdentityFlag) \
+ if ((m_dwAttributesSeen & kAssemblyIdentityFlag) != 0) \
+ { \
+ fIsValid = FALSE; \
+ goto Exit; \
+ } \
+ else \
+ { \
+ m_dwAttributesSeen |= kAssemblyIdentityFlag; \
+ }
+
+#define GO_IF_WILDCARD(valueString) \
+ { \
+ SmallStackSString wildCard(W("*")); \
+ if (valueString.Equals(wildCard)) \
+ { \
+ goto Exit; \
+ } \
+ }
+
+#define GO_IF_VALIDATE_FAILED(validateProc, kIdentityFlag) \
+ if (!validateProc(valueString)) \
+ { \
+ fIsValid = FALSE; \
+ goto Exit; \
+ } \
+ else \
+ { \
+ m_pAssemblyIdentity->SetHave(kIdentityFlag); \
+ }
+
+#define FROMHEX(a) ((a)>=W('a') ? a - W('a') + 10 : a - W('0'))
+#define TOHEX(a) ((a)>=10 ? W('a')+(a)-10 : W('0')+(a))
+#define TOLOWER(a) (((a) >= W('A') && (a) <= W('Z')) ? (W('a') + (a - W('A'))) : (a))
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ const int iPublicKeyTokenLength = 8;
+
+ const int iPublicKeyMinLength = 0;
+ const int iPublicKeyMaxLength = 2048;
+
+ const int iVersionMax = 65535;
+ const int iRequiredVersionParts = 4;
+
+ inline void UnicodeHexToBin(LPCWSTR pSrc, UINT cSrc, LPBYTE pDest)
+ {
+ BYTE v;
+ LPBYTE pd = pDest;
+ LPCWSTR ps = pSrc;
+
+ if (cSrc == 0)
+ return;
+
+ for (UINT i = 0; i < cSrc-1; i+=2)
+ {
+ v = (BYTE)FROMHEX(TOLOWER(ps[i])) << 4;
+ v |= FROMHEX(TOLOWER(ps[i+1]));
+ *(pd++) = v;
+ }
+ }
+
+ inline void BinToUnicodeHex(const BYTE *pSrc, UINT cSrc, __out_ecount(2*cSrc) LPWSTR pDst)
+ {
+ UINT x;
+ UINT y;
+
+ for (x = 0, y = 0 ; x < cSrc; ++x)
+ {
+ UINT v;
+
+ v = pSrc[x]>>4;
+ pDst[y++] = (WCHAR)TOHEX(v);
+ v = pSrc[x] & 0x0f;
+ pDst[y++] = (WCHAR)TOHEX(v);
+ }
+ }
+
+ inline BOOL EqualsCaseInsensitive(SString &a, LPCWSTR wzB)
+ {
+ SString b(SString::Literal, wzB);
+
+ return ::BINDER_SPACE::EqualsCaseInsensitive(a, b);
+ }
+
+ BOOL ValidateHex(SString &publicKeyOrToken)
+ {
+ if ((publicKeyOrToken.GetCount() == 0) || ((publicKeyOrToken.GetCount() % 2) != 0))
+ {
+ return FALSE;
+ }
+
+ SString::Iterator cursor = publicKeyOrToken.Begin();
+ SString::Iterator end = publicKeyOrToken.End() - 1;
+
+ while (cursor <= end)
+ {
+ WCHAR wcCurrentChar = cursor[0];
+
+ if (((wcCurrentChar >= W('0')) && (wcCurrentChar <= W('9'))) ||
+ ((wcCurrentChar >= W('a')) && (wcCurrentChar <= W('f'))) ||
+ ((wcCurrentChar >= W('A')) && (wcCurrentChar <= W('F'))))
+ {
+ cursor++;
+ continue;
+ }
+
+ return FALSE;
+ }
+
+ return TRUE;
+ }
+
+ inline BOOL ValidatePublicKeyToken(SString &publicKeyToken)
+ {
+ return ((publicKeyToken.GetCount() == (iPublicKeyTokenLength * 2)) &&
+ ValidateHex(publicKeyToken));
+ }
+
+ inline BOOL ValidatePublicKey(SString &publicKey)
+ {
+
+ return ((publicKey.GetCount() >= (iPublicKeyMinLength * 2)) &&
+ (publicKey.GetCount() <= (iPublicKeyMaxLength * 2)) &&
+ ValidateHex(publicKey));
+ }
+
+ const struct {
+ LPCWSTR strValue;
+ PEKIND enumValue;
+ } wszKnownArchitectures[] = { { W("x86"), peI386 },
+ { W("IA64"), peIA64 },
+ { W("AMD64"), peAMD64 },
+ { W("ARM"), peARM },
+ { W("MSIL"), peMSIL } };
+
+ BOOL ValidateAndConvertProcessorArchitecture(SString &processorArchitecture,
+ PEKIND *pkProcessorAchitecture)
+ {
+ for (int i = LENGTH_OF(wszKnownArchitectures); i--;)
+ {
+ if (EqualsCaseInsensitive(processorArchitecture, wszKnownArchitectures[i].strValue))
+ {
+ *pkProcessorAchitecture = wszKnownArchitectures[i].enumValue;
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+ }
+
+ LPCWSTR PeKindToString(PEKIND kProcessorArchitecture)
+ {
+ _ASSERTE(kProcessorArchitecture != peNone);
+
+ for (int i = LENGTH_OF(wszKnownArchitectures); i--;)
+ {
+ if (wszKnownArchitectures[i].enumValue == kProcessorArchitecture)
+ {
+ return wszKnownArchitectures[i].strValue;
+ }
+ }
+
+ return NULL;
+ }
+
+ LPCWSTR ContentTypeToString(AssemblyContentType kContentType)
+ {
+ _ASSERTE(kContentType != AssemblyContentType_Default);
+
+ if (kContentType == AssemblyContentType_WindowsRuntime)
+ {
+ return W("WindowsRuntime");
+ }
+
+ return NULL;
+ }
+ }; // namespace (anonymous)
+
+ TextualIdentityParser::TextualIdentityParser(AssemblyIdentity *pAssemblyIdentity)
+ {
+ m_pAssemblyIdentity = pAssemblyIdentity;
+ m_dwAttributesSeen = AssemblyIdentity::IDENTITY_FLAG_EMPTY;
+ }
+
+ TextualIdentityParser::~TextualIdentityParser()
+ {
+ // Nothing to do here
+ }
+
+ BOOL TextualIdentityParser::IsSeparatorChar(WCHAR wcChar)
+ {
+ return ((wcChar == W(',')) || (wcChar == W('=')));
+ }
+
+ StringLexer::LEXEME_TYPE TextualIdentityParser::GetLexemeType(WCHAR wcChar)
+ {
+ switch (wcChar)
+ {
+ case W('='):
+ return LEXEME_TYPE_EQUALS;
+ case W(','):
+ return LEXEME_TYPE_COMMA;
+ case 0:
+ return LEXEME_TYPE_END_OF_STREAM;
+ default:
+ return LEXEME_TYPE_STRING;
+ }
+ }
+
+ /* static */
+ HRESULT TextualIdentityParser::Parse(SString &textualIdentity,
+ AssemblyIdentity *pAssemblyIdentity,
+ BOOL fPermitUnescapedQuotes)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("TextualIdentityParser::Parse"));
+
+ IF_FALSE_GO(pAssemblyIdentity != NULL);
+
+ BINDER_LOG_STRING(W("textualIdentity"), textualIdentity);
+
+ EX_TRY
+ {
+ TextualIdentityParser identityParser(pAssemblyIdentity);
+
+ if (!identityParser.Parse(textualIdentity, fPermitUnescapedQuotes))
+ {
+ IF_FAIL_GO(FUSION_E_INVALID_NAME);
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("TextualIdentityParser::Parse"), hr);
+ return hr;
+ }
+
+ /* static */
+ HRESULT TextualIdentityParser::ToString(AssemblyIdentity *pAssemblyIdentity,
+ DWORD dwIdentityFlags,
+ SString &textualIdentity)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("TextualIdentityParser::ToString"));
+
+ IF_FALSE_GO(pAssemblyIdentity != NULL);
+
+ EX_TRY
+ {
+ SmallStackSString tmpString;
+
+ textualIdentity.Clear();
+
+ if (pAssemblyIdentity->m_simpleName.IsEmpty())
+ {
+ goto Exit;
+ }
+
+ EscapeString(pAssemblyIdentity->m_simpleName, tmpString);
+ textualIdentity.Append(tmpString);
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_VERSION))
+ {
+ tmpString.Clear();
+ tmpString.Printf(W("%d.%d.%d.%d"),
+ pAssemblyIdentity->m_version.GetMajor(),
+ pAssemblyIdentity->m_version.GetMinor(),
+ pAssemblyIdentity->m_version.GetBuild(),
+ pAssemblyIdentity->m_version.GetRevision());
+
+ textualIdentity.Append(W(", Version="));
+ textualIdentity.Append(tmpString);
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CULTURE))
+ {
+ textualIdentity.Append(W(", Culture="));
+ if (pAssemblyIdentity->m_cultureOrLanguage.IsEmpty())
+ {
+ textualIdentity.Append(W("neutral"));
+ }
+ else
+ {
+ EscapeString(pAssemblyIdentity->m_cultureOrLanguage, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY))
+ {
+ textualIdentity.Append(W(", PublicKey="));
+ tmpString.Clear();
+ BlobToHex(pAssemblyIdentity->m_publicKeyOrTokenBLOB, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ else if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN))
+ {
+ textualIdentity.Append(W(", PublicKeyToken="));
+ tmpString.Clear();
+ BlobToHex(pAssemblyIdentity->m_publicKeyOrTokenBLOB, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ else if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL))
+ {
+ textualIdentity.Append(W(", PublicKeyToken=null"));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE))
+ {
+ textualIdentity.Append(W(", processorArchitecture="));
+ textualIdentity.Append(PeKindToString(pAssemblyIdentity->m_kProcessorArchitecture));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE))
+ {
+ textualIdentity.Append(W(", Retargetable=Yes"));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE))
+ {
+ textualIdentity.Append(W(", ContentType="));
+ textualIdentity.Append(ContentTypeToString(pAssemblyIdentity->m_kContentType));
+ }
+
+ if (AssemblyIdentity::Have(dwIdentityFlags, AssemblyIdentity::IDENTITY_FLAG_CUSTOM))
+ {
+ textualIdentity.Append(W(", Custom="));
+ tmpString.Clear();
+ BlobToHex(pAssemblyIdentity->m_customBLOB, tmpString);
+ textualIdentity.Append(tmpString);
+ }
+ else if (AssemblyIdentity::Have(dwIdentityFlags,
+ AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL))
+ {
+ textualIdentity.Append(W(", Custom=null"));
+ }
+ }
+ EX_CATCH_HRESULT(hr);
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("TextualIdentityParser::ToString"), hr);
+ return hr;
+ }
+
+ /* static */
+ BOOL TextualIdentityParser::ParseVersion(SString &versionString,
+ AssemblyVersion *pAssemblyVersion)
+ {
+ BOOL fIsValid = FALSE;
+ DWORD dwFoundNumbers = 0;
+ DWORD dwCurrentNumber = 0;
+ DWORD dwNumbers[iRequiredVersionParts];
+
+ BINDER_LOG_ENTER(W("TextualIdentityParser::ParseVersion"));
+
+ if (versionString.GetCount() > 0) {
+ SString::Iterator cursor = versionString.Begin();
+ SString::Iterator end = versionString.End();
+
+ while (cursor <= end)
+ {
+ WCHAR wcCurrentChar = cursor[0];
+
+ if (dwFoundNumbers >= static_cast<DWORD>(iRequiredVersionParts))
+ {
+ goto Exit;
+ }
+ else if (wcCurrentChar == W('.') || wcCurrentChar == 0x00)
+ {
+ dwNumbers[dwFoundNumbers++] = dwCurrentNumber;
+ dwCurrentNumber = 0;
+ }
+ else if ((wcCurrentChar >= W('0')) && (wcCurrentChar <= W('9')))
+ {
+ dwCurrentNumber = (dwCurrentNumber * 10) + (wcCurrentChar - W('0'));
+
+ if (dwCurrentNumber > static_cast<DWORD>(iVersionMax))
+ {
+ goto Exit;
+ }
+ }
+ else
+ {
+ goto Exit;
+ }
+
+ cursor++;
+ }
+
+ if (dwFoundNumbers == static_cast<DWORD>(iRequiredVersionParts))
+ {
+ pAssemblyVersion->SetFeatureVersion(dwNumbers[0], dwNumbers[1]);
+ pAssemblyVersion->SetServiceVersion(dwNumbers[2], dwNumbers[3]);
+ fIsValid = TRUE;
+ }
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE(W("TextualIdentityParser::ParseVersion"));
+ return fIsValid;
+ }
+
+ /* static */
+ BOOL TextualIdentityParser::HexToBlob(SString &publicKeyOrToken,
+ BOOL fValidateHex,
+ BOOL fIsToken,
+ SBuffer &publicKeyOrTokenBLOB)
+ {
+ // Optional input verification
+ if (fValidateHex)
+ {
+ if ((fIsToken && !ValidatePublicKeyToken(publicKeyOrToken)) ||
+ (!fIsToken && !ValidatePublicKey(publicKeyOrToken)))
+ {
+ return FALSE;
+ }
+ }
+
+ UINT ccPublicKeyOrToken = publicKeyOrToken.GetCount();
+ BYTE *pByteBLOB = publicKeyOrTokenBLOB.OpenRawBuffer(ccPublicKeyOrToken / 2);
+
+ UnicodeHexToBin(publicKeyOrToken.GetUnicode(), ccPublicKeyOrToken, pByteBLOB);
+ publicKeyOrTokenBLOB.CloseRawBuffer();
+
+ return TRUE;
+ }
+
+ /* static */
+ void TextualIdentityParser::BlobToHex(SBuffer &publicKeyOrTokenBLOB,
+ SString &publicKeyOrToken)
+ {
+ UINT cbPublicKeyOrTokenBLOB = publicKeyOrTokenBLOB.GetSize();
+ WCHAR *pwzpublicKeyOrToken =
+ publicKeyOrToken.OpenUnicodeBuffer(cbPublicKeyOrTokenBLOB * 2);
+
+ BinToUnicodeHex(publicKeyOrTokenBLOB, cbPublicKeyOrTokenBLOB, pwzpublicKeyOrToken);
+ publicKeyOrToken.CloseBuffer(cbPublicKeyOrTokenBLOB * 2);
+ }
+
+ BOOL TextualIdentityParser::Parse(SString &textualIdentity, BOOL fPermitUnescapedQuotes)
+ {
+ BOOL fIsValid = TRUE;
+ BINDER_LOG_ENTER(W("TextualIdentityParser::Parse(textualIdentity)"));
+ SString unicodeTextualIdentity;
+
+ // Lexer modifies input string
+ textualIdentity.ConvertToUnicode(unicodeTextualIdentity);
+ Init(unicodeTextualIdentity, TRUE /* fSupportEscaping */);
+
+ SmallStackSString currentString;
+
+ // Identity format is simple name (, attr = value)*
+ GO_IF_NOT_EXPECTED(GetNextLexeme(currentString, fPermitUnescapedQuotes), LEXEME_TYPE_STRING);
+ m_pAssemblyIdentity->m_simpleName.Set(currentString);
+ m_pAssemblyIdentity->m_simpleName.Normalize();
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_SIMPLE_NAME);
+
+ for (;;)
+ {
+ SmallStackSString attributeString;
+ SmallStackSString valueString;
+
+ GO_IF_END_OR_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_COMMA);
+ GO_IF_NOT_EXPECTED(GetNextLexeme(attributeString), LEXEME_TYPE_STRING);
+ GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_EQUALS);
+ GO_IF_NOT_EXPECTED(GetNextLexeme(valueString), LEXEME_TYPE_STRING);
+
+ if (!PopulateAssemblyIdentity(attributeString, valueString))
+ {
+ fIsValid = FALSE;
+ break;
+ }
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_BOOL(W("TextualIdentityParser::Parse(textualIdentity)"), fIsValid);
+ return fIsValid;
+ }
+
+ BOOL TextualIdentityParser::ParseString(SString &textualString,
+ SString &contentString)
+ {
+ BOOL fIsValid = TRUE;
+ BINDER_LOG_ENTER(W("TextualIdentityParser::ParseString"));
+ SString unicodeTextualString;
+
+ // Lexer modifies input string
+ textualString.ConvertToUnicode(unicodeTextualString);
+ Init(unicodeTextualString, TRUE /* fSupportEscaping */);
+
+ SmallStackSString currentString;
+ GO_IF_NOT_EXPECTED(GetNextLexeme(currentString), LEXEME_TYPE_STRING);
+
+ contentString.Set(currentString);
+ currentString.Normalize();
+
+ Exit:
+ BINDER_LOG_LEAVE_BOOL(W("TextualIdentityParser::ParseString"), fIsValid);
+ return fIsValid;
+ }
+
+ BOOL TextualIdentityParser::PopulateAssemblyIdentity(SString &attributeString,
+ SString &valueString)
+ {
+ BINDER_LOG_ENTER(W("TextualIdentityParser::PopulateAssemblyIdentity"));
+ BOOL fIsValid = TRUE;
+
+ if (EqualsCaseInsensitive(attributeString, W("culture")) ||
+ EqualsCaseInsensitive(attributeString, W("language")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ GO_IF_WILDCARD(valueString);
+
+ if (!EqualsCaseInsensitive(valueString, W("neutral")))
+ {
+ // culture/language is preserved as is
+ m_pAssemblyIdentity->m_cultureOrLanguage.Set(valueString);
+ m_pAssemblyIdentity->m_cultureOrLanguage.Normalize();
+ }
+
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CULTURE);
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("version")))
+ {
+ AssemblyVersion *pAssemblyVersion = &(m_pAssemblyIdentity->m_version);
+
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ GO_IF_WILDCARD(valueString);
+
+ if (ParseVersion(valueString, pAssemblyVersion))
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_VERSION);
+ }
+ else
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("publickeytoken")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ GO_IF_WILDCARD(valueString);
+
+ if (!EqualsCaseInsensitive(valueString, W("null")) &&
+ !EqualsCaseInsensitive(valueString, W("neutral")))
+ {
+ GO_IF_VALIDATE_FAILED(ValidatePublicKeyToken,
+ AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ HexToBlob(valueString,
+ FALSE /* fValidateHex */,
+ TRUE /* fIsToken */,
+ m_pAssemblyIdentity->m_publicKeyOrTokenBLOB);
+ }
+ else
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN_NULL);
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("publickey")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY_TOKEN);
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
+
+ if (!EqualsCaseInsensitive(valueString, W("null")) &&
+ !EqualsCaseInsensitive(valueString, W("neutral")))
+ {
+ GO_IF_VALIDATE_FAILED(ValidatePublicKey, AssemblyIdentity::IDENTITY_FLAG_PUBLIC_KEY);
+ HexToBlob(valueString,
+ FALSE /* fValidateHex */,
+ FALSE /* fIsToken */,
+ m_pAssemblyIdentity->m_publicKeyOrTokenBLOB);
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("processorarchitecture")))
+ {
+ PEKIND kProcessorArchitecture = peNone;
+
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ GO_IF_WILDCARD(valueString);
+
+ if (ValidateAndConvertProcessorArchitecture(valueString, &kProcessorArchitecture))
+ {
+ m_pAssemblyIdentity->m_kProcessorArchitecture = kProcessorArchitecture;
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_PROCESSOR_ARCHITECTURE);
+ }
+ else
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("retargetable")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+
+ if (EqualsCaseInsensitive(valueString, W("yes")))
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_RETARGETABLE);
+ }
+ else if (!EqualsCaseInsensitive(valueString, W("no")))
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("contenttype")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ GO_IF_WILDCARD(valueString);
+
+ if (EqualsCaseInsensitive(valueString, W("windowsruntime")))
+ {
+ m_pAssemblyIdentity->m_kContentType = AssemblyContentType_WindowsRuntime;
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CONTENT_TYPE);
+ }
+ else
+ {
+ fIsValid = FALSE;
+ }
+ }
+ else if (EqualsCaseInsensitive(attributeString, W("custom")))
+ {
+ GO_IF_SEEN(AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+
+ if (EqualsCaseInsensitive(valueString, W("null")))
+ {
+ m_pAssemblyIdentity->SetHave(AssemblyIdentity::IDENTITY_FLAG_CUSTOM_NULL);
+ }
+ else
+ {
+ GO_IF_VALIDATE_FAILED(ValidateHex, AssemblyIdentity::IDENTITY_FLAG_CUSTOM);
+ HexToBlob(valueString,
+ FALSE /* fValidateHex */,
+ FALSE /* fIsToken */,
+ m_pAssemblyIdentity->m_customBLOB);
+ }
+ }
+ else
+ {
+ // Fusion compat: Silently drop unknown attribute/value pair
+ BINDER_LOG_STRING(W("unknown attribute"), attributeString);
+ BINDER_LOG_STRING(W("unknown value"), valueString);
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("TextualIdentityParser::PopulateAssemblyIdentity"),
+ (fIsValid ? S_OK : S_FALSE));
+ return fIsValid;
+ }
+
+ /* static */
+ void TextualIdentityParser::EscapeString(SString &input,
+ SString &result)
+ {
+ BINDER_LOG_ENTER(W("TextualIdentityParser::EscapeString"));
+
+ BINDER_LOG_STRING(W("input"), input);
+
+ BOOL fNeedQuotes = FALSE;
+ WCHAR wcQuoteCharacter = W('"');
+
+ SmallStackSString tmpString;
+ SString::Iterator cursor = input.Begin();
+ SString::Iterator end = input.End() - 1;
+
+ // Leading/Trailing white space require quotes
+ if (IsWhitespace(cursor[0]) || IsWhitespace(end[0]))
+ {
+ fNeedQuotes = TRUE;
+ }
+
+ // Fusion textual identity compat: escape all non-quote characters even if quoted
+ while (cursor <= end)
+ {
+ WCHAR wcCurrentChar = cursor[0];
+
+ switch (wcCurrentChar)
+ {
+ case W('"'):
+ case W('\''):
+ if (fNeedQuotes && (wcQuoteCharacter != wcCurrentChar))
+ {
+ tmpString.Append(wcCurrentChar);
+ }
+ else if (!fNeedQuotes)
+ {
+ fNeedQuotes = TRUE;
+ wcQuoteCharacter = (wcCurrentChar == W('"') ? W('\'') : W('"'));
+ tmpString.Append(wcCurrentChar);
+ }
+ else
+ {
+ tmpString.Append(W('\\'));
+ tmpString.Append(wcCurrentChar);
+ }
+ break;
+ case W('='):
+ case W(','):
+ case W('\\'):
+ tmpString.Append(W('\\'));
+ tmpString.Append(wcCurrentChar);
+ break;
+ case 9:
+ tmpString.Append(W("\\t"));
+ break;
+ case 10:
+ tmpString.Append(W("\\n"));
+ break;
+ case 13:
+ tmpString.Append(W("\\r"));
+ break;
+ default:
+ tmpString.Append(wcCurrentChar);
+ break;
+ }
+
+ cursor++;
+ }
+
+ if (fNeedQuotes)
+ {
+ result.Clear();
+ result.Append(wcQuoteCharacter);
+ result.Append(tmpString);
+ result.Append(wcQuoteCharacter);
+ }
+ else
+ {
+ result.Set(tmpString);
+ }
+
+ BINDER_LOG_LEAVE(W("TextualIdentityParser::EscapeString"));
+ }
+};
diff --git a/src/binder/utils.cpp b/src/binder/utils.cpp
new file mode 100644
index 0000000000..a6853c86e1
--- /dev/null
+++ b/src/binder/utils.cpp
@@ -0,0 +1,319 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Utils.cpp
+//
+
+
+//
+// Implements a bunch of binder auxilary functions
+//
+// ============================================================
+
+#define DISABLE_BINDER_DEBUG_LOGGING
+
+#include "utils.hpp"
+
+#include <shlwapi.h>
+
+#include "strongname.h"
+#include "corpriv.h"
+
+namespace BINDER_SPACE
+{
+ namespace
+ {
+ inline BOOL IsPathSeparator(WCHAR wcChar)
+ {
+ // Invariant: Valid only for MutateUrlToPath treated pathes
+ return (wcChar == W('\\'));
+ }
+
+ inline const WCHAR *GetPlatformPathSeparator()
+ {
+#ifdef PLATFORM_UNIX
+ return W("/");
+#else
+ return W("\\");
+#endif // PLATFORM_UNIX
+ }
+
+ inline WCHAR ToPlatformPathSepator(WCHAR wcChar)
+ {
+#ifdef PLATFORM_UNIX
+ if (IsPathSeparator(wcChar))
+ {
+ wcChar = W('/');
+ }
+#endif // PLATFORM_UNIX
+
+ return wcChar;
+ }
+
+ inline BOOL IsDoublePathSeparator(SString::CIterator &cur)
+ {
+ return (IsPathSeparator(cur[0]) && IsPathSeparator(cur[1]));
+ }
+
+ bool NeedToRemoveDoubleAndNormalizePathSeparators(SString const &path)
+ {
+#ifdef PLATFORM_UNIX
+ return true;
+#else
+ SString::CIterator begin = path.Begin();
+ SString::CIterator end = path.End();
+ SString::CIterator cur = path.Begin();
+
+ while (cur < end)
+ {
+ if ((cur != begin) && ((cur + 2) < end) && IsDoublePathSeparator(cur))
+ {
+ return true;
+ }
+
+ cur++;
+ }
+
+ return false;
+#endif
+ }
+
+ void RemoveDoubleAndNormalizePathSeparators(SString &path)
+ {
+ BINDER_LOG_ENTER(W("Utils::RemoveDoubleAndNormalizePathSeparators"));
+
+ SString::Iterator begin = path.Begin();
+ SString::Iterator end = path.End();
+ SString::Iterator cur = path.Begin();
+ PathString resultPath;
+
+ BINDER_LOG_STRING(W("path"), path);
+
+ while (cur < end)
+ {
+ if ((cur != begin) && ((cur + 2) < end) && IsDoublePathSeparator(cur))
+ {
+ // Skip the doublette
+ cur++;
+ }
+
+ resultPath.Append(ToPlatformPathSepator(cur[0]));
+ cur++;
+ }
+
+ BINDER_LOG_STRING(W("resultPath"), resultPath);
+
+ path.Set(resultPath);
+
+ BINDER_LOG_LEAVE(W("Utils::RemoveDoubleAndNormalizePathSeparators"));
+ }
+ }
+
+ HRESULT FileOrDirectoryExists(PathString &path)
+ {
+ HRESULT hr = S_FALSE;
+
+ DWORD dwFileAttributes = WszGetFileAttributes(path.GetUnicode());
+ if (dwFileAttributes == INVALID_FILE_ATTRIBUTES)
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)))
+ {
+ hr = S_FALSE;
+ }
+ }
+ else
+ {
+ hr = S_TRUE;
+ }
+
+ return hr;
+ }
+
+ HRESULT FileOrDirectoryExistsLog(PathString &path)
+ {
+ HRESULT hr = S_FALSE;
+ BINDER_LOG_ENTER(W("Utils::FileOrDirectoryExistsLog"));
+ BINDER_LOG_STRING(W("path"), path);
+
+ hr = FileOrDirectoryExists(path);
+
+ BINDER_LOG_LEAVE_HR(W("Utils::FileOrDirectoryExistsLog"), hr);
+ return hr;
+ }
+
+ BOOL IsURL(SString &urlOrPath)
+ {
+ // This is also in defined rotor pal
+ return PathIsURLW(urlOrPath);
+ }
+
+ void MutateUrlToPath(SString &urlOrPath)
+ {
+ BINDER_LOG_ENTER(W("Utils::MutateUrlToPath"));
+ const SString fileUrlPrefix(SString::Literal, W("file://"));
+ SString::Iterator i = urlOrPath.Begin();
+
+ BINDER_LOG_STRING(W("URL"), urlOrPath);
+
+ if (urlOrPath.MatchCaseInsensitive(i, fileUrlPrefix))
+ {
+ urlOrPath.Delete(i, fileUrlPrefix.GetCount());
+
+ i = urlOrPath.Begin() + 1;
+ if (i[0] == W(':'))
+ {
+ // CLR erroneously passes in file:// prepended to file paths,
+ // so we can't tell the difference between UNC and local file.
+ goto Exit;
+ }
+
+ i = urlOrPath.Begin();
+#if !defined(PLATFORM_UNIX)
+ if (i[0] == W('/'))
+ {
+ // Disk path file:///
+ urlOrPath.Delete(i, 1);
+ }
+ else if (i[0] != W('\\'))
+ {
+ // UNC Path, re-insert "//" if not the wrong file://\\...
+ urlOrPath.Insert(i, W("//"));
+ }
+#else
+ // Unix doesn't have a distinction between local and network path
+ _ASSERTE(i[0] == W('\\') || i[0] == W('/'));
+#endif
+ }
+
+ Exit:
+ while (urlOrPath.Find(i, W('/')))
+ {
+ urlOrPath.Replace(i, W('\\'));
+ }
+
+ BINDER_LOG_STRING(W("Path"), urlOrPath);
+ BINDER_LOG_LEAVE(W("Utils::MutateUrlToPath"));
+ }
+
+ void MutatePathToUrl(SString &pathOrUrl)
+ {
+ BINDER_LOG_ENTER(W("Utils::MutatePathToUrl"));
+ SString::Iterator i = pathOrUrl.Begin();
+
+ BINDER_LOG_STRING(W("Path"), pathOrUrl);
+
+#if !defined(PLATFORM_UNIX)
+ // Network path \\server --> file://server
+ // Disk path c:\dir --> file:///c:/dir
+ if (i[0] == W('\\'))
+ {
+ const SString networkUrlPrefix(SString::Literal, W("file:"));
+
+ // Network path
+ pathOrUrl.Insert(i, networkUrlPrefix);
+ pathOrUrl.Skip(i, networkUrlPrefix);
+ }
+ else
+ {
+ const SString diskPathUrlPrefix(SString::Literal, W("file:///"));
+
+ // Disk path
+ pathOrUrl.Insert(i, diskPathUrlPrefix);
+ pathOrUrl.Skip(i, diskPathUrlPrefix);
+ }
+#else
+ // Unix doesn't have a distinction between a network or a local path
+ _ASSERTE(i[0] == W('\\') || i[0] == W('/'));
+ const SString fileUrlPrefix(SString::Literal, W("file://"));
+
+ pathOrUrl.Insert(i, fileUrlPrefix);
+ pathOrUrl.Skip(i, fileUrlPrefix);
+#endif
+
+ while (pathOrUrl.Find(i, W('\\')))
+ {
+ pathOrUrl.Replace(i, W('/'));
+ }
+
+ BINDER_LOG_STRING(W("URL"), pathOrUrl);
+ BINDER_LOG_LEAVE(W("Utils::MutatePathToUrl"));
+ }
+
+ void PlatformPath(SString &path)
+ {
+ BINDER_LOG_ENTER(W("Utils::PlatformPath"));
+ BINDER_LOG_STRING(W("input path"), path);
+
+ // Create platform representation
+ MutateUrlToPath(path);
+ if (NeedToRemoveDoubleAndNormalizePathSeparators(path))
+ RemoveDoubleAndNormalizePathSeparators(path);
+
+ BINDER_LOG_STRING(W("platform path"), path);
+
+ BINDER_LOG_LEAVE(W("Utils::PlatformPath"));
+ }
+
+ void CombinePath(SString &pathA,
+ SString &pathB,
+ SString &combinedPath)
+ {
+ BINDER_LOG_ENTER(W("Utils::CombinePath"));
+
+ BINDER_LOG_STRING(W("path A"), pathA);
+ BINDER_LOG_STRING(W("path B"), pathB);
+
+ SString platformPathSeparator(SString::Literal, GetPlatformPathSeparator());
+ combinedPath.Set(pathA);
+
+ if (!combinedPath.EndsWith(platformPathSeparator))
+ {
+ combinedPath.Append(platformPathSeparator);
+ }
+
+ combinedPath.Append(pathB);
+
+ BINDER_LOG_LEAVE(W("Utils::CombinePath"));
+ }
+
+ HRESULT GetTokenFromPublicKey(SBuffer &publicKeyBLOB,
+ SBuffer &publicKeyTokenBLOB)
+ {
+ HRESULT hr = S_OK;
+ BINDER_LOG_ENTER(W("GetTokenFromPublicKey"));
+
+ const BYTE *pByteKey = publicKeyBLOB;
+ DWORD dwKeyLen = publicKeyBLOB.GetSize();
+ BYTE *pByteToken = NULL;
+ DWORD dwTokenLen = 0;
+
+ if (!StrongNameTokenFromPublicKey(const_cast<BYTE *>(pByteKey),
+ dwKeyLen,
+ &pByteToken,
+ &dwTokenLen))
+ {
+ BINDER_LOG(W("StrongNameTokenFromPublicKey failed!"));
+ IF_FAIL_GO(StrongNameErrorInfo());
+ }
+ else
+ {
+ _ASSERTE(pByteToken != NULL);
+ publicKeyTokenBLOB.Set(pByteToken, dwTokenLen);
+ StrongNameFreeBuffer(pByteToken);
+ }
+
+ Exit:
+ BINDER_LOG_LEAVE_HR(W("GetTokenFromPublicKey"), hr);
+ return hr;
+ }
+
+ BOOL IsFileNotFound(HRESULT hr)
+ {
+ return RuntimeFileNotFound(hr);
+ }
+};
diff --git a/src/binder/v3binder/.gitmirror b/src/binder/v3binder/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/binder/v3binder/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/binder/v3binder/CMakeLists.txt b/src/binder/v3binder/CMakeLists.txt
new file mode 100644
index 0000000000..e0fb28f37b
--- /dev/null
+++ b/src/binder/v3binder/CMakeLists.txt
@@ -0,0 +1,4 @@
+add_library_clr(v3binder
+ STATIC
+ ${BINDER_SOURCES}
+)
diff --git a/src/binder/v3binder/v3binder.nativeproj b/src/binder/v3binder/v3binder.nativeproj
new file mode 100644
index 0000000000..5412d69020
--- /dev/null
+++ b/src/binder/v3binder/v3binder.nativeproj
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\Debug\SetDebugTargetLocal.props" />
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <BuildCoreBinaries>true</BuildCoreBinaries>
+ <BuildSysBinaries>true</BuildSysBinaries>
+ <OutputName>v3binder</OutputName>
+ </PropertyGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\Binder\binder.targets" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/binder/v3binder_crossgen/.gitmirror b/src/binder/v3binder_crossgen/.gitmirror
new file mode 100644
index 0000000000..f507630f94
--- /dev/null
+++ b/src/binder/v3binder_crossgen/.gitmirror
@@ -0,0 +1 @@
+Only contents of this folder, excluding subfolders, will be mirrored by the Git-TFS Mirror. \ No newline at end of file
diff --git a/src/binder/v3binder_crossgen/CMakeLists.txt b/src/binder/v3binder_crossgen/CMakeLists.txt
new file mode 100644
index 0000000000..cf8040291e
--- /dev/null
+++ b/src/binder/v3binder_crossgen/CMakeLists.txt
@@ -0,0 +1,6 @@
+include(${CLR_DIR}/crossgen.cmake)
+
+add_library_clr(v3binder_crossgen
+ STATIC
+ ${BINDER_CROSSGEN_SOURCES}
+)
diff --git a/src/binder/v3binder_crossgen/v3binder_crossgen.nativeproj b/src/binder/v3binder_crossgen/v3binder_crossgen.nativeproj
new file mode 100644
index 0000000000..61348e3f62
--- /dev/null
+++ b/src/binder/v3binder_crossgen/v3binder_crossgen.nativeproj
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ToolsVersion="dogfood">
+ <!--Import the settings-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\xplat\SetCrossGen.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.props" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\Debug\SetDebugTargetLocal.props" />
+
+ <!--Leaf project Properties-->
+ <PropertyGroup>
+ <OutputName>v3binder_crossgen</OutputName>
+ </PropertyGroup>
+ <!--Import the targets-->
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\src\Binder\binder.targets" />
+ <Import Project="$(_NTDRIVE)$(_NTROOT)\ndp\clr\clr.targets" />
+</Project>
diff --git a/src/binder/variables.cpp b/src/binder/variables.cpp
new file mode 100644
index 0000000000..615b358deb
--- /dev/null
+++ b/src/binder/variables.cpp
@@ -0,0 +1,134 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+// ============================================================
+//
+// Variables.cpp
+//
+
+
+//
+// Implements the Variables class
+//
+// ============================================================
+
+#include "variables.hpp"
+
+#include "ex.h"
+
+namespace BINDER_SPACE
+{
+#ifdef FEATURE_VERSIONING_LOG
+ namespace
+ {
+ HRESULT CheckFileExistence(LPCWSTR pwzFile, LPDWORD pdwAttrib)
+ {
+ HRESULT hr = S_FALSE;
+ DWORD dwRet = 0;
+
+ _ASSERTE(pwzFile && pdwAttrib);
+
+ *pdwAttrib = 0;
+
+ dwRet = WszGetFileAttributes(pwzFile);
+ if (dwRet == INVALID_FILE_ATTRIBUTES)
+ {
+ hr = HRESULT_FROM_GetLastError();
+
+ if ((hr == HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND)) ||
+ (hr == HRESULT_FROM_WIN32(ERROR_PATH_NOT_FOUND)))
+ {
+ GO_WITH_HRESULT(S_FALSE);
+ }
+ }
+ else
+ {
+ *pdwAttrib = dwRet;
+ GO_WITH_HRESULT(S_OK);
+ }
+
+ Exit:
+ return hr;
+ }
+ };
+#endif // FEATURE_VERSIONING_LOG
+
+ Variables *g_BinderVariables = NULL;
+
+ Variables::Variables()
+ {
+ // Nothing to do here
+ }
+
+ Variables::~Variables()
+ {
+ // Nothing to do here
+ }
+
+ HRESULT Variables::Init()
+ {
+ HRESULT hr = S_OK;
+
+ EX_TRY
+ {
+ // ApplicationContext string constants
+
+ // AssemblyBinder string constants
+ httpURLPrefix.SetLiteral(W("http://"));
+
+ // AssemblyName string constants
+ architectureMSIL.SetLiteral(W("MSIL"));
+ architectureX86.SetLiteral(W("x86"));
+ architectureAMD64.SetLiteral(W("AMD64"));
+ architectureARM.SetLiteral(W("ARM"));
+ architectureARM64.SetLiteral(W("ARM64"));
+ cultureNeutral.SetLiteral(W("neutral"));
+ mscorlib.SetLiteral(CoreLibName_W);
+
+ emptyString.Clear();
+
+#ifdef FEATURE_VERSIONING_LOG
+ REGUTIL::CORConfigLevel kCorConfigLevel =
+ static_cast<REGUTIL::CORConfigLevel>(REGUTIL::COR_CONFIG_ENV |
+ REGUTIL::COR_CONFIG_FUSION);
+
+ DWORD dwLoggingNeeded = REGUTIL::GetConfigDWORD_DontUse_(CLRConfig::EXTERNAL_ForceLog,
+ 0,
+ kCorConfigLevel,
+ TRUE);
+ fLoggingNeeded = (dwLoggingNeeded ? TRUE : FALSE);
+
+ NewArrayHolder<WCHAR> pwzLogDirectory = REGUTIL::GetConfigString_DontUse_(CLRConfig::INTERNAL_LogPath,
+ TRUE,
+ kCorConfigLevel,
+ FALSE /* fUsePerfCache */);
+
+ // When no directory is specified, we can't log.
+ if (pwzLogDirectory == NULL)
+ {
+ fLoggingNeeded = FALSE;
+ }
+ else
+ {
+ DWORD dwAttr = 0;
+
+ // If we do not get a regular directory, then we can't log either
+ hr = CheckFileExistence(pwzLogDirectory, &dwAttr);
+ if ((hr == S_OK) && ((dwAttr & FILE_ATTRIBUTE_DIRECTORY) != 0))
+ {
+ logPath.Set(pwzLogDirectory);
+ }
+ else
+ {
+ // Any failure here simply yields no logging.
+ hr = S_OK;
+ fLoggingNeeded = FALSE;
+ }
+ }
+#endif // FEATURE_VERSIONING_LOG
+ }
+ EX_CATCH_HRESULT(hr);
+
+ return hr;
+ }
+};