.net

【.net】PInvokeStackImbalanceが検出されましたの対策

旧システムのリプレース作業中に↓の例外に遭遇した。

PInvokeStackImbalance が検出されました

なんのこっちゃいって感じなので調べてみた。


発生原因

これは、VS2010以降でDllImport等を使用して、アンマネージドのDLLを呼び出す場合に発生する。
通常、DLLを作成する際に呼び出し規則(_stdcallなど)をつけてexportするが、その指定が 作成したDLL側と、呼び出すC#側で不一致 だということらしい。

なぜVS2008以前は起きなかったかというと、VS2008以前では↑の規則の不一致をチェックする例外「PInvokeStackImbalance」が無効(設定できない)となっており、VS2010から有効となったからだ。
『”P/Invoke”呼び出し規則のチェックの厳格化』ということらしい。

この事象はプロジェクトの「対象のフレームワーク」に応じて設定値がかわるわけではなく、Visual Studioのバージョンによって初期値がかわる。

VS2008には、例外設定内のManaged Debugging Assistantsに、「PInvokeStackImbalance」がないのがわかる。VS2008 ~ VS2010は↓の手順で確認できる。

デバッグ ⇒ 例外 で例外ウィンドウを開く。
例外ウィンドウで Managed Debugging Assistants ⇒ PInvokeStackImbalance

2008の例外ウィンドウ
2008の例外ウィンドウ
2010の例外ウィンドウ
2010の例外ウィンドウ

VS2015以降の場合は↓の手順となる。

デバッグ ⇒ ウィンドウ ⇒ 例外の設定 で例外ウィンドウを開く。
例外ウィンドウで Managed Debugging Assistants ⇒ PInvokeStackImbalance

2015の例外ウィンドウ
2015の例外ウィンドウ

対策方法

DLLインポートの記述を↓のように修正する。

[DllImport("Hoge.dll")]

[DllImport("Hoge.dll", CallingConvention = CallingConvention.XXXX)]

“XXXX”はDLLエクスポートの定義と合わせる。
CallingConventionを省略すると、StdCallが既定値(呼び出し先がStackを削除)となる。

CallingConventionとは、エントリポイントの呼び出し規則で、列挙の内容はMSDNを参照して頂きたい。
MSDN:CallingConvention列挙方メンバー

ちなみに上記のCallingConventionを正しく設定しないと、ぼくの環境では不穏な動き(再現性が一定でない不具合)をしたため、やはり設定するのが正しいやり方であろう。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です