2009-07-30 29 views
3

私は、C#で最終的に使用するためにC++/CLIでネイティブC++ DLLをラップした状況があります。無効なバリアントクラッシュ

実行時にいくつかの問題を引き起こすコールバック関数がいくつかあります。

がToadWrapTest.dll

で発生したタイプ 'System.Runtime.InteropServices.InvalidOleVariantTypeException' の未処理の例外追加情報:指定されたOLE バリアントが無効である。特に、私は次の例外を取得します。コード(C++/CLI)のこのラインで

public delegate int ManagedCallbackFunction (Object^ inst, const Object^ data); 
public delegate int UnManagedCallbackFunction (void* inst, const void* data); 

ManagedCallbackFunction^ m_callbackFn; 

int intermidiaryCallback(void * pInstance, const void * pData) 
    { 
     void* temp = (void*)pData; 
     System::IntPtr ip1 = IntPtr(pInstance); 
     System::IntPtr ip2 = IntPtr(temp); 
     Object^ oInst = Marshal::GetObjectForNativeVariant(ip1); 
     Object^ oData = Marshal::GetObjectForNativeVariant(ip2); 
     //invoke the callback to c# 
     //return m_callbackFn::Invoke(oInst, oData); 
     return 0; 
    }; 

私は、この「中間のコールバック」を作った理由は、私がしようとしたときにスローされる無効なバリアント例外を回避するための試みでしたデリゲートをC#からネイティブのC++コードに直接マップします。回避策として、私はC#側でデリゲートを宣言し、そのファンクションをC++/CLIラッパーに渡します。私はネイティブC + +に中間funcptrを渡し、呼び出しを一緒にデイジーチェーンします。

私が知っていることは、すべてがネイティブのC++世界で動作することです。問題は、void *を管理された世界にマッピングすることです。次のコードは、コールバックのネイティブC++バージョンを示しています。誰もが、私はそれを本当に感謝し、ここに助けることができる場合

int (*CallbackFunction) (void *inst, const void *data); 

を。

答えて

2

pInstanceとpDataは実際にはVARIANTですか?その場合、私はあなたのコールバック関数がより強く型付けされることを期待します:

int (*CallbackFunction)(VARIANT *inst, VARIANT *data); 

そのような場合、あなたのコードでは、あなたはそれをチェック手に実際VARIANTを見てすることができるはずです。実際にVARIANTを取得していない場合(つまり、実際にvoid *ポインターを取得している場合)、それらに固有の意味がないため、C#オブジェクトに変換しようとすべきではありません。彼らはIntPtrとして渡されるべきです。他の種類の固有の意味があることがわかっている場合は、適切な型としてマーシャリングする必要があります。

+0

コールバックは、サードパーティの開発者が提供するヘッダーで定義されています。もし私がそれをVARIANTに変えることができたら、私はそうするでしょう。 IntPtrをC#に渡して、何が起こるかを見てみよう。アップデート予定... – TomO

2

大きなこの台の台頭!私はこのようなサードパーティーの楽しみに対処しなければならない誰かに、以下の最終的な解決策を投稿しています!私はコードを最適化していないので、自由に批評をしてください。これはまだ解決策を巡っているかもしれません。

まず、コールバック関数になった:

public delegate int ManagedCallbackFunction (IntPtr oInst, IntPtr oData); 
public delegate int UnManagedCallbackFunction (void* inst, const void* data); 
ManagedCallbackFunction^ m_callbackFn; 

ビッグ小道具をこの1に。 void *から直接Object ^にキャストしようとすると、それは単純に機能しません。 IntPtrと私の中間のコールバックを使用する:

int intermidiaryCallback(void * pInstance, const void * pData) 
{ 
    void* temp = (void*)pData; 
    return m_callbackFn->Invoke(IntPtr(pInstance), IntPtr(temp)); 
}; 

我々は最終的に、オブジェクトのいくつかのマッサージでのC#側のワーキングモデルを取得:

public static int hReceiveTestMessage(IntPtr pInstance, IntPtr pData) 
{ 
    // provide object context for static member function 
    helloworld2 hw = (helloworld2)GCHandle.FromIntPtr(pInstance).Target; 
    if (hw == null || pData == null) 
    { 
     Console.WriteLine("hReceiveTestMessage received NULL data or instance pointer\n"); 
     return 0; 
    } 

    // populate message with received data 
    IntPtr ip2 = GCHandle.ToIntPtr(GCHandle.Alloc(new DataPacketWrap(pData))); 
    DataPacketWrap dpw = (DataPacketWrap)GCHandle.FromIntPtr(ip2).Target; 
    uint retval = hw.m_testData.load_dataSets(ref dpw); 
    // display message contents 
    hw.displayTestData(); 

    return 1; 
} 

デリゲートがあるので、私はオブジェクトを「マッサージ」に言及しますこのコールバック関数に固有のものではなく、実行時まで(デリゲートPOVから)どのオブジェクトpDataがあるかわかりません。この問題のため、私はpDataオブジェクトを使って余分な作業をする必要があります。私は基本的には、IntPtrを受け入れるためにラッパーにコンストラクターをオーバーロードしなければなりませんでした。

DataPacketWrap (IntPtr dp) 
{ 
DataPacket* pdp = (DataPacket*)(dp.ToPointer()); 
m_NativeDataPacket = pdp; 
};