Calling managed code from unmanaged

imageWe are faced with the task of invoking unmanaged code from managed code quite often, and this task has a simple solution in the form of a single attribute [DllImport] and a small set of additional rules that are well stated in MSDN. The inverse problem is much less common. In this article, we will consider a small example of how this can be done. It should not be considered as exhaustive, but rather, only as a line of thought and a concept. So, let's begin.


Our example will consist of three projects:
  1. MixedLibrary - C ++ / CLI
  2. SimpleLibrary - C #
  3. Win32App - C ++

image

Let's start with the simplest - SimpleLibrary . This library contains one simple service that adds two numbers and prints the result to the console:

public class Service
    {
        public void Add(Int32 a, Int32 b)
        {
            Console.WriteLine("Hello from Managed Code!");
            Console.WriteLine(String.Format("Result: {0}", a + b));
        }
    }


Now let's move on to the MixedLibrary library . This library contains a wrapper class over our SimpleService. The contents of the CppService.h file:

// Директивы препроцессора нужны, чтобы компилятор сгенерировал записи
// об экспорте класса из библиотеки
#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;
	};
}

And the contents of the CppService.cpp file:

#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(handle.Target);
		service->Add(a, b);
	}
}


Also, for compilation, you need to add the INSIDE_MANAGED_CODE preprocessor directive:

image

And the final touch is our usual unmanaged application:

#include "stdafx.h"
#pragma comment(lib, "../Debug/MixedLibrary.lib")
#include 
#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();
}

And, of course, the result:

image

Author: nikitam

Also popular now: