FAQ: __cdecl calling convention bei callbacks
-
Ich möchte eine Korrektur eines FAQ Beitrages vorschlagen:
http://www.c-plusplus.net/forum/viewtopic-var-t-is-192725.htmlDarin wird über die Möglichkeiten von Callbacks geredet, unteranderem dass Callbacks über die
__cdecl
Konvention nicht möglich seien. Das ist aber Unfug, wie ich heute nach langem knübeln und grübeln rausgefunden habe.Problemstellung
Wir haben eine C++ DLL mit ca. folgendem Code:typedef void(*theCallback)(int, int); extern "C" __declspec(dllexport) void callMeBack(theCallback callback) { int a, b; a = 0; b = 0; callback(a, b); callback(a, b); }
Wir wollen diese Funktion nun per P/Invoke aufrufen:
internal delegate void theCallback(Int32 a, Int32 b); [DllImport("the.dll")] internal static void callMeBack(theCallback callback); // ... private void myCallback(int a, int b) { } public void foo() { callMeBack(this.myCallback); }
Mit sehr hoher Wahrscheinlichkeit wird dies eine
AccessViolationException
auslösen, mit der Begründung dass protected Speicher beschädigt wurde. Um genau zu sein ist es der ESP (Extended Stack Pointer). Das Problem hier ist nämlich die Calling Convention. Eine C++ DLL verwendet standardmässig__cdecl
, währendDllImport
standardmässigCallingConvention.Winapi
verwendet. Für die WinAPI ist diese Einstellung auch absolut sinnvoll, für die C++ DLL allerdings weniger.Lösung
Erster Schritt ist diese Korrektur:[DllImport("the.dll", CallingConvention = CallingConvention.Cdecl)] internal static void callMeBack(theCallback callback);
Jetzt wird immerhin schon mal die Funktion korrekt aufgerufen. Wir haben aber immer noch ein Problem, nämlich die Callback-Funktion wird falsch aufgerufen. Um dies zu lösen müssen wir die
delegate
Deklaration mit einem Attribute ausstatten.[UnmanagedFunctionPointer(CallingConvention.Cdecl)] internal delegate void theCallback(Int32 a, Int32 b);
Nun sollte alles einwandfrei funktionieren. Zumindest hat es bei mir dann endlich geklappt
Referenzen:
MSDN - DllImportAttribute
MSDN - CallingConvention
MSDN - UnmanagedFunctionPointerAttributeGrüssli
-
*push*
Wollte nur mal nachfragen, was nun damit eigentlich ist? Wird das korrigiert oder nicht? Oder liegt sonst irgendein Problem damit vor?Grüssli