0

ac# アプリケーションからアンマネージ Dll を呼び出すと、AccessViolationException. 奇妙なことに、エクスポートされた関数には引数がないため、問題はデータのマーシャリングにはありません。この関数は引数を取得せず、整数を返すだけです。また、呼び出し規約は問題ではないことに注意してください。同じゼロ引数と整数の戻り値 (ただし名前は異なる) を持つ同一の関数は問題なく動作します。マーシャリングと呼び出し規則が除外されているという事実を考慮して、そのような呼び出しがこの例外を引き起こす可能性がある残りの候補となる理由は何ですか?

更新: プレーン リンクを介して他のアンマネージ コードから呼び出された場合、完全に機能するため、dll 関数は正しいです。

更新 2: すべてがコンパイルされ、32 ビットで実行されます。Windows XP SP2 と Vista を試しました。ここに興味深い事実があります。Vista システムでは、これは魔法のように機能します。XPでは失敗します。

更新 3: ソース コードを入手できませんでしたが、この dll が本質的に何をするかを知ったので、自分の dll で問題を再現しようとしました。ここに話があります: 元の dll は、ei.lib (Erlang の c インターフェイス ライブラリ) へのある種のラッパーです。いくつかのヘルパー関数をエクスポートします。したがって、問題を再現するために、「test()」という 1 つの関数のみをエクスポートする ei.lib のラッパー dll を作成しました。マーシャリングなどを台無しにしないように、そうしました。初期化、接続、メッセージの送信をテストしたかっただけです。したがって、この dll の test() func は、 を呼び出してei_connect_init()から、最後ei_connect()ei_reg_send()、内部にハードコードされた引数を持ちます。問題は、この dll を呼び出して別のアンマネージ コードから test() 関数を使用すると、問題なく動作することです。メッセージが送信されます。しかし、DllImport を介して c# から呼び出すと、Vista でのみ機能します。XPではありません。XP では、.net 層で AccessViolationException で失敗します。私は問題を追跡しようとしましたが、XP で実行されていてマネージ コードによって呼び出されている場合、dll 内から への呼び出しei_connect()、または読み取りの試みerl_errno(これらは ei.lib で定義されています) が読み取ろうとしていることがわかります。または、アプリがクラッシュするように保護されたメモリを書き込みます。Vistaで動作し、アンマネージコードから呼び出されたときに動作するため、些細なことではありません。

4

2 に答える 2

1

OK、私は問題を知っていると思います: ei.lib は TLS (Thread Local Storage) を使用します。ei_pthreads.cei インターフェイス ソース コードのファイルには、次のスニペットがあります。

#ifdef __WIN32__
#ifdef USE_DECLSPEC_THREAD
/* Define (and initialize) the variable __erl_errno */
volatile __declspec(thread) int __erl_errno = 0;
#else
static volatile DWORD errno_tls_index = TLS_OUT_OF_INDEXES;
static LONG volatile tls_init_mutex = 0;
#endif
#endif

が定義されていない場合USE_DECLSPEC_THREADは、ソース ファイルの下部で、代わりに TLS Api が使用されます。さて、msdnから次のことがわかりました:

Windows Vista より前の Windows オペレーティング システムでは、__declspec( thread ) いくつかの制限があります。DLL が非ローカル データまたはオブジェクトを として宣言する__declspec( thread )場合、動的に読み込まれると保護違反が発生する可能性があります。DLL が LoadLibrary で読み込まれると、コードが非ローカル__declspec( thread )データを参照するたびにシステム エラーが発生します。スレッドのグローバル変数領域は実行時に割り当てられるため、この領域のサイズは、アプリケーションの要件と、静的にリンクされているすべての DLL の要件の計算に基づいています。LoadLibrary を使用する場合、このスペースを拡張して、で宣言されたスレッド ローカル変数を許可することはできません__declspec( thread )。DLL が LoadLibrary で読み込まれる可能性がある場合は、DLL で TlsAlloc などの TLS API を使用して TLS を割り当てます。

USE_DECLSPEC_THREADですから、Windows 用の erlang のプリコンパイル済みバイナリ ディストリビューションで提供されている erl インターフェイス ライブラリを使用しているので、これらのバイナリをコンパイルするときに定義されているのだろうかと思います。そうでない場合、私は行き詰まっており、仕事をするために何か他のことを試みます. 彼らがそれを定義した場合は、cygwin をインストールし、定義せずにソースを再コンパイルする必要があります。(うわぁ...)。

最終更新: 確かにこれが問題でした。cygwin をインストールし、erl_interface コードを定義せずに再度コンパイルする必要がありましたUSE_DECLSPEC_TRHEAD。また、再コンパイル時に別の小さな問題があります。小さな変更が必要です。これにより_WIN32_WINNT、winbase.h をインクルードする前にの定義が行われるようにUSE_DECLSPEC_THREADなります。これは、コードの省略後、winbase.h で定義されている SwitchToThread が定義_WIN32_WINNTされていて、値が大きい場合にのみ使用されるためです。 0x400よりも。

于 2009-11-18T12:14:22.743 に答える
0

この例外は、アンマネージ コードによってメモリ アクセス違反が発生した場合に発生します。アンマネージ関数が正しいことを確認してください。アンマネージ コードのソースがある場合は、デバッガーを有効にしてアンマネージ コードにステップ インし、問題の場所を確認することもできます。

于 2009-11-13T15:02:32.430 に答える