J'essaye de faire l'exemple minimal le plus simple et absolu de la façon de passer des chaînes vers et depuis un C++ DLL en C #.
Mon C++ ressemble à ceci:
using std::string;
extern "C" {
string concat(string a, string b){
return a + b;
}
}
Avec un en-tête comme
using std::string;
extern "C" {
// Returns a + b
__declspec(dllexport) string concat(string a, string b);
}
Mon C # est
[DllImport("*****.dll", CallingConvention = CallingConvention.Cdecl)]
static extern string concat(string a, string b);
}
Et je l’appelle avec: Console.WriteLine (concat ("a", "b"));
Mais cela donne une System.AccessViolationException. Cela semble être la chose la plus insignifiante à traiter, mais je suis complètement coincé là-dessus. Lorsque j'ai essayé de faire une expérience similaire avec une fonction "Ajouter" qui prenait deux doubles et renvoyait un double, je n'avais aucun problème.
Vous ne pouvez pas transmettre un C++ std::string
à travers une limite d'interopérabilité. Vous ne pouvez pas en créer un dans votre code C #. Donc, votre code ne peut jamais fonctionner.
Vous devez utiliser des types compatibles interop à la limite d'interopérabilité. Par exemple, des tableaux de caractères à terminaison nulle. Cela fonctionne bien lorsque vous allouez et désallouez la mémoire dans le même module. Donc, c'est assez simple lorsque vous passez des données de C # à C++.
C++
void foo(const char *str)
{
// do something with str
}
C #
[DllImport("...", CallingConvention = CallingConvention.Cdecl)
static extern void foo(string str);
....
foo("bar");
Dans l’autre sens, vous vous attendez généralement à ce que l’appelant alloue le tampon dans lequel l’appelé peut écrire:
C++
void foo(char *str, int len)
{
// write no more than len characters into str
}
C #
[DllImport("...", CallingConvention = CallingConvention.Cdecl)
static extern void foo(StringBuilder str, int len);
....
StringBuilder sb = new StringBuilder(10);
foo(sb, sb.Capacity);
C’est le moyen le plus simple que j’aime: passer une chaîne et utiliser un lambda pour obtenir la réponse.
C #
[DllImport(@"MyDLL.dll", EntryPoint ="Foo", CallingConvention = CallingConvention.StdCall)]
public static extern void Foo(string str, ResponseDelegate response);
...
Foo("Input", s =>
{
// response is returned in s - do what you want with it
});
C++
typedef void(_stdcall *LPEXTFUNCRESPOND) (LPCSTR s);
extern "C"
{
__declspec(dllexport) void __stdcall Foo(const char *str, LPEXTFUNCRESPOND respond)
{
// Input is in str
// Put your response in respond()
respond("HELLO");
}
}