Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is this usage of gcroot safe?

I need to use an unmanaged API from C++/CLI. This API stores a void pointer to arbitrary user data and a few callbacks. It then eventually calls those callbacks, passing the user data in as void*.

So far I had a native class passing its "this" pointer as the user data, and using that pointer to have the API call back into this class, i.e.:

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

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

I'm trying to translate this using a managed class. I found that the type gcroot can be used to safely store a managed reference in native code, so here's how I'm doing it now:

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

While this seems fine to the C++/CLI compiler, I am not perfectly re-assured. From what I understand, gcroot somehow keeps track of its managed reference as it is moved by the GC. Will it manage to do this while stored as a void* by unmanaged code? Is this code safe?

Thanks.

like image 935
Asik Avatar asked Nov 04 '22 03:11

Asik


1 Answers

This is what I ended up doing and it works perfectly. The purpose of gcroot is to store a managed reference on the native heap, which is precisely what I'm doing here.

like image 79
Asik Avatar answered Nov 12 '22 17:11

Asik