我想创建一个C++类,该类封装对win窗体应用程序中存在的托管对象的引用,以便可以从两个方面(C#和C++)对其进行操作。
此对象将从C++异步访问。为此,我想在本机代码中存储对该托管对象的引用。我知道GC可以收集它,所以我读到我应该在托管代码中的某个地方引用它来防止这种情况。
我的问题是:是否可以将对托管对象的引用存储在本机DLL中(不使用CLI/CLR),并使用它异步调用方法?如果是,传递对象的语法是什么?另外,那个托管对象的方法呢?我是否还需要在本机代码中存储对它们的引用?
谢谢。:)
我写这篇文章是希望David Heffernan能纠正我并教我一些东西:-)
正如我在评论中所写:
我的问题是:是否可以将对托管对象的引用存储在本机DLL中(不使用CLI/CLR)
在某种程度上,您必须告诉CLR您不希望收集对象。您可以在静态属性中保留引用,可以直接用GCHandle
将其固定,也可以使用COM,但事实是您必须告诉CLR。
使用COM对象很复杂(至少对我来说:-)。
我会做什么:
给定一个MyClass
,在C#端创建一个对象,在DoSomething
方法中,我想同时使用C#和C++端。
public class MyClass
{
public string Name;
public string Surname;
public bool DoSomething(int value1, int value2)
{
return Name.Length == value1 || Surname.Length == value2;
}
}
我会创建这样的MyProxyClass
:
public class MyProxyClass
{
private delegate void FreeMeDelegate();
[return:MarshalAs(UnmanagedType.I1)]
private delegate bool DoSomethingDelegate(int value1, int value2);
private GCHandle Handle;
private DoSomethingDelegate DoSomething { get; set; }
// You pass this function pointer to C++. Its signature is:
// bool(__stdcall *DoSomething)(int32_t, int32_t)
public IntPtr DoSomethingPtr { get; private set; }
private FreeMeDelegate FreeMe { get; set; }
// You have to pass this function too to C++. C++ code must use it
// to free MyProxyClass. Its signature is:
// void (__stdcall *FreeMe)(void)
public IntPtr FreeMePtr { get; private set; }
public void FreeMeImpl()
{
if (Handle.IsAllocated)
{
Handle.Free();
DoSomething = null;
DoSomethingPtr = IntPtr.Zero;
FreeMe = null;
FreeMePtr = IntPtr.Zero;
}
}
public MyProxyClass(MyClass obj)
{
Handle = GCHandle.Alloc(this, GCHandleType.Normal);
// This will implicitly create a reference to obj. GC can't
// collect MyProxyClass because we have a GCHandle on it,
// and can't collect obj because there is a delegate that
// has a reference on it.
DoSomething = obj.DoSomething;
DoSomethingPtr = Marshal.GetFunctionPointerForDelegate(DoSomething);
FreeMe = FreeMeImpl;
FreeMePtr = Marshal.GetFunctionPointerForDelegate(FreeMe);
}
}
这个类在创建时会自动阻止GC收集她。然后创建一些IntPtr
委托给方法DoSomething
和FreeMe
,C++代码需要使用这些方法来释放它
现在,C#端:
MyClass myclass = ...; // you instance of myclass
var proxy = new MyProxyClass(myclass);
// Now you pass these to C++
//proxy.DoSomethingPtr;
//proxy.FreeMePtr;