📜 ⬆️ ⬇️

Calling managed code from unmanaged

image We encounter the task of calling unmanaged code from managed code quite often, and this problem has a simple solution in the form of a single [DllImport] attribute and a small set of additional rules that are well laid out in MSDN. The reverse task is much less common. In this article we will consider a small example of how this can be done. It should not be regarded as exhaustive, rather, only as a direction 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 outputs 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)); } } 


We now turn to the MixedLibrary library. This library contains a wrapper class over our SimpleService. 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<Service^>(handle.Target); service->Add(a, b); } } 


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

image

And the final touch is our usual unmanaged application:

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

And, of course, the result:

image

Posted by: nikitam

Source: https://habr.com/ru/post/335620/


All Articles