Categories

Recent Posts

Archive

Links

How to call unmanaged C++ from C#

10th February 2012. Posted in C# Snippets and tagged , , , , , , , , .

 

This article explores a method to call unmanaged C++ from C#.


Recommended Approach

A few people have asked us recently ‘can we call our legacy unmanaged C++ code from MTF.NET?’. Well the answer to this question is yes you can by wrapping your unmanaged C++ classes in managed C++ classes. This is great news if you are interested in continuing to use your unmanaged legacy C++ investment, but at the same time wish to use MTF.NET for new ventures and to also move toward C#, thereby ultimately taking advantage of the productivity gains offered by both MTF.NET and C#.

The approach that we recommend to MTF.NET users is to wrap your unmanaged C++ classes in managed C++ classes, here is how to do it.


Unmanaged C++

The following simple example shows an unmanaged C++ class which allows a simple text message to be stored and the stored text to be retrieved. It also provides a function to get the current system time as a string. I’ve put everything inline in the header file to aid readability. We will treat the following simple class as our legacy unmanaged C++ code.

#pragma once

#include <windows.h>
#include <atlstr.h>
 
class MyUnmanagedClass
{
    private :CString mMsg;
    private :CString mSysTime;

    public:
        LPCWSTR GetMessage()
        {
            return (LPCWSTR)mMsg;
        }

        void SetMessage( LPCWSTR msg)
        {
            mMsg = msg;
        }

        LPCWSTR GetSysTime()
        {
            SYSTEMTIME sysTime;

            GetSystemTime(&sysTime);

            mSysTime.Format(_T("%02d/%02d/%04d %02d:%02d:%02d.%03d"),
                            sysTime.wDay,
                            sysTime.wMonth,
                            sysTime.wYear,
                            sysTime.wHour,
                            sysTime.wMinute,
                            sysTime.wSecond,
                            sysTime.wMilliseconds);

            return (LPCWSTR)mSysTime;
        }
};


Wrapping in Managed C++

In order to be able to call the unmanaged C++ code above from C#, we need to wrap our unmanaged C++ class in a managed C++ class. Building upon the code above, the code below shows the introduction of a managed C++ class which as can been seen wraps the unmanaged C++ class (the two classes do not necessarily have to be in the same file):

#pragma once

#include <windows.h>
#include <atlstr.h>

using namespace System;

class MyUnmanagedClass
{
    private :CString mMsg;
    private :CString mSysTime;

    public:
        LPCWSTR GetMessage()
        {
            return (LPCWSTR)mMsg;
        }

        void SetMessage( LPCWSTR msg)
        {
            mMsg = msg;
        }

        LPCWSTR GetSysTime()
        {
            SYSTEMTIME sysTime;

            GetSystemTime(&sysTime);

            mSysTime.Format(_T("%02d/%02d/%04d %02d:%02d:%02d.%03d"),
                            sysTime.wDay,
                            sysTime.wMonth,
                            sysTime.wYear,
                            sysTime.wHour,
                            sysTime.wMinute,
                            sysTime.wSecond,
                            sysTime.wMilliseconds);

            return (LPCWSTR)mSysTime;
        }
};

namespace UnmanagedToManaged
{
    public ref class MyManagedClass
    {
        private:
            MyUnmanagedClass* mMyUnmanagedClass;

        public:
            // Allocate the native object from the C++ heap at construction.
            MyManagedClass()
            {
                mMyUnmanagedClass = new MyUnmanagedClass;
            }

            // Deallocate the native object on dustruction.
            ~MyManagedClass()
            {
                delete mMyUnmanagedClass;
            }

        protected:
            // Deallocate the native object on the finaliser
            // in case the destructor doesn't get called.
            !MyManagedClass()
            {
                delete mMyUnmanagedClass;
            }

        public:
            property String^ GetMessage
            {
                String^ get()
                {
                    return gcnew String( mMyUnmanagedClass->GetMessage());
                }
            }

            void SetMessage( String^ msg )
            {
                pin_ptr str = PtrToStringChars(msg);
                mMyUnmanagedClass->SetMessage(str);
            }

            property String^ GetSysTime
            {
                String^ get()
                {
                    return gcnew String( mMyUnmanagedClass->GetSysTime());
                }
            }
    };
}

The code above can be cut and paste in its entirety into the header file provided by a newly created Visual Studio 2010 C++ CLR Class Library project. This project when built will produce a .dll file that can be referenced by a C# application.


Calling from C#

The following code shows the C# side of the equation:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using UnmanagedToManaged;

namespace MainApp
{
    class Program
    {
        static void Main(string[] args)
        {
            MyManagedClass myManagedClass = new MyManagedClass();

            myManagedClass.SetMessage("Hello, this is a test message!");

            String msg = myManagedClass.GetMessage;

            String sysTime = myManagedClass.GetSysTime;
        }
    }
}

As can be seen above calling your legacy unmanaged C++ class is now as simple as calling any other class from within C#.

The code above can be cut and paste in its entirety into the Program.cs file which is provided by a newly created C# Console Application.

The results can easily be seen by stepping the C# program in the debugger.

Don’t’ forget to add a reference to the .dll containing the unmanaged C++ and managed C++ wrapper!

It would be just as easy to call the managed C++ code via C# from within an MTF.NET Actioner or Device for example.

You can download some supporting example code from here.

 

Posted in C# Snippets and tagged , , , , , , , , . | No Comments

 

 

Comments

Leave a Reply

All comments are fully moderated by persons at Multicore Consulting Limited.
To report a comment to the moderator click the associated 'Report this comment' link.
To contact the moderator please use the Contact Us form.
Your email address will not be published. Required fields are marked *