Internals (Deep dive) of Metro Application calling WinRT Component DLL

We have created a C++ XAML application that consumes the WinRT C++ DLL in part 1

we have seen the compiler generated components when we compile a WinRT Component DLL.  Part2  discusses how the C# application interacts with the C++ WinRT component.

We have seen the packaging and installation process that happens in the background during building and deploying of the applications here Under the hood Part 3 : WinRT, Windows 8, C++, C#.NET, Metro, WinRT Component DLL

We have seen the C++ XAML application calling the C++ WinRT Component DLL here Under the hood Part 4 : C++ WinRT Component DLL & C++ XAML application – WinRT, Windows 8, C++, Metro

Part5 discusses developing JavaScript application that consumes WinRT Component DLL

Lets dig deeper into how the C++ Application makes  a call across the WinRT Application Binary Interface to access the class methods inside the WinRT DLL. The slide in fig 1 is taken from the build conference which shows the internals of the method calls. We will examine the ABI and how C++ compiler extensions help reference that ABI without exposing the internal details of dealing with COM interfaces and COM activation.

Download the source code from here.

image

Fig 1: Slide showing the flow of the method calls across the boundaries.

A WinRT component implements the IInspectable interface, which is derived from IUnknown. IInspectable is used by the dynamic language bindings from JavaScript. Given a reference to a WinRT component, the JavaScript interpreter can call the IInspectable::GetRuntimeClassName method and obtain the fully-qualified class name of the WinRT component. Using the namespace name the interpreter can ask Windows to load the metadata file (.winmd) describing the component, and from the metadata determine how to use the interfaces implemented by the component.

When WinRT components are accessed from C++ or from .NET languages, there is no need for the IInspectable interface – IUnknown::QueryInterface suffices for all intents and purposes. In fact, .NET “interop” with WinRT relies on simple COM interop – an RCW created by the CLR manages the lifetime of the underlying WinRT component. For C++ language bindings, the story is somewhat more complicated, and the language extensions come into play.

The left side in Fig 1 is the C++ client application code which calls the method in right side WinRT DLL. So here if the method in C++ DLL throws an exception, it should be caught by the C++ application. But it’s not a good practice throw exceptions directly across boundaries.

The left side call (C++ Client App: Consumer) to Add() method causes the compiler to create an inline native to COM wrapper method. Also, on the left hand side, COM HRESULTs are converted to exceptions and COM “retval” arguments are converted to return values. The Add() method makes a call to this wrapper method. This inline methods generated will be something like a COM method that we write in COM components. We can see the source code generated by the compiler using some compiler switch options. we have seen the compiler generated components for making the C# application access the C++ WinRT component here Under the hood Part 2 : C++ WinRT Component DLL & C#.NET Metro application.

From the WinMD file, the C++ application knows the WinRT API signature(shown at the top of the slide) and makes the appropriate call across the WinRT ABI.

HRESULT __stdcall Add(Calculator* this, int i, int j, int * result)

//On the LHS Application, the native to COM Wrapper is as follows (Consumer-side stub pseudo-code) . See the last section of this post to see the compiler generated code. 
inline int Add(int i, int j) {
int res;
HRESULT hr = __cli_Add(this, i, j, &res);
if (hr != 0) {

__throw_hr_as_exception(hr); }
return res;
}

On the right hand side too (C++ Component DLL), C++ compiler generates inline functions. Also, WinRT and C++ exceptions are converted to HRESULTs and return values are converted to “retval” arguments. Note that the only HRESULT, which does not represent an exceptional condition, is S_OK (numeric value 0). No more positive HRESULTs (such as S_FALSE) that need to be checked explicitly by the caller.

//On the RHS C++ Component, COM to Native Wrapper stub pseudo-code is as follows:
HRESULT __stdcall ___cli_Add(Calculator* calc,
int i, int j, int* result) {
try { *result = calc->Add(i, j); }
catch(Platform::Exception^ e) { return e->HResult; }
return S_OK;
}

See the last section of this post to see the compiler generated code.

By the way, the inline wrappers can be called directly, bypassing the C++ language extensions.

image

The C++ language extensions (enabled by the /ZW switch) map WinRT to standard C++ patterns like constructors, destructors, class methods, and exceptions. For example, the language extensions hide the COM-style activation (RoActivateInstance) behind a constructor call (albeit with the ref new keyword), and hide reference counting (IUnknown::AddRef and Release) by automatically managing references. The syntax of these extensions is very similar to C++/CLI

Code Snippet
    CalculatorSample^ calcobj = ref new  CalculatorSample();
    txtAddResult->Text = calcobj->Add(10,20).ToString();

In the above code snippet, you can see we created the object of CalculatorSample class which is present in WinRT C++ Component using ref new. If you know COM, this is something like cocreateinstance() but its more than that. For now, use ref new to create objects of WinRT classes.

Let us see how to skip to exception wrapper and directly calling the Add() method present in WinRT Component. Every function in the class has a low level equivalent inside the class and currently it is prefixed with __cli_ and it takes the output as last parameter. So using ToString() on an integer. So this is another way of calling the methods inside the WinRT components. If we need HResult, we need reference to windows.h. For that include Windows.h in pch.h file as shown below.

Code Snippet
//
// pch.h
// Header for standard system include files.
//

#pragma once

#include <Windows.h>
#include “App.xaml.h”

The complete code to call the WinRT component method is as follows.

Code Snippet
MainPage::MainPage()
{
    InitializeComponent();

    CalculatorSample^ calcobj = ref new  CalculatorSample();
    //txtAddResult->Text = calcobj->Add(10,20).ToString();

    // declare a stack variable to hold the value of the result
    int result;
    //call into  calc object low level __cli_Add() but no intellisense in this preview
    HRESULT hr = calcobj->__cli_Add(10,20,&result);

    //typedef HRESULT (__std

    txtAddResult->Text = result.ToString();
}

 

Another (3rd) way is to use function pointers and call the methods using pointers. Basically, we we can take the calculator^ object, which is a pointer to a pointer to a vtable and reinterpret cast it so that it has a pointer to virtual function, which are vtables. Then we can find out the location of the method we need to call using some compiler switches which I will show below. For the Add function, we are going to specifically pick the sixth function of that and call into it. In the class layout mentioned below, I highlighted the member at 6th location. reinterpret_cast takes the calcobj ^ and cast it to a pointer to a pointer, that’s it. This is how the functions inside the components are called internally at a low level.

Code Snippet
MainPage::MainPage()
{
    InitializeComponent();

    CalculatorSample^ calcobj = ref new  CalculatorSample();
    //txtAddResult->Text = calcobj->Add(10,20).ToString();

    // declare a stack variable to hold the value of the result
    int result;
    //call into  calc object low level __cli_Add() but no intellisense in this preview
    //HRESULT hr = calcobj->__cli_Add(10,20,&result);

    //create a c function that actually represent an ABI call we will be making
    //to add function which takes this pointer, 2 input parameters and an out parameter.
    typedef HRESULT (__stdcall* AddFunc_t) (CalculatorSample^ calc, int i, int j, int * result);
    //now we can take the calculator^ object, which is a pointer to a pointer to a vtable
    //and reinterpret cast it so that it can say ok now i have a pointer of  virtual function
    //which are vtables and i am going to specifically pick the sixth function of that and call into it.
    //reinterpret_cast takes the calcobj ^ and cast it to a pointer to a pointer
    AddFunc_t* addFunc = *reinterpret_cast<AddFunc_t**>(calcobj);
    addFunc[6](calcobj,10,20, &result);

    txtAddResult->Text = result.ToString();
}

Basically a hat is a pointer to a pointer to an array of function pointers, which is Pointer to vptr to vtable. Hat (^) provides automatic reference counting.

To find out the class layout, use the /d1reportSingleClassLayout<class name> compiler switch option. Right click on the WinRTComponent.cpp file in C++ WinRT Component DLL project and select Command Line which is under C/C++. In the Additional Options, mention /d1reportSingleClassLayoutCalculatorSample, click ok and compile the project. See the output window for the magic. There is also another option to see all classes layout by using the option /d1reportAllClassLayout.

image

 

1>—— Rebuild All started: Project: CppWinRTComponentDll, Configuration: Debug Win32 ——
pch.cpp
WinRTComponent.cpp
class __ICalculatorSamplePublicNonVirtuals    size(4):
    +—
    | +— (base class Object)
0    | | {vfptr}
    | +—
    +—

__ICalculatorSamplePublicNonVirtuals::$vftable@:
    | &__ICalculatorSamplePublicNonVirtuals_meta
    |  0
0    | &Object::__cli_QueryInterface
1    | &Object::__cli_AddRef
2    | &Object::__cli_Release
3    | &Object::__cli_GetIids
4    | &Object::__cli_GetRuntimeClassName
5    | &Object::__cli_GetTrustLevel
6    | &__ICalculatorSamplePublicNonVirtuals::__cli_Add
7    | &__ICalculatorSamplePublicNonVirtuals::Add

__ICalculatorSamplePublicNonVirtuals::Add this adjustor: 0
__ICalculatorSamplePublicNonVirtuals::__cli_Add this adjustor: 0

class __CalculatorSampleActivationFactory    size(12):
    +—
    | +— (base class IActivationFactory)
    | | +— (base class Object)
0    | | | {vfptr}
    | | +—
    | +—
    | +— (base class Object)
4    | | {vfptr}
    | +—
8    | __cli_MultiThreadedRefCount __cli_refcount
    +—

__CalculatorSampleActivationFactory::$vftable@Object@:
    | -4
0    | &thunk: this-=4; goto __CalculatorSampleActivationFactory::__cli_QueryInterface
1    | &thunk: this-=4; goto __CalculatorSampleActivationFactory::__cli_AddRef
2    | &thunk: this-=4; goto __CalculatorSampleActivationFactory::__cli_Release
3    | &thunk: this-=4; goto __CalculatorSampleActivationFactory::__cli_GetIids
4    | &thunk: this-=4; goto __CalculatorSampleActivationFactory::__cli_GetRuntimeClassName
5    | &thunk: this-=4; goto __CalculatorSampleActivationFactory::__cli_GetTrustLevel

__CalculatorSampleActivationFactory::$vftable@IActivationFactory@:
    | &__CalculatorSampleActivationFactory_meta
    |  0
0    | &__CalculatorSampleActivationFactory::__cli_QueryInterface
1    | &__CalculatorSampleActivationFactory::__cli_AddRef
2    | &__CalculatorSampleActivationFactory::__cli_Release
3    | &__CalculatorSampleActivationFactory::__cli_GetIids
4    | &__CalculatorSampleActivationFactory::__cli_GetRuntimeClassName
5    | &__CalculatorSampleActivationFactory::__cli_GetTrustLevel
6    | &__CalculatorSampleActivationFactory::__cli_Platform_IActivationFactory____cli_ActivateInstance
7    | &__CalculatorSampleActivationFactory::ActivateInstance

__CalculatorSampleActivationFactory::ActivateInstance this adjustor: 0
__CalculatorSampleActivationFactory::__cli_QueryInterface this adjustor: 0
__CalculatorSampleActivationFactory::__cli_AddRef this adjustor: 0
__CalculatorSampleActivationFactory::__cli_Release this adjustor: 0
__CalculatorSampleActivationFactory::__cli_GetIids this adjustor: 0
__CalculatorSampleActivationFactory::__cli_GetRuntimeClassName this adjustor: 0
__CalculatorSampleActivationFactory::__cli_GetTrustLevel this adjustor: 0
__CalculatorSampleActivationFactory::__cli_Platform_IActivationFactory____cli_ActivateInstance this adjustor: 0

class CalculatorSample    size(12):
    +—
    | +— (base class __ICalculatorSamplePublicNonVirtuals)
    | | +— (base class Object)
0    | | | {vfptr}
    | | +—
    | +—
    | +— (base class Object)
4    | | {vfptr}
    | +—
8    | __cli_MultiThreadedRefCount __cli_refcount
    +—

CalculatorSample::$vftable@__ICalculatorSamplePublicNonVirtuals@:
    | &CalculatorSample_meta
    |  0
0    | &CalculatorSample::__cli_QueryInterface
1    | &CalculatorSample::__cli_AddRef
2    | &CalculatorSample::__cli_Release
3    | &CalculatorSample::__cli_GetIids
4    | &CalculatorSample::__cli_GetRuntimeClassName
5    | &CalculatorSample::__cli_GetTrustLevel
6    | &CalculatorSample::

__cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add
7    | &CalculatorSample::Add

CalculatorSample::$vftable@Object@:
    | -4
0    | &thunk: this-=4; goto CalculatorSample::__cli_QueryInterface
1    | &thunk: this-=4; goto CalculatorSample::__cli_AddRef
2    | &thunk: this-=4; goto CalculatorSample::__cli_Release
3    | &thunk: this-=4; goto CalculatorSample::__cli_GetIids
4    | &thunk: this-=4; goto CalculatorSample::__cli_GetRuntimeClassName
5    | &thunk: this-=4; goto CalculatorSample::__cli_GetTrustLevel

CalculatorSample::Add this adjustor: 0
CalculatorSample::__cli_QueryInterface this adjustor: 0
CalculatorSample::__cli_AddRef this adjustor: 0
CalculatorSample::__cli_Release this adjustor: 0
CalculatorSample::__cli_GetIids this adjustor: 0
CalculatorSample::__cli_GetRuntimeClassName this adjustor: 0
CalculatorSample::__cli_GetTrustLevel this adjustor: 0
CalculatorSample::__cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add this adjustor: 0

Analyzing the layout:

Every WinRT object is laid out in the following way. The first 3 methods in the Vtable are from IUnknown and the next 3 interfaces methods are there for dynamic languages. The important one is GetRuntimeClassName and it allows JavaScript to call into .net  obtain the fully-qualified class name of the WinRT component. When JavaScript calls GetRuntimeClassName, it returns  CppWinRTComponentDll. CalculatorSample. JavaScript then goes and finds out which WinMD file in the system has the classname CppWinRTComponentDll.CalculatorSample. so Windows 8 will inform that it is inside CppWinRTComponentDll.DLL. It then loads the WinMD file of CppWinRTComponentDll.DLL and calls the Add function inside it. In C++, we don’t use these methods as we can directly interact with the class. It doesn’t do dynamic dispatch.

0 | &CalculatorSample::__cli_QueryInterface
1 | &CalculatorSample::__cli_AddRef
2 | &CalculatorSample::__cli_Release

3 | &CalculatorSample::__cli_GetIids
4 | &CalculatorSample::__cli_GetRuntimeClassName
5 | &CalculatorSample::__cli_GetTrustLevel

6 | &CalculatorSample::

__cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add

 

Coming to the calculator class, you notice CalculatorSample is of size 12. The first vprt we have is ICalculatorSamplePublicNonVirtuals and then we have vprt to Object and then the ref count.

class CalculatorSample size(12):
+—
| +— (base class __ICalculatorSamplePublicNonVirtuals)
| | +— (base class Object)
0 | | | {vfptr}
| | +—
| +—
| +— (base class Object)
4 | | {vfptr}
| +—
8 | __cli_MultiThreadedRefCount __cli_refcount
+—

If we analyze the first vptr, it points to ICalculatorSamplePublicNonVirtuals. The layout of the interface is as follows. The first 3 methods are for IUnknown and the other 3 are IInspectable. Notice 6 and 7 are referencing the Add method we wrote in the DLL. There are here for a reason. No 7 is to support compile time inheritance. The C++ can directly call into C++.

CalculatorSample::$vftable@__ICalculatorSamplePublicNonVirtuals@:
| &CalculatorSample_meta
| 0
0 | &CalculatorSample::__cli_QueryInterface
1 | &CalculatorSample::__cli_AddRef
2 | &CalculatorSample::__cli_Release
3 | &CalculatorSample::__cli_GetIids
4 | &CalculatorSample::__cli_GetRuntimeClassName
5 | &CalculatorSample::__cli_GetTrustLevel
6 | &CalculatorSample::__cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add
7 | &CalculatorSample::Add

To understand more, let us use the compiler option. right click on WinRTComponent.cpp and add /d1ZWtokens as shown below and compile the WinRTComponent.cpp class.

image

In the output window, search for __cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add and see the inline code generated by the compiler. This gives us a better understanding of the inner workings of calling the WinRT components.

 

1>—— Build started: Project: CppWinRTComponentDll, Configuration: Debug Win32 ——
1>  WinRTComponent.cpp
1>  Declaring Member 2: __ICalculatorSamplePublicNonVirtuals::Add (int __cdecl CppWinRTComponentDll::__ICalculatorSamplePublicNonVirtuals::Add(int,int)). [isVirtual=1 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __ICalculatorSamplePublicNonVirtuals::__cli_Add (long __stdcall CppWinRTComponentDll::__ICalculatorSamplePublicNonVirtuals::__cli_Add(int,int,int *)). [isVirtual=1 isPure=1 isStatic=0]
1> 
1>  Declaring Member 4a: CalculatorSample::__cli_refcount
1> 
1>  Declaring Member 2: CalculatorSample::__cli_QueryInterface (long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_QueryInterface(class Platform::Guid %,void **)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: CalculatorSample::__cli_AddRef (unsigned long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_AddRef(void)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: CalculatorSample::__cli_Release (unsigned long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_Release(void)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: CalculatorSample::__cli_GetIids (long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_GetIids(unsigned long *,class Platform::Guid **)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: CalculatorSample::__cli_GetRuntimeClassName (long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_GetRuntimeClassName(struct __cli_HSTRING__ **)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: CalculatorSample::__cli_GetTrustLevel (long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_GetTrustLevel(enum __cli_TrustLevel *)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: CalculatorSample::__cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add (long __stdcall CppWinRTComponentDll::CalculatorSample::__cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add(int,int,int *)=long __stdcall CppWinRTComponentDll::__ICalculatorSamplePublicNonVirtuals::__cli_Add(int,int,int *)). [isVirtual=1 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: IActivationFactory::__cli_ActivateInstance (long __stdcall Platform::IActivationFactory::__cli_ActivateInstance(class Platform::Object ^*)). [isVirtual=1 isPure=1 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::ActivateInstance (class Platform::Object ^__thiscall CppWinRTComponentDll::__CalculatorSampleActivationFactory::ActivateInstance(void)). [isVirtual=1 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::CreateFactory (long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::CreateFactory(unsigned int *,struct __cli___classObjectEntry *,class Platform::Guid %,struct __cli_IUnknown **)). [isVirtual=0 isPure=0 isStatic=1]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::GetTargetClassName (const wchar_t *__stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::GetTargetClassName(void)). [isVirtual=0 isPure=0 isStatic=1]
1> 
1>  Declaring Member 4a: __CalculatorSampleActivationFactory::__cli_refcount
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_QueryInterface (long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_QueryInterface(class Platform::Guid %,void **)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_AddRef (unsigned long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_AddRef(void)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_Release (unsigned long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_Release(void)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_GetIids (long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_GetIids(unsigned long *,class Platform::Guid **)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_GetRuntimeClassName (long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_GetRuntimeClassName(struct __cli_HSTRING__ **)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_GetTrustLevel (long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_GetTrustLevel(enum __cli_TrustLevel *)). [isVirtual=0 isPure=0 isStatic=0]
1> 
1>  Declaring Member 2: __CalculatorSampleActivationFactory::__cli_Platform_IActivationFactory____cli_ActivateInstance (long __stdcall CppWinRTComponentDll::__CalculatorSampleActivationFactory::__cli_Platform_IActivationFactory____cli_ActivateInstance(class Platform::Object ^*)=long __stdcall Platform::IActivationFactory::__cli_ActivateInstance(class Platform::Object ^*)). [isVirtual=1 isPure=0 isStatic=0]
1> 
1>  inline function header symbol: {ctor}
1> 
1>  {
1> 
1>   
1> 
1>  }
1> 
1>  inline function header symbol: {ctor}
1> 
1>  {
1> 
1>   
1> 
1>  }
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>   inline int :: CppWinRTComponentDll :: __ICalculatorSamplePublicNonVirtuals :: Add ( int x , int y )
1> 
1>    {
1> 
1>      int __cli_returnValue ;
1> 
1>      long __hr = __cli_Add ( x , y , & __cli_returnValue ) ;
1> 
1>      __cli_WinRTThrowError ( __hr ) ;
1> 
1>      return __cli_returnValue ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    inline long __stdcall :: CppWinRTComponentDll :: CalculatorSample :: __cli_CppWinRTComponentDll___ICalculatorSamplePublicNonVirtuals____cli_Add ( int x , int y , int * __cli_returnValue )
1> 
1>    {
1> 
1>      long __hr = 0 ;
1> 
1>      * __cli_returnValue = 0 ;
1> 
1>      try
1> 
1>      {
1> 
1>        auto __tempValue = Add ( x , y ) ;
1> 
1>        * __cli_returnValue = __tempValue ;
1> 
1>       
1> 
1>      }
1> 
1>      catch ( :: Platform :: Exception ^ __param0 )
1> 
1>      {
1> 
1>        __hr = __param0 -> HResult ;
1> 
1>       
1> 
1>      }
1> 
1>      catch ( … )
1> 
1>      {
1> 
1>        __hr = -2147467259 ;
1> 
1>       
1> 
1>      }
1> 
1>      return __hr ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    long :: CppWinRTComponentDll :: CalculatorSample :: __cli_QueryInterface ( class Platform::Guid % __param0 , void ** __param1 )
1> 
1>    {
1> 
1>      if ( __param0 . Equals ( __uuidof ( __cli_IUnknown ) ) || __param0 . Equals ( __uuidof ( __cli_IInspectable ) ) || __param0 . Equals ( __uuidof ( struct CppWinRTComponentDll::__ICalculatorSamplePublicNonVirtuals ^ ) ) )
1> 
1>      {
1> 
1>        * __param1 = reinterpret_cast < void * > ( static_cast < struct CppWinRTComponentDll::__ICalculatorSamplePublicNonVirtuals ^ > ( this ) ) ;
1> 
1>        __cli_refcount . Increment ( ) ;
1> 
1>        return 0 ;
1> 
1>       
1> 
1>      }
1> 
1>      return -2147467262 ;
1> 
1>     
1> 
1>    }
1> 
1>    unsigned long :: CppWinRTComponentDll :: CalculatorSample :: __cli_AddRef ( )
1> 
1>    {
1> 
1>      long __cli_returnValue = __cli_refcount . Increment ( ) ;
1> 
1>      return ( unsigned long ) __cli_returnValue ;
1> 
1>     
1> 
1>    }
1> 
1>    unsigned long :: CppWinRTComponentDll :: CalculatorSample :: __cli_Release ( )
1> 
1>    {
1> 
1>      long __cli_returnValue = __cli_refcount . Decrement ( ) ;
1> 
1>      if ( ! __cli_returnValue )
1> 
1>      {
1> 
1>        delete this ;
1> 
1>        :: Platform :: Heap :: Free ( reinterpret_cast < void * > ( this ) ) ;
1> 
1>       
1> 
1>      }
1> 
1>      return ( unsigned long ) __cli_returnValue ;
1> 
1>     
1> 
1>    }
1> 
1>    long :: CppWinRTComponentDll :: CalculatorSample :: __cli_GetIids ( unsigned long * __param0 , class Platform::Guid ** __param1 )
1> 
1>    {
1> 
1>      struct __s_GUID __interfaceList [ ] =
1> 
1>      {
1> 
1>       
1> 
1>        {
1> 
1>          -1302793136 , 5274 , 13110 , 160 , 43 , 249 , 241 , 108 , 73 , 159 , 212
1> 
1>        }
1> 
1>       
1> 
1>      } ;
1> 
1>     
1> 
1>      return __winRT :: __winRTRuntime . __getIids ( 1 , __param0 , __interfaceList , __param1 ) ;
1> 
1>     
1> 
1>    }
1> 
1>    long :: CppWinRTComponentDll :: CalculatorSample :: __cli_GetRuntimeClassName ( struct __cli_HSTRING__ ** __param0 )
1> 
1>    {
1> 
1>      return __winRT :: __winRTRuntime . __windowsCreateString ( ( const wchar_t * ) L”CppWinRTComponentDll.CalculatorSample” , 37 , __param0 ) ;
1> 
1>     
1> 
1>    }
1> 
1>    long :: CppWinRTComponentDll :: CalculatorSample :: __cli_GetTrustLevel ( enum __cli_TrustLevel * __param0 )
1> 
1>    {
1> 
1>      * __param0 = __cli_FullTrust ;
1> 
1>      return 0 ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace Platform
1> 
1>  {
1> 
1>    inline class Platform::Object ^ :: Platform :: IActivationFactory :: ActivateInstance ( )
1> 
1>    {
1> 
1>      class Platform::Object ^ __cli_returnValue ;
1> 
1>      long __hr = __cli_ActivateInstance ( & __cli_returnValue ) ;
1> 
1>      __cli_WinRTThrowError ( __hr ) ;
1> 
1>      return __cli_returnValue ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    inline long __stdcall :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_Platform_IActivationFactory____cli_ActivateInstance ( class Platform::Object ^* __cli_returnValue )
1> 
1>    {
1> 
1>      long __hr = 0 ;
1> 
1>      * __cli_returnValue = nullptr ;
1> 
1>      try
1> 
1>      {
1> 
1>        auto __tempValue = ActivateInstance ( ) ;
1> 
1>        * __cli_returnValue = __tempValue ;
1> 
1>       
1> 
1>      }
1> 
1>      catch ( :: Platform :: Exception ^ __param0 )
1> 
1>      {
1> 
1>        __hr = __param0 -> HResult ;
1> 
1>       
1> 
1>      }
1> 
1>      catch ( … )
1> 
1>      {
1> 
1>        __hr = -2147467259 ;
1> 
1>       
1> 
1>      }
1> 
1>      return __hr ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    long :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_QueryInterface ( class Platform::Guid % __param0 , void ** __param1 )
1> 
1>    {
1> 
1>      if ( __param0 . Equals ( __uuidof ( __cli_IUnknown ) ) || __param0 . Equals ( __uuidof ( __cli_IInspectable ) ) || __param0 . Equals ( __uuidof ( struct Platform::IActivationFactory ^ ) ) )
1> 
1>      {
1> 
1>        * __param1 = reinterpret_cast < void * > ( static_cast < struct Platform::IActivationFactory ^ > ( this ) ) ;
1> 
1>        __cli_refcount . Increment ( ) ;
1> 
1>        return 0 ;
1> 
1>       
1> 
1>      }
1> 
1>      return -2147467262 ;
1> 
1>     
1> 
1>    }
1> 
1>    unsigned long :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_AddRef ( )
1> 
1>    {
1> 
1>      long __cli_returnValue = __cli_refcount . Increment ( ) ;
1> 
1>      return ( unsigned long ) __cli_returnValue ;
1> 
1>     
1> 
1>    }
1> 
1>    unsigned long :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_Release ( )
1> 
1>    {
1> 
1>      long __cli_returnValue = __cli_refcount . Decrement ( ) ;
1> 
1>      if ( ! __cli_returnValue )
1> 
1>      {
1> 
1>        delete this ;
1> 
1>        :: Platform :: Heap :: Free ( reinterpret_cast < void * > ( this ) ) ;
1> 
1>       
1> 
1>      }
1> 
1>      return ( unsigned long ) __cli_returnValue ;
1> 
1>     
1> 
1>    }
1> 
1>    long :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_GetIids ( unsigned long * __param0 , class Platform::Guid ** __param1 )
1> 
1>    {
1> 
1>      struct __s_GUID __interfaceList [ ] =
1> 
1>      {
1> 
1>       
1> 
1>        {
1> 
1>          53 , 0 , 0 , 192 , 0 , 0 , 0 , 0 , 0 , 0 , 70
1> 
1>        }
1> 
1>       
1> 
1>      } ;
1> 
1>     
1> 
1>      return __winRT :: __winRTRuntime . __getIids ( 1 , __param0 , __interfaceList , __param1 ) ;
1> 
1>     
1> 
1>    }
1> 
1>    long :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_GetRuntimeClassName ( struct __cli_HSTRING__ ** __param0 )
1> 
1>    {
1> 
1>      return __winRT :: __winRTRuntime . __windowsCreateString ( ( const wchar_t * ) L”CppWinRTComponentDll.__CalculatorSampleActivationFactory” , 56 , __param0 ) ;
1> 
1>     
1> 
1>    }
1> 
1>    long :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: __cli_GetTrustLevel ( enum __cli_TrustLevel * __param0 )
1> 
1>    {
1> 
1>      * __param0 = __cli_FullTrust ;
1> 
1>      return 0 ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    class Platform::Object ^ :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: ActivateInstance ( )
1> 
1>    {
1> 
1>      return gcnew class CppWinRTComponentDll::CalculatorSample ( ) ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    long __stdcall :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: CreateFactory ( unsigned int * , struct __cli___classObjectEntry * , class Platform::Guid % __param2 , struct __cli_IUnknown ** __param3 )
1> 
1>    {
1> 
1>      class CppWinRTComponentDll::__CalculatorSampleActivationFactory ^ __pActivationFactory = gcnew :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory ( ) ;
1> 
1>      return __pActivationFactory -> __cli_QueryInterface ( __param2 , reinterpret_cast < void ** > ( __param3 ) ) ;
1> 
1>     
1> 
1>    }
1> 
1>    const wchar_t * __stdcall :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: GetTargetClassName ( )
1> 
1>    {
1> 
1>      return L”CppWinRTComponentDll.CalculatorSample” ;
1> 
1>     
1> 
1>    }
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
1>  <TokenStream>
1> 
1>  namespace CppWinRTComponentDll
1> 
1>  {
1> 
1>    const struct __cli___classObjectEntry __CalculatorSampleActivationFactory_Registration =
1> 
1>    {
1> 
1>      :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: CreateFactory , :: CppWinRTComponentDll :: __CalculatorSampleActivationFactory :: GetTargetClassName , nullptr , & __cli_no_factory_cache , nullptr
1> 
1>    } ;
1> 
1>   
1> 
1>    extern “C” __declspec ( allocate ( “minATL$__r” ) ) __declspec ( selectany ) const :: __cli___classObjectEntry * const CppWinRTComponentDll___CalculatorSampleActivationFactory__Entry = & __CalculatorSampleActivationFactory_Registration ;
1> 
1>   
1> 
1>  }
1>  </TokenStream>
1> 
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========

 

The complete code of MainPage.xaml.cpp is as follows.

Code Snippet
//
// MainPage.xaml.cpp
// Implementation of the MainPage.xaml class.
//

#include “pch.h”
#include “MainPage.xaml.h”

using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Data;
using namespace CPPApplication1;

using namespace CppWinRTComponentDll;

MainPage::MainPage()
{
    InitializeComponent();

    CalculatorSample^ calcobj = ref new  CalculatorSample();
    //txtAddResult->Text = calcobj->Add(10,20).ToString();

    //// declare a stack variable to hold the value of the result
    int result;
    //call into  calc object low level __cli_Add() but no intellisense in this preview
    //HRESULT hr = calcobj->__cli_Add(10,20,&result);

    //create a c function that actually represent an ABI call we will be making
    //to add function which takes this pointer, 2 input parameters and an out parameter.
    typedef HRESULT (__stdcall* AddFunc_t) (CalculatorSample^ calc, int i, int j, int * result);
    //now we can take the calculator^ object, which is a pointer to a pointer to a vtable
    //and reinterpret cast it so that it can say ok now i have a pointer of  virtual function
    //which are vtables and i am going to specifically pick the sixth function of that and call into it.
    //reinterpret_cast takes the calcobj ^ and cast it to a pointer to a pointer
    AddFunc_t* addFunc = *reinterpret_cast<AddFunc_t**>(calcobj);
    addFunc[6](calcobj,10,20, &result);

    ////CalculatorSample^ calcobj = ref new CalculatorSample();
    ////int* vtable_array = (int*)calcobj;
    ////int* icalc_vtable = (int*)vtable_array[0];
    ////int* compute_will_be_fptr = (int*)icalc_vtable[6];
    ////typedef HRESULT (__stdcall *compute_fptr_t)(CalculatorSample^, int, int, int*);
    ////compute_fptr_t compute_fptr = (compute_fptr_t)compute_will_be_fptr;
    ////compute_fptr(calcobj,10,20, &result);

    txtAddResult->Text = result.ToString();
}

MainPage::~MainPage()
{
}

 

Download the source code from here.

“If you limit your choices only to what seems possible or reasonable, you disconnect yourself from what you truly want, and all that is left is a compromise.”