2011-01-15 17 views
3

これはC++/CLIの指導者にとっては簡単だと思います。オブジェクトへの単純なデータ型と複雑なデータ型のマーシャリング^%/ void *

高性能なC++ネイティブクラスをC#WinFormsアプリケーションに公開するラッパーを作成しています。 単純な既知のオブジェクトですべてがうまく行きましたし、デリゲートするコールバック関数もラップできます。しかし、今私は少し混乱しています。

ネイティブC++クラスには、次の方法があります:最初は

int GetProperty(int propId, void* propInOut) 

を私はのIntPtrとして*空使うことができると思ったが、その後、私はC#のからそれにアクセスする必要があることが分かりました。

int GetProperty(int propId, Object^ propInOut) 
が、私はC++ソースから見えたとして、私は、メソッドがオブジェクトを変更する必要があることが分かった。だから私は、ラッパー・メソッドについて考えました。だから、明らかに私は必要があります。

int GetProperty(int propId, Object^% propInOut) 

私はラッパーでそれらを扱う方法を知っておく必要がありますので、今、私はネイティブメソッドにオブジェクトを渡すことはできません。呼び出し側は常に彼/彼女は/受信を渡しているデータの種類を知っている必要がありますように、私はラッパーを宣言:

int GetProperty(int propId, int dataType, Object^% propInOut) 

私は、私は次のように、例えば、参照と値の型を渡すためにINTをそれを使用することができますねこの:

Object count = 100; // yeah, I know boxing is bad but this will not be real-time call anyway 
myWrapper.GetProperty(Registry.PROP_SMTH, DATA_TYPE_INT, ref count); 

私はちょうど私が必要とするすべてのデータ型のデータ型定数の束を追加しました:

DATA_TYPE_INT, DATA_TYPE_FLOAT, DATA_TYPE_STRING, DATA_TYPE_DESCRIPTOR, DATA_TYPE_BYTE_ARRAY 

(DATA_TYPE_DESCRIPTORは、2つのフィールドを持つシンプルな構造体です:int型イドとwstringの説明 - この型もラップされるので、マーシャリングは単純なデータの前後コピーです。すべてのネイティブ文字列はUnicodeです)。

ここで、問題は、これらの5つのタイプすべてに対してラッパーメソッドを実装する方法です。 Object ^%を何かにキャストするだけで(int、浮動小数点でも安全です)、ネイティブメソッドに渡すと、いつpin_ptrを使用する必要がありますか、さらに複雑なマーシャリングが必要です。

int GetProperty(int propId, int dataType, Object^% propInOut) 
{ 
    if(dataType == DATA_TYPE_INT) 
    { 
     int* marshaledPropInOut = ??? 
     int result = nativeObject->GetProperty(propId, (void*)marshaledPropInOut); 
     // need to do anything more? 
     return result; 
    } 
else 
    if(dataType == DATA_TYPE_FLOAT) 
    { 
     float* marshaledPropInOut = ??? 
     int result = nativeObject->GetProperty(propId, (void*)marshaledPropInOut); 
     // need to do anything more ? 
     return result; 
    } 
else 
    if(dataType == DATA_TYPE_STRING) 
    { 
     // will pin_ptr be needed or it is enough with the tracking reference in the declaration? 
     // the pointers won't get stored anywhere in C++ later so I don't need AllocHGlobal 
     int result = nativeObject->GetProperty(propId, (void*)marshaledPropInOut); 
     // need to do anything more? 
     return result; 
    } 
else 
    if(dataType == DATA_TYPE_BYTE_ARRAY) 
    { 
     // need to convert form managed byte[] to native char[] and back; 
     // user has already allocated byte[] so I can get the size of array somehow 

     return result; 
    } 
else 
    if(dataType == DATA_TYPE_DESCRIPTOR) 
    { 
     // I guess I'll have to do a dumb copying between native and managed struct, 
     // the only problem is pinning of the string again before passing to the native 

     return result; 
    } 

    return -1; 
} 

P.S.おそらく、このvoid *メソッドを多数のデータ型でラップするためのより洗練されたソリューションがありますか?

答えて

0

C#オブジェクトをvoid *と同じにすることは必ずしも意味をなさないものです。任意のデータをマーシャリングする方法はありません。オブジェクトであっても、C#はその下にある型を認識しており、マーシャリングを行うためにはC++の世界からC#への変換、またはその逆の変換を意味します。データの型を知る必要があります。 void *は完全に未知の型のメモリへのポインタに過ぎないので、型を知る必要があるオブジェクトにどのように変換しますか?

C#の世界から渡される可能性がある記述型の数が限られている場合は、C++/CLIコードでいくつかのオーバーロードを作成し、渡された型を固定し(必要な場合)、void *に変換し、void *を取るC++関数に渡してから、型に応じて元に戻します。

リストのとおりにcase文を実装できますが、渡された型を処理できない場合はどうしますか?C#から関数を呼び出す人は、受け入れ可能な型を知る方法がなく、コンパイラはあなたが何か間違ったことを理解するのを助けることができません。

関連する問題