С задачей вызова неуправляемого кода из управляемого мы сталкиваемся довольно часто, и эта задача имеет простое решение в виде одного атрибута [DllImport] и небольшого набора дополнительных правил, которые хорошо изложены в MSDN. Обратная же задача встречается гораздо реже. В данной статье мы и рассмотрим небольшой пример, как это можно сделать. Его не стоит рассматривать как исчерпывающий, скорее лишь, как направление хода мыслей и концепцию. Итак, начнем. Наш пример будет состоять из трех проектов:
- MixedLibrary — C++/CLI
- SimpleLibrary — C#
- Win32App — C++

Начнем с самого простого — SimpleLibrary. Эта библиотека содержит один простой сервис, который складывает два числа и выводит результат в консоль:
public class Service { public void Add(Int32 a, Int32 b) { Console.WriteLine("Hello from Managed Code!"); Console.WriteLine(String.Format("Result: {0}", a + b)); } }
Теперь перейдем к библиотеке MixedLibrary. Эта библиотека содержит в себе класс-обертку над нашим SimpleService. Содержимое файла CppService.h:
// Директивы препроцессора нужны, чтобы компилятор сгенерировал записи // об экспорте класса из библиотеки #ifdef INSIDE_MANAGED_CODE # define DECLSPECIFIER __declspec(dllexport) # define EXPIMP_TEMPLATE #else # define DECLSPECIFIER __declspec(dllimport) # define EXPIMP_TEMPLATE extern #endif namespace MixedLibrary { class DECLSPECIFIER CppService { public: CppService(); virtual ~CppService(); public: void Add(int a, int b); private: void * m_impl; }; }
И содержимое файла CppService.cpp:
#include "CppService.h" using namespace System; using namespace System::Runtime::InteropServices; using namespace SimpleLibrary; namespace MixedLibrary { CppService::CppService() { Service^ service = gcnew Service(); m_impl = GCHandle::ToIntPtr(GCHandle::Alloc(service)).ToPointer(); } CppService::~CppService() { GCHandle handle = GCHandle::FromIntPtr(IntPtr(m_impl)); handle.Free(); } void CppService::Add(int a, int b) { GCHandle handle = GCHandle::FromIntPtr(IntPtr(m_impl)); Service^ service = safe_cast<Service^>(handle.Target); service->Add(a, b); } }
Также для компилируемости необходимо добавить директиву препроцессора INSIDE_MANAGED_CODE:

И последний штрих — наше обычное неуправляемое приложение:
#include "stdafx.h" #pragma comment(lib, "../Debug/MixedLibrary.lib") #include <iostream> #include "../MixedLibrary/CppService.h" using namespace std; using namespace MixedLibrary; int main() { CppService* service = new CppService(); service->Add(5, 6); cout << "press any key..." << endl; getchar(); }
И, конечно же, результат:

Автор: nikitam

