c#, unmanaged C++ dll & verlorene Parameter
-
Hallo Leute,
kann mir jemand erklären oder irgendwelche Hinweise geben, warum der Aufruf von bar1:
[DllImport("foo1.dll", CharSet = CharSet.Ansi)]
public static extern short bar1(ushort param1, ushort param2, StringBuilder param3);hervorragend funktioniert aber der von bar2:
[DllImport("foo2.dll", CharSet = CharSet.Ansi)]
public static extern string bar2(ushort param1, ushort param2, ushort param3, ushort param4, ushort param5, uint param6);beim Aufruf eine AccessViolationException verursacht? Also die AccessViolationException ist mir eigentlich klar, da in der foo2.dll die ankommenden Parameter alle um eins nach vorne verschoben sind, sprich anstelle von param1 kommt param2 usw. bis letztlich bei param6 irgendetwas übergeben wird, was die Exception verursacht. Aber wo ist der 1. Parameter hin?
Die üblichen Googletreffer ergaben da auch keine weiteren Erkenntnisse bisher ...
Gruß,
crkn
-
ins blaue geraten: bar2.dll exportiert mit einer "falschen" calling convention
-
Mh, also bar2 ist in der dll wie folgt definiert:
extern "C" __declspec(dllexport) string bar2(unsigned short param1, unsigned short param2, unsigned short param3, unsigned short param4, unsigned short param5, unsigned int param6);
Zu __declspec sollte doch __StdCall passen bzw.:
[DllImport("foo2.dll", CallingConvention=CallingConvention.StdCall, CharSet = CharSet.Ansi)]
passen, oder? Führt aber weiterhin zu obigem Ergebnis.
-
Wurde leider noch nicht in die FAQ aufgenommen:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-261175.htmlDreht sich zwar um Callbacks, aber hat allgemeines über CallingConvention drin
Und nein, zu
__declspec
gehört nicht__stdcall
.Grüssli
-
Wenn Du die DLL selbst schreibst, kannst du stdcall trotz __cdecl(dllexport) benutzen, indem du zwischen Rückgabetyp und Funktionsname einfach __stdcall ergänzt.
-
So, bei den Calling Conventions führte alles zu keiner Verbesserung oder es kam noch nicht mal so weit. Nach weiterem Suchen kam ich nun dank http://discuss.fogcreek.com/dotnetquestions/default.asp?cmd=show&ixPost=1108 und http://groups.google.com/group/microsoft.public.dotnet.framework/msg/9807f3b190c31f6d zu folgender Lösung (Änderungen unterstrichen):
C#-Seite:
[DllImport("foo2.dll")] private static extern [b][u]IntPtr[/u][/b] bar2(ushort param1, ushort param2, ushort param3, ushort param4, ushort param5, uint param6); [b][u]public static string getBar2(ushort param1, ushort param2, ushort param3, ushort param4, ushort param5, uint param6) { return Marshal.PtrToStringAnsi(bar2(ushort param1, ushort param2, ushort param3, ushort param4, ushort param5, uint param6)); }[/u][/b]
C++-Seite:
extern "C" __declspec(dllexport) [b][u]const char*[/u][/b] bar2(unsigned short param1, unsigned short param2, unsigned short param3, unsigned short param4, unsigned short param5, unsigned int param6);
Das funktioniert auch hervorragend, aber so 100% verstanden habe ich es noch nicht. Falls mir noch einer erklären könnte wieso der Returnstring auf dem Heap liegen muss und welche Abneigungen die C++ und C# Strings untereinander haben und wieso sich das schon auf den Funktionsaufruf auswirkt, wäre ich sehr dankbar.
-
Gut, wenns hier sonst auch keiner weiß, bin ich ja beruhigt.
-
crkn schrieb:
Gut, wenns hier sonst auch keiner weiß, bin ich ja beruhigt.
Ist doch ziemlich logisch, wieso es nicht geht. Als ich nochmals den Code angeschaut habe, welchen du hier exportieren willst, war es mir sofort klar. Vorher hatte ich das übersehen, weil der Code nicht in entsprechenden Code-Tags war.
Du willst über eine C Schnittstelle eine C++ Klasse
std::string
zurückgeben? Wie stellst du dir vor, dass dies gehen soll, wenn C gar keinestd::string
Klasse kennt? Und mit P/Invoke ruft man schliesslich auch C Funktionen auf, daher kannst du das C++ in der Signatur sowieso knicken.Das ganze geht übrigens deutlich einfacher:
[DllImport("foo2.dll", CharSet = CharSet.Ansi)] private static extern String bar2(ushort param1, ushort param2, ushort param3, ushort param4, ushort param5, uint param6);
Und die C Schnittstelle bar2 muss natürlich weiterhin einen
char const*
zurückgeben. Wobei mich gerade wunder nehmen würde, wie du diesenchar const*
zurückgibst. Ich hoffe, dass es nicht sowas ähnliches ist:extern "C" __declspec(dllexport) char const* bar2(...) { std::string obj; // ... return obj.c_str(); // <- ARGH!! }
Grüssli