This document shows how to use the Windows Runtime C++ Template Library (WRL) to create a basic Windows Runtime component. The component adds two numbers and raises an event when the result is prime. This document also demonstrates how to use the component from a Windows Store app that uses JavaScript.
-
Experience with the Windows Runtime.
-
Experience with COM.
To create a basic Windows Runtime component that adds two numbers
-
In Visual Studio, create a Visual C++ WRLClassLibrary project. The document WRL Class Library Project Template describes how to download this template. Name the project Contoso.
-
In Contoso.cpp and Contoso.idl, replace all instances of "WinRTClass" with "Calculator".
-
In Contoso.idl, add the Add method to the ICalculator interface.
HRESULT Add([in] int a, [in] int b, [out, retval] int* value);
-
In Contoso.cpp, add the Add method to the public section of the Calculator class.
HRESULT __stdcall Add(_In_ int a, _In_ int b, _Out_ int* value) { if (value == nullptr) { return E_POINTER; } *value = a + b; return S_OK; }
Important
Because you’re creating a COM component, remember to use the __stdcall calling convention.
We recommend that you use _Out_ and other source annotation language (SAL) annotations to describe how a function uses its parameters. SAL annotations also describe return values. SAL annotations work with the C/C++ Code Analysis tool to discover possible defects in C and C++ source code. Common coding errors that are reported by the tool include buffer overruns, uninitialized memory, null pointer dereferences, and memory and resource leaks.
To use the component from a Windows Store app that uses JavaScript
-
In Visual Studio, add a new JavaScript Blank App project to the Contoso solution. Name the project CalculatorJS.
-
In the CalculatorJS project, add a reference to the Contoso project.
-
In default.html, replace the body section with these UI elements:
<div> <input id="a" /> <input id="b" /> <p id="result">Result:</p> <button onclick="Add()">Add</button> </div>
-
In default.js, implement the OnClick function.
function Add() { "use strict"; var calculator = new Contoso.Calculator(); var a = document.getElementById("a"); var b = document.getElementById("b"); document.getElementById("result").innerHTML = "Result: " + calculator.add(a.value, b.value); }
Note
In JavaScript, the first letter of a method name is changed to lowercase to match the standard naming conventions.
To add an event that fires when a prime number is calculated
-
In Contoso.idl, before the declaration of ICalculator, define the delegate type, PrimeNumberEvent, which provides an int argument.
[uuid(3FBED04F-EFA7-4D92-B04D-59BD8B1B055E), version(COMPONENT_VERSION)] delegate HRESULT PrimeNumberEvent(int primeNumber);
When you use the delegate keyword, the MIDL compiler creates an interface that contains an Invoke method that matches that delegate's signature. In this example, the generated file Contoso_h.h defines the IPrimeNumberEvent interface, which is used later in this procedure.
MIDL_INTERFACE("3FBED04F-EFA7-4D92-B04D-59BD8B1B055E") IPrimeNumberEvent : public IUnknown { public: virtual HRESULT STDMETHODCALLTYPE Invoke( int primeNumber) = 0; };
-
In the ICalculator interface, define the PrimeNumberFound event. The eventadd and eventremove attributes specify that the consumer of the ICalculator interface can both subscribe to and unsubscribe from this event.
[eventadd] HRESULT PrimeNumberFound( [in] PrimeNumberEvent* eventHandler, [out, retval] EventRegistrationToken* eventCookie); [eventremove] HRESULT PrimeNumberFound( [in] EventRegistrationToken eventCookie); -
In Contoso.cpp, add a private Microsoft::WRL::EventSource member variable to manage the event subscribers and invoke the event handler.
EventSource<IPrimeNumberEvent> m_events;
-
In Contoso.cpp, implement the add_PrimeNumberFound and remove_PrimeNumberFound methods.
HRESULT __stdcall add_PrimeNumberFound(_In_ IPrimeNumberEvent* event, _Out_ EventRegistrationToken* eventCookie) { return m_events.Add(event, eventCookie); } HRESULT __stdcall remove_PrimeNumberFound(_In_ EventRegistrationToken eventCookie) { return m_events.Remove(eventCookie); }
To raise the event when a prime number is calculated
-
In Contoso.cpp, add the IsPrime method to the private section of the Calculator class.
// Determines whether the input value is prime. bool IsPrime(int n) { if (n < 2) { return false; } for (int i = 2; i < n; ++i) { if ((n % i) == 0) { return false; } } return true; }
-
Modify the Calculator’s Add method to call the Microsoft::WRL::EventSource::InvokeAll method when a prime number is calculated.
HRESULT __stdcall Add(_In_ int a, _In_ int b, _Out_ int* value) { if (value == nullptr) { return E_POINTER; } int c = a + b; if (IsPrime(c)) { m_events.InvokeAll(c); } *value = c; return S_OK; }
To handle the event from JavaScript
-
In default.html, modify the body section to include a text area that contains prime numbers.
<div> <input id="a" /> <input id="b" /> <p id="result">Result:</p> <p id="primes" style="color:#808080">Primes found:</p> <button onclick="Add()">Add</button> </div>
-
In default.js, modify the Add function to handle the PrimeNumberFound event. The event handler appends the prime number to the text area that was defined by the previous step.
function Add() { "use strict"; var calculator = new Contoso.Calculator(); calculator.onprimenumberfound = function (ev) { document.getElementById("primes").innerHTML += " " + ev.target; }; var a = document.getElementById("a"); var b = document.getElementById("b"); document.getElementById("result").innerHTML = "Result: " + calculator.add(a.value, b.value); }
Note
In JavaScript, the event names are changed to lower-case and are prepended with "on" to match the standard naming conventions.
The following illustration shows the basic Calculator app.