📜 ⬆️ ⬇️

Interaction of managed and unmanaged code

This article discusses the call to managed code (managed) from unmanaged and their interaction (without using COM and PInvoke).
The following method can be considered as an alternative to the method described by the user klsaymon .

The situation is taken from personal experience. There is a certain application (ArchiCAD), interaction with which is carried out thanks to libraries (plug-ins). The library (plugin) can be implemented only in C \ C ++. There is a custom application (WindowForms) with business logic and UI written in C # (managed). It is necessary to implement the ability to run an application (Windows Forms) from a library (plugin) and their interaction. In this case, the C \ C ++ library (plugin) acts as a bridge between a third-party application (ArchiCAD) and ours (WindowsForms).

For simplicity, we discard the third-party application and assume that the call is made directly from the unmanaged code. Those. Let's replace the bundle plugin application with one unmanaged application.

The final interaction scheme is presented in this scheme:

')
Let's start with the WindowsForms application.
Suppose we need to get a structure with data from a third-party application. Let's create this structure, let's call it Entity. Set ComVisible and StructLayout attributes.
[ComVisible(true)] [StructLayout(LayoutKind.Sequential)] public struct Entity { // entity external id public int id; [MarshalAs(UnmanagedType.BStr)] // entity name public string name; } 

Using the command "% SYSTEMROOT% \ Microsoft .NET \ Framework \ v2.0.50727 \ regasm.exe" "$ (TargetPath)" /tlb:$TargetName).tlb / codebase (you can add to PostBuild Events) create a type library ( * .tlb) and import it into an unmanaged C ++ application.
 #import ".\\..\\Managed.Csharp\\bin\\Debug\\Managed.Csharp.tlb" no_namespace 

Create an interface for interacting with a third-party application.
  public interface IExternalApplication { /// <summary> /// Returns the <see cref="Entity"/> instance. /// </summary> /// <returns></returns> Entity GetEntity(int id); } 

Add a class with the SetExternalApplication method with which you can set the created interface for further work with the program (and immediately implement a small test of the result).
  public class Program { private static IExternalApplication _externalApplication; /// <summary> /// Sets the <see cref="IExternalApplication"/> interface. /// </summary> /// <param name="externalApplication"></param> /// <returns></returns> public static void SetExternalApplication(IExternalApplication externalApplication) { _externalApplication = externalApplication; // test var entity = _externalApplication.GetEntity(1234); MessageBox.Show(string.Format("Id={0}; Name={1}", entity.id, entity.name)); } } 

In the unmanages / managed C ++ library (bridge) we add a reference (reference) to the WindowsForms application.

Now in our bridge library you need to implement the IExternalApplication interface. To do this, create a class ExternalApplication and implement the interface.
We transfer handle unmanaged C \ C ++ libraries (plugin) to the constructor.
 typedef void* (__cdecl *GetEntityFunc)(int); public ref class ExternalApplication: public IExternalApplication { public: // constructor ExternalApplication(HMODULE win32Handle); virtual Entity GetEntity(int id); private: GetEntityFunc m_GetEntity; }; ExternalApplication::ExternalApplication(HMODULE win32Handle) { // initialize functions m_GetEntity = (GetEntityFunc)GetProcAddress(win32Handle, "GetEntity"); } Entity ExternalApplication::GetEntity(int id) { void *entityPtr = m_GetEntity(id); Entity entity = (Entity)Marshal::PtrToStructure((IntPtr)entityPtr, Entity::typeid); return entity; } 

We implement the method necessary to run the managed application and export the StartApplication function.
 // exported functions extern "C" __declspec(dllexport) void StartApplication(HMODULE); void StartApplication(HMODULE win32Handle) { Program::SetExternalApplication(gcnew ExternalApplication(win32Handle)); } 

In plugin, we implement the function to get the Entity structure and export it.
 // exported functions extern "C" __declspec(dllexport) void* GetEntity(int); void* GetEntity(int id) { Entity *entity = new Entity(); entity->id = id; entity->name = _bstr_t("I'm entity!").copy(); return entity; } 

Load the bridge library and run the application.
 typedef void (__cdecl *StartApplicationFunc)(HMODULE); int _tmain(int argc, _TCHAR* argv[]) { HMODULE bridgeHandle = LoadLibrary(L"UnmanagedManaged.C++.dll"); StartApplicationFunc startApplication = (StartApplicationFunc)GetProcAddress(bridgeHandle, "StartApplication"); HMODULE handle = GetCurrentModule(); startApplication(handle); return 0; } 

Run and check the result.

The result has reached.

Coogle Code Sources

ps source code is far from beautiful and ideal and only reflects the logic of interaction

all this miracle is spinning in the same process with all the resulting advantages

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


All Articles