web-dev-qa-db-ja.com

PInvoke関数 '[...]'の呼び出しにより、スタックのバランスが崩れました

かなり長い間使用してきたもので、この奇妙なエラーが発生しています。 Visual Studio 2010の新しいものかもしれませんが、よくわかりません。
C#からC++で記述された無人の関数を呼び出そうとしています。
インターネットで読んだものとエラーメッセージ自体から、C#ファイルの署名がC++の署名と同じではないという事実に関係していますが、実際には表示されません。それ。
まず第一に、これは私の下にある機能です。

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

そして、C#での私の機能は次のとおりです。

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

C++にデバッグすると、すべての引数が正常に表示されるため、TEngine(CEngineというクラスへのポインター)からIntPtrへの変換に関係しているとしか思えません。 VS2008でこれを問題なく使用しました。

45
Sanctus2099

たぶん問題は呼び出し規約にある。アンマネージ関数はstdcallとしてコンパイルされ、他の何かではありません(fastcallを推測します)。

22
PeterK

Visual Studio 2008から問題なく呼び出した_cdecl c ++ dllがあり、Visual Studio 2010の同じコードは機能しませんでした。同じPInvokeを取得しました...スタックエラーもアンバランスになりました。

私にとっての解決策は、DllImport(...)属性で呼び出し規則を指定することでした。

[DllImport(CudaLibDir)] 

に:

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

.NET 3.5と.NET 4.0の間でDLLImportのデフォルトの呼び出し規約を変更したと思いますか?

86
Scott Morken

.NET Frameworkバージョン3.5では、pInvokeStackImbalance MDAがデフォルトで無効になっている可能性もあります。 4.0(またはVS2010)では、 デフォルトで有効 です。

はい。技術的には、コードは常に間違っていて、以前のバージョンのフレームワークは黙って修正しました。

。NET Framework 4 Migration Issues document :「アンマネージコードとの相互運用性のパフォーマンスを向上させるために、プラットフォーム呼び出しの不正な呼び出し規約により、アプリケーションが失敗するようになりました。以前のバージョンでは、マーシャリングレイヤーが解決されましたこれらのエラーはスタックを上に...更新できないバイナリがある場合は、アプリケーションの構成ファイルに< NetFx40_PInvokeStackResilience >要素を含めると、呼び出しエラーを以前のようにスタックで解決できます。ただし、これはアプリケーションのパフォーマンスに影響を与える可能性があります。」

これを修正する簡単な方法は、呼び出し規約を指定し、それがDLLと同じであることを確認することです。 __declspec(dllexport)cdecl形式を生成する必要があります。

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

DLLの名前がMyDLL.dllで、Dll内で関数MyFunctionを使用する場合は、次のコードを使用します

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

これは私のために働いた。

5
user3610819

私の場合(VB 2010およびDLL Intel Fortran 2011 XEでコンパイル))、アプリケーションが.NET Framework 4をターゲットにしているときに問題が発生します。ターゲットフレームワークをバージョン3.5に変更すると、すべてが正常に動作しますだから、私はその理由が.Net Framework 4で導入されたものであると推測しますが、どの時点で

更新:この問題は、Fortran DLLを再コンパイルし、DLLのエクスポート名の呼び出し規則としてSTDCALLを明示的に指定することで解決しました。

2