Я провожу небольшой эксперимент, чтобы понять, насколько сложно будет отображать некоторые окна 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 с целочисленным ползунком