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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With