grogroot的这种用法安全吗?

Is this usage of gcroot safe?

本文关键字:安全 用法 grogroot      更新时间:2023-10-16

我需要使用来自c++/CLI的非托管API。这个API存储了一个指向任意用户数据的空指针和一些回调函数。然后它最终调用这些回调函数,将用户数据作为void*.

传入。到目前为止,我有一个本地类传递它的"this"指针作为用户数据,并使用该指针有API回调到这个类,即:
static void __stdcall Callback(void* userData) {
    ((MyType*)userData)->Method();
}
class MyType {
public:
    MyType() { RegisterWithApi((void*)this, Callback); }
    void Method();
};

我正试图用一个托管类来翻译这个。我发现可以使用类型groot在本机代码中安全地存储托管引用,所以我现在是这样做的:

// 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编译器来说似乎很好,但我并不完全放心。据我所知,当它被GC移动时,groot以某种方式跟踪它的托管引用。它会设法做到这一点,而存储为一个void*由非托管代码?这个代码安全吗?

谢谢。

这就是我最终所做的,它工作得很好。groot的目的是在本机堆上存储托管引用,这正是我在这里所做的。

不!正好相反。groot是一个本地类模板。您可以使用它以本机类型存储托管内存的句柄,该本机类型使用clr支持进行编译。您通常将使用它将对本机对象的成员函数的调用转移到存储在ggroot类型成员中的托管对象。

编辑:我昨天在手机上键入代码示例有点尴尬…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)); 
}

您的本机应用程序调用CreateCallback,接收ICallback的实例,当Invoke -d调用托管类型的方法时,在gcroot<System::Action^>中保存…