C++ in C#

 
13 mei 2013

C++ in C#

Heeft u ook nog C++ libraries liggen die u wilt gebruiken, maar die u niet kunt gebruiken omdat alles nu C# is geworden? Daar kunnen we wat aan gaan doen.

Ik zal in een aantal stappen beschrijven welk zaken benodigd zijn om dit te verwezenlijken.

Voor wie?

Voor ontwikkelaars die zelf C++ libraries hebben geschreven en die willen hergebruiken of ontwikkelaars die bestaande C++ libraries willen gebruiken.

Benodigd:

Ik heb gebruik gemaakt van de volgende onderdelen:

  • .NET Framework 4.0
  • Visual Studio 2010 C#
  • C++ Library

Voor de C++ library hebben we nodig:

  • DLL: .dll
  • Library: .lib
  • Headers: .h

Er wordt vanuit gegaan dat de lezer bekend is met Visual Studio 2010 en met het ontwikkelen in C# en C++.

Oplossing (theorie):

Voordat we kunnen beginnen eerst een overzicht waar we uiteindelijk op zullen gaan uitkomen.

Oplossingsstructuur

Fig 1: Oplossingsstructuur

In figuur 1 is het tweede blok gevuld met vraagtekens. De reden dat er een tussenblok nodig is, heeft te maken met op welke wijze objecten worden gecreëerd in de verschillende talen. Objecten in C# worden in een ‘managed’ omgeving gecreëerd en in C++ wordt gebruikt gemaakt van ‘native’ objecten, die op de ‘heap’ worden aangemaakt. ‘managed’ C# objecten bevinden zich binnen de CLR.

Hiervoor bestaat een oplossing. Die heet C++/CLI. Deze uitbreiding op C++ is in staat om met ‘native’ objecten te communiceren en heeft een ‘managed’ interface voor talen zoals C#. Mijn oplossing ziet er als volgt uit:

Fig 2: Ingevulde oplossingsstructuur

De C# Library heeft een referentie naar het C++/CLI object. In het C++/CLI object wordt een pointer naar het C++ object gecreëerd. Door het gebruik van een referentie in C# en een pointer in C++/CLI maken we gebruik van encapsulatie uit OO.

Naast het gebruik van C++/CLI zijn er een aantal andere mogelijkheden om ‘code interoperability’ te verkrijgen. Dit kan middels P/Invoke (Platform Invoke) en via COM (Component Object Model).

Zie voor meer informatie het einde van deze blog onder ‘Meer Informatie / Code Interoperability’.

Voordat we over gaan tot de implementatie het volgende: We gaan er vanuit dat de C++ functies of klasse is gedefinieerd met __declspec(dllexport). Dit zorgt ervoor dat losstaande functie en klasses zichtbaar zijn, voor iedereen die de DLL gebruikt.

Oplossing (praktijk):

C++

Om te kunnen beginnen hebben we een C++ library nodig in de vorm van een DLL.

Mocht u niet in het bezit zijn van een C++ DLL, maar deze blog willen volgen, dan kunt u gebruik maken van onderstaande C++ code. Hiervoor kunt u een Visual C++ – General – Empty Project gebruiken, waarbij u de volgende eigenschap (Properties) als volgt dient in te stellen:

Configuration Properties – General – Configuration Type: Dynamic Library (.dll)

De onderstaande code wordt als verdere basis gebruikt voor het vervolg van deze blog.

// HelloWorld.h
#ifndef _H_HELLO_WORLD_H_
#define _H_HELLO_WORLD_H_

class __declspec (dllexport) HelloWorld
{
  public:
    HelloWorld ();
    virtual ~HelloWorld ();

    void sayHelloToWorld ();
    static void sayStaticToWorld ();
};
#endif // _H_HELLO_WORLD_H_
// HelloWorld.cpp
#include "HelloWorld.h"
#include <iostream>
using std::cout;
using std::endl;

HelloWorld::HelloWorld ()
{
}

HelloWorld::~HelloWorld ()
{
}

void HelloWorld::sayHelloToWorld ()
{
  cout << "Hello World!" << endl;
}

void HelloWorld::sayStaticToWorld ()
{
  cout << "Hello Static World!" << endl;
}

Wanneer deze klasse gebouwd is, zorgt dit voor een HelloWorld.dll en HellWorld.lib.

C++/CLI

We beginnen met het aanmaken van nieuw project. Onderneem de volgende stappen:

  • Creëer een nieuw ‘Visual C++’ – ‘CLR’ – ‘Class Library’ project;
  • Noem het project ManagedHelloWorld.

Nieuw Project C++-CLI

Fig 3: Nieuw C++/CLI project.

Bovenstaande stappen zijn de basis voor de ontwikkeling van de conversielaag tussen managed objecten (C#) en native objecten (C++). Om onze ‘HelloWorld’-klasse aan te kunnen roepen, maken we gebruik van onderstaande code. Pas deze code aan zodat u uw DLL kunt aanroepen.

// ManagedHelloWorld.h
#pragma once
#include "..\HelloWorld\HelloWorld.h"

namespace ManagedHW
{
  public ref class ManagedHelloWorld
  {
    private:
      HelloWorld *hw;

    public:
      ManagedHelloWorld ();
      ~ManagedHelloWorld ();

    void sayHelloToWorld ();
    static void sayStaticToWorld ();
  };
}
// ManagedHelloWorld.cpp
#include "Stdafx.h"
#include "ManagedHelloWorld.h"
using namespace ManagedHW;

ManagedHelloWorld::ManagedHelloWorld ()
{
  hw = new HelloWorld ();
}

ManagedHelloWorld::~ManagedHelloWorld ()
{
  delete hw;
}

void ManagedHelloWorld::sayHelloToWorld ()
{
  hw->sayHelloToWorld ();
}

void ManagedHelloWorld::sayStaticToWorld ()
{
  HelloWorld::sayStaticToWorld ();
}

HelloWorld *hw is de pointer naar de klasse in onze C++ DLL. Verder is de definitie van de klasse exact gelijk als die van onze C++ klasse.

Als u het project bouwt, zult u een aantal LNK2028 en LNK2019 errors krijgen. Dit komt omdat Visual Studio niet weet welke DLL ingeladen moet worden tijdens het linken. Hiervoor dienen we de volgende stappen uit te voeren:

  • Open eigenschappen van ‘ManagedHelloWorld’;
  • Kies bij ‘Configuration:’ voor ‘All Configurations’;
  • Selecteer ‘Configuration Properties – Linker – Input’.
  • Vul in het veld ‘Additional Dependencies’, het absolute of relatieve pad naar onze C++ DLL library file (*.lib).

Add .lib C++-CLI

Fig 4: Toevoegen van afhandelijkheid met onze C++ DLL.

Het bouwen van deze library levert ManagedHelloWorld.dll op.

C#

Nu komen we uiteindelijk bij onze C# code. In dit voorbeeld maken we gebruik van een console-applicatie, maar u kunt er ook voor kiezen om een klassebibliotheek te gebruiken; dat is afhankelijk van uw wensen.

  • Voeg een nieuw ‘Visual C# – Windows – Console Application’ project toe aan de huidige Visual Studio solution.
  • Noem het project C++Console.

Nieuw Project C#

Fig 5: Nieuw C# project.

  • Voeg een nieuwe referentie toe naar ManagedHelloWorld.

Referentie toevoegen gebeurt alsvolgt:

  • Ga hierbij naar het tabblad Projects en kies ManagedHelloWorld.

Add Reference C#

Fig 6: Referentie naar ManagedHelloWorld toevoegen.

  • De laatste stap is het toevoegen van onze C++ DLL, zodat de applicatie er gebruik van kan maken.
  • Selecteer C++Console en open het snelmenu.
  • Kies vervolgens voor ‘Add’ en ‘Existing Item…’
  • In het dialoog dat volgt, zorg dat het filter (rechts onderin het venster) op ‘All Files (*.*) staat.
  • Navigeer naar de DLL en bevestig dit.
  • Open het snelmenu op de in de vorige stap toegevoegde DLL en kies voor ‘Properties’.
  • Kies bij ‘Copy to Output Directory’ voor de optie ‘Copy Always’.Add C++ DLL

Fig 7: Altijd kopiëren van C++ DLL naar output directory.

Nu kunnen we C# code toevoegen.

// Program.cs
using ManagedHW;
namespace C__Console
{
  class Program
  {
    static void Main (string[] args)
    {
      ManagedHelloWorld managedHW = new ManagedHelloWorld ();

      managedHW.sayHelloToWorld ();

      ManagedHelloWorld.sayStaticToWorld ();
    }
  }
}

Bij het uitvoeren van C++Console.exe krijgt u de volgende output te zien:

Hello World!
Hello Static World!

Slot:

U heeft nu gezien hoe u C++ in C# kunt krijgen. Hiervoor maken we gebruik van een tussenlaag, genaamd C++/CLI. Dit hebben we nodig om te zorgen dat ‘managed’ C# objecten met ‘native’ C++ objecten kunnen communiceren.

Meer informatie:

EMCA-372:
Volgende link bevat meer informatie over de standaard van C++/CLI (ECMA-372): http://www.ecma-international.org/publications/standards/Ecma-372.htm

Marshalling:
In C++/CLI dienen sommige referenties omgezet te worden naar voor C++ begrijpbare objecten. Dit heet ‘marshalling’. Zie volgende link voor meer informatie over marshalling tussen C++ en C#: http://msdn.microsoft.com/en-us/library/bb384865(v=vs.100).aspx

Code Interoperability:
De volgende link geeft meer informatie over code interoperability in samenwerking met .NET:  http://msdn.microsoft.com/en-us/library/ms973872.aspx


Werken met ?
Kijk dan bij onze mogelijkheden voor zowel starters als ervaren engineers.


Categorieën: Development, .Net, Overige talen en platformen

Tags: , , , ,