Forum: PC-Programmierung Brauche Hilfe bei unmanaged C++ Code und C++/CLI Wrapper in C#


von cppUser (Gast)


Lesenswert?

Hallo,
hoffe jemand kann mir helfen. Habe nach dieser Anleitung meinen 
unmanaged C++ Code über einen C++/CLI Wrapper in mein C# Projekt 
eingebunden.
http://drthitirat.wordpress.com/2013/06/03/use-c-codes-in-a-c-project-wrapping-native-c-with-a-managed-clr-wrapper/

Funktioniert auch, allerdings verwenden meine Funktionen in C++ einen 
Parameter const char*:

C++
[code}
float Funcs::ValueFunction(const char* filename, int num) {
....
return a;
}
[/code}

Im C++/CLI Wrapper passiert eigentlich nichts.

In C# kann ich auf die Funktion auch zugreifen, allerdings wird mir der 
Parameter der Funktion als sbyte* angezeigt und meinen C# string kann 
ich ja nicht damit nutzen.

Kann mir jemand ein gutes Beispiel senden? Habe schon einiges über 
marshal gelesen, aber kein gutes Beipiel gefunden. Danke

von Peter II (Gast)


Lesenswert?


von cppUset (Gast)


Lesenswert?

Danke,
leider hat mich das noch nicht weiter gebracht. Ich lade heute Abend mal 
ein Beispiel hier hoch.
Möchte gerne den C++/CLI wrapper nutzen und nicht die unmanaged C++ DLL 
in C# laden, wie in dem verlinkten Beispiel.

PS: Auch wenn ich im nativ C++ Code strings in der Funktion nutze und 
die Funktion über den Wrapper an C# weitergeben kann ich keinen String 
als Parameter an die Funktion übergeben. Ich stehe irgendwie mit den 
Datentypen aufm Schlauch.

von cppUser (Gast)


Lesenswert?

Hallo,
die Konvertierung vom C# String zu char* muss ich im Wrapper durchführen 
oder? So wie unten funktioniert der C# Code natürlich nicht.


SimpleFunctions.h
1
#pragma once
2
#include <stdexcept>
3
4
using namespace std;
5
6
class MySimpleFunctions {
7
public:
8
  int TextOK(const char* text);
9
};

SimpleFunctions.cpp
1
#pragma once
2
#include "SimpleFunctions.h"
3
4
int MySimpleFunctions::TextOK(const char* text) {
5
  int a = 0;
6
7
  if (text == "Hello")
8
    a = 1;
9
  else
10
    a = 2;
11
  
12
  return a;
13
}

nativeCppWrapper.h
1
// nativeCppWrapper.h
2
3
#pragma once
4
5
#include "SimpleFunctions.cpp"
6
#include "SimpleFunctions.h"
7
8
using namespace System;
9
10
namespace nativeCppWrapper {
11
  public ref class MySimpleFunctionsWrapper
12
  {
13
  public:
14
    MySimpleFunctionsWrapper();
15
    int TextOK(const char* text);
16
    
17
  private:
18
    MySimpleFunctions *myCppClass;
19
  };
20
}

nativeCppWrapper.cpp
1
// This is the main DLL file.
2
3
#include "stdafx.h"
4
#include "nativeCppWrapper.h"
5
6
nativeCppWrapper::MySimpleFunctionsWrapper::MySimpleFunctionsWrapper()
7
{
8
  myCppClass = new MySimpleFunctions();
9
}
10
11
int nativeCppWrapper::MySimpleFunctionsWrapper::TextOK(const char* text)
12
{
13
  return myCppClass->TextOK(text);
14
}

Form1.cs
1
using System;
2
using System.Collections.Generic;
3
using System.ComponentModel;
4
using System.Data;
5
using System.Drawing;
6
using System.Linq;
7
using System.Text;
8
using System.Threading.Tasks;
9
using System.Windows.Forms;
10
using nativeCppWrapper;
11
12
namespace CsharpApp
13
{
14
    public partial class Form1 : Form
15
    {
16
        MySimpleFunctionsWrapper myFunction = new MySimpleFunctionsWrapper();
17
        public Form1()
18
        {
19
            InitializeComponent();
20
        }
21
22
        private void button1_Click(object sender, EventArgs e)
23
        {
24
            String str = "Hello";
25
            int x = myFunction.TextOK(str);
26
        }
27
    }
28
}

von Georg B. (diereinegier)


Lesenswert?

Der CLI-Wrapper sollte einen .net-String entgegennehmen und zwar per 
Referenz:

MySimpleFunctionsWrapper::TextOK(String% txt)

So kann C# die Methode ganz einfach als TextOK("text") aufrufen.

Dann mußt Du den String entweder mit dem gewünschten Encoding in ein 
Byte-Array schreiben (das kannst Du auch erstmal in C# üben) oder Dir 
den Zeiger auf die interne UTF-16 Representation geben lassen.

Das Netz ist voll von Beispielen dazu, weil es ja auch wirklich eine 
immer wiederkehrende nervige Aufgabe ist.

Siehe z.B. hier:
http://support.microsoft.com/kb/311259

Wichtig ist, zu verstehen warum und wann man Pinnen muß bzw. wann man 
GC.keepalive() benutzen muß.

von cppUser (Gast)


Lesenswert?

Danke für den Tipp. Kann jetzt die Funktion richtig aufrufen, allerdings 
wird der String nicht korrekt übergeben.
Zumindest bekomme ich nicht das korrekte Ergebnis von der Funktion 
geliefert.
1
int nativeCppWrapper::MySimpleFunctionsWrapper::TextOK(String^ text)
2
{
3
  using namespace Runtime::InteropServices;
4
  const char* str = (const char*)(Marshal::StringToHGlobalAnsi(text)).ToPointer();
5
  return myCppClass->TextOK(str);
6
  Marshal::FreeHGlobal(IntPtr((void*)str));
7
}

von cppUser (Gast)


Lesenswert?

Ok,
funktioniert alles ;) Hatte noch einen anderen Fehler.

Danke!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.