Hallo,
beim Portieren eines Programms von C++ nach C# tritt bei mir folgendes Problem auf:
Ich rufe Funktionen einer externen DLL auf. Dies funktioniert bei allen DLL-Funktionen bis auf eine. (In C++ klappt's bei allen).
[DllImport(@"mydll.DLL", EntryPoint = "TrickyFunction")]
static extern int TrickyFunction
(double[] va1, int va2, int va3, double va4, int va5, int va6, int va7, byte[] va8);
Ich bin mir wirklich sicher, den Funktionsaufruf genau wie in C++ zu machen:
TrickyFunction(va1DoubleArray, va2Int, va3Int, va4Int, va5Int, va6Int, va7Int, va8ByteArray);
Leider bekomme ich den folgenden Fehler:
"Eine nicht behandelte Ausnahme des Typs "System.EntryPointNotFoundException" ist in mydll.dll aufgetreten.
Zusätzliche Informationen: Der Einstiegspunkt TrickyFunction wurde nicht in der DLL mydll.DLL gefunden."
Ich bin deswegen beim byte array misstrauisch, weil diese die einzige Funktion ist, die mit einem solchen aufgerufen wird - und nicht funktioniert. Ich gehe davon aus, dass byte Arrays in C# identisch zu denen in C++ sind, oder liege ich falsch?
Danke für eure Tips.
Hallo,
EntryPointNotFoundException bedeutet der Name "TrickyFunction" wurde in der Dll nicht exportiert.
Wenn es sich um eine C++ Dll Handelt hat der Entwickler vermutlich vergessen ein extern "C" vor die Funktion zu schreiben.
Schau dir mit z.B. Dependency Walker an, welche Funktionen die Dll exportiert.
Also,
mit Dependency Walker sehe ich meine "TrickyFunction". Sie wird korrekt exportiert, deswegen kann ich sie ja vom existierenden C++-Projekt auch aufrufen.
Wie gesagt, sehr komisch ist, dass der - anscheinend - identische Funktionsaufruf in C++ funktioniert, in C# aber nicht. Woran könnte das noch liegen?
Steht da auch nur "TrickyFunktion" oder etwas in der Art "?TrickyFunction@@xxx"?
Was hast du beim DllImport als CallingConvention angegeben? Bin mir jetzt nicht sicher, ob .Net das auflösen kann.
Wie sieht es mit den anderen Funktionen aus, welche die Dll exportiert, sehen die ähnlich aus?
Ansonsten beim DllImport mit Entrypoint den exakten Namen, wie ihn dir DependencyWalker anzeigt verwenden.
Kanst ansonsten auch direkt über die Adresse (0x00005170) die funktion aufrufen. Benutze die Marshal Klasse um den Zeiger in ein Delegate zu legen.
Kanst ansonsten auch direkt über die Adresse (0x00005170) die funktion aufrufen. Benutze die Marshal Klasse um den Zeiger in ein Delegate zu legen.
Das ist nicht nötig, einfach bei DllImport das EntryPoint Feld auf den exakten Namen setzten.
Einglich nicht bei ihm scheint es aber nicht zu funktionieren...
Ja, weil er vermutlich eine falsche CallingConvention verwendet.
Danke für die Antworten, also der Reihe nach...
@marsgk:
Ich benutze bisher die default-CallingConvention. Habe aber jetzt auch andere Werten ausprobiert (winapi, stdcall, cdecl). Der Fehler ist unverändert.
Die anderen Funktionen, die ja funktionieren, sehen im DependencyWalker alle sehr ähnlich aus wie die beschriebene.
Wenn ich den exakten Namen _TrickyFunction@32 als EntryPoint setze, bekomme ich statt "EntryPoint not found" folgenden Fehler:
"Eine nicht behandelte Ausnahme des Typs "System.AccessViolationException" ist in NAL-NL1.dll aufgetreten."
@Ayke: Ich versuche gerade, deinen Vorschlag auszuprobieren, kenne diese Variante aber noch nicht. Es läuft bei mir nicht. Hier mein Code:
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.UnmanagedCode)]
public static Delegate GetDelegateForFunctionPointer(IntPtr ptr, Type t);
Und hier die Compilermeldung:
Fehler CS0501: "xy.xy.GetDelegateForFunctionPointer(System.IntPtr, System.Type)" ist nicht als abstrakt, extern oder partiell gekennzeichnet und muss daher einen Text deklarieren.
Zeig doch mal die Definition der C Funktion und wie du bisher versucht hast diese einzubinden.
Vermutlich stimmen die Parameter nicht überein und deshalb hat .Net die Funktion nicht gefunden.
Lieber marsgk,
genau das ist ja mein Problem, dass die Parameter meines Wissens nach korrekt sind, es aber trotzdem nicht funktioniert.
Die Funktionsdefinition der DLL liegt mir nicht vor, da sie von einer externen Quelle kommt. Ich habe mich aber genau an die Import-Anweisung desjenigen Programmierers gehalten (und an den Funktionsaufruf vom funktionierenden C++-Programm). Hier aus seiner Anleitung:
DllImport int WINAPI TrickyFunction( double va1[19], int va2, int va3, int va4, int va5, int va6, int va7, bool va8[19] );
Bei mir habe ich in der letzten Variable byte statt bool verwendet, das macht hier jedoch keinen Unterschied - mit bool geht es auch nicht.
Was genau meinst du? Am Anfang des Threads habe ich alle Zeilen, in denen die Funktion vorkommt, gepostet - den DllImport-Abschnitt und den Funktionsaufruf. Mehr gibts da nicht.
Ah, das habe ich übersehen.
Warum hast du Parameter va4 als double deklariert? Laut Beschreibung sollte es ein int sein.
Bei bool musst du aufpassen kann 8 bzw. 32 Bits haben, meistens aber 32.