2009-06-10 4 views
0

概要:複雑のPInvokeの状況 - のオーバーロード機能を避ける

私はC#のから呼び出す必要がありますC関数の束を持っています。私の現在の作業ソリューションは、関数のオーバーロードに基づいており、より洗練されたソリューションがあるかどうかは疑問です。

Cのもの:ヘッダーファイル内のどこか

typedef struct _unknown_stuff * handle; // a opaque pointer 

C関数

func(uint  num_entries, 
     handle * objects, 
     uint * n) 
{ ... } 

の例関数はこれに類似する使用されるべきである。

// warning: i bet that the syntax is not correct but you should get the idea... 

uint n; 

func(0, null, &n); 

handle * objects = malloc(n * sizeof(handle)); 

func(n, objects, null); 

C#のようなもの:右

今私はC#で、次のやっている:そして

public struct handle 
{ 
    public IntPtr Pointer; 
} 

// version to get number of objects 
[DllImport(dll, ...] 
private static extern void 
func( uint  must_be_zero, 
     object  must_be_null, 
     out uint n); 

// version to get the actual data 
[DllImport(dll, ...] 
private static extern void 
func( uint   num_entries, 
     [Out] handle[] objects, 
     int   must_be_zero); 

をして:

handle[] objects; 

uint n = 42; 

func(0, null, out n); 

objects = new handle[n]; 

func(n, objects, 0); 

質問

ので、私はC#のnoobだ、私はこれが最善の方法であるかどうか疑問に思っていたこれを行う。特に、関数のオーバーロードを回避する方法があるかどうかを知りたいと思います。

答えて

1

まず、2番目のC#シグネチャでは、3番目の引数がintであり、対応するCの引数がまだint*であるため、コードは間違っています。 sizeof(int)==sizeof(int*)が存在するので、32ビットWindowsをターゲットにすると動作します。つまり、0のintを渡すと、nullポインタを渡してしまいますが、64ビットでは安全ではありません。このようにしたい場合は、IntPtrを使用する必要があります。それはさておき

、あなたが試みることができる:あなたはnullをそこに渡すことができるように

[DllImport(dll, ...] 
private static extern void func(
    uint num_entries, 
    [Out] handle[] objects, 
    [Out] int[] num_devices); 

3番目の引数の配列を作ります。

またはポインタを使用してください。それは何も悪いことではなく、unsafeキーワードを恐れてはいけません。P/Invokeは本質的に安全ではないので、明示的に記述することもできます。

+0

私はちょっと恥ずかしいです... C#がポインターをサポートしているかどうかは分かりませんでした。 ポインタを使用すると、ヒントのおかげでうまくいくようです:) ライブラリをオフにしてC#の本を探しています –

0

C DLLは0を見ないでしょうか?それをnullとして処理しますか?

これには1つの機能しかありません。つまり、C関数は一度定義され、nullの場合は別に定義されず、そこに

if(objects == NULL)
のチェックがあります。ほとんどのシステム(ターゲットシステムのstdio.hを調べてください)は0です。 この場所で0の値を指定してpinvokeから呼び出すと、オーバーロードを実行する必要があります。

+0

ええ、あなたは正しいですが、型変換に重大な問題があったため、メソッドをオーバーロードすることにしました。 –

+0

最初のC#シグネチャ(3番目の引数が 'out'の場合)を使用すると、0を渡すことは役に立ちません。変数を宣言して0を代入し、それを' out'として渡す必要があります。 C関数は実際にその変数のアドレスを0にします。 もし彼が2番目の署名を使うなら、彼は0を渡すことができます(私はすでにそれが間違っている理由をすでに説明しています)。しかし、値を必要とする場合には実際のint変数を渡すことはできません取り出された。 –

関連する問題