Question

I have a WP C++ Runtime Component that is to be consumed by a C# WP application.

In C++ Runtime Component, I have

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

    };

In C# Application, I have CallbackImp, which implements ICallback. Then I do

CallbackImp cb = new CallbackImp ();
WindowsPhoneRuntimeComponent com = new WindowsPhoneRuntimeComponent();

// Set callback
com.SetCallback(cb);

// Get dictionary
IDictionary<string, object> dict = com.CreateDictionary();

I have the following questions

  1. cb and com are managed objects. So where are the C++/CX objects? I've heard that cb and com point to some C++/CX objects (which reside on native heap), right ?
  2. If cb and com are released by .NET GC, how are C++/CX objects released then?
  3. When I pass cb to the Runtime component, does cb belongs to managed or native heap ?
  4. Where does dict reside? Who will release it?
Was it helpful?

Solution

There is no relationship whatsoever. C++/CX is a pure unmanaged language extension, designed to make interop with WinRT types easy. Which are actually COM types under the hood. The syntax resembles the managed C++/CLI language a lot, mostly because they were designed to solve the same problem, making interop with unmanaged types easy.

Something similar happens in your C# code as well. Much less visibly, your C# component is exposing the managed type as an unmanaged WinRT type. Taking advantage of the language projection built into the CLR. Which in turn takes advantage of the existing COM interop built into the CLR. It is not entirely invisible, you must for example declare your C# class sealed, a restriction brought on by COM only supporting interface inheritance, not implementation inheritance. And various other tidbits, like having to use DateTimeOffset instead of DateTime, a side-effect of the language projection only mapping DateTimeOffset. Etcetera.

So addressing your questions:

  1. There are no C++/CX objects here, they are an implementation detail of the COM server. The underlying low-level api to create WinRT objects is RoCreateInstance(), same animal as the COM CoCreateInstance() function. Which uses a class factory to get the object created. The object is owned by the server, it isn't exposed at all to other code beyond the normal COM interface pointers.
  2. Memory is managed in COM, and thus WinRT, by reference counting. IUnknown::AddRef() adds a reference, IUnknown::Release() releases a reference. The server destroys the object when the last Release call decrements the count to 0. The AddRef() call is automatically generated a ref new or object reference assignment statement in your C++/CX code, Release() is auto-generated by the compiler when your C++/CX reference goes out of scope. Exact same behavior as the CComPtr and _com_ptr_t wrapper classes you'd use in COM code but with the difference that the compiler takes care of it instead of you having to create a smart pointer yourself. With the additional detail that this removes the managed object reference held by the CCW. which, eventually, allows the GC to garbage collect the C# object.
  3. The cb object exists on the GC heap. As noted above, COM exposes only interface pointers, WinRT is completely agnostic of where an object actually lives. The class factory and the IUnknown methods hide that detail
  4. Same as 3.
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top