DOBON.NET DOBON.NETプログラミング掲示板過去ログ

C#でdllを使う時の引数の型(void**版)

環境/言語:[Win XP、C#、.NET 1.1]
分類:[.NET]

C++で作成したdllをC#でimportして
利用したいのですが
引数 void** の型をどのように宣言すれば
よろしいでしょうか?

C++版で作成されたdllの関数は
仮に
void init(long* h , void** m)
void lock(long h,int cnt, void** m)
void unlock(long h, void** m)

となっていた場合

C#では以下のようにしました。

[DllImport("test.dll")]
static extern void init(long h,out IntPtr m);
[DllImport("test.dll")]
static extern void lock(long h, int cnt,out IntPtr m);
[DllImport("test.dll")]
static extern void unlock(long h,out IntPtr m);

呼び出しは

IntPtr m;
long h;
init(h,m);
lock(h,10,m);
unlock(h,m);

です。
この実装では、ビルドは通りましたが
実行時に、lock()を呼び出すと、例外が発生しました。
(null exception)

他にやったことは、
(1)IntPtrをやめてlongに変更 →例外エラー

(2)IntPtrをやめてMarshalAsを使用  →例外エラー
以下のように書きました
[DllImport("test.dll")]
static extern void init(long h,[MarshalAs(UnmanagedType.AsAny)] out object m);
他の関数も同様

(3)unsafeを使用 →例外エラー
[DllImport("test.dll")]
static unsafe extern void init(long* h,void** m);
他の関数も同様

呼び出しは
unsafe{
void* m;
long h;
fixed(void** address = &m){
init(&h,address);
lock(h,10,address);
unlock(h,address);
}
}
と書きました。同じようにlock()で例外が発生します。

ちなみにC++でdllを呼び出す場合、
以下のような実装で正常に動いています
ので,dll側に問題はないです。

long h;
void* m;
init(&h,&m); mのアドレスが取得される
lock(h,10,&m);
ここでmを別の型にキャストして値を代入してます
unlock(h,&m);

C#はじめて間もないです。
C/C++ の long のサイズと C$ の long のサイズを調べてみてください。
あと init の第一引数はポインタで、値を渡すだけじゃ意味がありませんよ。初期化時の識別子を「受け取る」んでしょうから。
■No16741に返信(Hongliangさんの記事)
> C/C++ の long のサイズと C$ の long のサイズを調べてみてください。
> あと init の第一引数はポインタで、値を渡すだけじゃ意味がありませんよ。初期化時の識別子を「受け取る」んでしょうから。

返信ありがとうございます。

コード箇所は、思い出しながら書きましたので
ミスがありました。

C/C++ long 4byte
C# int 4byte
ですね。

[DllImport("test.dll")]
static extern void init(ref int h,out IntPtr m);
[DllImport("test.dll")]
static extern void lock(int h, int cnt,out IntPtr m);
[DllImport("test.dll")]
static extern void unlock(int h,out IntPtr m);

呼び出し
init(ref h,out m);
といった実装になります。

本題のvoid**の部分ですが
これは、C#ではどう書けばよろしいでしょうか?
ref を使うべきか out を使うべきかはその関数の仕様次第ですが、それでいいはずです(ので、触れなかったんですが)。
あ、out のせいな気がひしひしと。
言語仕様とかで out と ref の違いを調べてください。
自己解決です。

C++のvoid**を
C#では
IntPtrで宣言すればよいみたいです。
アドレス値を見ると、整数値が入ってました。

以上
解決済み!
ポイント先が必要でないならそれでも良いですね。元々ハンドルなんてそんなもんだし。
// ポインタのポインタも結局はポインタ
解決済み!

DOBON.NET | プログラミング道 | プログラミング掲示板