Partager via


Develop Your Application by Adding C++ Code (Compact 7)

3/12/2014

After you import the Expression Blend project into a Platform Builder subproject and verify that the resulting application template builds and executes on your target device, you can add C++ code to make the application work.

Prerequisites

Convert an Expression Blend Project to a Silverlight for Windows Embedded Application Template

Examine the Generated Application Template

When the Platform Builder Subproject Application Wizard creates the initial MyClock application template, it generates a source tree that contains files associated with the application. You can examine this source tree at the following location:

C:\WINCE700\OSDesigns\VCEPC\MyClock\MyClock

The following table summarizes the important source files that make up the MyClock application.

Name Description

WinMain.cpp

Contains the main entry point of the application. Normally requires no changes.

App.cpp and App.h

Contain the derived application class.

MainPage.cpp and MainPage.h

Implement the minimum code required to use the <UserControl> defined in MainPage.xaml. These files also may contain member variables that are mapped to named objects and stubs for event handlers. You must complete these event handler implementations to get a working application.

MyClock.rc

Listing of all of the Windows resources that the program uses when it compiles for a platform that uses the standard Windows Embedded Compact shell. It includes the XAML files, images, and other assets that are stored in the resources subdirectory. You can edit MyClock.rc directly in Visual Studio.

resource.h

Standard header file, which defines new resource IDs. Visual Studio reads and updates this file automatically.

Port Code-Behind Files

To add application functionality to the Silverlight for Windows Embedded Clock, you modify App.h.

Typically, the source Expression Blend project has existing .NET code-behind files that the designer uses to demonstrate and test the user-interface design. You can save development time by porting this existing functionality to your Windows Embedded Compact application.

The Silverlight for Windows Embedded Clock sample contains several C# code-behind files that animate the hands of the clock face. To add functionality to MyClock, you can port functionality from the Expression Blend project C# code-behind file associated with MainPage.xaml (MainPage.xaml.cs) to C++ code that works with the native Silverlight for Windows Embedded runtime of Windows Embedded Compact.

The Silverlight for Windows Embedded Clock sample uses the storyboard and animation features of Silverlight for Windows Embedded to move the hands around the clock face. In MainPage.xaml (located in the WindowsEmbeddedSilverlightClock folder), a Storyboard object is declared with three child DoubleAnimation objects, one for each hand of the clock:

Important

For readability, the following code example does not contain security checking or error handling. Do not use the following code example in a production environment.

<Storyboard x:Name="ClockStoryboard">
    <!-- This animation targets the hour-hand transform. -->
    <DoubleAnimation x:Name="HourAnimation"
            Storyboard.TargetName="HourHandTransform"
            Storyboard.TargetProperty="Angle"
            Duration="12:0:0" RepeatBehavior="Forever" />
    <!-- This animation targets the minute-hand transform. -->
    <DoubleAnimation x:Name="MinuteAnimation"
            Storyboard.TargetName="MinuteHandTransform" 
            Storyboard.TargetProperty="Angle"
            Duration="1:0:0" RepeatBehavior="Forever" />
    <!-- This animation targets the second-hand transform.  -->
    <DoubleAnimation x:Name="SecondAnimation"
             Storyboard.TargetName="SecondHandTransform" 
             Storyboard.TargetProperty="Angle"
             Duration="0:1:0" RepeatBehavior="Forever" />
</Storyboard>

As shown in the XAML excerpt above, each animation declares a duration time for the animation of the associated clock hand. The hour-hand animation has a Duration of 12 hours, the minute-hand animation has a Duration of one hour, and the second-hand animation has a Duration of one minute. The RepeatBehavior of each animation is set to Forever, which means that each animation starts over at the end of its cycle and repeats indefinitely, moving the hands continuously around the clock face with durations that correspond to the hours, minutes, and seconds as appropriate for each hand.

Silverlight for Windows Embedded does the work of animating the hand objects declared in this XAML file. Therefore, the core logic of your Windows Embedded Compact application only has to perform the following tasks:

  1. Determine the current time.
  2. Calculate start angles for each clock hand.
  3. Find the clock face objects in the Silverlight for Windows Embedded visual tree.
  4. Initialize the clock face objects and start the animation.

The following subsections describe how to port this functionality to Windows Embedded Compact. We begin by showing you snippets of the original Silverlight for Windows Embedded Clock sample source in C#, explain what each code snippet does, and then show you the equivalent C++ version of that code for use in Windows Embedded Compact. The final code example lists the complete C++ code sample so that you can cut and paste it into a MyClock source file to try it out.

Important

For readability, the following code examples do not contain security checking or error handling. Do not use the following code examples in a production environment.

Determine the Current Time

In the code-behind file of the Silverlight for Windows Embedded Clock sample, DateTime.Now provides the current time:

// Get the current date and time.
System.DateTime date = DateTime.Now;

In Windows Embedded Compact, you can get the current time by calling the GetLocalTime function:

// Get the current time.
SYSTEMTIME st;
GetLocalTime(&st);

After you call GetLocalTime, you read the current time in hours, minutes, and seconds from the SYSTEMTIME structure. Next, you use these values to calculate the start angles of the clock hands.

Calculate Start Angles

The code-behind file of the sample Silverlight for Windows Embedded Clock has C# source code that calculates the starting angle, in degrees, of each hand. The hands correspond to the current time. Because the XAML declares the initial position of each hand in a pointing-downward position (at six o’clock) when the application starts, the sample code adds 180 degrees to each hand so that the time/angle calculation is made relative to the twelve o’clock position on the clock face:

// Calculate the initial angle (in degrees) for the hour
// hand based on the current time:
double hourAngle = (((float)date.Hour) / 12) * 360 + 
                    date.Minute / 2;
hourAngle += 180;

// Similarly, calculate the initial angle of the minute hand:
double minuteAngle = (((float)date.Minute) / 60) * 360;
minuteAngle += 180;

// Similarly, calculate the initial angle of the second hand:
double secondAngle = (((float)date.Second) / 60) * 360;
secondAngle += 180;

This code can readily be ported to C++ for use in the MyClock Windows Embedded Compact application. The SYSTEMTIME structure provides the current hours, minutes, and seconds to use in the same calculations as shown previously:

// Initialize hand angles to their current position at 6 o'clock:
float hourAngle = 180.0, minuteAngle = 180.0, secondAngle = 180.0;

// Calculate the initial angle (in degrees) for each
// hand based on the current time.
hourAngle   += (((float)st.wHour) / 12) * 360 + (float)st.wMinute / 2;
minuteAngle += (((float)st.wMinute) / 60) * 360;
secondAngle += (((float)st.wSecond) / 60) * 360;

Once these initial angle values are calculated, you use them to position the hands of the clock to the current time before you start the animation of the clock face.

Find the Storyboard and Animation Objects

When the Platform Builder Subproject Application Wizard creates the initial application template, it does not generate named variables for all of the objects declared in the XAML. Instead, you must manually declare IXRStoryboardPtr and IXRDoubleAnimationPtr smart pointers and use the FindName method of the root element to locate the objects declared in the XAML file. In the case of the MyClock example, you use FindName to locate the ClockStoryboard object and the three animation objects that correspond to each of the clock hands. For each object, you pass the x:Name property declared in the XAML for that object to the first argument of FindName:

IXRFrameworkElementPtr pRoot;
IXRStoryboardPtr pStoryboard;
IXRDoubleAnimationPtr pSecondAnimation;
IXRDoubleAnimationPtr pMinuteAnimation;
IXRDoubleAnimationPtr pHourAnimation;

// Get the root element of the visual host:
m_pVisualHost->GetRootElement(&pRoot);

// Find the storyboard and animation objects:
pRoot->FindName(L"ClockStoryboard",&pStoryboard);
pRoot->FindName(L"SecondAnimation", &pSecondAnimation);
pRoot->FindName(L"MinuteAnimation", &pMinuteAnimation);
pRoot->FindName(L"HourAnimation", &pHourAnimation);

Note that the Silverlight for Windows Embedded Clock sample code-behind does not use a FindName method to locate the Storyboard and animation objects. In the C# source code of the Silverlight for Windows Embedded Clock sample, Expression Blend creates a named variable for each object declared in the XAML, so the Silverlight for Windows Embedded Clock sample code simply references each of these objects by name without having to perform a lookup of each one. However, the application template that Windows Embedded Silverlight Tools produces does require that you locate each object in the Silverlight for Windows Embedded visual tree and assign it to a smart pointer before you use it.

Initialize and Start the Animation

Each clock hand animation is associated with a RotateTransform in MainPage.xaml. For example, here is the XAML declaration for the RotateTransform of the clock’s second hand:

<Rectangle.RenderTransform>
    <RotateTransform x:Name="SecondHandTransform" />
</Rectangle.RenderTransform>

The XAML declaration for the animation object of the second hand sets the Storyboard.TargetName to the SecondHandTransform declared above:

<!-- This animation targets the second-hand transform.  -->
    <DoubleAnimation x:Name="SecondAnimation"
             Storyboard.TargetName="SecondHandTransform" 
             Storyboard.TargetProperty="Angle"
             Duration="0:1:0" RepeatBehavior="Forever" />

Each clock hand animation declares its TargetProperty to be the Angle property of the associated RotateTransform. Therefore, changing the From and To properties of a clock hand animation sets the Angle property of its associated RotateTransform. To prepare the clock for animation, initialize the From property to the initial angle of the animation for that clock hand, and set the To property of that hand to one complete sweep around the clock face from the starting point (that is, add 360 degrees). The C# code in the Silverlight for Windows Embedded Clock sample sets each of these properties directly and starts the animation by calling the Begin method on the parent object, ClockStoryboard:

// Set the beginning and end of the hour-hand animation.
HourAnimation.From = hourAngle;
HourAnimation.To = hourAngle + 360;

// Set the beginning and end of the minute-hand animation.
MinuteAnimation.From = minuteAngle;
MinuteAnimation.To = minuteAngle + 360;

// Set the beginning and end of the second-hand animation.
SecondAnimation.From = secondAngle;
SecondAnimation.To = secondAngle + 360;

// Start the storyboard.
ClockStoryboard.Begin();

Notice that the C# sample code sets the From and To properties of each DoubleAnimation instance directly. In the C++ environment of Windows Embedded Compact, you use the SetFrom and SetTo methods to initialize instances of the DoubleAnimation class:

// Set the beginning and end of the hour-hand animation.
pHourAnimation->SetFrom(hourAngle);
pHourAnimation->SetTo(hourAngle + 360);

// Set the beginning and end of the minute-hand animation.
pMinuteAnimation->SetFrom(minuteAngle);
pMinuteAnimation->SetTo(minuteAngle + 360);

// Set the beginning and end of the second-hand animation.
pSecondAnimation->SetFrom(secondAngle);
pSecondAnimation->SetTo(secondAngle + 360);

// Start the animation.
pStoryboard->Begin();

Once the animations are initialized with these beginning and end values, the call to the Begin method of the Storyboard starts the animation of all three clock hands.

In the next section, you add this ported code to the application template, which the Windows Embedded Silverlight Tools created using Platform Builder Subproject Application Wizard.

Add Functionality to the Application Template

When the application template starts (see WinMain.cpp), it instantiates the App class, calls its Initialize method, and then calls its Run method to execute the functionality of the application:

INT WINAPI WinMain(. . .)
{
    App AppInstance;
    HRESULT hr = AppInstance.Initialize(hInstance);
    if(SUCCEEDED(hr))
    {
        hr = AppInstance.Run();
    }
    return AppInstance.GetWinMainResultCode();
}

The App::Initialize method prepares the application to run your code by completing the following preliminary tasks:

  1. Initializing the XAML runtime.
  2. Retrieving the XAML runtime application instance.
  3. Initializing the application’s resource dictionary.
  4. Creating the visual host object.

When App::Initialize completes successfully, the XAML runtime is ready and the application message loop for receiving events starts. You can add additional startup code by modifying the methods that App::Initialize calls or by inserting calls to your own methods (see App.h).

After App::Initialize completes successfully, the application passes control to the App::Run method (see App.h). You use the App::Run method to start the core functionality of your application. For the Silverlight for Windows Embedded Clock example, you add code directly to App::Run to animate the second hand, minute hand, and hour hand of MyClock.exe. The code below shows what App::Run looks like after you add the code that you ported in the previous section:

inline HRESULT App::Run()
{
    HRESULT hr = E_FAIL;
    UINT uiExitCode = 0;

    IXRFrameworkElementPtr pRoot;
    IXRStoryboardPtr pStoryboard;
    IXRDoubleAnimationPtr pSecondAnimation;
    IXRDoubleAnimationPtr pMinuteAnimation;
    IXRDoubleAnimationPtr pHourAnimation;

    if(m_pVisualHost != NULL)
    {
        // Get the root element of the visual host:

        m_pVisualHost->GetRootElement(&pRoot);

        // Find the storyboard and animation objects:
        pRoot->FindName(L"ClockStoryboard",&pStoryboard);
        pRoot->FindName(L"SecondAnimation", &pSecondAnimation);
        pRoot->FindName(L"MinuteAnimation", &pMinuteAnimation);
        pRoot->FindName(L"HourAnimation", &pHourAnimation);

        // Get the current time:
        SYSTEMTIME st;
        GetLocalTime(&st);

        // Initialize hand angles to 6 o'clock:
        float hourAngle = 180.0, minuteAngle = 180.0;
        float secondAngle = 180.0;

        // Calculate the initial angle (in degrees) for each
        // hand based on the current time.
        hourAngle   += (((float)st.wHour) / 12) * 360 +
                        (float)st.wMinute / 2;
        minuteAngle += (((float)st.wMinute) / 60) * 360;
        secondAngle += (((float)st.wSecond) / 60) * 360;

        // Set the beginning and end of the hour-hand animation.
        pHourAnimation->SetFrom(hourAngle);
        pHourAnimation->SetTo(hourAngle + 360);

        // Set the beginning and end of the minute-hand animation.
        pMinuteAnimation->SetFrom(minuteAngle);
        pMinuteAnimation->SetTo(minuteAngle + 360);

        // Set the beginning and end of the second-hand animation.
        pSecondAnimation->SetFrom(secondAngle);
        pSecondAnimation->SetTo(secondAngle + 360);

        // Start the animation:
        pStoryboard->Begin();

        // Save the exit code for WinMain
        hr = m_pVisualHost->StartDialog(&uiExitCode);
        SetWinMainResultCode(uiExitCode);
    }
    . . .
} // Run

Error-handling code paths have been omitted in these examples for clarity. In production code, you should check the return code from FindName so that your application can recover if FindName returns an error.

Run the Application

After you make the above changes to the App::Run method in App.h, you can build and run MyClock.exe again.

To run the application

  1. If the previous instance of MyClock is still running, right-click the MyClock taskbar button on your Windows Embedded Compact device, and then click Close.

  2. In Visual Studio, locate and right-click the MyClock subproject that you created earlier, and then click Build.

  3. On the Target menu, click Run Programs.

  4. In the Run Program dialog box, under Available Programs, select MyClock.exe and then click Run.

On the display of your device, the second hand should move while the hour hand and minute hand report the current time, as shown in the following figure.

Running the Application

Running the Application

The hands of the MyClock application should continue to report the current time, with the second hand moving around the clock face once per minute, updating the animation at the default Silverlight for Windows Embedded frame rate.

Next Steps

Add Event Handlers

See Also

Concepts

Getting Started with Silverlight for Windows Embedded