Member 13911570 Ответов: 1

Проблема с CLR / it не работает с runtime v4.0.30319


У меня есть библиотека dll C++, которая вызывает мой код C# после инъекции с помощью CLR.

Итак, это мой код C++ (dll) :

#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;
}


А это мой код C# (dll) :



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;
        }
    }
}


Так что это очень хорошо работает для большинства программ и игр, но не совсем. На некоторых программах ничего не происходит. Введенная библиотека dll c++ пытается запустить код c#, но ничего не происходит. Моя теория заключается в том, что библиотека DLL c++ не создаст ни одного экземпляра библиотеки dll c#.

Но есть один вариант исправить это: если я изменю среду выполнения с v4.0.30319 на v2.0.50727, она будет работать нормально.

Это не работает:

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

Это работает:

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

А теперь мы подходим к моей "главной" проблеме: я должен уменьшить свою .Чистая версия от 4+ до 3.5, потому что CLR V2 поддерживает только .NET 2 - 3.5. и это приносит проблемы с моим кодом C# (dll).

Итак, теперь я перехожу к своему вопросу(ам):

Почему это не работает на всех программах и играх? (Я имею в виду время выполнения v4.0.30319). С CLR RunTimeHost v2.0.50727 это работает.

И как я могу это исправить или изменить что-то в своем коде, чтобы запустить его?

Если у вас, ребята, есть какие-то идеи или примеры кода, я был бы очень благодарен.

Что я уже пробовал:

Я пытался выяснить, почему это работает не на всех программах, но не могу распознать закономерность.

Mehdi Gholam

Вполне возможно, что у вас есть 32/64-битные проблемы.

Dave Kreskowiak

Это также процессы, в которые вы вводите свой код .NET apps, соответствующие требованиям .NET 2.0, 3.0 или 3.5? Если так, то у вас есть проблема. .NET CLR 2.x не поддерживает несколько версий среды выполнения в одном процессе.

Member 13911570

Я знаю свою ошибку, я забыл нажать кнопку "Использовать CLR" в настройках, теперь она работает. (С CLR v4)

1 Ответов

Рейтинг:
4

Bartje_

Я думаю, что это может быть одно из двух:

использовать приложения.Метод Run для запуска формы (Подробнее: Приложение.Метод Выполнения (System.Окна.Формы) | Microsoft Docs )

Или попробуйте добавить атрибут STAThread к вашему методу EntryPoint (Подробнее: Атрибут STAThreadAttribute )

Согласно документации, атрибут STAThread устанавливается автоматически, но если я не ошибаюсь, приложение.Бегство имеет к этому какое-то отношение...

Удачи вам!