Interoperating between JavaScript and C++ in the Bing Maps Trip Optimizer sample
Bing Maps Trip Optimizer uses JavaScript to define the UI and C++ to perform the trip optimization. This document describes how the JavaScript and C++ parts of the Bing Maps Trip Optimizer sample interoperate. It describes how the JavaScript component initializes the C++ component and sends data to it, and how the C++ component sends data back to the JavaScript component. The individual JavaScript and C++ components are described in greater detail in the documents Using JavaScript in the Bing Maps Trip Optimizer sample and Using C++ in the Bing Maps Trip Optimizer sample.
Note
Recall that we refer to default.html, default.css, and default.js as the local context because these files can reference the Windows Runtime (this includes the custom C++ Windows Runtime component), but they can't access the web. We refer to web.html, web.css, and web.js as the web context because these files can access the web, but they can't access the Windows Runtime. The web context also defines the user interface.
Note
The sample code that corresponds to this document is found in the Bing Maps trip optimizer sample.
In this article
Initializing the C++ component from JavaScript
Sending data to the C++ component
Receiving data from the C++ component
Migration from ActiveX
Next steps
Initializing the C++ component from JavaScript
The local context declares variables that represent the C++ component and the current trip optimization operation.
// The C++ component.
var tripOptimizer = null;
// The current asynchronous trip optimization.
var asyncOperation = null;
The optimizerLoad function, which is called during app initialization, creates the TripOptimizer object.
function optimizerLoad() {
"use strict";
tripOptimizer = new TripOptimizerComponent.TripOptimizer();
}
The Windows Runtime can locate and load the TripOptimizer object because the JavaScript Visual Studio project contains a reference to the C++ project.
[Top]
Sending data to the C++ component
The document Using JavaScript in the Bing Maps Trip Optimizer sample describes how the web and local contexts communicate. When the user selects the Get Directions or Cancel button, the web context sends a message to the local context to call the appropriate TripOptimizer method in the C++ component. For example, when the user chooses Get Directions, the web context sends the string "optimizeTrip" as part of the message to the local context. When the user chooses Cancel, the web context sends the string "cancel". The following code shows how the local context receives these messages from the web context.
function receiveMessage(message) {
"use strict";
// Verify event origin.
if (message.origin !== "ms-appx-web://microsoft.sdksamples.tripoptimizer.js") {
return;
}
var data = JSON.parse(message.data);
if (data.invoke === "load") {
optimizerLoad();
} else if (data.invoke === "optimizeTrip") {
optimizerOptimizeTrip(
data.locations,
data.travelMode,
data.optimize,
data.bingMapsKey,
data.alpha,
data.beta,
data.rho,
data.iterations,
data.parallel);
} else if (data.invoke === "cancel") {
optimizerCancel();
} else if (data.invoke === "alert") {
// Show message dialog.
new Windows.UI.Popups.MessageDialog(data.message).showAsync().then();
}
}
The optimizerOptimizeTrip function forwards the parameters from the web context to the C++ component.
function optimizerOptimizeTrip(locations, travelMode, optimize, bingMapsKey, alpha, beta, rho, iterations, parallel) {
"use strict";
asyncOperation = tripOptimizer.optimizeTripAsync(locations, travelMode, optimize, bingMapsKey,
alpha, beta, rho, iterations, parallel);
This example also sets the asyncOperation variable. We set this variable so that we can cancel the operation when the user chooses Cancel.
function optimizerCancel() {
"use strict";
if (asyncOperation !== null) {
asyncOperation.cancel();
}
}
Note
The TripOptimizer::OptimizerTripAsync method in the C++ component is exposed to JavaScript as TripOptimizer.optimizerTripAsync (the first letter is changed to lowercase to match the standard JavaScript naming conventions).
[Top]
Receiving data from the C++ component
The TripOptimizer::OptimizerTripAsync method in the C++ component behaves asynchronously. Therefore, the JavaScript part of the app must be able to process the data when it becomes available. The JavaScript part uses promises to react when an asynchronous operation completes, throws an error, or reports progress. The following example shows how the optimizerOptimizeTrip function defines the completion, error, and progress callbacks for the call to TripOptimizer::OptimizeTripAsync.
function optimizerOptimizeTrip(locations, travelMode, optimize, bingMapsKey, alpha, beta, rho, iterations, parallel) {
"use strict";
asyncOperation = tripOptimizer.optimizeTripAsync(locations, travelMode, optimize, bingMapsKey,
alpha, beta, rho, iterations, parallel);
asyncOperation.then(
function (result) {
if (result !== null) {
// If the result contains certain keys, then we know that the results contain
// the optimize route.
if (result.size === 2 && result.hasKey("locations") && result.hasKey("displayNames")) {
routeCallback(result);
}
// Otherwise, we know that the component is asking us to resolve ambiguous locations.
else {
locationsCallback(result);
}
}
else {
canceledCallback();
}
asyncOperation = null;
},
function (error) {
if (error.description === "Canceled") {
canceledCallback();
}
else {
errorCallback("Error: " + error.message);
}
asyncOperation = null;
},
function (progress) {
progressCallback(progress);
}
);
}
Note that when the user chooses Cancel, the C++ component cancels the current operation. The runtime calls the error handler for the operation. It sets the description field of the error to "Canceled" to indicate that the result is due to cancellation. For more information about how to work with asynchronous operations in JavaScript, see Asynchronous programming.
When the local context receives progress or the result of an asynchronous operation, it forwards the event data to the web context so that the web context can update the UI. For example, the progressCallback function sends the string "progressCallback" as part of the message that it sends to the web context.
// Event handler for progress notifications from the Windows Runtime component.
function progressCallback(info) {
"use strict";
var message = { "invoke": "progressCallback", "message": info };
window.parent.frames.mapFrame.postMessage(JSON.stringify(message), "*");
}
The following example shows the receiveMessage function for the web context. This function receives messages from the local context.
// Receives a message from the local context.
function receiveMessage(message) {
"use strict";
// Verify event origin.
if (message.origin !== "ms-appx://microsoft.sdksamples.tripoptimizer.js") {
return;
}
var data = JSON.parse(message.data);
if (data.invoke === "progressCallback") {
progressCallback(data.message);
} else if (data.invoke === "locationsCallback") {
locationsCallback(JSON.parse(data.locationOptions));
} else if (data.invoke === "routeCallback") {
routeCallback(data.locations, data.displayNames);
} else if (data.invoke === "canceledCallback") {
canceledCallback();
} else if (data.invoke === "errorCallback") {
errorCallback(data.message);
}
}
For the "progressCallback" message, the web context calls the progressCallback function, which updates the UI to show the progress message.
// Event handler for progress notifications from the control.
function progressCallback(message) {
"use strict";
// Set message.
progressMessageText.innerHTML = message;
}
[Top]
Migration from ActiveX
For information about how we migrated from the ActiveX version of Bing Maps Trip Optimizer to a Windows Store app, see Migrating existing code in the Bing Maps Trip Optimizer sample.
[Top]
Next steps
This article explained how we used JavaScript and C++ to create a complete Windows Store app. Consider using a C++ component along with your JavaScript app to leverage code that you’ve already written and tested, and to improve performance.
[Top]