Uma chamada para a function PInvoke ” desequilibrou a pilha

Eu estou recebendo este erro estranho em algumas coisas que eu tenho usado por um bom tempo. Pode ser uma coisa nova no Visual Studio 2010, mas não tenho certeza.
Eu estou tentando chamar uma function não autorizada escrita em C ++ de c #.
Do que eu li na internet e a mensagem de erro em si tem algo a ver com o fato de que a assinatura no meu arquivo c # não é o mesmo que o do C ++, mas eu realmente não posso vê-lo.
Primeiro de tudo, esta é a minha function não autorizada abaixo:

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

E aqui está minha function em C #:

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

Quando eu depurar em C ++ eu vejo todos os argumentos muito bem, então eu só posso pensar que tem algo a ver com a transformação de TEngine (que é um ponteiro para uma class chamada CEngine) para IntPtr. Eu usei isso antes no VS2008 sem nenhum problema.

Talvez o problema esteja na convenção de chamada. Tem certeza de que a function não gerenciada foi compilada como stdcall e não outra coisa (eu diria fastcall)?

Eu tinha um _cdecl c ++ dll que eu liguei sem nenhum problema do Visual Studio 2008 e, em seguida, o código idêntico no Visual Studio 2010 não funcionaria. Eu tenho o mesmo PInvoke … desequilibrou o erro da pilha também.

A solução para mim era especificar a convenção de chamada no atributo DllImport (…): De:

 [DllImport(CudaLibDir)] 

Para:

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

Eu acho que eles mudaram a convenção de chamada padrão para DLLImport entre .NET 3.5 e .NET 4.0?

Também pode ser que no .NET Framework versão 3.5, o pDAVokeStackImbalance MDA esteja desabilitado por padrão. Em 4.0 (ou talvez VS2010), ele é ativado por padrão .

Sim. Tecnicamente, o código estava sempre errado e as versões anteriores do framework o corrigiam silenciosamente.

Para citar o documento de Problemas de Migração do .NET Framework 4 : “Para melhorar o desempenho na interoperabilidade com código não gerenciado, as convenções de chamada incorretas em uma plataforma invocadas agora fazem com que o aplicativo falhe. Nas versões anteriores, a camada de empacotamento resolveu esses erros na pilha. Se você tem binários que não podem ser atualizados, você pode include o elemento < NetFx40_PInvokeStackResilience > no arquivo de configuração do seu aplicativo para permitir que os erros de chamada sejam resolvidos na pilha como nas versões anteriores. No entanto, isso pode afetar o desempenho do seu aplicativo. ”

Uma maneira fácil de corrigir isso é especificar a convenção de chamada e certificar-se de que ela seja igual à da DLL. Um __declspec(dllexport) deve render um formato cdecl .

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

Use o seguinte código, se disser que sua DLL tem o nome MyDLL.dll e você deseja usar a function MyFunction dentro da DLL

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

isso funcionou para mim.

No meu caso (VB 2010 e DLL compilado com Intel Fortran 2011 XE) o problema existe quando meu aplicativo é direcionado para o .NET Framework 4. Se eu alterar a estrutura de destino para a versão 3.5, tudo funcionará bem conforme o esperado. Então, eu acho que a razão é algo introduzido no .Net Framework 4, mas eu não tenho idéia no momento de qual

Atualização: O problema foi resolvido recompilando a DLL Fortran e explicitamente especificando STDCALL como convenção de chamada para nomes de exportação na DLL.