5

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

これまでのところ、ネイティブクラスがその「this」ポインタをユーザーデータとして渡し、そのポインタを使用してAPIをこのクラスに呼び戻す必要がありました。

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

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

マネージドクラスを使用してこれを翻訳しようとしています。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*として保存されている間、これを実行できますか?このコードは安全ですか?

ありがとう。

4

2 に答える 2

2

これは私がやったことであり、完全に機能します。gcroot の目的は、マネージ参照をネイティブ ヒープに格納することです。これはまさに、ここで行っていることです。

于 2013-04-04T02:35:49.597 に答える
0

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

編集: 私は昨日、モバイルでコード例を入力するのが少し厄介でした... の意図的で典型的な使用法は、gcroot<T^>次の行のどこかにあります:

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

それが、ネイティブ アプリまたはライブラリが参照し、含めるものです。次に、CLR サポートを使用してコンパイルされた混合コンポーネントがあり、管理対象オブジェクトへのハンドルを実装ICallbackして に格納しますgcroot<ManagedType^>

// 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)); 
}

ネイティブ アプリが を呼び出し、 -d がマネージド型のメソッドを呼び出したときにCreateCallbackそのインスタンスを受け取り、...に保持されます。ICallbackInvokegcroot<System::Action^>

于 2013-03-08T21:31:21.247 に答える