Вызов управляемого кода из неуправляемого

в 13:14, , рубрики: C#, c++, cli, msdn, Блог компании ICL Services, неуправляемый код, Программирование, разработка под windows, системное программирование

image С задачей вызова неуправляемого кода из управляемого мы сталкиваемся довольно часто, и эта задача имеет простое решение в виде одного атрибута [DllImport] и небольшого набора дополнительных правил, которые хорошо изложены в MSDN. Обратная же задача встречается гораздо реже. В данной статье мы и рассмотрим небольшой пример, как это можно сделать. Его не стоит рассматривать как исчерпывающий, скорее лишь, как направление хода мыслей и концепцию. Итак, начнем.

Наш пример будет состоять из трех проектов:

  1. MixedLibrary — C++/CLI
  2. SimpleLibrary — C#
  3. Win32App — C++

image

Начнем с самого простого — 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:

image

И последний штрих — наше обычное неуправляемое приложение:

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

И, конечно же, результат:

image

Автор: nikitam

Автор: ICL Services

Источник

Поделиться

* - обязательные к заполнению поля