- PR -

[C#] 引数にcallbackを持つDLLメソッドの使用について

投稿者投稿内容
ふぉる
会議室デビュー日: 2004/06/17
投稿数: 8
投稿日時: 2004-06-17 16:05
はじめまして。

C++builderで作成されたDLLをVC#で利用しているのですが、その中に
引数の一つにcallbackを持つメソッドがあります。
ヘルプの「Callback のサンプル」の情報を参照して作成、動作確認したところ
DLLのメソッドで指定したcallbackが呼ばれるまでは動作しているのですが
そのcallback終了時に下記のエラーメッセージボックスが出て、callbackが無限に
繰り返されてしまいます。(当然エラーメッセージも繰り返されます。)

The value of ESP was not properly saved across a function call.
This is usually a result of calling a function declared with one calling convention
with a function pointer declared with a different convention.

下記のようなコードを書いたのですが、何かの指定が不足しているのでしょうか。
呼び出し規約が間違えているとこのメッセージが出るという情報をどこかで見たのですが・・・

public class LibWrap
{
 // delegate
 public delegate void funcPtr( int nA, int nB );

 [DllImport("Hoge.dll")]
 public extern static int HogeHoge(
  string pcName, // char *
  string pcTargetName, // char *
  System.IntPtr pData, // void *
  funcPtr funcCB // void (*Callback)(int nA, int nB)
 );
}

public class Form1 : System.Windows.Forms.Form
{
 private System.Windows.Forms.Button button1;
 private System.ComponentModel.Container components = null;

 LibWrap.funcPtr funcCB;

 (中略)

 // CallBack用
 private static void CallBack( int nA, int nB )
 {
  return;
 }

 unsafe private void button1_Click(object sender, System.EventArgs e)
 {
  byte[] buf = new byte[5];
  buf[0] = 0x41;
  buf[1] = 0x42;
  buf[2] = 0x43;
  buf[3] = 0x44;

  funcCB = new LibWrap.funcPtr( Form1.CallBack );
  fixed( byte *byp = &buf[0] )
  {
   System.IntPtr pBuf = new System.IntPtr( byp );
   LibWrap.HogeHoge("app", "targ", pBuf, funcCB );
  }
 }
}

[ メッセージ編集済み 編集者: ふぉる 編集日時 2004-06-17 16:09 ]
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2004-06-18 07:31
引用:

そのcallback終了時に下記のエラーメッセージボックスが出て、callbackが無限に
繰り返されてしまいます。(当然エラーメッセージも繰り返されます。)



スタックフレームが壊れていますね。
呼び出し規約があってないんでしょう。

[DllImport("Hoge.dll",CallingConvention=XXX)]
public extern static int HogeHoge

の XXX のところを適切な値に置き換えて調節してください。

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
ふぉる
会議室デビュー日: 2004/06/17
投稿数: 8
投稿日時: 2004-06-18 12:25
お返事ありがとうございます。
CallingConvention については既に試してあるのですが、cdecl,thiscall
いずれを指定して実行しても問題は解決されない状態です。
soluna
ベテラン
会議室デビュー日: 2004/06/15
投稿数: 59
投稿日時: 2004-06-18 12:56
C++Builder側の宣言はどうなっていますか?
__fastcallは付いていませんよね?
ふぉる
会議室デビュー日: 2004/06/17
投稿数: 8
投稿日時: 2004-06-18 15:43
DLL側の宣言は下記のようになっています。

#define EXPORTDLL extern "C" __declspec(dllexport)

EXPORTDLL long __stdcall HogeHoge( char* pcName, char* pcTargetName, void *pData, void (*Callback)(int nA, int nB) );
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2004-06-18 16:19
引用:

DLL側の宣言は下記のようになっています。
EXPORTDLL long __stdcall HogeHoge( char* pcName, char* pcTargetName, void *pData, void (*Callback)(int nA, int nB) );



delegate の方の呼び出し規約を調整する必要がありますね。

_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://hidori.jp/
// Microsoft MVP for Visual C#
//
// @IT会議室 RSS 配信中: http://hidori.jp/rss/atmarkIT/
ふぉる
会議室デビュー日: 2004/06/17
投稿数: 8
投稿日時: 2004-06-18 20:42
引用:
delegate の方の呼び出し規約を調整する必要がありますね。



すみません。それは具体的にどのように記述するのでしょうか。
[DllImport("Hoge.dll",CallingConvention=CallingConvention.StdCall)]
という記述では直りませんでしたし
渋木宏明(ひどり)
ぬし
会議室デビュー日: 2004/01/14
投稿数: 1155
お住まい・勤務地: 東京
投稿日時: 2004-06-18 21:40
引用:

EXPORTDLL long __stdcall HogeHoge( char* pcName, char* pcTargetName, void *pData, void (*Callback)(int nA, int nB) );



の Callback の呼び出し規約を指定しなければならないはずなんですが、具体的にどうすればいいかは私は分かりません。

引用:

EXPORTDLL long __stdcall HogeHoge( char* pcName, char* pcTargetName, void *pData, [XXX] void (*Callback)(int nA, int nB) );



の XXX の位置で属性で指定するだとは思いますが、まさか、Win32 API にコールバック関数を与えることしか考えていなくて、引数としての関数ポインタの呼び出し規約を指定する方法が無かったりして。。。

元プログラムの修正が可能であれば、Callback の呼び出し規約を通常の Win32 API と同じ __stdcall すれば、C# 側のコードで特に何も対応をしなくても通るはずです。


_________________
// 渋木宏明 (Hiroaki SHIBUKI)
// http://www.hidori.jp/
// Microsoft MVP for Visual Developer - C# since 2004

[ メッセージ編集済み 編集者: 渋木宏明(ひどり) 編集日時 2004-06-18 22:55 ]

スキルアップ/キャリアアップ(JOB@IT)