From 172506218ef056caf787f0ef4846c93c7f6ff53e Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Fri, 12 Oct 2018 15:10:06 -0400 Subject: [PATCH] Add test for ICLRRuntimeHost::ExecuteInDefaultAppDomain --- tests/src/Interop/CMakeLists.txt | 1 + tests/src/Interop/ExecInDefAppDom/CMakeLists.txt | 10 +++ .../src/Interop/ExecInDefAppDom/ExecInDefAppDom.cs | 90 ++++++++++++++++++++++ .../Interop/ExecInDefAppDom/ExecInDefAppDom.csproj | 36 +++++++++ .../Interop/ExecInDefAppDom/ExecInDefAppDomDll.cpp | 62 +++++++++++++++ 5 files changed, 199 insertions(+) create mode 100644 tests/src/Interop/ExecInDefAppDom/CMakeLists.txt create mode 100644 tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.cs create mode 100644 tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.csproj create mode 100644 tests/src/Interop/ExecInDefAppDom/ExecInDefAppDomDll.cpp diff --git a/tests/src/Interop/CMakeLists.txt b/tests/src/Interop/CMakeLists.txt index 282cda7..affc629 100644 --- a/tests/src/Interop/CMakeLists.txt +++ b/tests/src/Interop/CMakeLists.txt @@ -38,6 +38,7 @@ add_subdirectory(SizeConst) add_subdirectory(DllImportAttribute/ExeFile) add_subdirectory(DllImportAttribute/FileNameContainDot) add_subdirectory(DllImportAttribute/Simple) +add_subdirectory(ExecInDefAppDom) if(WIN32) # This test doesn't necessarily need to be Windows-only, but the implementation is very tied to Windows APIs diff --git a/tests/src/Interop/ExecInDefAppDom/CMakeLists.txt b/tests/src/Interop/ExecInDefAppDom/CMakeLists.txt new file mode 100644 index 0000000..e1c903c --- /dev/null +++ b/tests/src/Interop/ExecInDefAppDom/CMakeLists.txt @@ -0,0 +1,10 @@ +cmake_minimum_required (VERSION 2.6) +project (ExecInDefAppDomDll) +set(SOURCES ExecInDefAppDomDll.cpp ) + +# add the executable +add_library (ExecInDefAppDomDll SHARED ${SOURCES}) +target_link_libraries(ExecInDefAppDomDll ${LINK_LIBRARIES_ADDITIONAL}) + +# add the install targets +install (TARGETS ExecInDefAppDomDll DESTINATION bin) diff --git a/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.cs b/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.cs new file mode 100644 index 0000000..fe094fb --- /dev/null +++ b/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.cs @@ -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. +using System; +using System.Runtime.InteropServices; + +using Console = Internal.Console; + +public class FakeInjectedCode +{ + int NonStatic(String argument) { return 0;} + static bool WrongReturnType(String argument) { return false;} + static int Return0(String argument) { return 0;} + static int Return1(String argument) { return 1;} + static int ThrowAnything(String argument) { throw new Exception("Throwing something");} + static int ParseArgument(String argument) { return int.Parse(argument);} +} + +public class Program +{ + public static class NativeMethods + { + [DllImport("ExecInDefAppDomDll")] + public static extern int + CallExecuteInDefaultAppDomain( + [In, MarshalAs( UnmanagedType.LPWStr )] String assemblyPath, + [In, MarshalAs( UnmanagedType.LPWStr )] String typeName, + [In, MarshalAs( UnmanagedType.LPWStr )] String methodName, + [In, MarshalAs( UnmanagedType.LPWStr )] String argument, + [In, Out, MarshalAs( UnmanagedType.I4 )] ref int result + ); + } + + static int TestExecuteInAppDomain(string assemblyPath, string typeName, string methodName, string argument, int expectedHResult, int expectedResult) + { + bool passed = true; + try + { + int result = 0; + int hresult = NativeMethods.CallExecuteInDefaultAppDomain(assemblyPath, typeName, methodName, argument, ref result); + + if (hresult != expectedHResult) + { + Console.WriteLine($"Bad HRESULT: expected {expectedHResult:X} actual {hresult:X}"); + passed = false; + } + else if (result != expectedResult) + { + Console.WriteLine($"Bad result: expected {expectedResult} actual {result}"); + passed = false; + } + } + catch (Exception e) + { + Console.WriteLine($"Unexpected exception: {e}"); + passed = false; + } + return passed ? 0 : 1; + } + + public static int Main(string[] args) + { + int result = 100; + String myPath = System.Reflection.Assembly.GetExecutingAssembly().Location; + String bogusPath = myPath + "random"; + + const int S_OK = unchecked((int)0); + const int COR_E_FILENOTFOUND = unchecked((int)0x80070002); + const int COR_E_TYPELOAD = unchecked((int)0x80131522); + const int COR_E_MISSINGMETHOD = unchecked((int)0x80131513); + const int COR_E_EXCEPTION = unchecked((int)0x80131500); + const int COR_E_FORMAT = unchecked((int)0x80131537); + + result += TestExecuteInAppDomain(bogusPath, "BogusType", "Return0", "None", COR_E_FILENOTFOUND, 0); + + result += TestExecuteInAppDomain(myPath, "BogusType", "Return0", "None", COR_E_TYPELOAD, 0); + + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "NonStatic", "None", COR_E_MISSINGMETHOD, 0); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "WrongReturnType", "None", COR_E_MISSINGMETHOD, 0); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "Return0", "None", S_OK, 0); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "Return1", "None", S_OK, 1); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "ThrowAnything", "None", COR_E_EXCEPTION, 0); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "ParseArgument", "0", S_OK, 0); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "ParseArgument", "200", S_OK, 200); + result += TestExecuteInAppDomain(myPath, "FakeInjectedCode", "ParseArgument", "None", COR_E_FORMAT, 0); + + return result; + } + +} diff --git a/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.csproj b/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.csproj new file mode 100644 index 0000000..edbf53d --- /dev/null +++ b/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDom.csproj @@ -0,0 +1,36 @@ + + + + + + Debug + AnyCPU + ExecInDefAppDom + 2.0 + {0A370152-9D24-475E-A171-AB58897132C3} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + $(DefineConstants);STATIC + true + + + + + + + False + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDomDll.cpp b/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDomDll.cpp new file mode 100644 index 0000000..cd83137 --- /dev/null +++ b/tests/src/Interop/ExecInDefAppDom/ExecInDefAppDomDll.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. + +#include +#include "mscoree.h" + +typedef HRESULT (STDAPICALLTYPE *FnGetCLRRuntimeHost)(REFIID riid, IUnknown **pUnk); + +// Returns the ICLRRuntimeHost instance or nullptr on failure. +ICLRRuntimeHost* GetCLRRuntimeHost() +{ + HMODULE coreCLRModule = ::GetModuleHandle(L"coreclr.dll"); + if (!coreCLRModule) + { + coreCLRModule = ::GetModuleHandle(L"coreclr.so"); + } + if (!coreCLRModule) + { + coreCLRModule = ::GetModuleHandle(L"coreclr.dynlib"); + } + if (!coreCLRModule) + { + return nullptr; + } + + FnGetCLRRuntimeHost pfnGetCLRRuntimeHost = (FnGetCLRRuntimeHost)::GetProcAddress(coreCLRModule, "GetCLRRuntimeHost"); + if (!pfnGetCLRRuntimeHost) + { + return nullptr; + } + + ICLRRuntimeHost* clrRuntimeHost = nullptr; + HRESULT hr = pfnGetCLRRuntimeHost(IID_ICLRRuntimeHost, (IUnknown**)&clrRuntimeHost); + if (FAILED(hr)) { + return nullptr; + } + + return clrRuntimeHost; +} + +extern "C" DLL_EXPORT int STDMETHODCALLTYPE +CallExecuteInDefaultAppDomain(LPCWSTR pwzAssemblyPath, + LPCWSTR pwzTypeName, + LPCWSTR pwzMethodName, + LPCWSTR pwzArgument, + DWORD *pReturnValue) +{ + ICLRRuntimeHost* host = GetCLRRuntimeHost(); + + if (!host) + return E_FAIL; + + if(host->Start()) + return E_FAIL; + + auto result = host->ExecuteInDefaultAppDomain(pwzAssemblyPath, pwzTypeName, pwzMethodName, pwzArgument, pReturnValue); + + host->Stop(); + + return result; +} -- 2.7.4