C++ sinnvoll mit C# verbinden

Ich habe mich früher sehr viel mit C und C++ beschäftigt (ja mit ASM auch, aber das is egal :-)) und obwohl ich .NET unglaublich toll finde, braucht man trotzdem hier und da immer mal wieder das gute alte c++, denn das große .NET kann leider auch noch nicht alles (einfach SmartCards auslesen zum Beispiel.. hehe). Deswegen wollt ich euch mal kurz im Allgemeinen zeigen, wie man sich schnell und einfach ein C++-Projekt baut, und das auch in .NET benutzen kann.

Zuerst in Visual Studio eurer .NET-Solution ein leeres C++-Projekt hinzufügen ("Leeres Projekt") und dann meinetwegen eine Klasse hinzufügen ("Hinzufügen/C++-Klasse") (Es gibt auch nen Assistenten, aber das is zu einfach... Wir wollen ja mal unter die Haube gucken und das richtig machen... hehe).

Danach gehen wir mal mit einem Rechtsklick auf das Projekt und Eigenschaften in die gesamten Eigenschaften. Unter Allgemein stellen wir diese beiden Dinge ein: Konfigurationstyp auf Dynamische dll und Common Language Runtime-Unterstützung aud Common Language Runtime-Unterstützung (/clr)).

Eigenschaften

Wenn man nun einen Verweis in seinem C#-Projekt hinzufügt, kann man unter Projekte direkt das C++-Projekt auswählen und hinzufügen. Und kompilieren kann man dann auch, denn es kommt kein Fehler mehr wie: "Fehler 2 error C3381: test": Assemblyzugriffsspezifizierer sind nur in Code verfügbar, der mit einer /clr-Option kompiliert wurde. d:\leer\test.h 4 leer".

Ok, in meinem Beispielchen heisst meine C++-Klasse einfach nur Test. und jetzt kann man schon kompilieren und auf die c++-Klasse zugreifen von C# aus. Da wir keinen namespace in c++ vergeben haben, kann man direkt in C# schreiben "Test t = new Test():".

Ok, aber wir sind noch nicht fertig, denn das Problem liegt ja wie immer im Detail. Und da ich kein Evangelist bin, wollen wir nochmal ein wenig weitermachen und schnell eine kleine Methode einfügen in unsere C++-Klasse. Ich füge nun eine Methode "int Add(int a, int b) { return a + b;}" hinzu. In der Headerdatei wird se deklariert und in der cpp ausprogrammiert. Tja, und in C#, wenn ich nun mache t.... erscheint einfach meine Add-Methode nich... Unglaublich.

 Code

So, also was macht man da? Ja wir versehen unsere C++-Klasse mit dem Schlüsselwörtchen "ref" in "public ref class Test"...

Und siehe da, schon können wir kompilieren. So, und ich hör aber immer noch nicht auf. Solltet ihr nun zufällig wenn ihr drauf zugreift, eine BadImageFormatException erhalten mit dem dummen Text "Die Datei oder Assembly "xxx, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null" oder eine Abhängigkeit davon wurde nicht gefunden. Es wurde versucht, eine Datei mit einem falschen Format zu laden.", dann prüft mal, ob euer C#-Projekt zufällig 64 Bit is (oder auch AnyCPU) und euer C++-Projekt zufällig 32 Bit. Wenn ja, vereinheitlicht das, denn das zu mischen is wohl nich so einfach (Unter den C++-Einstellungen unter Linker/Erweitert/Zielcomputer und unter C# unter Projekteigenschaften/Ertellen/Zielplattform) (siehe Bild unten). Nachdem beide Projekte die gleiche Zielplattform haben, gehts auf einmal...

Um strings mit der C++-Welt austauschen zu können, wird das Zeichen Accent Zirkumflex (^) benötigt. Die hier dargestellte C++-Methode liefert für C# einen String zurück. Mich erreichte weiterhin eine Anfrage, wie man denn das mit Arrays machen könnte. Siehe dazu die Methode GetPoints. Sie bekommt einen double-Pointer, und auf der .NET-Seite habe ich ein double-Array. Leider musste ich hierfür mit dem “unsafe”-Schlüsselwort arbeiten. Wenn jemand weiss, wie man Arrays übergeben kann ohne dieses Schlüsselwort, kann er das ja gern mal als Kommentar hinterlassen”. Hier nochmal der Code ganz übersichtlich:

Test.h

   1:  
   2: public ref class Test
   3: {
   4:     public:
   5:         Test(void);
   6:         int Add(int a, int b);
   7:         System::String^ GetName();
   8:         void GetPoints(double* myData);
   9:         ~Test(void);
  10: };

Test.cpp

   1: #include "Test.h"  
   2:   Test::Test(void)   
   3:   {}  
   4:  
   5:   int Test::Add(int a, int b)   
   6:   {
   7:     return a + b;   
   8:   }  
   9:  
  10:   System::String^ Test::GetName()
  11:   {
  12:     char str[80] = "";
  13:     System::String ^realStr;
  14:  
  15:     CoolCppFunction(str);        // Im Array str befindet sich nun unser gewünschter String
  16:     realStr=gcnew System::String(str);
  17:     return realStr;
  18:   }
  19:  
  20:   void  Test::GetPoints(double* myData)
  21:   {
  22:       myData[0]=1;
  23:       myData[1]=2;
  24:       myData[2]=3;
  25:       myData[3]=4;
  26:   }
  27:  
  28:   Test::~Test(void)   
  29:   {}

Program.cs

   1: Test t = new Test();
   2: t.Add(5, 6);
   3:  
   4: unsafe
   5: {
   6:     double[] data = new double[4];
   7:  
   8:     fixed (double* pArray = data)
   9:         t.GetPoints(pArray);
  10: }

Einige Ergänzungen zum Unsafe-Schlüsselwort. Das sagt euch zwar auch der Compiler, aber die Option “Unsicheren Code zulassen” muss in den Projekteinstellungen aktiviert werden, sonst funktioniert das unsafe-Schlüsselwort nicht und somit auch die Pointer nicht. Das soll verhindern, dass gewiefte C++-Entwickler “mal ausversehen” alles doch wieder mit Pointern machen… :-)

(Die Zielplattform hab ich hier auch mal gelb gemacht, weil die vorhin erwähnt wurde in Bezug auf die BadImageFormatException)

image

Einfach großartig diese Zusammenarbeit dieser beiden Supermächte. C++ is wie ein alter weiser Greis und .NET wie ein fast fertig ausgebildeter Meister. Der Greis isn bissl alt und schwerfällig, kann aber dafür alles. Und .NET is modern, dynamisch, flexibel, leicht zu erlernen, einfach geil, kann aber in manchen Situationen noch nich so viel wie C++... Ein perfektes Team. Spätestens damit geht einfach alles!

Published 01 Oktober 2009 12:19 von Dosihris

Kommentare

# klaus_b said on 05 Dezember, 2009 03:12

Die Verbindung beider Sprachen ist bei API-Intensiven Anwendungen sicher sinnvoll. Da kann man herrlich mit C++ die API-Zugriffe regeln und als Wrapper für die Geschäftslogik in C# darstellen.

Ich bin schon immer ein Freund von P/Invoke in C#, dazu brauchst du nicht einmal die /clr Compileroption in C++.

# Diana said on 12 August, 2010 12:00

Hallo wie fügt man in C# einen Veweis auf das C++-Projekt hinzu??

# Dosihris said on 12 August, 2010 12:16

Hi Diana,

schreib mir doch einfach kurz eine Mail (Adresse auf nfranze.de) und dann beantworte ich deine Fragen direkt. Ggf. werde ich auch diesen Blogeintrag um deine Fragen erweitern, damit die Fragen auch für andere gleich beantwortet sind.

Nico

# Leon said on 07 September, 2010 04:29

Hy,

Ich habe ein größeres C# Projekt mit WPF erstellt.

Mein Ziel ist es mit C# die WPF Oberfläche zu füttern, und mit C++ dann einen 3D-Editor zu erstellen.

Also Header und .CPP für Vektoren etc.

Wie kann ich nun in mein WPF/C# Projekt, Header und CPP Dateien einbinden, so dass ich sie dann in einem Control benutzen kann?!

Meine E-Mail: leonbothe@yahoo.de

DANKE!

Kommentar abgeben

(verpflichtend) 
(verpflichtend) 
(optional)
(verpflichtend) 
Nico Franze Herzlich Willkommen auf meinem Blog. Ich bin Nico, freier Softwareentwickler sowie Autor für Fachzeitschriften. Hab mit .NET Version 1.0 begonnen (damals noch VB.Net) und bin dann schlussendlich bei C# gelandet. Mehr Infos gibts unter www.nfranze.de


Suche

Los

Translator Widget

Dieser Blog

Syndikation


Locations of visitors to this page