void* StartClrBootstrap( wchar_t* dllPath, wchar_t* userData, wchar_t* appBase, wchar_t* privatePath ) { // Bind to the CLR runtime.. ICLRRuntimeHost *pClrHost = NULL; HRESULT clrResult = CorBindToRuntimeEx( NULL, L"wks", 0, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*)&pClrHost); // Push the big START button shown above clrResult = pClrHost->Start(); // Create parameters to pass into Bootstrap assembly // Bootstrapper is responsible for setting up the // apppath and privatebin parameters for the AppDomain wstring outParam = FormParameter(dllPath, appBase, privatePath, userData); // Get path to Bootstrap assembly wstring pathBootstrap = PathResolve(L"BootStrapper.dll"); // Okay, the CLR is up and running in this (previously native) process. // Now call a method on our managed C# class library. DWORD retCode = 0; clrResult = pClrHost->ExecuteInDefaultAppDomain ( pathBootstrap.c_str(), L"BootStrapper.Main", L"Initialize", outParam.c_str(), &retCode ); return (void*)retCode; }
void Bootstrap::StartTheDotNetRuntime() { ofstream myfile; myfile.open(L"C:\\Temp\\cppLog.txt"); myfile << "Entered Injection function"; myfile.close(); ICLRMetaHost *pMetaHost = NULL; CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); ICLRRuntimeInfo *pRuntimeInfo = NULL; pMetaHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (LPVOID*)&pRuntimeInfo); ICLRRuntimeHost *pClrRuntimeHost = NULL; pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&pClrRuntimeHost); //Run the CLR so run a >NET runtime pClrRuntimeHost->Start(); HRESULT hr = LoadManagedLibrary(pClrRuntimeHost); myfile.open(L"C:\\Temp\\cppLog.txt"); myfile << "After to loading .NET dll"; myfile.close(); // free resources pMetaHost->Release(); pRuntimeInfo->Release(); pClrRuntimeHost->Release(); }
extern "C" __declspec(dllexport) HRESULT Inject(_In_ LPCSTR param) { DWORD pReturnValue; ICLRMetaHost* pMetaHost = NULL; ICLRRuntimeInfo* pRuntimeInfo = NULL; ICLRRuntimeHost* pClrRuntimeHost = NULL; if (CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)) != S_OK) { return -1; } if (pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)) != S_OK) { return -1; } if (pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)) != S_OK) { return -1; } if (pClrRuntimeHost->Start() != S_OK) { return -1; } WCHAR wsz[MAX_PATH]; MultiByteToWideChar(CP_ACP, 0, param, -1, wsz, MAX_PATH); HRESULT hr = pClrRuntimeHost->ExecuteInDefaultAppDomain( wsz, L"FakePacketSender.InjectedEntry", L"Run", wsz, &pReturnValue); if (hr = pClrRuntimeHost->Stop() != S_OK) { _com_error err(hr); MessageBox(0, err.ErrorMessage(), L"Error", 0); return -1; } if (hr != S_OK) { _com_error err(hr); MessageBox(0, err.ErrorMessage(), L"Error", 0); return -1; } pMetaHost->Release(); pRuntimeInfo->Release(); pClrRuntimeHost->Release(); return hr; }
HRESULT clrWrapper(LPCWSTR runtimeVersion, std::function<HRESULT(ICLRRuntimeHost* pClrRuntimeHost)> callback) { HRESULT hr = E_FAIL; ICLRMetaHost* pMetaHost = nullptr; ICLRRuntimeInfo* pRuntimeInfo = nullptr; ICLRRuntimeHost* pClrRuntimeHost = nullptr; do { hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); if (FAILED(hr)) { break; } hr = pMetaHost->GetRuntime(runtimeVersion, IID_PPV_ARGS(&pRuntimeInfo)); if (FAILED(hr)) { break; } hr = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)); if (FAILED(hr)) { break; } hr = pClrRuntimeHost->Start(); if (FAILED(hr)) { break; } if (callback) { hr = callback(pClrRuntimeHost); if (FAILED(hr)) { break; } } } while (false); if (pClrRuntimeHost) { pClrRuntimeHost->Release(); pClrRuntimeHost = nullptr; } if (pRuntimeInfo) { pRuntimeInfo->Release(); pRuntimeInfo = nullptr; } if (pMetaHost) { pMetaHost->Release(); pMetaHost = nullptr; } return hr; }
EASYHOOK_NT_INTERNAL CompleteManagedInjection(LPREMOTE_INFO InInfo) { /* Description: Loads the NET runtime into the calling process and invokes the managed injection entry point (EasyHook.InjectionLoader.Main). */ ICLRMetaHost* MetaClrHost = NULL; ICLRRuntimeInfo* RuntimeInfo = NULL; ICLRRuntimeHost* RuntimeClrHost = NULL; DWORD ErrorCode = 0; WCHAR ParamString[MAX_PATH]; REMOTE_ENTRY_INFO EntryInfo; HMODULE hMsCorEE = LoadLibraryA("mscoree.dll"); PROC_CorBindToRuntime* CorBindToRuntime = (PROC_CorBindToRuntime*)GetProcAddress(hMsCorEE, "CorBindToRuntime"); // .NET 2.0/3.5 framework creation method PROC_CLRCreateInstance* CLRCreateInstance = (PROC_CLRCreateInstance*)GetProcAddress(hMsCorEE, "CLRCreateInstance"); // .NET 4.0+ framework creation method DWORD RetVal; bool UseCorBindToRuntime = false; if(CorBindToRuntime == NULL && CLRCreateInstance == NULL) UNMANAGED_ERROR(10); // mscoree.dll does not exist or does not expose either of the framework creation methods UseCorBindToRuntime = CLRCreateInstance == NULL; // invoke user defined entry point EntryInfo.HostPID = InInfo->HostProcess; EntryInfo.UserData = InInfo->UserData; EntryInfo.UserDataSize = InInfo->UserDataSize; if (!UseCorBindToRuntime) { // Attempt to use .NET 3.5/4 runtime object creation method rather than deprecated .NET 2.0 CorBindToRuntime if (FAILED(CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&MetaClrHost))) { // Failed to get a MetaHost instance DEBUGOUT("Failed to retrieve CLRMetaHost instance"); UseCorBindToRuntime = true; } else { /* It is possible to create a ICLRRuntimeInfo object based on the runtime required by InInfo->UserLibrary however this requires that the assembly containing the "EasyHook.InjectionLoader" (usually EasyHook.dll) must be targetting the same framework version as the assembly(ies) to be injected. This is because the first CLR assembly injected into the target process in this case is usually the EasyHook.dll assembly. So instead we are providing a specific .NET version (for now v4.0.30319), this will need to be passed as a parameter in the future. */ // TODO: add documentation about what happens when injecting into a managed process where the .NET framework is already loaded LPCWSTR frameworkVersion = L"v4.0.30319"; // TODO: .NET version string to be passed in "InInfo" if (FAILED(MetaClrHost->GetRuntime( frameworkVersion, IID_ICLRRuntimeInfo, (LPVOID*)&RuntimeInfo))) { // .NET version requested is not available DEBUGOUT("Failed to retrieve runtime info for framework version: %s", frameworkVersion); UseCorBindToRuntime = true; } else { if (FAILED(RuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&RuntimeClrHost))) { // Failed to create the requested CLR host version // TODO: add documentation about why this might happen - e.g. does this happen if an older framework version is already loaded by the target? DEBUGOUT("Failed to create CLR host for framework version: %s", frameworkVersion); UseCorBindToRuntime = true; } else { RuntimeClrHost->Start(); // Enable support for running older .NET v2 assemblies within .NET v4 (e.g. EasyHook.dll is .NET 2.0) if (FAILED(RuntimeInfo->BindAsLegacyV2Runtime())) DEBUGOUT("Unable to BindAsLegacyV2Runtime"); } } } } if (UseCorBindToRuntime) { // load NET-Runtime and execute user defined method if(!RTL_SUCCESS(CorBindToRuntime(NULL, NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**)&RuntimeClrHost))) { DEBUGOUT("CorBindToRuntime failed"); UNMANAGED_ERROR(11); } RuntimeClrHost->Start(); } /* Test library code. This is because if once we have set the remote signal, there is no way to notify the host about errors. If the following call succeeds, then it will also do so some lines later... If not, then we are still able to report an error. The EasyHook managed injection loader will establish a connection to the host, so that further error reporting is still possible after we set the event! */ RtlLongLongToUnicodeHex((LONGLONG)&EntryInfo, ParamString); if(!RTL_SUCCESS(RuntimeClrHost->ExecuteInDefaultAppDomain( InInfo->UserLibrary, L"EasyHook.InjectionLoader", L"Main", ParamString, &RetVal))) { if (UseCorBindToRuntime) UNMANAGED_ERROR(12); // We already tried the CorBindToRuntime method and it has failed // Running the assembly in the .NET 4.0 Runtime did not work; // Stop and attempt to run it in the .NET 2.0/3.5 Runtime if(RuntimeClrHost != NULL) RuntimeClrHost->Release(); if(!RTL_SUCCESS(CorBindToRuntime(NULL, NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**)&RuntimeClrHost))) UNMANAGED_ERROR(11); RuntimeClrHost->Start(); RtlLongLongToUnicodeHex((LONGLONG)&EntryInfo, ParamString); if(!RTL_SUCCESS(RuntimeClrHost->ExecuteInDefaultAppDomain(InInfo->UserLibrary, L"EasyHook.InjectionLoader", L"Main", ParamString, &RetVal))) UNMANAGED_ERROR(14); // Execution under both .NET 4 and .NET 2/3.5 failed (new ErrorCode: 14, for EasyHook 2.7) } if(!RetVal) UNMANAGED_ERROR(13); // set and close event if(!SetEvent(InInfo->hRemoteSignal)) UNMANAGED_ERROR(22); CloseHandle(InInfo->hRemoteSignal); InInfo->hRemoteSignal = NULL; // execute library code (no way for error reporting, so we dont need to check) RuntimeClrHost->ExecuteInDefaultAppDomain( InInfo->UserLibrary, L"EasyHook.InjectionLoader", L"Main", ParamString, &RetVal); ABORT_ERROR: // release resources if(MetaClrHost != NULL) MetaClrHost->Release(); if(RuntimeInfo != NULL) RuntimeInfo->Release(); if(RuntimeClrHost != NULL) RuntimeClrHost->Release(); if(hMsCorEE != NULL) FreeLibrary(hMsCorEE); return ErrorCode; }
ICLRRuntimeHost* StartCLR(LPCWSTR dotNetVersion) { HRESULT hr; ICLRMetaHost* pClrMetaHost = NULL; ICLRRuntimeInfo* pClrRuntimeInfo = NULL; ICLRRuntimeHost* pClrRuntimeHost = NULL; // Get the CLRMetaHost that tells us about .NET on this machine hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pClrMetaHost); if (hr == S_OK) { OutputDebugStringW(L"[Bootstrap] Created CLR instance\n"); // Get the runtime information for the particular version of .NET hr = pClrMetaHost->GetRuntime(dotNetVersion, IID_PPV_ARGS(&pClrRuntimeInfo)); if (hr == S_OK) { OutputDebugStringW(L"[Bootstrap] Got CLR runtime\n"); // Check if the specified runtime can be loaded into the process. This // method will take into account other runtimes that may already be // loaded into the process and set pbLoadable to TRUE if this runtime can // be loaded in an in-process side-by-side fashion. BOOL fLoadable; hr = pClrRuntimeInfo->IsLoadable(&fLoadable); if ((hr == S_OK) && fLoadable) { OutputDebugStringW(L"[Bootstrap] Runtime is loadable!\n"); // Load the CLR into the current process and return a runtime interface // pointer. hr = pClrRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)); if (hr == S_OK) { OutputDebugStringW(L"[Bootstrap] Got interface.\n"); // Start it. This is okay to call even if the CLR is already running hr = pClrRuntimeHost->Start(); // if (hr == S_OK) // { OutputDebugStringW(L"[Bootstrap] Started the runtime!\n"); // Success! return pClrRuntimeHost; // } } } } } // Cleanup if failed if (pClrRuntimeHost) { pClrRuntimeHost->Release(); pClrRuntimeHost = NULL; } if (pClrRuntimeInfo) { pClrRuntimeInfo->Release(); pClrRuntimeInfo = NULL; } if (pClrMetaHost) { pClrMetaHost->Release(); pClrMetaHost = NULL; } return NULL; }
/// <summary> /// Starts the dot net runtime. /// </summary> /// <remarks>http://www.codingthewheel.com/archives/how-to-inject-a-managed-assembly-dll/</remarks> HRESULT StartTheDotNetRuntime(_In_ LPCTSTR lpCommand) { FILE *file; fopen_s(&file, logPath, "a+"); fprintf(file, "binding runtime.\r\n"); fflush(file); fprintf(file, "Loading the .NET runtime host.\n"); fflush(file); ICLRMetaHost *pMetaHost = NULL; auto result = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&pMetaHost)); if (FAILED(result)) { fprintf(file, "Error: failed to create CLR instance.\n"); fflush(file); return result; } fprintf(file, "Loading the .NET runtime.\n"); fflush(file); ICLRRuntimeInfo *pRuntimeInfo = NULL; result = pMetaHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&pRuntimeInfo)); if (FAILED(result)) { fprintf(file, "Error: failed to create CLR instance.\n"); fflush(file); pMetaHost->Release(); return result; } fprintf(file, "Acquiring the .NET runtime.\n"); fflush(file); ICLRRuntimeHost *pClrRuntimeHost = NULL; result = pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&pClrRuntimeHost)); if (FAILED(result)) { fprintf(file, "Error: failed to acquire CLR runtime.\n"); fflush(file); pMetaHost->Release(); return result; } fprintf(file, "Starting the .NET runtime.\n"); fflush(file); result = pClrRuntimeHost->Start(); if (FAILED(result)) { fprintf(file, "Error: failed to start CLR runtime.\n"); fflush(file); pClrRuntimeHost->Release(); pMetaHost->Release(); return result; } fprintf(file, "Executing payload assembly.\n"); fflush(file); DWORD dwRet = 0; result = pClrRuntimeHost->ExecuteInDefaultAppDomain( assemblyPath, classFqn, methodName, parameter, &dwRet); if (FAILED(result)) { fprintf(file, "Error: unable to execute example code.\n"); fflush(file); pClrRuntimeHost->Stop(); pClrRuntimeHost->Release(); pMetaHost->Release(); return result; } fprintf(file, "Stopping the .NET runtime.\n"); fflush(file); pClrRuntimeHost->Stop(); fprintf(file, "Releasing the .NET runtime.\n"); fflush(file); pClrRuntimeHost->Release(); pMetaHost->Release(); fclose(file); return ERROR_SUCCESS; }
int _tmain(int argc, _TCHAR* argv[]) { // Bind to the runtime. ICLRRuntimeHost *pClrHost = NULL; HRESULT hrCorBind = CorBindToRuntimeEx( NULL, // Load the latest CLR version available L"wks", // Workstation GC ("wks" or "svr" overrides) 0, // No flags needed CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (PVOID*)&pClrHost); CheckFail(hrCorBind, "Bind to runtime failed (0x%x)"); // Construct our host control object. DHHostControl *pHostControl = new DHHostControl(pClrHost); if (!pHostControl) Fail("Host control allocation failed"); pClrHost->SetHostControl(pHostControl); // Now, begin the CLR. HRESULT hrStart = pClrHost->Start(); if (hrStart == S_FALSE) _ASSERTE(!L"Runtime already started; probably OK to proceed"); else CheckFail(hrStart, "Runtime startup failed (0x%x)"); // Construct the shim path (i.e. shim.exe). WCHAR wcShimPath[MAX_PATH]; if (!GetCurrentDirectoryW(MAX_PATH, wcShimPath)) CheckFail(HRESULT_FROM_WIN32(GetLastError()), "GetCurrentDirectory failed (0x%x)"); wcsncat_s(wcShimPath, sizeof(wcShimPath) / sizeof(WCHAR), L"\\shim.exe", MAX_PATH - wcslen(wcShimPath) - 1); // Gather the arguments to pass to the shim. LPWSTR wcShimArgs = NULL; if (argc > 1) { SIZE_T totalLength = 1; // 1 is the NULL terminator for(int i = 1; i < argc; i++) { // TODO: add characters for quotes around args w/ spaces inside them if (i != 1) totalLength++; // add a space between args totalLength += _tcslen(argv[i]) + 1; } wcShimArgs = new WCHAR[totalLength]; wcShimArgs[0] = '\0'; for(int i = 1; i < argc; i++) { if (i != 1) wcscat_s(wcShimArgs, totalLength, L" "); wcsncat_s(wcShimArgs, totalLength, argv[i], wcslen(argv[i])); } } if (wcShimArgs == NULL) Fail("Missing program path (host.exe <exePath>)\r\n"); // And execute the program... DWORD retVal; HRESULT hrExecute = pClrHost->ExecuteInDefaultAppDomain( wcShimPath, L"Shim", L"Start", wcShimArgs, &retVal); CheckFail(hrExecute, "Execution of shim failed (0x%x)\r\n"); if (wcShimArgs) delete wcShimArgs; // Stop the CLR and cleanup. pHostControl->ShuttingDown(); pClrHost->Stop(); pClrHost->Release(); return retVal; }
EASYHOOK_NT_INTERNAL CompleteManagedInjection(LPREMOTE_INFO InInfo) { /// Region: Temporary workaround for InInfo->Assemblies not being received correctly InInfo->AssembliesCount = 3; InInfo->Assemblies = new RhAssemblyInfo[InInfo->AssembliesCount]; InInfo->Assemblies[0].FullName = L"ProcMonInject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d34a061f079be347, ProcessorArchitecture=MSIL"; InInfo->Assemblies[0].AssemblyLoadPath = L"D:/Documenten/Documenten/Projects/EasyHook/EasyHook - CLRHostingAPI - vs2008/Debug/x64/ProcMonInject.dll"; InInfo->Assemblies[0].AssemblyDebugInfoPath = NULL; InInfo->Assemblies[1].FullName = L"ProcessMonitor, Version=1.0.0.0, Culture=neutral, PublicKeyToken=d34a061f079be347, ProcessorArchitecture=MSIL"; InInfo->Assemblies[1].AssemblyLoadPath = L"D:/Documenten/Documenten/Projects/EasyHook/EasyHook - CLRHostingAPI - vs2008/Debug/x64/ProcessMonitor.exe"; InInfo->Assemblies[1].AssemblyDebugInfoPath = NULL; InInfo->Assemblies[2].FullName = L"EasyHook, Version=2.5.0.0, Culture=neutral, PublicKeyToken=4b580fca19d0b0c5, ProcessorArchitecture=MSIL"; InInfo->Assemblies[2].AssemblyLoadPath = L"D:/Documenten/Documenten/Projects/EasyHook/EasyHook - CLRHostingAPI - vs2008/Debug/x64/EasyHook.dll"; InInfo->Assemblies[2].AssemblyDebugInfoPath = NULL; /// Endregion /* Description: Loads the NET runtime into the calling process and invokes the managed injection entry point. */ #ifdef _NET4 ICLRMetaHost* pMetaClrHost = NULL; ICLRRuntimeInfo* pRuntimeInfo = NULL; #endif REMOTE_ENTRY_INFO EntryInfo; ICLRRuntimeHost* pClr = NULL; WCHAR ParamString[MAX_PATH]; DWORD ErrorCode = 0; HMODULE hMsCorEE = LoadLibraryA("mscoree.dll"); PROC_CorBindToRuntime* CorBindToRuntime = (PROC_CorBindToRuntime*)GetProcAddress(hMsCorEE, "CorBindToRuntime"); if(CorBindToRuntime == NULL) UNMANAGED_ERROR(10); // Invoke user defined entry point EntryInfo.HostPID = InInfo->HostProcess; EntryInfo.UserData = InInfo->UserData; EntryInfo.UserDataSize = InInfo->UserDataSize; RtlLongLongToUnicodeHex((LONGLONG)&EntryInfo, ParamString); // Load the Common Language Runtime if(!RTL_SUCCESS(CorBindToRuntime(NULL, NULL, CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**)&pClr))) UNMANAGED_ERROR(11); if (!RTL_SUCCESS(AssociateCustomCLRHost(pClr, InInfo->Assemblies, InInfo->AssembliesCount))) UNMANAGED_ERROR(14); pClr->Start(); /* Test library code. This is because if once we have set the remote signal, there is no way to notify the host about errors. If the following call succeeds, then it will also do so some lines later... If not, then we are still able to report an error. The EasyHook managed injection loader will establish a connection to the host, so that further error reporting is still possible after we set the event! */ RtlLongLongToUnicodeHex((LONGLONG)&EntryInfo, ParamString); HRESULT result = pClr->ExecuteInDefaultAppDomain( InInfo->UserLibrary, L"EasyHook.InjectionLoader", L"Main", ParamString, &ErrorCode); if(!RTL_SUCCESS(result)) { // Test failed! #ifdef _NET4 // Target CLR might be .NET 4.0, try to load this CLR instead. if(NULL != pClr) pClr->Release(); if(FAILED(CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (void**)&pMetaClrHost))) UNMANAGED_ERROR(11); if(FAILED(pMetaClrHost->GetRuntime(L"v4.0.30319", IID_ICLRRuntimeInfo, (void**)&pRuntimeInfo))) UNMANAGED_ERROR(11); if(FAILED(pRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (void**) &pClr))) UNMANAGED_ERROR(11); AssociateCustomCLRHost(pClr); pClr->Start(); RtlLongLongToUnicodeHex((LONGLONG)&EntryInfo, ParamString); if(!RTL_SUCCESS(RuntimeClrHost->ExecuteInDefaultAppDomain(InInfo->UserLibrary, L"EasyHook.InjectionLoader", L"Main", ParamString, &RetVal))) #endif UNMANAGED_ERROR(12); } if(!ErrorCode) UNMANAGED_ERROR(13); // set and close event if(!SetEvent(InInfo->hRemoteSignal)) UNMANAGED_ERROR(22); CloseHandle(InInfo->hRemoteSignal); InInfo->hRemoteSignal = NULL; // Execute library code (no way for error reporting, so we dont need to check) pClr->ExecuteInDefaultAppDomain( InInfo->UserLibrary, L"EasyHook.InjectionLoader", L"Main", ParamString, &ErrorCode); ABORT_ERROR: // Release Resources if(NULL != pClr) pClr->Release(); #ifdef _NET4 if (NULL != pMetaClrHost) pMetaClrHost->Release(); if (NULL != pRuntimeInfo) pRuntimeInfo->Release(); #endif return ErrorCode; }
VOID StartAssembly(vector<wstring> const& params) { ICLRMetaHost *pMetaHost = NULL; HRESULT hr; hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_ICLRMetaHost, (LPVOID*)&pMetaHost); if (SUCCEEDED(hr)) { IEnumUnknown *peunkRuntimes; hr = pMetaHost->EnumerateInstalledRuntimes(&peunkRuntimes); if (SUCCEEDED(hr)) { // *** FINDING LATEST RUNTIME *** IUnknown *punkRuntime; ICLRRuntimeInfo *prtiLatest = NULL; WCHAR szLatestRuntimeVersion[MAX_PATH]; while (peunkRuntimes->Next(1, &punkRuntime, NULL) == S_OK) { ICLRRuntimeInfo *prtiCurrent; hr = punkRuntime->QueryInterface(IID_PPV_ARGS(&prtiCurrent)); if (SUCCEEDED(hr)) { if (!prtiLatest) { hr = prtiCurrent->QueryInterface(IID_PPV_ARGS(&prtiLatest)); if (SUCCEEDED(hr)) { DWORD cch = ARRAYSIZE(szLatestRuntimeVersion); hr = prtiLatest->GetVersionString(szLatestRuntimeVersion, &cch); } } else { WCHAR szCurrentRuntimeVersion[MAX_PATH]; DWORD cch = ARRAYSIZE(szCurrentRuntimeVersion); hr = prtiCurrent->GetVersionString(szCurrentRuntimeVersion, &cch); if (SUCCEEDED(hr)) { if (wcsncmp(szLatestRuntimeVersion, szCurrentRuntimeVersion, cch) < 0) { hr = prtiCurrent->GetVersionString(szLatestRuntimeVersion, &cch); if (SUCCEEDED(hr)) { prtiLatest->Release(); hr = prtiCurrent->QueryInterface(IID_PPV_ARGS(&prtiLatest)); } } } } prtiCurrent->Release(); } punkRuntime->Release(); } peunkRuntimes->Release(); // *** STARTING CLR *** if (SUCCEEDED(hr)) { ICLRRuntimeHost *prth; hr = prtiLatest->GetInterface(CLSID_CLRRuntimeHost, IID_ICLRRuntimeHost, (LPVOID*)&prth); if (SUCCEEDED(hr)) { hr = prth->Start(); if (SUCCEEDED(hr)) { DWORD dwRet = 0; hr = prth->ExecuteInDefaultAppDomain(params.at(0).c_str(), params.at(1).c_str(), params.at(2).c_str(), params.at(3).c_str(), &dwRet); // hr = 0x80131513 (System.MissingMethodException) if (SUCCEEDED(hr)) { // *** Success *** MessageBox(GetDesktopWindow(), L"Successfully called managed function.", L"Success", MB_OK); } hr = prth->Stop(); } prth->Release(); } } } pMetaHost->Release(); } }