我有一个要由C#WP应用程序使用的WP C++运行时组件。
在C++运行时组件中,我有
public interface class ICallback
{
public:
virtual void DoSomething();
};
public ref class WindowsPhoneRuntimeComponent sealed
{
public:
WindowsPhoneRuntimeComponent();
void SetCallback(ICallback ^callback);
IMap<Platform::String^, Platform::Object^>^ CreateDictionary();
};
在C#应用程序中,我有实现ICallback
的CallbackImp
。然后我做
CallbackImp cb = new CallbackImp ();
WindowsPhoneRuntimeComponent com = new WindowsPhoneRuntimeComponent();
// Set callback
com.SetCallback(cb);
// Get dictionary
IDictionary<string, object> dict = com.CreateDictionary();
我有以下问题
- cb和com是托管对象。那么C++/CX对象在哪里呢?我已经听说cb和com指向一些C++/CX对象(它们位于在本机堆上),对吧
- 如果cb和com是由.NET GC发布的,那么C++/CX对象如何然后释放
- 当我将cb传递给Runtime组件时,cb是否属于托管还是原生堆
- dict位于何处?谁来发布它
没有任何关系。C++/CX是一个纯非托管语言扩展,旨在简化与WinRT类型的互操作。它们实际上是隐藏在引擎盖下的COM类型。语法与托管C++/CLI语言非常相似,主要是因为它们旨在解决相同的问题,使与非托管类型的互操作变得容易。
类似的事情也发生在您的C#代码中。更不明显的是,您的C#组件将托管类型公开为非托管WinRT类型。利用CLR中内置的语言投影。这反过来又利用了CLR中内置的现有COM互操作。它不是完全不可见的,例如,您必须声明您的C#类sealed,这是COM带来的限制,只支持接口继承,而不支持实现继承。以及其他各种花絮,比如必须使用DateTimeOffset而不是DateTime,这是仅映射DateTimeOffset的语言投影的副作用。等等。
因此,解决您的问题:
- 这里没有C++/CX对象,它们是COM服务器的实现细节。创建WinRT对象的底层api是RoCreateInstance(),与COM CoCreateInstance(()函数相同。它使用类工厂来创建对象。该对象由服务器所有,除了普通的COM接口指针之外,它根本不会暴露给其他代码
- 内存是通过引用计数在COM中管理的,因此在WinRT中也是如此。IUnknown::AddRef()添加引用,IUnkknown::Release()释放引用。当最后一次Release调用将计数减为0时,服务器将销毁对象。AddRef()调用是在C++/CX代码中通过ref new或对象引用赋值语句自动生成的,当C++/CX引用超出范围时,编译器会自动生成Release()。行为与您在com代码中使用的CComPtr和_com_ptr_t包装类完全相同,但不同的是编译器会处理它,而不必自己创建智能指针。这将删除CCW所持有的托管对象引用,并提供其他详细信息。这最终允许GC对C#对象进行垃圾收集
- cb对象存在于GC堆上。如上所述,COM只公开接口指针,WinRT完全不知道对象的实际位置。类工厂和IUnknown方法隐藏了这一细节
- 与3相同