Invoke C# code from native C++

In this post I will demonstrate how one can call C# code from native C++ code.

Let us assume the following case: you have created a library using C# and the same functionality from this library is required in a native C++ application. In order to solve this issue one has two possibilities:

  1. Rewrite the library in C++ (not recommended)
  2. Expose the library to C++ code

In order to expose the C# library to C++ there are again two options:

  1. Expose the .Net components to COM (link)
  2. Create a C++/CLI wrapper

I will demonstrate the creation of C++/CLI wrapper. As stated on wikipedia, C++/CLI (Common Language Infrastructure) is a language specification created by Microsoft and intended to supersede Managed Extensions for C++.

For this example Visual Studio 2012 will be used since it offers Intellisense for the C++/CLI code.

1. Create empty Visual Studio solution

Interop_Empty_Solution

2. Create a C# Class Library project

Interop_ManagedCode

The ManagedCode Class Library project contains a public class (Service). We assume that Service class main responsibility is to process int messages and those messages can be provided by managed code as well as by native code.

Below is the definition of Service class:

public class Service
{
    public Service()
    {
        Console.WriteLine("ManagedCode - Service has been istantiated");
    }

    public void Process(int message)
    {
        Console.WriteLine("ManagedCode - Process : {0}", message);
    }
}

3. Create a C++ CLI project

By now we have C# functionality that should be made available to native code. In order to achieve this, we will define a C++ CLI wrapper that marshals and un-marshals data between managed and native code.

Add a new CLR Class Library to the solution using the following VS template:

Interop_CLR_Project_Explorer

I have already added a class named CppService to the project (the explanation is below) :

Interop_MixedCode

Before explaining the responsibility of the CppService class we should add in MixedCode project a reference to the ManagedCode project:

– Right click MixedCode project -> Properties -> Common Properties -> Framework and References-> Add New Reference

Interop_MixedCode_ManagedCode_Reference

Also we should add to MixedCode project a preprocessor definition (INSIDE_MANAGED_CODE) that will enable us later on to use Microsoft-specific storage-class attributes  extensions to the C++ languages.  Storage-class attributes  extensions will enable us to export and import functions, data, and objects to and from the MixedCode DLL. For more information you can check the link.

To add the preprocessor definition follow the steps:

– Right click MixedCode project -> Properties -> Configuration Properties -> C/C++ -> Preprocessor -> Preprocessor Definitions

Interop_MixedCode_Preprocessor

Now back to the CppService class. The CppService class acts like a wrapper on the C# Service class. The main responsibilities are :

  • to instantiate the C# Service class (for this the C++ CLI gcnew keyword will be used)
  • to allow the GC to collect the allocated C# Service object when this object is no longer needed
  • to forward requests to C# Service instance

Below is the CppService class code with additional information.

Declaration:

#pragma once

#ifdef INSIDE_MANAGED_CODE
#    define DECLSPECIFIER __declspec(dllexport)
#    define EXPIMP_TEMPLATE
#else
#    define DECLSPECIFIER __declspec(dllimport)
#    define EXPIMP_TEMPLATE extern
#endif

namespace MixedCode
{
    class DECLSPECIFIER CppService
    {
    public:
        CppService();
        virtual ~CppService();

    public:
        void process(int message);

    private:
        void * m_impl;
    };
}

Definition:

#include "stdafx.h"
#include "CppService.h"

using namespace ManagedCode;
using namespace System;
using namespace System::Runtime::InteropServices;

namespace MixedCode
{
    CppService::CppService()
    {
        // Instantiate the .Net opbject
        Service^ service = gcnew Service();

        // Pin the .NET object, and record the address of the pinned object in m_impl
        m_impl = GCHandle::ToIntPtr(GCHandle::Alloc(service)).ToPointer();
    }

    CppService::~CppService()
    {
        // Get the GCHandle associated with the pinned object based on its 
        // address, and free the GCHandle. At this point, the C#
        // object is eligible for GC.
        GCHandle handle = GCHandle::FromIntPtr(IntPtr(m_impl));
        handle.Free();
    }

    void CppService::process(int message)
    {
        // Get the pinned .Net object from its memory address
        GCHandle handle = GCHandle::FromIntPtr(IntPtr(m_impl));
        Service^ service = safe_cast<Service^>(handle.Target);

        service->Process(message);
    }
}

CppService class contains definitions for the macros that will enable us to export and import functions, data, and objects to and from a DLL (see link for more information).

4. Create a native C++ project

Now is time to test if the C# ManagedCode can be use from native C++ code. For this we will create a new Visual C++ Empty Project whcich will be called NativeCode and add to it a *.cpp file named main.cpp:

Interop_NativeCode

Since NativeCode project depends on ManagedCode and MixedCode projects the project dependencies should be set accordingly. In order to do this follow the steps:

– Right click Interop solution -> Common Properties -> Project Dependencies -> Projects

Interop_NativeCode_Dependencies

The final step is to to include MixedCode.lib, include CppService class, instantiate the class and the invocation of the process method:

#pragma comment(lib, "../Debug/MixedCode.lib")

#include <iostream>
#include "../MixedCode/CppService.h"

using namespace std;
using namespace MixedCode;

int main(int argc, char* argv[])
{
    CppService service;
    service.process(123);

    cout << "press any key..." << endl;
    getchar();
}

After execution you should be able to see the following result:

Advertisements

2 thoughts on “Invoke C# code from native C++

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s