Category Archives: Under the hood Part 5 : JavaScript App & C++ WinRT DLL

Under the hood Part 5 : JavaScript application & C++ WinRT Component DLL – WinRT, Windows 8, C++, Metro

JavaScript application calling WinRT Component DLL

In this part, we will create a C++ WinRT Component DLL and access it from a JavaScript application.

We have developed a C++ WinRT Component DLL & C#.NET application in the post here Under the hood Part 1 : C++ WinRT Component DLL & C#.NET Metro application

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

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

Generally, in a LOB application, we might have to build a C++ Component DLL to take advantage of the performance of C++ in complex or computationally-intensive operations. The C++ component can access Windows operating system services that are not accessible through the Windows Runtime in the current version. Mostly, to reuse existing code that is already written and tested.

Download the source code here.

Step 1:

Create a Windows Runtime C++ Component DLL:

Open Visual Studio 2011 –> File –> New Project –> Go to Installed Templates section –> Visual C++ –>Select WinRT Component DLL and name it as CPPWinRTComponentDll as shown in the following figure.

image

Fig 1: CPPWinRTComponentDll project

Open WinRTComponent.h file and create an Employee class as shown in the following code snippet. The Platform namespace is where C++ defines its classes that are specific Windows Runtime types.

Create a private variables address_ and employeeid_. These are used as backing store to hold the values. We will use get() & set() properties to set or get these values.

    private:
            // Backing store for property address_ & employeeid_.
            Platform::String^ address_;
            int employeeid_;

 

In the public section, add the following code which are properties for the above backing store.

        property Platform::String^ Address
        {
            Platform::String^ get()
            {
                return  (address_);
            }
        }

        // Property with custom setter/getter
        property int EmployeeId
        {
            int get()
            {
                return employeeid_;
            }

            //    ‘set’ accessor is missing its value parameter
            void set(int value)
            {
                if(value <= 0)
                {
                    throw ref new Platform::InvalidArgumentException();
                    employeeid_ = value;
                }
            }
        }

 

We can also add some trivial get/set property with the compiler generating the backing store.

    public:
        // Trivial get/set property with compiler-generated backing store.
        property Platform::String^ Name;

 

Following is the complete code of the Employee class.

Code Snippet
public ref class Employee sealed
    {
    private:
            Platform::String^ address_;
            int employeeid_;
           
            //If i use a stack syntax, i get compilation error
            //Platform::String address2_;
            //Error    1    error C3149: ‘Platform::String’ : cannot use this type here without a top-level ‘^’   
            //c:\projects\cppwinrtcomponentdll with cpp app string\cppwinrtcomponentdll\winrtcomponent.h   

    public:

        property Platform::String^ Name;
        property Platform::String^ Address
        {
            Platform::String^ get()
            {
                return  (address_);
            }
        }

        property int EmployeeId
        {
            int get()
            {
                return employeeid_;
            }

            //    ‘set’ accessor is missing its value parameter
            void set(int value)
            {
                if(value <= 0)
                {
                    throw ref new Platform::InvalidArgumentException();
                    employeeid_ = value;
                }
            }
        }

    public:
        Platform::String^ SayHello()
        {
            return "Hello World";
        }

    public:
        int Add(int x, int y)
        {
            return x+y;
        }

    };

 

When you code your C++ component, if needed, you can use the regular C++ library and built-in types inside the class code except at the abstract binary interface (ABI) boundary where you are passing data to and from JavaScript. There, use Windows Runtime types and the special syntax that Visual C++ supports for creating and manipulating those types.

You have to make the Employee class as activatable class so that it can instantiated from another language such as JavaScript. To be consumable from another language such as JavaScript, a component must contain at least one activatable class. If needed, a Windows Runtime component can contain multiple activatable classes as well as additional classes known only internally to the component. Client code creates an instance of the component by using the new keyword just as for any class.

The Employee class must be declared as public ref class sealed. The ref class keywords tell the compiler to create the class as a Windows Runtime compatible type, and the sealed keyword specifies that the class cannot be inherited. A class must be sealed to be consumed by JavaScript.

In the Platform::String^ address_, the ^ operator signifies a handle to a Windows Runtime string type that under the covers is reference-counted and deleted when the count reaches zero. Instances of these types are created by using the ref new keywords. Do not explicitly call delete on these instances.

Types must be passed to and from the public methods as Windows Runtime types. If you use the C++ built-in types such as int, double and so on, the compiler will automatically convert them to the appropriate Windows Runtime type. No such conversion occurs unless you are passing the type across the ABI. Complex types such as Platform::String^ must be specified explicitly.

Step 2:

Creating a JavaScript Windows Metro style Application project:

To create a project in this solution, right-click the solution node in Solution Explorer. and select Add Project > Blank Application. Name it as WinWebApp1.

image

Fig 2: creating the JavaScript project
Add a reference to the component project

After you have compiled the C++ project for the first time, you can add it as a project reference in the JavaScript project. Right-click the References node in the JavaScript project, and select Add. When the Add References Manager dialog box appears, click “Solution” to display the available references in the solution. Select  “CPPWinRTComponentDll ” in this solution and click on Add button as shown in figure 3; The namespace and all public types and methods are now available to your JavaScript code. You can verify this by experimenting with the Member List or Statement Completion feature in the JavaScript file.

image

Fig 3: Adding reference to the C++ WinRT Component DLL.
Add the HTML markup that invokes JavaScript.

Add the following HTML into the <body> node of the default.html page

<body>
    <button id="callwinrt" onclick="CallWinRT()">Call WinRT</button>
<p></p>
    <label id ="Label1" style="background-color: grey;">Activation Object Result ->  </label><label id ="loaded" style="background-color: #51B65A;"></label>
    <p></p>
     <label id ="Label2" style="background-color: grey;">Calling Employee::SayHello() method     </label><label id ="callmethod" style="background-color: #51B65A;"></label>
    <p></p>
     <label id ="Label3" style="background-color: grey;" >Getting  Employee.Name Property value    </label><label id ="retrievedproperty" style="background-color: #51B65A;"></label>
    <p></p>

</body>

 

The default.html page appears as following.

Code Snippet
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>WinWebApp1</title>
    <!– WinJS references –>
    <link rel="stylesheet" href="/winjs/css/ui-dark.css" />
    <script src="/winjs/js/base.js"></script>
    <script src="/winjs/js/wwaapp.js"></script>
    <!– WinWebApp1 references –>
    <link rel="stylesheet" href="/css/default.css" />
    <script src="/js/default.js"></script>
</head>
<body>
    <button id="callwinrt" onclick="CallWinRT()">Call WinRT</button>
<p></p>
    <label id ="Label1" style="background-color: grey;">Activation Object Result ->  </label><label id ="loaded" style="background-color: #51B65A;"></label>
    <p></p>
     <label id ="Label2" style="background-color: grey;">Calling Employee::SayHello() method     </label><label id ="callmethod" style="background-color: #51B65A;"></label>
    <p></p>
     <label id ="Label3" style="background-color: grey;" >Getting  Employee.Name Property value    </label><label id ="retrievedproperty" style="background-color: #51B65A;"></label>
    <p></p>

</body>
</html>

 

Add the JavaScript event handlers that call into the component DLL

Add the following function CallWinRT() at the end of the default.js file. This function is called when you click the button “Call WinRT” on the main page. Notice how JavaScript activates the C++ class, and then calls its methods and populates the HTML labels with the return values.

function CallWinRT() {
    // activate the native Windows Runtime component
    var nativeObject = new CppWinRTComponentDll.Employee();
    document.getElementById(‘loaded’).innerHTML = nativeObject;

    //call a method
    var num = nativeObject.sayHello();
    document.getElementById(‘callmethod’).innerHTML = num;

    nativeObject.name = "Kishore Babu";

    // get the value of the string property
    var propValue = nativeObject.name;
    document.getElementById(‘retrievedproperty’).innerHTML = propValue;
}

 

The complete code of default.js file is as follows.

Code Snippet
(function () {
    ‘use strict’;
    // Uncomment the following line to enable first chance exceptions.
    // Debug.enableFirstChanceException(true);

    WinJS.Application.onmainwindowactivated = function (e) {
        if (e.detail.kind === Windows.ApplicationModel.Activation.ActivationKind.launch) {
            // TODO: startup code here
        }
    }

    WinJS.Application.start();
})();

function CallWinRT() {
    // activate the native Windows Runtime component
    var nativeObject = new CppWinRTComponentDll.Employee();
    document.getElementById(‘loaded’).innerHTML = nativeObject;

    //call a method
    var num = nativeObject.sayHello();
    document.getElementById(‘callmethod’).innerHTML = num;

    nativeObject.name = "Kishore Babu";

    // get the value of the string property
    var propValue = nativeObject.name;
    document.getElementById(‘retrievedproperty’).innerHTML = propValue;
}

 

Build the solution & deploy the application. If you go to start window, you will find an application WinWebApp1. Click on it.

image

Click on call WinRT button. The values from the C++ DLL are returned and set in the JavaScript application as shown in the following figure.

image

When you build a solution that contains a JavaScript project and a Windows Runtime Component DLL project, the JavaScript project files and the compiled DLL are merged into one package, which you can then deploy locally or remotely for testing or submit to the Windows Store. You can also distribute just the component project as an Extension SDK.

Debugging: When you debug a JavaScript solution that has a component DLL, you can set the debugger to enable either stepping through script, or stepping through native code in the component, but not both at the same time. To change the setting, right-click the JavaScript project node in Solution Explorer, then select Properties > Debugging > Debugger Type.

Be sure to select appropriate capabilities in the package designer. For example, if you are attempting to open a file using the Windows Runtime APIs, be sure to select the Document Library Access checkbox in the Capabilities pane of the package designer.

Download the source code here.

As a C++ developer, I find this useful. If you are a C++ developer and new to JavaScript, you sometimes make the mistake of not using the camel-casing in JS. If your JavaScript code does not seem to be recognizing the public properties or methods in the component, make sure that in JavaScript you are using camel-casing. For example, the Platform::String^ SayHello() C++ method must be referenced as sayHello() in JavaScript.

"The task of the leader is to get his people from where they are to where they have not been." — Henry Kissinger