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

Your email address will not be published. Required fields are marked *