Udostępnij za pośrednictwem


Migrating existing code in the Bing Maps Trip Optimizer sample

This document highlights some of key guidelines that we followed when we migrated from the ActiveX version of Bing Maps Trip Optimizer to a Windows Store app. This document does not provide a full explanation of how to migrate existing code to the Windows Runtime. Rather, it highlights our experience and the important aspects we had to keep in mind.

Note

The sample code that corresponds to this document is found in the Bing Maps trip optimizer sample (Windows Store app) and Bing Maps Trip Optimizer (ActiveX web app).

In this article

  • JavaScript migration key points

  • C++ migration key points

  • Interop migration key points

JavaScript migration key points

The ActiveX version of Bing Maps Trip Optimizer uses one code file, OptimizerControl.htm, for the UI. As described in this documentation, when we migrated to use the Windows Runtime, we had to make separate contexts for components that interact with the web and those that interact with the Windows Runtime. We had to write additional code to enable the contexts to communicate. The document Features and restrictions by context explains more about the differences between local and web contexts.

We were able to use the majority of the code from the original version in the Windows Store app version. One main difference is that because the Windows Store app no longer references an ActiveX control, we replaced the object element with a global variable that represents the C++ component. This mechanism is explained in greater detail in Interoperating between JavaScript and C++ in the Bing Maps Trip Optimizer sample.

Window methods such as alert, prompt, and open don't work in JavaScript Windows Store apps. The ActiveX version of the control uses alert to inform the user of a problem, such as when more than 25 locations have been entered. The Windows Store version of the app uses the Windows.UI.Popups.MessageDialog class to display messages to the user.

// Show message dialog.            
new Windows.UI.Popups.MessageDialog(data.message).showAsync().then();

Because there is no action to perform after the message dialog is displayed, the then statement is empty. For more information about how to work with asynchronous operations in JavaScript, see Asynchronous programming.

For more information about some of the some differences to how you use existing HTML features in a JavaScript Windows Store app, see HTML, CSS, and JavaScript features and differences.

The ActiveX version of the app uses Bing Maps AJAX Control, Version 6.3 to display the map on the UI. The Windows Store app version uses Bing Maps AJAX Control, Version 7.0. Upgrading from version 6.3 to version 7.0 was not a requirement; you can use version 6.3 in a Windows Store app. We chose version 7.0 in this implementation because it includes performance improvements and improved support for touch, and we wanted to demonstrate the newer way to get information from Bing Maps.

[Top]

C++ migration key points

When you use C++/CX to create Windows Store components, the compiler and the Windows Runtime handle the infrastructure that's required to interoperate with other components and languages. When we migrated the ActiveX version of the control to a Windows Store component, we were able to remove the infrastructure code that's required to implement a custom COM interface. For example, a Windows Runtime component doesn't require IDL files that define the interfaces and events that a component provides. In addition, we maintained the implementation details that use pure native code when we could. The use of C++/CX and the Windows Runtime is required only when the control interacts with other Windows Runtime objects and components.

Consider these guidelines as you migrate your ActiveX controls to controls that use the Windows Runtime.

Tip

Many of these guidelines involve working with the C++/CX syntax. For more information about this syntax, see Visual C++ Language Reference (C++/CX).

  • Use the WinRT Class Library template to create the Visual Studio project.

  • Add the public interface methods and properties from the ActiveX control to your Windows Runtime class. Convert the parameter and return types to use types that are compatible with the Windows Runtime. For example, TripOptimizerImpl.idl defines the IOptimizerControl interface for the ActiveX control.

    interface IOptimizerControl : IDispatch{
       [id(1)] HRESULT OptimizeTripAsync([in] VARIANT* waypoints, [in] BSTR travelMode, 
          [in] BSTR optmz, [in] BSTR bingMapsKey,
          [in] DOUBLE alpha, [in] DOUBLE beta, [in] DOUBLE rho, [in] ULONG iterations,
          [in] VARIANT_BOOL parallel);
       [id(2)] HRESULT CancelAsync();
    };
    

    For the Windows Store component, here is the declaration for the TripOptimizer::OptimizeTripAsync method in the Windows Runtime component. We use the actual return type, Windows::Foundation::Collections::IMap<K, V>, instead of HRESULT. We also use the appropriate Windows Runtime type for each parameter.

    Note

    We were able to remove the CancelAsync method in this implementation because cancellation functionality is provided by the Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress>::Cancel method.

    // Optimizes a trip as an asynchronous process.
    Windows::Foundation::IAsyncOperationWithProgress<
        Windows::Foundation::Collections::IMap<
            Platform::String^, 
            Windows::Foundation::Collections::IVector<Platform::String^>^>^, 
        Platform::String^>^ OptimizeTripAsync(
            Windows::Foundation::Collections::IVector<Platform::String^>^ waypoints, 
            Platform::String^ travelMode, 
            Platform::String^ optimize,
            Platform::String^ bingMapsKey, 
            double alpha, double beta, double rho,
            unsigned int iterations, bool parallel);
    

    The TripOptimizer::OptimizeTripAsync method is explained in more detail in the section Creating the TripOptimizer and TripOptimizerImpl classes.

  • Add the public events from the ActiveX control to your Windows Runtime class. As with methods and properties, convert the parameter and return types to use types that are compatible with the Windows Runtime.

    In this implementation, we were able to remove all of the events that were defined in the ActiveX version because these actions are all handled by other means. For example, we no longer have to define a completion event because we return the result directly as part of the IAsyncOperationWithProgress<TResult, TProgress> object that is returned by TripOptimizer::OptimizeRouteAsync. The error and progress callbacks are also handled by the IAsyncOperationWithProgress<TResult, TProgress> object. For more information about how the JavaScript part of the app consumes the asynchronous operation, see Interoperating between JavaScript and C++ in the Bing Maps Trip Optimizer sample.

  • Choose the appropriate standard C++ and Windows Runtime types when you define data members for your Windows Runtime class.

    For example, the COptimizerControl class uses COM types such as _bstr_t to hold string values.

    In the Windows Store version of the app, we used std::wstring, the standard C++ string type, to hold string values. For example, in the TripOptimizerImpl::OptimizeTripAsync method, we convert the Windows::Foundation::Collections::IVector<T> and Platform::String parameters to std::vector and std::wstring because these variables are not passed back to a Windows Runtime component.

    // Copy inputs to a OptimizeTripParams structure.
    auto params = make_shared<OptimizeTripParams>();
    for (auto waypoint : waypoints)
    {
        params->Waypoints.push_back(waypoint->Data());
    }
    params->TravelMode = wstring(travelMode->Data());
    params->Optimize = wstring(optimize->Data());
    params->BingMapsKey = UriEncode(bingMapsKey->Data());
    params->Alpha = alpha;
    params->Beta = beta;
    params->Rho = rho;
    params->Iterations = iterations;
    params->Parallel = parallel;
    

    When you use this convention, you can more clearly distinguish which variables are used with the Windows Runtime. The Windows Runtime string and collection types (such as Windows::Foundation::Collections::IMap<K, V> and Windows::Foundation::Collections::IVector<T>) are useful when you communicate regularly between the Windows Runtime and your code because it reduces the number of string type conversions that the app must make. Otherwise, consider whether to use standard C++ collection types such as std::map and std::vector.

    The implementation details of the control are described in more detail in the section Component workflow.

  • Use the Windows::Foundation::IAsyncAction, Windows::Foundation::IAsyncActionWithProgress<TProgress>, Windows::Foundation::IAsyncOperation<TResult>, or Windows::Foundation::IAsyncOperationWithProgress<TResult, TProgress> interfaces to help define asynchronous methods. The concurrency::create_async function is the recommended way to create these objects from a C++ Windows Store app or component.

  • Use as much existing code as possible. We were able to migrate implementation details, such as the ant colony optimization algorithm, with little or no code modifications. However, because Windows Store apps can use a subset of the Win32 and COM API, we had to use alternative mechanisms for some parts of the component. For example, the ActiveX version of the control uses IXMLHTTPRequest to communicate with HTTP servers. In the C++ component, we use IXMLHTTPRequest2, which is the recommended way to communicate with HTTP servers in a Windows Store app. To process the XML response from Bing Maps, the ActiveX control uses XmlLite. In the Windows Store component, we use the Windows Runtime XmlDocument class because it's easy to use and because we wanted to demonstrate how you can update existing COM code to use the Windows Runtime types. However, if you have existing Win32 or COM code that's available in a Windows Store app, you can continue to use it.

    For more information about how to use Win32 and COM in a Windows Store app, see Win32 and COM for Windows Store apps.

    Important

    If you use Win32 and COM in your Windows Store app, it might run in your development environment, but it might not be approved for distribution from the Windows Store. Therefore, we recommend that you run the application verifier frequently to guarantee that your app passes verification. For more information, see Preparing your app for the Windows Store and How to: Install, validate, and upload your package.

  • Visual C++ projects now use pch.h and pch.cpp to hold precompiled header info. Migrate the relevant #include statements from stdafx.h to pch.h.

[Top]

Interop migration key points

In the Windows Store app version of Bing Maps Trip Optimizer, we were able to use most of the JavaScript code from the ActiveX version. The main difference is how the HTML and JavaScript code reference the C++ component.

The ActiveX version uses the HTML object tag to reference the C++ component.

<object id="OptimizerControl" name="OptimizerControl" classid="CLSID:10FFAAB9-0E73-4C4D-8118-6225C7F2E692"></object>

Accordingly, the ActiveX version uses the id value, "OptimizerControl", to call the COptimizerControl methods.

The Windows Store app version of the Bing Maps Trip Optimizer sets a project reference and uses a global variable instead of using the object tag. The project system performs the steps that are required for the JavaScript app to find and load the C++ component. The article Creating Windows Runtime Components in C++ explains in more detail how to set up project references.

The ActiveX version uses the :: syntax to handle events.

// Event handler for progress notifications from the control.
function document.OptimizerControl::ProgressCallback(message) {
   // Set message.
   ProgressMessageText.innerHTML = message;
}

The Windows Store app version uses asynchronous processing and promises to react to responses from the C++ component. This process is explained in the section Receiving data from the C++ component.

[Top]