c# c++ pinvoke unmanaged managed

c# - Una llamada a la función PInvoke ''[...]'' ha desequilibrado la pila



c++ unmanaged (5)

Recibo este extraño error en algunas cosas que he estado usando durante bastante tiempo. Puede ser algo nuevo en Visual Studio 2010, pero no estoy seguro.
Intento llamar a una función no controlada escrita en C ++ desde C #.
De lo que he leído en Internet y el mensaje de error en sí tiene algo que ver con el hecho de que la firma en mi archivo C # no es la misma que la de C ++, pero realmente no puedo verlo.
En primer lugar, esta es mi función no controlada a continuación:

TEngine GCreateEngine(int width,int height,int depth,int deviceType);

Y aquí está mi función en C #:

[DllImport("Engine.dll", EntryPoint = "GCreateEngine", CallingConvention = CallingConvention.StdCall)] public static extern IntPtr CreateEngine(int width,int height,int depth,int device);

Cuando depuro en C ++ veo todos los argumentos muy bien, así que solo puedo pensar que tiene algo que ver con la transformación de TEngine (que es un puntero a una clase llamada CEngine) a IntPtr. Lo he usado antes en VS2008 sin ningún problema.


En mi caso (VB 2010 y DLL compilados con Intel Fortran 2011 XE), el problema existe cuando mi aplicación se dirige a .NET Framework 4. Si cambio el framework de destino a la versión 3.5, todo funciona bien como se esperaba. Entonces, supongo que la razón es algo introducido en .Net Framework 4 pero no tengo idea en este momento cuál

Actualización: El problema se resolvió compilando Fortran DLL y especificando STDCALL como convención de llamadas para los nombres de exportación en la DLL.


Tal vez el problema radica en la convención de llamadas. ¿Estás seguro de que la función no gestionada se compiló como stdcall y no como algo más (supongo que llamada rápida)?


También podría ser que en .NET Framework versión 3.5, pInvokeStackImbalance MDA esté deshabilitado de forma predeterminada. Menos de 4.0 (o tal vez VS2010) está habilitado por defecto .

Sí. Técnicamente, el código siempre fue incorrecto, y las versiones anteriores del marco lo corrigieron silenciosamente.

Para citar el documento de problemas de migración de .NET Framework 4 : "Para mejorar el rendimiento en interoperabilidad con código no administrado, las convenciones de llamadas incorrectas en una invocación de plataforma ahora causan que la aplicación falle. En versiones anteriores, la capa de cálculo resolvió estos errores en la pila. Si tiene binarios que no se pueden actualizar, puede incluir el elemento < NetFx40_PInvokeStackResilience > en el archivo de configuración de su aplicación para permitir que los errores de llamadas se resuelvan en la pila como en versiones anteriores. Sin embargo, esto puede afectar el rendimiento de su aplicación.

Una manera fácil de solucionar esto es especificar la convención de llamadas y asegurarse de que sea la misma que en la DLL. Un __declspec(dllexport) debería producir un formato cdecl .

[DllImport("foo.dll", CallingConvention = CallingConvention.Cdecl)]


Tenía un _cdecl c ++ dll al que llamé sin problemas desde Visual Studio 2008, y luego el código idéntico en Visual Studio 2010 no funcionaría. Obtuve el mismo PInvoke ... también ha desequilibrado el error de la pila.

La solución para mí fue especificar la convención de llamadas en el atributo DllImport (...): From:

[DllImport(CudaLibDir)]

A:

[DllImport(CudaLibDir, CallingConvention = CallingConvention.Cdecl)]

Supongo que cambiaron la convención de llamadas predeterminada para DLLImport entre .NET 3.5 y .NET 4.0.


Use el siguiente código, si su DLL tiene el nombre MyDLL.dll y desea usar la función MyFunction dentro del Dll.

[DllImport("MyDLL.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)] public static extern void MyFunction();

esto funcionó para mí.