2013-03-08 17 views
5

C++/CLIのアンマネージAPIを使用する必要があります。このAPIは、任意のユーザーデータといくつかのコールバックに対するvoidポインタを格納します。その後、最終的にそれらのコールバックを呼び出し、ユーザーデータをvoid *として渡します。私がしようとしているgcrootのこの使用法は安全ですか?

static void __stdcall Callback(void* userData) { 
    ((MyType*)userData)->Method(); 
} 

class MyType { 
public: 
    MyType() { RegisterWithApi((void*)this, Callback); } 
    void Method(); 
}; 

を:

これまでのところ私はすなわち、ユーザデータとしての「この」ポインタを渡して、このクラスに戻ってAPI呼び出しを持つようにそのポインタを使用してネイティブクラスを持っていました管理クラスを使用してこれを翻訳します。私は、型gcrootが安全にネイティブコードで管理対象の参照を格納するために使用することができることを見出しので、ここで私は今それをやっている方法は次のとおりです。

// This is called by the native API 
static void __stdcall Callback(void* userData) { 
    // Cast back to gcroot and call into managed code 
    (*(gcroot<MyType^>*)userData)->Method(); 
} 

ref class MyType { 
    gcroot<MyType^>* m_self; 
public: 
    MyType() { 
     m_self = new gcroot<MyType^>; 
     RegisterWithApi((void*)m_self, Callback); 
    } 
    ~MyType() { delete m_self; } 
    // Method we want called by the native API 
    void Method(); 
} 

これはC++/CLIコンパイラへの罰金だが、私はないです完全に再保証されています。私が理解していることから、g​​crootは、GCによって移動されるときに、管理された参照をどうにかして追跡します。管理されていないコードによってvoid *として格納されている間にこれを行うことができますか?このコードは安全ですか?

ありがとうございました。

+1

Marshal :: GetFunctionPointerForDelegate()の例、[ここにあります](http://stackoverflow.com/questions/2972452/c-cli-pass-managed-delegate-to-unmanaged-code/2973278#2973278) ) –

答えて

2

で保持されている管理されたタイプのメソッドを呼び出します。これは私がやったことです。 gcrootの目的は、管理されている参照をネイティブヒープに格納することです。これは私がここでやっていることです。

0

いいえ!これはまったく逆です。 gcrootはネイティブクラスのテンプレートです。 clrサポートでコンパイルされたネイティブ・タイプの管理対象メモリーへのハンドルの保管に使用します。通常はネイティブオブジェクトのメンバ関数への呼び出しをgcroot型のメンバに格納されている管理オブジェクトに転送するために使用します。

編集:私は、コード例を入力すると少し厄介であるモバイル昨日だった... gcroot<T^>の意図と典型的な使用法は、これらの線に沿ってどこかにある:

// ICallback.h 
struct ICallback { 
    virtual void Invoke() = 0; 
    virtual void Release() = 0; 
    protected: 
     ~ICallback() {} 
}; 

が何であるかを、あなたのネイティブアプリケーションやライブラリ参照してください。その後、あなたはICallbackを実装し、gcroot<ManagedType^>でいくつかの管理対象オブジェクトへのハンドルを格納CLRのサポートでコンパイル混合成分があります:あなたのネイティブアプリがCreateCallbackを呼び出す

// Callback.cpp (this translation unit must be compiled with /clr) 
// I did not compile and test, but you get the point... 
template<class T^> class Callback : public ICallback { 
    gcroot<T^> m_Managed; 

    virtual void Invoke() 
    { 
     m_Managed->Invoke(); 
    } 

    virtual void Release() 
    { 
     delete this; 
    } 
public: 
    Callback(T^ p_Managed) : m_Managed(p_Managed) {} 
}; 

__declspec(dllexport) ICallback* CreateCallback() 
{ 
    auto t_Managed = gcnew SomeManagedType(); 
    return new Callback<System::Action^>(
     gcnew System::Action(t_Managed, &SomeManagedType::Method)); 
} 

を、ときInvoke -d ICallbackのインスタンスを受け取りますgcroot<System::Action^> ...

+1

したがって、ネイティブAPIがclrサポートでコンパイルされないという問題がありますか?なぜなら、あなたが言うことはまさに私がやっていることだからです。 – Asik

+0

gcrootを使用するネイティブクラスは、clrサポートでコンパイルする必要があります。私が説明したのは、あなたの質問に示されているものとまったく逆です。管理されたオブジェクトにネイティブgcrootポインタを格納します。 –

+0

さて、gcroot( "コールバック")*を使用する関数はCLRサポートでコンパイルされます。 gcrootは、明らかに許可されているアンマネージヒープに格納されます。どのような違いがあると、マネージクラスはそのクラスへのポインタを保持しますか? – Asik

関連する問題