Когда и как CLR инициализируется при вызове управляемого кода из собственного приложения? - PullRequest
0 голосов
/ 01 октября 2018

Я провожу небольшой эксперимент, чтобы понять, насколько сложно будет отображать некоторые окна WPF из собственного приложения C ++ (MFC).После просмотра этого , а затем этого я решил использовать DLL-оболочку C ++ / CLI вокруг библиотеки классов .NET .DLL.

[native C++ .exe] -> [C++/CLI wrapper .lib] -> [C# Class Library .dll]

Это, предположительно, позволит моему нативному приложению C ++ остаться неуправляемым, и мне не нужно будет использовать опцию компиляции / clr.

Затем я получил свой код песочницы, работающий после преодоления некоторых препятствий, необходимых дляотобразить окно и запустить диспетчер.Нативное консольное приложение запускается, отображает окно WPF, позволяющее пользователю ввести число, и при закрытии окна номер возвращается и записывается в вывод консоли.

Теперь я уже использовал CLI в прошломдля обратного (вызов неуправляемого кода из управляемого), но движение в этом направлении оставило меня немного озадаченным.

После прочтения некоторого материала о том, как CLR инициализируется для исполняемого файла .NET, такого как обсуждение CLR"process" в комментариях этого SO-ответа и как Engine Execution загружается при загрузке, мне интересно, когда и как все это происходит в ситуации, когда основной исполняемый файл не управляетсяили связанный с .NET?Кроме того, каково «время жизни» компонентов CLR - если я сделаю один вызов метода, инициализируется и будет ли уничтожен сборщик мусора и JIT-компилятор?Они живут с моим процессом, пока он не выйдет?Влияет ли это каким-либо образом на мое собственное приложение?

Код для моего тестового проекта выглядит примерно следующим образом и, насколько я могу судить, работает нормально.


ConsoleApplication (.exe)

CLIWrapper.lib добавлен в «AdditionalDependencies»

mainfile.cpp

#include "CLIInterface.h"

int main()
{
    APIWrapper wrapper;
    int rint = wrapper.GetAnInteger();

    char buffer[100];
    snprintf(buffer, sizeof(buffer), "Value: %d\n", rint);
    std::cout << buffer;
}

CLIInterface.h

class APIWrapperPrivate;

class APIWrapper
{
private:
    APIWrapperPrivate* _private;
public:
    APIWrapper();
    ~APIWrapper();
    int GetAnInteger();
};

CLIWrapper(.dll)

CLIWrapper.cpp

#include <msclr\auto_gcroot.h>
#using "..\CSharpLibrary\bin\Debug\CSharpLibrary.dll"

using namespace System;
using namespace System::Runtime::InteropServices;

class APIWrapperPrivate
{
public:
    msclr::auto_gcroot<CSharpLibrary::TheCSharpInterface^> theCSharpInterface;
};

class __declspec(dllexport) APIWrapper
{
private:
    APIWrapperPrivate* _private;

public:
    APIWrapper()
    {
        _private = new APIWrapperPrivate();
        _private->theCSharpInterface = gcnew CSharpLibrary ::TheCSharpInterface();
    }

    ~APIWrapper()
    {
        delete _private;
    }

    int GetAnInteger()
    {
        return _private->theCSharpInterface->GetAnItegerValue();
    }
};

CSharpLibrary (.dll)

TheCSharpInterface.cs

public class TheCSharpInterface
{
    public int GetAnItegerValue()
    {
        int anIntegerValue;

        ThreadStart ThreadProc = new ThreadStart(() =>
        {
            SynchronizationContext.SetSynchronizationContext(
               new DispatcherSynchronizationContext(
                   Dispatcher.CurrentDispatcher));

            SomeWindow window = new SomeWindow();
            window.Closed += (sender, e) =>
            {
                anIntegerValue = window.Power;
                Dispatcher.CurrentDispatcher.InvokeShutdown();
            };
            window.Show();
            Dispatcher.Run();
        });

        Thread t = new Thread(ThreadProc);
        t.SetApartmentState(ApartmentState.STA);
        t.IsBackground = true;
        t.Start();
        t.Join();

        return this.anIntegerValue;
    }
}

SomeWindow.xaml

Окно wpf с целочисленным ползунком

...