Click here to Skip to main content
15,887,812 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I have a C++ dll which is calling my C# code after an injection with CLR.

So this is my C++ (dll) code:

C++
#include "stdafx.h"
#include <iostream>
#include <metahost.h>
#include <atlbase.h>
#include <atlcom.h>
#pragma comment(lib, "mscoree.lib")

#define IfFailRet(expr)                { hr = (expr); if(FAILED(hr)) return (hr); }
#define IfNullFail(expr)                { if (!expr) return (E_FAIL); }

extern "C" int __declspec(dllexport) CALLBACK CallClrMethod(
    const WCHAR *AssemblyName,
    const WCHAR *TypeName,
    const WCHAR *MethodName,
    const WCHAR *args,
    LPDWORD pdwResult
)
{
    int hr = S_OK;
    CComPtr<ICLRMetaHost> spHost;
    hr = CLRCreateInstance(CLSID_CLRMetaHost, IID_PPV_ARGS(&spHost));
    CComPtr<ICLRRuntimeInfo> spRuntimeInfo;
    CComPtr<IEnumUnknown> pRunTimes;
    IfFailRet(spHost->EnumerateInstalledRuntimes(&pRunTimes));
    CComPtr<IUnknown> pUnkRuntime;
    while (S_OK == pRunTimes->Next(1, &pUnkRuntime, 0))
    {
        CComQIPtr<ICLRRuntimeInfo> pp(pUnkRuntime);
        if (pUnkRuntime != nullptr)
        {
            spRuntimeInfo = pp;
            break;
        }
    }
    IfNullFail(spRuntimeInfo);

    BOOL bStarted;
    DWORD dwStartupFlags;
    hr = spRuntimeInfo->IsStarted(&bStarted, &dwStartupFlags);
    if (hr != S_OK) // sometimes 0x80004001  not implemented  
    {
        spRuntimeInfo = nullptr; //v4.0.30319 //v2.0.50727
        hr = spHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&spRuntimeInfo));
        bStarted = false;
    }

    CComPtr<ICLRRuntimeHost> spRuntimeHost;
    IfFailRet(spRuntimeInfo->GetInterface(CLSID_CLRRuntimeHost, IID_PPV_ARGS(&spRuntimeHost)));
    if (!bStarted)
    {
        hr = spRuntimeHost->Start();
    }
    hr = spRuntimeHost->ExecuteInDefaultAppDomain(
        AssemblyName,
        TypeName,
        MethodName,
        args,
        pdwResult);
    return hr;
}


int _tmain(int argc, _TCHAR* argv[])
{
    DWORD dwResult;
    HRESULT hr = CallClrMethod(
        L"D:\\Dev\\CSharpDll\\CSharpDll\\bin\\x64\\Debug\\CSharpDll.dll",
        L"CSharpDll.MainClass",
        L"EntryPoint",
        L"Im successfully called from a C++ dll",
        &dwResult);
    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved
)
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        CreateThread(NULL, NULL, (LPTHREAD_START_ROUTINE)_tmain, hModule, NULL, NULL);
        break;
    case DLL_THREAD_ATTACH:
        break;
    case DLL_THREAD_DETACH:
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}


And this is my C# (dll) code:



C#
using System.Windows.Forms;
namespace CSharpDll
{
    public class MainClass
    {
        public static int EntryPoint(string MessageFromCppDll)
        {
            MessageBox.Show(MessageFromCppDll);

            Form form = new MainForm();
            form.ShowDialog();

            return 0;
        }
    }
}


So it works very well for the most programs and games, but not at all. On some programs it happens nothing. The injected c++ dll try to run the c# code, but it happen nothing. My theory is that the c++ dll will create no instance of the c# dll.

But there is one option to fix that: If I change the runtime from v4.0.30319 to v2.0.50727 it works fine.

It don't work:

C++
hr = spHost->GetRuntime(L"v4.0.30319", IID_PPV_ARGS(&spRuntimeInfo));

It work:

C++
hr = spHost->GetRuntime(L"v2.0.50727", IID_PPV_ARGS(&spRuntimeInfo));

And now we come to my "main" problem: I have to decrease the .NET version from 4+ to 3.5 because the CLR V2 only support .NET 2 - 3.5. And this brings problems with my C# (dll) code.

So now I come to my question(s):

Why is this not working on all programs and games? (I mean with runtime v4.0.30319). With CLR RunTimeHost v2.0.50727 it works.

And how can I fix it or change something in my code to run it.

If you guys have any ideas or code examples, I would be very grateful.

What I have tried:

I tried to find out why it works not on all programs, but I can not recognize a pattern.
Posted
Updated 22-Oct-18 9:41am
Comments
Mehdi Gholam 22-Oct-18 14:20pm    
It is possible that you have 32/64bit issues.
Dave Kreskowiak 22-Oct-18 14:55pm    
Are the processes you are injecting your code into also .NET apps, complied against .NET 2.0, 3.0 or 3.5? If so, you've got a problem. .NET CLR 2.x doesn't support multiple versions of the runtime in the same process.
Member 13911570 23-Oct-18 7:49am    
I know my error, I forgot to to press the "Use CLR" button in settings, now it works. (With CLR v4)

1 solution

I think it could be one of two things:

Use the Application.Run method to start the form (More info: Application.Run Method (System.Windows.Forms) | Microsoft Docs )

Or try adding the STAThread attribute to your EntryPoint method (More info: STAThreadAttribute )

According to the documentation the STAThread attribute is set automatically but if I'm not mistaken Application.Run has something to do with it...

Good luck!
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900