C#/Managed C++/Native C++
Posted on November 7th, 2007 | by admin |Я дуже багато чув щасливих відгуків про те який кльовий, швидкий і зручний цей .NET. Можливо він і справді такий кльовий, якщо не використовувати Managed C++, але життя - річ дуже не справедлива. Зараз я спробую написати про особливості використання даної технології, на які я натрапив під час розробки.
64-bit .NET and Managed С++ code.
Чистий .NET код прекрасно транспортується між різними платформами, але не все так добре, як здається на перший погляд. 64-bit .NET вимагає 64-бітний код в managed c++ DLL. Виходить так що звичайний 32-bit x86 бінарний код значно транспортабельніший чим комплекс із .NET + managed C++. Особливий головний біль виникає якщо ваша managed C++ бібліотека використовує із десяток сторонніх бібліотек.
References and Dependences
В С# для того щоб скористатися класами із інших .NET/COM бібліотек достатньо зробити Add Reference в проекті і вибрати потрібний бінарний файл. “Розумне” середовище буде враховувати це під час відладки і розробки… але не все так просто.. я написав конрол (UserControl), який був прив’язаний до managed C++ DLL. Його можна було розмістити на формі і деякий час працювати, але після перезапуска середовища розробки редактор форми “падав” і скаржився на тещо не може завантажити мою нещасну DLL. Перед тим як видати це повідомлення середовище залипало секунд на 10 і при цьому дико срало в директорію
user\Local Settings\Application Data\Microsoft\VCSExpress\8.0\ProjectAssemblies\
виявляється що саму бібліотеку він знаходив, але не міг її завантажити, оскілкі у неї в залежності стояла інша DLL, причому native DLL, тому я не міг її додати в References. Причому її наявність в Target Directory в директорії із солюшином і проектом не допомогали.
проблему вирішив наступний Post Build Event для managed C++ бібліотеки
copy x:\engine_managed.dll “c:\Program Files\Microsoft.NET\Primary Interop Assemblies\”
copy x:\fmod.dll “c:\Program Files\Microsoft.NET\Primary Interop Assemblies\”
Managed/Native C++ tips
в managed C++ часто не достатньо просто прописати using namespace. Навіть System не повністю доступний - у мене виникли труднощі із System::ComponentModel. Проблема вирішується підключенням бібліотек за допомогою директиви #using. Ось як це виглядало в моєму випадку:
#using “system.dll”
#using “system.drawing.dll”
using namespace System::Drawing;
В managed C++, на відміну від native, інтерфейс мусить бути абсолютно абстрактним, тобто не можна писати імплементацію функції в інтерфейсах. А породжений від інтерфейсу клас мусить мати імплементацію, навіть якщо його екземпляр не створюється, хоча компілятор можна чемно попросити не ругатись за допомгою “=0″:
public ref class AnimNode_Stub : IAnimNode_Stub
{
public:
virtual Point GetPos() = 0;
Для простого перевизначення функції обов’язкові ключові слова virtual i override
public ref class AnimNode_Root_Stub : AnimNode_Stub {
public:
virtual Point GetPos() override
{
….
}
наступний код демонструє яким чином можна написати клас на managed C++, який буде можливо прибіндити до PropertyGrid контрола і заодно демонструє яким чином транспортувати текст між managed i native C++:
property System::String^ preview_skeletal_mesh
{
[System::ComponentModel::Bindable(true)]
System::String ^ get()
{
return gcnew System::String(m_node->GetPreviewSkelMesh());
}[System::ComponentModel::Bindable(true)]
void set(System::String^ value)
{
m_node->SetPreviewSkelMesh((char*)(Marshal::StringToHGlobalAnsi(value)).ToPointer());
}
}