美文网首页
通过GCHandle在native class内部保存一个man

通过GCHandle在native class内部保存一个man

作者: 左图右码 | 来源:发表于2021-07-11 15:40 被阅读0次

一般是通过gcroot<>或者auto_gcroot<>来完成这个工作.但也可以直接用GCHandle来实现。
其实,gcroot<>本身也是这么实现的。

using namespace System;
using namespace System::Runtime::InteropServices;
#pragma managed

class StringWrapper {  //native class
    IntPtr m_handle;
public:
    StringWrapper() {
    String ^ str = gcnew String("ManagedString");
    m_handle = static_cast<IntPtr>(GCHandle::Alloc(str));
    }
~StringWrapper() {
    static_cast<GCHandle>(m_handle).Free();
    }
void PrintString() {
    // Target是Object^,在此拆箱
    String ^ targetStr = safe_cast<String^>(static_cast<GCHandle>(m_handle).Target); 
    Console::WriteLine("StringWrapper::m_handle == {0}", targetStr);
    }
};
#pragma unmanaged

int main() {
    StringWrapper s;
    s.PrintString();
}

GCHandle和IntPtr有默认和显式的转换函数:

public static explicit operator GCHandle(IntPtr value);
public static GCHandle FromIntPtr(IntPtr value);
public static explicit operator IntPtr(GCHandle value);

这是因为GCHandle每次Alloc后,会将新的GCHandle的地址记录在内部的静态s_cookieTable上进行记录,转化的IntPtr就是它的地址,在GCHandle::Free的时候会从这个cook上删除。因为有个这个类级别的数据,GC才能通过它知道并忽略这些Object^的回收。
private static GCHandleCookieTable s_cookieTable;

pin_ptr应该采用了类似的技术,不过是在编译器级别进行了实现(从pin_ptr来看,它仅仅是定义了类型,具体的实现都是隐藏的,在编译器级别进行了行为的定义):�

template<typename T>
class pin_ptr
{
    T* operator*();
};

在你的工具箱里,GCHandle在混合编程领域,应该是个利器。

相关文章

网友评论

      本文标题:通过GCHandle在native class内部保存一个man

      本文链接:https://www.haomeiwen.com/subject/fpvkpltx.html