summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/System.Private.CoreLib/System.Private.CoreLib.csproj2
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs34
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs32
-rw-r--r--src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/IsolatedComponentLoadContext.cs47
-rw-r--r--src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs28
-rw-r--r--src/vm/appdomain.cpp2
-rw-r--r--src/vm/assemblynative.cpp36
-rw-r--r--src/vm/assemblynative.hpp3
-rw-r--r--src/vm/ceeload.cpp68
-rw-r--r--src/vm/domainfile.cpp8
-rw-r--r--src/vm/domainfile.h2
-rw-r--r--src/vm/ecalllist.h3
-rw-r--r--tests/issues.targets9
-rw-r--r--tests/src/Interop/CMakeLists.txt6
-rw-r--r--tests/src/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.csproj2
-rw-r--r--tests/src/Interop/IJW/FakeMscoree/mscoree.cpp19
-rw-r--r--tests/src/Interop/IJW/FakeMscoree/mscoree.def3
-rw-r--r--tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.cs53
-rw-r--r--tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.csproj44
-rw-r--r--tests/src/Interop/IJW/IjwNativeCallingManagedDll/CMakeLists.txt (renamed from tests/src/Interop/IJW/NativeCallingManaged/IjwNativeCallingManagedDll/CMakeLists.txt)0
-rw-r--r--tests/src/Interop/IJW/IjwNativeCallingManagedDll/IjwNativeCallingManagedDll.cpp (renamed from tests/src/Interop/IJW/NativeCallingManaged/IjwNativeCallingManagedDll/IjwNativeCallingManagedDll.cpp)28
-rw-r--r--tests/src/Interop/IJW/IjwNativeDll/CMakeLists.txt (renamed from tests/src/Interop/IJW/ManagedCallingNative/IjwNativeDll/CMakeLists.txt)0
-rw-r--r--tests/src/Interop/IJW/IjwNativeDll/IjwNativeDll.cpp (renamed from tests/src/Interop/IJW/ManagedCallingNative/IjwNativeDll/IjwNativeDll.cpp)0
-rw-r--r--tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.cs88
-rw-r--r--tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.csproj47
-rw-r--r--tests/src/Interop/IJW/ManagedCallingNative/ManagedCallingNative.csproj4
-rw-r--r--tests/src/Interop/IJW/NativeCallingManaged/NativeCallingManaged.csproj4
-rw-r--r--tests/src/Interop/IJW/ijwhostmock/CMakeLists.txt (renamed from tests/src/Interop/IJW/FakeMscoree/CMakeLists.txt)2
-rw-r--r--tests/src/Interop/IJW/ijwhostmock/mscoree.cpp34
29 files changed, 532 insertions, 76 deletions
diff --git a/src/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
index 0cf6733ad9..b052272158 100644
--- a/src/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -119,6 +119,7 @@
<!-- Sources -->
<ItemGroup>
<Compile Include="$(BclSourcesRoot)\Internal\Console.cs" />
+ <Compile Include="$(BclSourcesRoot)\Internal\Runtime\InteropServices\IsolatedComponentLoadContext.cs" />
<Compile Include="$(BclSourcesRoot)\Microsoft\Win32\UnsafeNativeMethods.cs" />
<Compile Include="$(BclSourcesRoot)\System\__Canon.cs" />
<Compile Include="$(BclSourcesRoot)\System\AppContext.CoreCLR.cs" />
@@ -365,6 +366,7 @@
<Compile Include="$(BclSourcesRoot)\System\Threading\ClrThreadPoolBoundHandle.Unix.cs" />
</ItemGroup>
<ItemGroup Condition="'$(TargetsWindows)' == 'true'">
+ <Compile Include="$(BclSourcesRoot)\Internal\Runtime\InteropServices\InMemoryAssemblyLoader.cs" />
<Compile Include="$(BclSourcesRoot)\System\DateTime.Windows.cs" />
<Compile Include="$(BclSourcesRoot)\Interop\Windows\OleAut32\Interop.VariantClear.cs" />
<Compile Include="$(BclSourcesRoot)\System\ApplicationModel.Windows.cs" />
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs b/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
index 608d1579fa..d1c6aa9bb7 100644
--- a/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/ComActivator.cs
@@ -215,7 +215,7 @@ $@"{nameof(GetClassFactoryForTypeInternal)} arguments:
{
if (!s_AssemblyLoadContexts.TryGetValue(assemblyPath, out alc))
{
- alc = new ComServerLoadContext(assemblyPath);
+ alc = new IsolatedComponentLoadContext(assemblyPath);
s_AssemblyLoadContexts.Add(assemblyPath, alc);
}
}
@@ -223,38 +223,6 @@ $@"{nameof(GetClassFactoryForTypeInternal)} arguments:
return alc;
}
- private class ComServerLoadContext : AssemblyLoadContext
- {
- private readonly AssemblyDependencyResolver _resolver;
-
- public ComServerLoadContext(string comServerAssemblyPath)
- {
- _resolver = new AssemblyDependencyResolver(comServerAssemblyPath);
- }
-
- protected override Assembly Load(AssemblyName assemblyName)
- {
- string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
- if (assemblyPath != null)
- {
- return LoadFromAssemblyPath(assemblyPath);
- }
-
- return null;
- }
-
- protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
- {
- string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
- if (libraryPath != null)
- {
- return LoadUnmanagedDllFromPath(libraryPath);
- }
-
- return IntPtr.Zero;
- }
- }
-
[ComVisible(true)]
private class BasicClassFactory : IClassFactory
{
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs b/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs
new file mode 100644
index 0000000000..097f47a825
--- /dev/null
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/InMemoryAssemblyLoader.cs
@@ -0,0 +1,32 @@
+// 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.
+
+using System;
+using System.Diagnostics;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using System.Runtime.Loader;
+
+namespace Internal.Runtime.InteropServices
+{
+ /// <summary>
+ /// This class enables the .NET IJW host to load an in-memory module as a .NET assembly
+ /// </summary>
+ public static class InMemoryAssemblyLoader
+ {
+ /// <summary>
+ /// Loads into an isolated AssemblyLoadContext an assembly that has already been loaded into memory by the OS loader as a native module.
+ /// </summary>
+ /// <param name="moduleHandle">The native module handle for the assembly.</param>
+ /// <param name="assemblyPath">The path to the assembly (as a pointer to a UTF-16 C string).</param>
+ public static unsafe void LoadInMemoryAssembly(IntPtr moduleHandle, IntPtr assemblyPath)
+ {
+ // We don't cache the ALCs here since each IJW assembly will call this method at most once
+ // (the load process rewrites the stubs that call here to call the actual methods they're supposed to)
+ AssemblyLoadContext context = new IsolatedComponentLoadContext(Marshal.PtrToStringUni(assemblyPath));
+ context.LoadFromInMemoryModule(moduleHandle);
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/IsolatedComponentLoadContext.cs b/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/IsolatedComponentLoadContext.cs
new file mode 100644
index 0000000000..d78d7dd51c
--- /dev/null
+++ b/src/System.Private.CoreLib/src/Internal/Runtime/InteropServices/IsolatedComponentLoadContext.cs
@@ -0,0 +1,47 @@
+// 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.
+
+using System;
+using System.Reflection;
+using System.Runtime.Loader;
+
+namespace Internal.Runtime.InteropServices
+{
+ /// <summary>
+ /// An <see cref="IsolatedComponentLoadContext" /> is an AssemblyLoadContext that can be used to isolate components such as COM components
+ /// or IJW components loaded from native. It provides a load context that uses an <see cref="AssemblyDependencyResolver" /> to resolve the component's
+ /// dependencies within the ALC and not pollute the default ALC.
+ ///</summary>
+ internal class IsolatedComponentLoadContext : AssemblyLoadContext
+ {
+ private readonly AssemblyDependencyResolver _resolver;
+
+ public IsolatedComponentLoadContext(string componentAssemblyPath)
+ {
+ _resolver = new AssemblyDependencyResolver(componentAssemblyPath);
+ }
+
+ protected override Assembly Load(AssemblyName assemblyName)
+ {
+ string assemblyPath = _resolver.ResolveAssemblyToPath(assemblyName);
+ if (assemblyPath != null)
+ {
+ return LoadFromAssemblyPath(assemblyPath);
+ }
+
+ return null;
+ }
+
+ protected override IntPtr LoadUnmanagedDll(string unmanagedDllName)
+ {
+ string libraryPath = _resolver.ResolveUnmanagedDllToPath(unmanagedDllName);
+ if (libraryPath != null)
+ {
+ return LoadUnmanagedDllFromPath(libraryPath);
+ }
+
+ return IntPtr.Zero;
+ }
+ }
+}
diff --git a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
index 60052d90ae..b36c382c38 100644
--- a/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
+++ b/src/System.Private.CoreLib/src/System/Runtime/Loader/AssemblyLoadContext.CoreCLR.cs
@@ -52,6 +52,34 @@ namespace System.Runtime.Loader
return loadedAssembly;
}
+
+#if !FEATURE_PAL
+ [DllImport(JitHelpers.QCall, CharSet = CharSet.Unicode)]
+ private static extern IntPtr LoadFromInMemoryModuleInternal(IntPtr ptrNativeAssemblyLoadContext, IntPtr hModule, ObjectHandleOnStack retAssembly);
+
+
+ /// <summary>
+ /// Load a module that has already been loaded into memory by the OS loader as a .NET assembly.
+ /// </summary>
+ internal Assembly LoadFromInMemoryModule(IntPtr moduleHandle)
+ {
+ if (moduleHandle == IntPtr.Zero)
+ {
+ throw new ArgumentNullException(nameof(moduleHandle));
+ }
+ lock (_unloadLock)
+ {
+ VerifyIsAlive();
+
+ RuntimeAssembly loadedAssembly = null;
+ LoadFromInMemoryModuleInternal(
+ _nativeAssemblyLoadContext,
+ moduleHandle,
+ JitHelpers.GetObjectHandleOnStack(ref loadedAssembly));
+ return loadedAssembly;
+ }
+ }
+#endif
// This method is invoked by the VM when using the host-provided assembly load context
// implementation.
diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp
index 9362dd9c7b..bcffb3b8aa 100644
--- a/src/vm/appdomain.cpp
+++ b/src/vm/appdomain.cpp
@@ -4223,8 +4223,8 @@ static const char *fileLoadLevelName[] =
"LOADLIBRARY", // FILE_LOAD_LOADLIBRARY
"POST_LOADLIBRARY", // FILE_LOAD_POST_LOADLIBRARY
"EAGER_FIXUPS", // FILE_LOAD_EAGER_FIXUPS
- "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
"DELIVER_EVENTS", // FILE_LOAD_DELIVER_EVENTS
+ "VTABLE FIXUPS", // FILE_LOAD_VTABLE_FIXUPS
"LOADED", // FILE_LOADED
"VERIFY_EXECUTION", // FILE_LOAD_VERIFY_EXECUTION
"ACTIVE", // FILE_ACTIVE
diff --git a/src/vm/assemblynative.cpp b/src/vm/assemblynative.cpp
index 30ee95b35f..ed2ce660e7 100644
--- a/src/vm/assemblynative.cpp
+++ b/src/vm/assemblynative.cpp
@@ -363,6 +363,42 @@ void QCALLTYPE AssemblyNative::LoadFromStream(INT_PTR ptrNativeAssemblyLoadConte
END_QCALL;
}
+#ifndef FEATURE_PAL
+/*static */
+void QCALLTYPE AssemblyNative::LoadFromInMemoryModule(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR hModule, QCall::ObjectHandleOnStack retLoadedAssembly)
+{
+ QCALL_CONTRACT;
+
+ BEGIN_QCALL;
+
+ // Ensure that the invariants are in place
+ _ASSERTE(ptrNativeAssemblyLoadContext != NULL);
+ _ASSERTE(hModule != NULL);
+
+ PEImageHolder pILImage(PEImage::LoadImage((HMODULE)hModule));
+
+ // Need to verify that this is a valid CLR assembly.
+ if (!pILImage->HasCorHeader())
+ ThrowHR(COR_E_BADIMAGEFORMAT, BFA_BAD_IL);
+
+ // Get the binder context in which the assembly will be loaded
+ ICLRPrivBinder *pBinderContext = reinterpret_cast<ICLRPrivBinder*>(ptrNativeAssemblyLoadContext);
+
+ // Pass the in memory module as IL in an attempt to bind and load it
+ Assembly* pLoadedAssembly = AssemblyNative::LoadFromPEImage(pBinderContext, pILImage, NULL);
+ {
+ GCX_COOP();
+ retLoadedAssembly.Set(pLoadedAssembly->GetExposedObject());
+ }
+
+ LOG((LF_CLASSLOADER,
+ LL_INFO100,
+ "\tLoaded assembly from pre-loaded native module\n"));
+
+ END_QCALL;
+}
+#endif
+
void QCALLTYPE AssemblyNative::GetLocation(QCall::AssemblyHandle pAssembly, QCall::StringHandleOnStack retString)
{
QCALL_CONTRACT;
diff --git a/src/vm/assemblynative.hpp b/src/vm/assemblynative.hpp
index d506b6e407..13db261359 100644
--- a/src/vm/assemblynative.hpp
+++ b/src/vm/assemblynative.hpp
@@ -120,6 +120,9 @@ public:
static void QCALLTYPE LoadFromPath(INT_PTR ptrNativeAssemblyLoadContext, LPCWSTR pwzILPath, LPCWSTR pwzNIPath, QCall::ObjectHandleOnStack retLoadedAssembly);
static INT_PTR QCALLTYPE InternalLoadUnmanagedDllFromPath(LPCWSTR unmanagedLibraryPath);
static void QCALLTYPE LoadFromStream(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR ptrAssemblyArray, INT32 cbAssemblyArrayLength, INT_PTR ptrSymbolArray, INT32 cbSymbolArrayLength, QCall::ObjectHandleOnStack retLoadedAssembly);
+#ifndef FEATURE_PAL
+ static void QCALLTYPE LoadFromInMemoryModule(INT_PTR ptrNativeAssemblyLoadContext, INT_PTR hModule, QCall::ObjectHandleOnStack retLoadedAssembly);
+#endif
static Assembly* LoadFromPEImage(ICLRPrivBinder* pBinderContext, PEImage *pILImage, PEImage *pNIImage);
static INT_PTR QCALLTYPE GetLoadContextForAssembly(QCall::AssemblyHandle pAssembly);
diff --git a/src/vm/ceeload.cpp b/src/vm/ceeload.cpp
index 1fec2c262d..b9cf4a7900 100644
--- a/src/vm/ceeload.cpp
+++ b/src/vm/ceeload.cpp
@@ -6482,6 +6482,59 @@ void Module::NotifyDebuggerUnload(AppDomain *pDomain)
}
#if !defined(CROSSGEN_COMPILE)
+using GetTokenForVTableEntry_t = mdToken(STDMETHODCALLTYPE*)(HMODULE module, BYTE**ppVTEntry);
+
+static HMODULE GetIJWHostForModule(Module* module)
+{
+#if !defined(FEATURE_PAL)
+ PEDecoder* pe = module->GetFile()->GetLoadedIL();
+
+ BYTE* baseAddress = (BYTE*)module->GetFile()->GetIJWBase();
+
+ IMAGE_IMPORT_DESCRIPTOR* importDescriptor = (IMAGE_IMPORT_DESCRIPTOR*)pe->GetDirectoryData(pe->GetDirectoryEntry(IMAGE_DIRECTORY_ENTRY_IMPORT));
+
+ for(; importDescriptor->Characteristics != 0; importDescriptor++)
+ {
+ IMAGE_THUNK_DATA* importNameTable = (IMAGE_THUNK_DATA*)pe->GetRvaData(importDescriptor->OriginalFirstThunk);
+
+ IMAGE_THUNK_DATA* importAddressTable = (IMAGE_THUNK_DATA*)pe->GetRvaData(importDescriptor->FirstThunk);
+
+ for (int thunkIndex = 0; importNameTable[thunkIndex].u1.AddressOfData != 0; thunkIndex++)
+ {
+ // The most significant bit will be set if the entry points to an ordinal.
+ if ((importNameTable[thunkIndex].u1.Ordinal & (1LL << (sizeof(importNameTable[thunkIndex].u1.Ordinal) * CHAR_BIT - 1))) == 0)
+ {
+ IMAGE_IMPORT_BY_NAME* nameImport = (IMAGE_IMPORT_BY_NAME*)(baseAddress + importNameTable[thunkIndex].u1.AddressOfData);
+ if (strcmp("_CorDllMain", nameImport->Name) == 0)
+ {
+ HMODULE ijwHost;
+
+ if (WszGetModuleHandleEx(
+ GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
+ (LPCWSTR)importAddressTable[thunkIndex].u1.Function,
+ &ijwHost))
+ {
+ return ijwHost;
+ }
+
+ }
+ }
+ }
+ }
+#endif
+ return nullptr;
+}
+
+static GetTokenForVTableEntry_t GetTokenGetterFromHostModule(HMODULE ijwHost)
+{
+ if (ijwHost != nullptr)
+ {
+ return (GetTokenForVTableEntry_t)GetProcAddress(ijwHost, "GetTokenForVTableEntry");
+ }
+
+ return nullptr;
+}
+
//=================================================================================
mdToken GetTokenForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry)
{
@@ -6504,7 +6557,6 @@ void SetTargetForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry, BYTE *pTarget)
DWORD oldProtect;
if (!ClrVirtualProtect(ppVTEntry, sizeof(BYTE*), PAGE_READWRITE, &oldProtect))
{
-
// This is very bad. We are not going to be able to update header.
_ASSERTE(!"SetTargetForVTableEntry(): VirtualProtect() changing IJW thunk vtable to R/W failed.\n");
ThrowLastError();
@@ -6548,6 +6600,18 @@ void Module::FixupVTables()
return;
}
+ // Try getting a callback to the IJW host if it is loaded.
+ // The IJW host substitutes in special shims in the vtfixup table
+ // so if it is loaded, we need to query it for the tokens that were in the slots.
+ // If it is not loaded, then we know that the vtfixup table entries are tokens,
+ // so we can resolve them ourselves.
+ GetTokenForVTableEntry_t GetTokenForVTableEntryCallback = GetTokenGetterFromHostModule(GetIJWHostForModule(this));
+
+ if (GetTokenForVTableEntryCallback == nullptr)
+ {
+ GetTokenForVTableEntryCallback = GetTokenForVTableEntry;
+ }
+
HINSTANCE hInstThis = GetFile()->GetIJWBase();
// <REVISIT_TODO>@todo: workaround!</REVISIT_TODO>
@@ -6648,7 +6712,7 @@ void Module::FixupVTables()
{
if (pData->IsMethodFixedUp(iFixup, iMethod))
continue;
- mdToken mdTok = GetTokenForVTableEntry(hInstThis, (BYTE **)(pPointers + iMethod));
+ mdToken mdTok = GetTokenForVTableEntryCallback(hInstThis, (BYTE**)(pPointers + iMethod));
CONSISTENCY_CHECK(mdTok != mdTokenNil);
rgMethodsToLoad[iCurMethod++].token = mdTok;
}
diff --git a/src/vm/domainfile.cpp b/src/vm/domainfile.cpp
index 0fd9c811d5..5c89767d1a 100644
--- a/src/vm/domainfile.cpp
+++ b/src/vm/domainfile.cpp
@@ -555,14 +555,14 @@ BOOL DomainFile::DoIncrementalLoad(FileLoadLevel level)
EagerFixups();
break;
- case FILE_LOAD_VTABLE_FIXUPS:
- VtableFixups();
- break;
-
case FILE_LOAD_DELIVER_EVENTS:
DeliverSyncEvents();
break;
+ case FILE_LOAD_VTABLE_FIXUPS:
+ VtableFixups();
+ break;
+
case FILE_LOADED:
FinishLoad();
break;
diff --git a/src/vm/domainfile.h b/src/vm/domainfile.h
index d6917b1fd5..ddc0384c58 100644
--- a/src/vm/domainfile.h
+++ b/src/vm/domainfile.h
@@ -45,8 +45,8 @@ enum FileLoadLevel
FILE_LOAD_LOADLIBRARY,
FILE_LOAD_POST_LOADLIBRARY,
FILE_LOAD_EAGER_FIXUPS,
- FILE_LOAD_VTABLE_FIXUPS,
FILE_LOAD_DELIVER_EVENTS,
+ FILE_LOAD_VTABLE_FIXUPS,
FILE_LOADED, // Loaded by not yet active
FILE_LOAD_VERIFY_EXECUTION,
FILE_ACTIVE // Fully active (constructors run & security checked)
diff --git a/src/vm/ecalllist.h b/src/vm/ecalllist.h
index 7302bb4e4a..c184633221 100644
--- a/src/vm/ecalllist.h
+++ b/src/vm/ecalllist.h
@@ -520,6 +520,9 @@ FCFuncStart(gAssemblyLoadContextFuncs)
QCFuncElement("LoadFromPath", AssemblyNative::LoadFromPath)
QCFuncElement("InternalLoadUnmanagedDllFromPath", AssemblyNative::InternalLoadUnmanagedDllFromPath)
QCFuncElement("LoadFromStream", AssemblyNative::LoadFromStream)
+#ifndef FEATURE_PAL
+ QCFuncElement("LoadFromInMemoryModuleInternal", AssemblyNative::LoadFromInMemoryModule)
+#endif
QCFuncElement("GetLoadContextForAssembly", AssemblyNative::GetLoadContextForAssembly)
FCFuncElement("GetLoadedAssemblies", AppDomainNative::GetLoadedAssemblies)
#if defined(FEATURE_MULTICOREJIT)
diff --git a/tests/issues.targets b/tests/issues.targets
index a206167a09..73a2884b99 100644
--- a/tests/issues.targets
+++ b/tests/issues.targets
@@ -458,6 +458,15 @@
<ExcludeList Include="$(XunitTestBinBase)/JIT/Directed/arglist/vararg/*">
<Issue>Needs triage</Issue>
</ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler/*">
+ <Issue>Needs triage</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded/*">
+ <Issue>Needs triage</Issue>
+ </ExcludeList>
+ <ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle/*">
+ <Issue>Needs triage</Issue>
+ </ExcludeList>
<ExcludeList Include="$(XunitTestBinBase)/Interop/IJW/ManagedCallingNative/ManagedCallingNative/*">
<Issue>Needs triage</Issue>
</ExcludeList>
diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt
index 32e4b77e16..acf4c849db 100644
--- a/tests/src/Interop/CMakeLists.txt
+++ b/tests/src/Interop/CMakeLists.txt
@@ -83,12 +83,12 @@ if(WIN32)
add_subdirectory(COM/NativeClients/Primitives)
add_subdirectory(COM/NativeClients/Licensing)
add_subdirectory(COM/NativeClients/DefaultInterfaces)
- add_subdirectory(IJW/FakeMscoree)
# IJW isn't supported on ARM64
if(NOT CLR_CMAKE_PLATFORM_ARCH_ARM64)
- add_subdirectory(IJW/ManagedCallingNative/IjwNativeDll)
- add_subdirectory(IJW/NativeCallingManaged/IjwNativeCallingManagedDll)
+ add_subdirectory(IJW/ijwhostmock)
+ add_subdirectory(IJW/IjwNativeDll)
+ add_subdirectory(IJW/IjwNativeCallingManagedDll)
add_subdirectory(IJW/CopyConstructorMarshaler)
endif()
endif(WIN32)
diff --git a/tests/src/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.csproj b/tests/src/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.csproj
index 34aad536a0..b1d38a911b 100644
--- a/tests/src/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.csproj
+++ b/tests/src/Interop/IJW/CopyConstructorMarshaler/CopyConstructorMarshaler.csproj
@@ -38,7 +38,7 @@
</ItemGroup>
<ItemGroup>
<ProjectReference Include="CMakeLists.txt" />
- <ProjectReference Include="../FakeMscoree/CMakeLists.txt" />
+ <ProjectReference Include="../ijwhostmock/CMakeLists.txt" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
diff --git a/tests/src/Interop/IJW/FakeMscoree/mscoree.cpp b/tests/src/Interop/IJW/FakeMscoree/mscoree.cpp
deleted file mode 100644
index 99319ec28b..0000000000
--- a/tests/src/Interop/IJW/FakeMscoree/mscoree.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// 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 <windows.h>
-
-#ifndef DLLEXPORT
-#ifdef _MSC_VER
-#define DLLEXPORT __declspec(dllexport)
-#else
-#define DLLEXPORT __attribute__((visibility("default")))
-#endif
-#endif
-
-// Entrypoint jumped to by IJW dlls when their dllmain is called
-extern "C" DLLEXPORT BOOL WINAPI _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
-{
- return TRUE;
-}
diff --git a/tests/src/Interop/IJW/FakeMscoree/mscoree.def b/tests/src/Interop/IJW/FakeMscoree/mscoree.def
deleted file mode 100644
index 9279b0364b..0000000000
--- a/tests/src/Interop/IJW/FakeMscoree/mscoree.def
+++ /dev/null
@@ -1,3 +0,0 @@
-LIBRARY MSCOREE
-EXPORTS
- _CorDllMain \ No newline at end of file
diff --git a/tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.cs b/tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.cs
new file mode 100644
index 0000000000..cfc5a9a73d
--- /dev/null
+++ b/tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.cs
@@ -0,0 +1,53 @@
+// 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.
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using TestLibrary;
+
+namespace FixupCallsHostWhenLoaded
+{
+ class FixupCallsHostWhenLoaded
+ {
+ static int Main(string[] args)
+ {
+ // Disable running on Windows 7 until IJW activation work is complete.
+ if(Environment.OSVersion.Platform != PlatformID.Win32NT || TestLibrary.Utilities.IsWindows7)
+ {
+ return 100;
+ }
+
+ try
+ {
+ // Load a fake mscoree.dll to avoid starting desktop
+ IntPtr ijwHost = NativeLibrary.Load(Path.Combine(Environment.CurrentDirectory, "mscoree.dll"));
+
+ WasModuleVTableQueriedDelegate wasModuleVTableQueried = Marshal.GetDelegateForFunctionPointer<WasModuleVTableQueriedDelegate>(NativeLibrary.GetExport(ijwHost, "WasModuleVTableQueried"));
+
+ // Load IJW via reflection
+ Assembly.Load("IjwNativeDll");
+
+ IntPtr ijwModuleHandle = GetModuleHandle("IjwNativeDll.dll");
+
+ Assert.AreNotEqual(IntPtr.Zero, ijwModuleHandle);
+ Assert.IsTrue(wasModuleVTableQueried(ijwModuleHandle));
+ }
+ catch (Exception e)
+ {
+ Console.WriteLine(e);
+ return 101;
+ }
+
+ return 100;
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate bool WasModuleVTableQueriedDelegate(IntPtr handle);
+
+ [DllImport("kernel32.dll")]
+ static extern IntPtr GetModuleHandle(string lpModuleName);
+ }
+}
diff --git a/tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.csproj b/tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.csproj
new file mode 100644
index 0000000000..20dc72f397
--- /dev/null
+++ b/tests/src/Interop/IJW/FixupCallsHostWhenLoaded/FixupCallsHostWhenLoaded.csproj
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>FixupCallsHostWhenLoaded</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{49D1D482-E783-4CA9-B6BA-A9714BF81036}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+
+ <!-- IJW is Windows-only -->
+ <!-- Test unsupported outside of windows -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+
+ <!-- IJW is not supported on ARM64 -->
+ <DisableProjectBuild Condition="'$(Platform)' == 'arm64'">true</DisableProjectBuild>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <PropertyGroup>
+ <CopyDebugCRTDllsToOutputDirectory>true</CopyDebugCRTDllsToOutputDirectory>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="FixupCallsHostWhenLoaded.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="../IjwNativeDll/CMakeLists.txt" />
+ <ProjectReference Include="../ijwhostmock/CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/IJW/NativeCallingManaged/IjwNativeCallingManagedDll/CMakeLists.txt b/tests/src/Interop/IJW/IjwNativeCallingManagedDll/CMakeLists.txt
index c8b0edcb83..c8b0edcb83 100644
--- a/tests/src/Interop/IJW/NativeCallingManaged/IjwNativeCallingManagedDll/CMakeLists.txt
+++ b/tests/src/Interop/IJW/IjwNativeCallingManagedDll/CMakeLists.txt
diff --git a/tests/src/Interop/IJW/NativeCallingManaged/IjwNativeCallingManagedDll/IjwNativeCallingManagedDll.cpp b/tests/src/Interop/IJW/IjwNativeCallingManagedDll/IjwNativeCallingManagedDll.cpp
index 9ba7e3ac0c..d672f3c0ab 100644
--- a/tests/src/Interop/IJW/NativeCallingManaged/IjwNativeCallingManagedDll/IjwNativeCallingManagedDll.cpp
+++ b/tests/src/Interop/IJW/IjwNativeCallingManagedDll/IjwNativeCallingManagedDll.cpp
@@ -1,12 +1,10 @@
// 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 "platformdefines.h"
#pragma managed
-int ManagedCallee()
-{
- return 100;
-}
+int ManagedCallee();
#pragma unmanaged
int NativeFunction()
@@ -14,12 +12,34 @@ int NativeFunction()
return ManagedCallee();
}
+extern "C" DLL_EXPORT int __cdecl NativeEntryPoint()
+{
+ return NativeFunction();
+}
+
#pragma managed
public ref class TestClass
{
+private:
+ static int s_valueToReturn = 100;
public:
int ManagedEntryPoint()
{
return NativeFunction();
}
+
+ static void ChangeReturnedValue(int i)
+ {
+ s_valueToReturn = i;
+ }
+
+ static int GetReturnValue()
+ {
+ return s_valueToReturn;
+ }
};
+
+int ManagedCallee()
+{
+ return TestClass::GetReturnValue();
+}
diff --git a/tests/src/Interop/IJW/ManagedCallingNative/IjwNativeDll/CMakeLists.txt b/tests/src/Interop/IJW/IjwNativeDll/CMakeLists.txt
index 612e6aa17f..612e6aa17f 100644
--- a/tests/src/Interop/IJW/ManagedCallingNative/IjwNativeDll/CMakeLists.txt
+++ b/tests/src/Interop/IJW/IjwNativeDll/CMakeLists.txt
diff --git a/tests/src/Interop/IJW/ManagedCallingNative/IjwNativeDll/IjwNativeDll.cpp b/tests/src/Interop/IJW/IjwNativeDll/IjwNativeDll.cpp
index cb25b445a4..cb25b445a4 100644
--- a/tests/src/Interop/IJW/ManagedCallingNative/IjwNativeDll/IjwNativeDll.cpp
+++ b/tests/src/Interop/IJW/IjwNativeDll/IjwNativeDll.cpp
diff --git a/tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.cs b/tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.cs
new file mode 100644
index 0000000000..e44d534158
--- /dev/null
+++ b/tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.cs
@@ -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.
+
+using System;
+using System.IO;
+using System.Reflection;
+using System.Runtime.InteropServices;
+using Internal.Runtime.InteropServices;
+using TestLibrary;
+
+using Console = Internal.Console;
+
+namespace LoadIjwFromModuleHandle
+{
+ class LoadIjwFromModuleHandle
+ {
+ unsafe static int Main(string[] args)
+ {
+ // Disable running on Windows 7 until IJW activation work is complete.
+ if(Environment.OSVersion.Platform != PlatformID.Win32NT || (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1))
+ {
+ return 100;
+ }
+
+ try
+ {
+ HostPolicyMock.Initialize(Environment.CurrentDirectory, null);
+
+ // Load our fake mscoree to prevent desktop from loading.
+ NativeLibrary.Load(Path.Combine(Environment.CurrentDirectory, "mscoree.dll"));
+
+ Console.WriteLine("Verify that we can load an IJW assembly from native code.");
+ string ijwModulePath = Path.Combine(Environment.CurrentDirectory, "IjwNativeCallingManagedDll.dll");
+ IntPtr ijwNativeHandle = NativeLibrary.Load(ijwModulePath);
+
+ using (HostPolicyMock.Mock_corehost_resolve_component_dependencies(
+ 0,
+ ijwModulePath,
+ string.Empty,
+ string.Empty))
+ fixed (char* path = ijwModulePath)
+ {
+ InMemoryAssemblyLoader.LoadInMemoryAssembly(ijwNativeHandle, (IntPtr)path);
+ }
+
+ NativeEntryPointDelegate nativeEntryPoint = Marshal.GetDelegateForFunctionPointer<NativeEntryPointDelegate>(NativeLibrary.GetExport(ijwNativeHandle, "NativeEntryPoint"));
+
+ Assert.AreEqual(100, nativeEntryPoint());
+
+ Console.WriteLine("Test calls from managed to native to managed when an IJW assembly was first loaded via native.");
+
+ Assembly ijwAssemblyManaged = Assembly.Load("IjwNativeCallingManagedDll");
+ Type testType = ijwAssemblyManaged.GetType("TestClass");
+ object testInstance = Activator.CreateInstance(testType);
+ MethodInfo testMethod = testType.GetMethod("ManagedEntryPoint");
+
+ Assert.AreEqual(100, (int)testMethod.Invoke(testInstance, null));
+
+ MethodInfo changeReturnedValueMethod = testType.GetMethod("ChangeReturnedValue");
+ MethodInfo getReturnValueMethod = testType.GetMethod("GetReturnValue");
+
+ int newValue = 42;
+ changeReturnedValueMethod.Invoke(null, new object[] { newValue });
+
+ Assert.AreEqual(newValue, (int)getReturnValueMethod.Invoke(null, null));
+
+ // Native images are only loaded into memory once. As a result, the stubs in the vtfixup table
+ // will always point to JIT stubs that exist in the first ALC that the module was loaded into.
+ // As a result, if an IJW module is loaded into two different ALCs, or if the module is
+ // first loaded via a native call and then loaded via the managed loader, the call stack can change ALCs when
+ // jumping from managed->native->managed code within the IJW module.
+ Assert.AreEqual(100, (int)testMethod.Invoke(testInstance, null));
+ return 100;
+ }
+ catch (Exception ex)
+ {
+ Console.WriteLine(ex.ToString());
+
+ return 101;
+ }
+ }
+
+ [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
+ delegate int NativeEntryPointDelegate();
+
+ }
+}
diff --git a/tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.csproj b/tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.csproj
new file mode 100644
index 0000000000..6228f2c8d7
--- /dev/null
+++ b/tests/src/Interop/IJW/LoadIjwFromModuleHandle/LoadIjwFromModuleHandle.csproj
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <AssemblyName>LoadIjwFromModuleHandle</AssemblyName>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{8B76A001-5654-4F11-A80B-EF12644EAD3D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ <ReferenceSystemPrivateCoreLib>true</ReferenceSystemPrivateCoreLib>
+ <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
+
+ <!-- IJW is Windows-only -->
+ <!-- Test unsupported outside of windows -->
+ <TestUnsupportedOutsideWindows>true</TestUnsupportedOutsideWindows>
+ <DisableProjectBuild Condition="'$(TargetsUnix)' == 'true'">true</DisableProjectBuild>
+
+ <!-- IJW is not supported on ARM64 -->
+ <DisableProjectBuild Condition="'$(Platform)' == 'arm64'">true</DisableProjectBuild>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
+ </PropertyGroup>
+ <PropertyGroup>
+ <CopyDebugCRTDllsToOutputDirectory>true</CopyDebugCRTDllsToOutputDirectory>
+ </PropertyGroup>
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="LoadIjwFromModuleHandle.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <ProjectReference Include="../IjwNativeCallingManagedDll/CMakeLists.txt" />
+ <ProjectReference Include="../ijwhostmock/CMakeLists.txt" />
+ <ProjectReference Include="../../../Common/hostpolicymock/CMakeLists.txt" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Interop.settings.targets))\Interop.settings.targets" />
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+</Project>
diff --git a/tests/src/Interop/IJW/ManagedCallingNative/ManagedCallingNative.csproj b/tests/src/Interop/IJW/ManagedCallingNative/ManagedCallingNative.csproj
index 55b632155c..c8c1ccae96 100644
--- a/tests/src/Interop/IJW/ManagedCallingNative/ManagedCallingNative.csproj
+++ b/tests/src/Interop/IJW/ManagedCallingNative/ManagedCallingNative.csproj
@@ -37,8 +37,8 @@
<Compile Include="ManagedCallingNative.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="IjwNativeDll/CMakeLists.txt" />
- <ProjectReference Include="../FakeMscoree/CMakeLists.txt" />
+ <ProjectReference Include="../IjwNativeDll/CMakeLists.txt" />
+ <ProjectReference Include="../ijwhostmock/CMakeLists.txt" />
<ProjectReference Include="../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/tests/src/Interop/IJW/NativeCallingManaged/NativeCallingManaged.csproj b/tests/src/Interop/IJW/NativeCallingManaged/NativeCallingManaged.csproj
index 9decb48bf8..d40837d7c6 100644
--- a/tests/src/Interop/IJW/NativeCallingManaged/NativeCallingManaged.csproj
+++ b/tests/src/Interop/IJW/NativeCallingManaged/NativeCallingManaged.csproj
@@ -37,8 +37,8 @@
<Compile Include="NativeCallingManaged.cs" />
</ItemGroup>
<ItemGroup>
- <ProjectReference Include="IjwNativeCallingManagedDll/CMakeLists.txt" />
- <ProjectReference Include="../FakeMscoree/CMakeLists.txt" />
+ <ProjectReference Include="../IjwNativeCallingManagedDll/CMakeLists.txt" />
+ <ProjectReference Include="../ijwhostmock/CMakeLists.txt" />
<ProjectReference Include="../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
diff --git a/tests/src/Interop/IJW/FakeMscoree/CMakeLists.txt b/tests/src/Interop/IJW/ijwhostmock/CMakeLists.txt
index cfb6ee2ab5..bdcf920dc1 100644
--- a/tests/src/Interop/IJW/FakeMscoree/CMakeLists.txt
+++ b/tests/src/Interop/IJW/ijwhostmock/CMakeLists.txt
@@ -1,7 +1,7 @@
cmake_minimum_required (VERSION 2.6)
project (mscoree)
include_directories( ${INC_PLATFORM_DIR} )
-set(SOURCES mscoree.cpp mscoree.def)
+set(SOURCES mscoree.cpp)
# add the shared library
add_library (mscoree SHARED ${SOURCES})
diff --git a/tests/src/Interop/IJW/ijwhostmock/mscoree.cpp b/tests/src/Interop/IJW/ijwhostmock/mscoree.cpp
new file mode 100644
index 0000000000..7c398cb1a3
--- /dev/null
+++ b/tests/src/Interop/IJW/ijwhostmock/mscoree.cpp
@@ -0,0 +1,34 @@
+// 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 <windows.h>
+#include <xplatform.h>
+#include <set>
+
+std::set<HINSTANCE> g_modulesQueried = {};
+
+#if defined _X86_
+// We need to use a double-underscore here because the VC linker drops the first underscore
+// to help people who are exporting cdecl functions to easily export the right thing.
+#pragma comment(linker, "/export:__CorDllMain=__CorDllMain@12")
+#pragma comment(linker, "/export:GetTokenForVTableEntry=_GetTokenForVTableEntry@8")
+#endif
+
+// Entry-point that coreclr looks for.
+extern "C" DLL_EXPORT INT32 STDMETHODCALLTYPE GetTokenForVTableEntry(HINSTANCE hInst, BYTE **ppVTEntry)
+{
+ g_modulesQueried.emplace(hInst);
+ return (INT32)(UINT_PTR)*ppVTEntry;
+}
+
+extern "C" DLL_EXPORT BOOL __cdecl WasModuleVTableQueried(HINSTANCE hInst)
+{
+ return g_modulesQueried.find(hInst) != g_modulesQueried.end() ? TRUE : FALSE;
+}
+
+// Entrypoint jumped to by IJW dlls when their dllmain is called
+extern "C" DLL_EXPORT BOOL WINAPI _CorDllMain(HINSTANCE hInst, DWORD dwReason, LPVOID lpReserved)
+{
+ return TRUE;
+}