We have developed a C++ WinRT Component DLL & C#.NET application in the post here:
The important point here is that the C# application is accessing the C++ WinRT component through RCW mechanism. The same application can be developed with JavaScript also that can use the C++ DLL that we developed. Wow, cool right?
To understand the simplicity of the new programming model, we created a C++ WinRT Component DLL in part 1, which is all the code you need to author a Windows Runtime component.
Please download the code and extract the files.
#pragma once
using namespace Windows::Foundation;
namespace CppWinRTComponentDll
{
public ref class CalculatorSample sealed
{
public:
int Add(int x, int y);
int Sub(int x, int y);
int Mul(int x, int y);
};
}
In this example, you will immediately notice some keywords that are not part of standard C++. Visual C++ defines a few Component Extensions that, in a Metro style app, are essentially syntactic sugar over the underlying COM calls involved in creating and consuming Windows Runtime types. You typically use these extensions in the public interface
s where your code is passing Windows Runtime types back and forth across the ABI to JavaScript, C#, or Visual Basic (or even another C++ module). Visual C++ provides a variety of implicit conversions between Windows Runtime types and standard C++ types. The typical pattern is to use standard C++ types and libraries internally as usual, and convert to Windows Runtime types in the public interface
s.
So how did the C++ component get pulled into .NET application? When we build the CppWinRTComponentDll
project, we see the following in the output window. Notice the highlighted CppWinRTComponentDll.winmd
text. This means the compiler is generating a file of type windmd
.
1>—— Build started: Project: CppWinRTComponentDll, Configuration: Debug Win32 ——
1> CppWinRTComponentDll.vcxproj ->
C:\Users\Kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll With
CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.winmd
1> LINK : C:\Users\kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll
With CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.dll not found or
not built by the last incremental link; performing full link
1> Creating library C:\Users\kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll
With CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.lib and object
C:\Users\kishore\Documents\Visual Studio 11\Projects\CppWinRTComponentDll With
CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.exp
1> CppWinRTComponentDll.vcxproj -> C:\Users\kishore\Documents\Visual Studio 11\
Projects\CppWinRTComponentDll With CSharp App\Debug\CppWinRTComponentDll\CppWinRTComponentDll.dll
========== Build: 1 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
You can notice the CppWinRTComponentDll.winmd file in the debug folder (CppWinRTComponentDll
With CSharp App\Debug\CppWinRTComponentDll) as shown in Figure 1.
Figure 1: .WinMD File present in CppWinRTComponentDll folder inside the Debug folder.
This WinMD file is essentially a CLI meta data file and can be opened in ILDASM as shown in figure 2. CppWinRTComponentDll
is exposed using API metadata present in CppWinRTComponentDll.winmd file. The format of WinMD file is Ecma-335 and this is the same format used by the .NET Framework. It just used the ECMA-335 file format standard & the framework and nothing more than that. The underlying binary contract makes it easy for us to access the CppWinRTComponentDll
APIs directly in the development language of our choice. The shape and structure of the CppWinRTComponentDll
APIs can be understood by both static languages such as C# and dynamic languages such as JavaScript. IntelliSense is available in JavaScript, C#, Visual Basic, and C++ as you can see in the C# application (CSharpApplication
project).
Figure 2: Opening CppWinRTComponentDll.winmd file using ILDASM.
This CppWinRTComponentDll.winmd file is created by C++ compiler and this can be seen as a cross language header file because C# cannot understand C++ header and neither JavaScript. So we need to have the file format that all languages understand and that is the .winmd file format. Although we authored a CalculatorSample
class, what the compiler did for us is that, it also created an interface __ICalculatorSamplePublicNonVirtuals
as shown in figure 3, which is the com interface used to talk to the calculator
class. This adds it to the public surface.
Figure 3: Interface ICalculatorSamplePublicNonVirtuals created by the compiler
Manifest of the CppWinRTComponentDll.winmd file can be seen in figure 4.
Figure 4: Manifest of the CppWinRTComponentDll.WinMD File. Note the first entry, mscorlib.
We can see the Add
method signature stored in the WinmD file in figure 5.
Figure 5: Add method signature present in CppWinRTComponentDll.winmd file.
.method public newslot abstract virtual instance int32
Add(int32 x,
int32 y) cil managed
{
}
In the ILDASM, click on the .class interface private abstract
auto ansi windowsruntime
. The GUID attribute. this is like specifying the GUID of the interface as shown in figure 6. This is the GUID for the component.
Fig 6: GUID of the interface.
The WinMD file does not contain any IL. This is just like a header information so that other languages can understand. This makes the Projections happen. The calculator
is a ref class
itself. The CppWinRTComponentDll.CalculatorSample
class implements from .__ICalculatorSamplePublicNonVirtuals
and it implements Add
, Sub
and Mul
methods as shown in the following figure 7.
Fig 7: CppWinRTComponentDll.CalculatorSample class implements from __ICalculatorSamplePublicNonVirtuals Interface.
Note that every object inside WinRT is ref
counted.
Details about the C++ WinRT Component DLL created in part 1 (MSDN): C++/CX (Component Extensions)
Visual C++ in Visual Studio 11 has a new programming model for creating Metro style apps and components. One of the primary features of the new model is the abstract binary interface, or ABI, which defines an interface for inter-language communication. In Windows Developer Preview, native C++ can communicate across the ABI with JavaScript and with the managed .NET languages C# and Visual Basic. This means you can create high-performance components in native C++ and consume them directly from one of these other languages. It also means you can consume Windows Runtime types directly in native C++, without having to interop with a managed layer as when you consume .NET Framework types.
At a low level, the new programming model is based on an updated version of COM, but the way that you program against this new model is more simple and natural than old-style COM programming. When you create a consumable Windows Runtime components or Metro style apps in native C++, you work primarily with classes and members just as in standard C++. JavaScript or .NET code instantiates your object by using new (or New) and the object is destroyed according to the mechanisms of the client language. When native C++ consumes a Windows Runtime object, destruction is handled by means of reference counting.
Download the code and extract the files.
"Cultivate optimism by committing yourself to a cause, a plan or a value system. You’ll feel that you are growing in a meaningful direction which will help you rise above day-to-day setbacks." — Dr. Robert Conroy
Note: The code is developed using Windows 8 & Visual Studio 2011 developer preview, which might change when the actual versions are released.