5

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?
onmyway133
  • 45,645
  • 31
  • 257
  • 263

1 Answers1

6

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.
Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • 1. When I call new WindowsPhoneRuntimeComponent() in C#, the constructor of the WindowsPhoneRuntimeComponent is called then, so there must be C++/CX object residing somewhere in the native heap ? Also, when I ref new in Runtime component project, I can see the address of that newly created object, so what do you mean by "The object is owned by the server" 2. What do you mean by "when your C++/CX reference goes out of scope"? I personally think that cb and com are in managed heap, so the GC will decide when to release them, and this will lead to the C++/CX objects to be released as well – onmyway133 Jul 11 '13 at 10:54
  • It is fine to put your own mental model on how this works. It is however not a very accurate one. You'll need to understand COM to grok WinRT types. Good luck with it. – Hans Passant Jul 11 '13 at 11:46
  • According to http://social.msdn.microsoft.com/Forums/windowsapps/en-US/d41b7773-d85e-4d1c-97a1-2c8579da62c2/how-does-memory-allocation-work-with-native-winrt-types-in-managed-code "WinRT types get created on the native heap, they are not garbage collected. As you said, they are ref-counted. Whenever a C# or VB caller releases a projected .NET object via a GC collection, the underlying RT object gets its ref count decremented. When the ref count hits 0, its destructor (if any) is called and the memory is deallocated" – onmyway133 Jul 11 '13 at 12:40
  • Sure, if the type is one implemented in WinRT itself. But you were asking about your own. – Hans Passant Jul 11 '13 at 12:48
  • 1
    How are my own classes different? Aren't my C++/CX objects created on the native heap ? – onmyway133 Jul 11 '13 at 13:06
  • We keep going around in circles here, your snippet is creating C# objects. It is important to understand the difference between an object and an interface pointer. This distinction exists in C# as well, you can't create an instance of an interface type. Only of a class that implements the interface. Other code can use the interface reference without having to know anything about the actual object. – Hans Passant Jul 11 '13 at 13:10