Vs2008からvs2010に切り替えました。 C++ dllを呼び出すたびに「pinvokestackimbalance」例外が発生することを除いて、まったく同じソリューションです。
この例外は2008年には発生しません。C++ dllおよび呼び出し側アプリケーションに完全にアクセスできます。ピンボークに問題はないようですが、この問題により他の問題のデバッグが不可能になっています。 IDEはこれらのことを私に伝えるために絶えず停止しています。
たとえば、C#署名は次のとおりです。
[DllImport("ImageOperations.dll")]
static extern void FasterFunction(
[MarshalAs(UnmanagedType.LPArray)]ushort[] inImage, //IntPtr inImage,
[MarshalAs(UnmanagedType.LPArray)]byte[] outImage, //IntPtr outImage,
int inTotalSize, int inWindow, int inLevel);
C++側では次のようになります。
#ifdef OPERATIONS_EXPORTS
#define OPERATIONS_API __declspec(dllexport)
#else
#define OPERATIONS_API __declspec(dllimport)
#endif
extern "C" {
OPERATIONS_API void __cdecl FasterFunction(unsigned short* inArray,
unsigned char* outRemappedImage,
int inTotalSize,
int inWindow, int inLevel);
}
これらの例外がスローされる原因となるvs2010とvs2008の違いは何ですか? DllImportディレクティブに別のパラメーターセットを追加する必要がありますか?
最初に、コードが間違っている(常にそうである)ことを理解します。 「pInvokeStackImbalance」はそれ自体例外ではなく、マネージデバッグアシスタントです。 VS2008ではデフォルトでオフになっていましたが、多くの人がオンにしなかったため、VS2010ではデフォルトでオンになっています。 MDAはリリースモードで実行されないため、リリース用にビルドしてもトリガーされません。
あなたの場合、呼び出し規約は間違っています。 DllImport
のデフォルトは_CallingConvention.WinApi
_で、x86デスクトップコードの_CallingConvention.StdCall
_と同じです。 _CallingConvention.Cdecl
_である必要があります。
これは、次のように[DllImport("ImageOperations.dll")]
行を編集することで実行できます。
_[DllImport("ImageOperations.dll", CallingConvention = CallingConvention.Cdecl)]
_
詳細については、「 このMSDNリファレンス 」を参照してください
オフにするには:
- Ctrl + Alt + E
- [管理されたデバッグアシスタント]で、PInvokeStackImbalanceのチェックを外します。
この問題を解決するのは、ここではそれほど難しくありませんが、いくつかの方法について言及していますが、上記の私の友人の一部と同じかもしれません。私はPCSCで1週間ほど費やしているSmartcardアプリケーションを使用していますが、多くの変更が最終的に解決されたことに腹を立てています。
私にとって、VS2010用にインストールしたPInvoke拡張機能との連携は、こちらからダウンロードできます http://www.red-gate.com/products/dotnet-development/pinvoke/
それをダウンロードしてインストールし、Visual Studioを閉じて再度開き、メニューバーで拡張機能を見つけます。
エラーが署名が一致しないためである場合は、PInvoke.net> Insert PInvoke Signaturesをクリックするだけです。
新しいウィンドウは次のように表示されます
Dllの名前を入力し、検索をクリックすると、検索結果ウィンドウにそのdllのすべての機能が表示されます。特定の機能の署名を取得する機能をクリックします。
その署名を使用すると、その署名、主にデータタイプに従ってプログラムを変更する必要があります。
これにより、callingConventionのような別の問題が発生したり、dllのインポート中に追加の属性を指定する必要があるという問題が解決します。
ハッピーコーディング
VS2010を使用しているときにもこの問題が発生しました。概要:Visual Studioのデフォルトでは、「任意のCPU」に対して64ビットコードが使用されます。変数(たとえば、文字列)へのポインターは、外部Dllを呼び出すと64ビットになります。信頼できるすべてのDllは32ビットポインターを使用します。
Dllに問題があると思い込まないでください。
VS設定を変更して、このようなX86コードを生成します(C#の高速バージョン)
- [ツール]-> [オプション]に移動します。
- [オプション]ダイアログの左下隅にある[すべての設定を表示する]チェックボックスをオンにします。
- 左側のツリービューで、[プロジェクトとソリューション]を選択します。
- 右側のオプションで、「高度なビルド構成を表示する」というボックスをオンにします。
- OKをクリックします。
- ビルド->構成マネージャーに移動...
- プロジェクトの横の「プラットフォーム」列で、コンボボックスをクリックして「」を選択します。
- [新しいプラットフォーム]設定で、[x86]を選択します。
- OKをクリックします。
- 閉じるをクリックします。
また、12か月ごとにコンピューターの電力が2倍になったにもかかわらず、RAMが1ギガバイトの現在のコンピューターは、4メガバイトの最初の486よりも速くないようです。 64ビットコードの使用について心配する必要はありません。巨大で扱いにくいオブジェクト指向の巨大なタワーの上に構築されているため、高速化も改善もされません。
CallingConvention
is ThisCall
でdllを呼び出そうとしましたが、うまくいきました。 BLOB MS Sql Serverで動作するコードを次に示します。
[DllImport("sqlncli11.dll", SetLastError = true, CharSet = CharSet.Unicode, CallingConvention = CallingConvention.ThisCall)]
private static extern SafeFileHandle OpenSqlFilestream(
string FilestreamPath,
UInt32 DesiredAccess,
UInt32 OpenOptions,
byte[] FilestreamTransactionContext,
UInt32 FilestreamTransactionContextLength,
Int64 AllocationSize);