Notes on the documentation

This description is only intended for the use of trained specialists in control and automation engineering who are familiar with the applicable national standards.
It is essential that the following notes and explanations are followed when installing and commissioning these components.

The responsible staff must ensure that the application or use of the products described satisfy all the requirements for safety, including all the relevant laws, regulations, guidelines and standards.

Disclaimer

The documentation has been prepared with care. The products described are, however, constantly under development.
For that reason the documentation is not in every case checked for consistency with performance data, standards or other characteristics.
In the event that it contains technical or editorial errors, we retain the right to make alterations at any time and without warning.
No claims for the modification of products that have already been supplied may be made on the basis of the data, diagrams and descriptions in this documentation.

Trademarks

Beckhoff®, TwinCAT®, EtherCAT®, Safety over EtherCAT®, TwinSAFE® and XFC® are registered trademarks of and licensed by Beckhoff Automation GmbH.
Other designations used in this publication may be trademarks whose use by third parties for their own purposes could violate the rights of the owners.

Patent Pending

The TwinCAT Technology is covered, including but not limited to the following patent applications and patents:
EP0851348, US6167425 with corresponding applications or registrations in various other countries.

Copyright

© Beckhoff Automation GmbH.
The reproduction, distribution and utilization of this document as well as the communication of its contents to others without express authorization are prohibited.
Offenders will be held liable for the payment of damages. All rights reserved in the event of the grant of a patent, utility model or design.


TcQuickStart Silverlight for Windows Embedded Machine Sample

jiu

TwinCAT Quick Start

Example for a machine with Microsoft Silverlight for Windows Embedded

Embedded CE 6.0 R3中出现了一项基于Windows Embedded 的新技术称之为 Microsoft Silverlight。 有了这项技术， CE设备的用户界面可以在XAML中写入或者利用Microsoft Expression Blend.等软件来设计。在机器实例的基础上，这里展示的是在 Windows Embedded 应用和ADS组件集成之间创建一个Silverlight 。

软件要求

- Microsoft Visual Studio 2008
- Microsoft Expression Blend 2 SP1
- TwinCAT 2.11

Required hardware

- Windows CE 6.0 R3 device (e.g. CX1020)

First steps...

1. 创建一个新的 Silverlight 2 项目:

Windows Embedded 的 Silverlight 设计是在XAML中完成的。 在Microsoft Expression Blend 2 SP1中通过 'File - > New Project' 创建一个Silverlight 2项目。在这个例子中，不需要创建 Visual Studio Solution 。此外，它不支持编程语(Visual C# 或 Visual Basic) 。 Windows Embedded的Silverlight只支持Visual C++, 并没有集成于Expression Blend。因此，也无法用这个工具生成源代码。尽量在Expression Blend 中禁用Visual Studio编辑以避免Visual C# 和 Visual Basic 代码自动生成。要做到这一点, 选择 'Clipboard only' 中 'Options->Event handlers'.

2. Creating a user interface

用户界面可以在Expression Blend中创建。

在左上角可以看到两个输出，这也是总线端子的输出。 左下角显示了工件计数的变量。 速度则可以在右边设置。 'Steps' 显示了对应的周期数。此外，右上角的按钮则是用于结束程序。

<UserControl
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="319" Height="255">

    <!-- Timelines -->
    <UserControl.Resources>

        <!-- Timeline Device Down -->
        <Storyboard x:Name="timelineDeviceDown">
            <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
                    Storyboard.TargetName="txtDeviceDown"
                    Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)">
                <SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFFF0000"/>
            </ColorAnimationUsingKeyFrames>
        </Storyboard>

        <!-- Timeline Device Up -->
        <Storyboard x:Name="timelineDeviceUp">
            <ColorAnimationUsingKeyFrames BeginTime="00:00:00"
                    Storyboard.TargetName="txtDeviceUp"
                    Storyboard.TargetProperty="(TextBlock.Foreground).(SolidColorBrush.Color)">
                <SplineColorKeyFrame KeyTime="00:00:00.4000000" Value="#FFFF0000"/>
            </ColorAnimationUsingKeyFrames>
        </Storyboard>

        <!-- Timeline Engine -->
        <Storyboard x:Name="timelineEngine"/>

    </UserControl.Resources>

    <!-- Beginn der Layout Beschreibung -->
    <Grid x:Name="LayoutRoot" Background="#FF595959">

        <!-- Title Machine -->
        <TextBlock Text="Machine" Margin="80,8.438,80,0" VerticalAlignment="Top"
                FontWeight="Bold" Foreground="#FFFFFFFF" FontSize="34"/>

        <!-- Device Up / Device Down -->
        <Grid Margin="15,60,0,0" HorizontalAlignment="Left" VerticalAlignment="Top"
                Height="53" Width="132.532">
            <Rectangle Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeThickness="2"
                    RadiusX="6" RadiusY="6"/>
            <TextBlock Text="Device Up" Margin="28.823,5.396,-8.823,0"
                    VerticalAlignment="Top" Foreground="#FFFFFFFF" FontSize="16"/>
            <TextBlock Text="Device Down" Margin="29.002,0,-9.002,4.994"
                    VerticalAlignment="Bottom" Foreground="#FFFFFFFF" FontSize="16"/>
            <TextBlock x:Name="txtDeviceDown" Text="ê" Margin="7.517,0,0,4.998"
                    HorizontalAlignment="Left" VerticalAlignment="Bottom" FontFamily="Wingdings"
                    FontWeight="Bold" Foreground="#FFFFFFFF" FontSize="16"/>
            <TextBlock x:Name="txtDeviceUp" Text="é" Margin="7.517,5.497,0,0"
                    HorizontalAlignment="Left" VerticalAlignment="Top" FontFamily="Wingdings"
                    FontWeight="Bold" Foreground="#FFFFFFFF" FontSize="16"/>
        </Grid>

        <!-- Counter -->
        <Grid Margin="15,0,0,71" HorizontalAlignment="Left" VerticalAlignment="Bottom"
                Height="53" Width="133">
            <Rectangle Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeThickness="2"
                    RadiusX="6" RadiusY="6"/>
            <StackPanel Margin="12.991,16,0,16" HorizontalAlignment="Left"
                    Orientation="Horizontal" Width="113">
                <TextBlock Text="Count:" Width="54.824" Foreground="#FFFFFFFF"
                FontSize="16"/>
                <TextBlock x:Name="txtCount" Margin="2,0,0,0" Foreground="#FFFFFFFF"
                        FontSize="16"/>
            </StackPanel>
        </Grid>

        <!-- Speed -->
        <Grid Margin="0,0,15,71" Height="53" HorizontalAlignment="Right"
                VerticalAlignment="Bottom" Width="132.532">
            <Rectangle Fill="{x:Null}" Stroke="#FFFFFFFF" StrokeThickness="2"
                    RadiusX="6" RadiusY="6"/>
            <StackPanel Margin="12.988,0,3.012,0" Orientation="Horizontal">
                <RadioButton x:Name="radSpeedSlow" Content="slow" Margin="0,0,6,0"
                        Foreground="#FFFFFFFF" FontSize="16" Height="19.496"/>
                <RadioButton x:Name="radSpeedFast" Content="fast" Foreground="#FFFFFFFF"
                        FontSize="16" Height="19.496"/>
            </StackPanel>
        </Grid>

        <!-- Steps -->
        <Grid Margin="15,0,15,5" VerticalAlignment="Bottom"
        Height="57">
            <ProgressBar x:Name="prgSteps" Margin="0,18,0,18"
            Maximum="25"/>
            <TextBlock Text="Steps:" HorizontalAlignment="Left"
                    VerticalAlignment="Top" Foreground="#FFFFFFFF"/>
            <TextBlock Text="0%" HorizontalAlignment="Left"
                    VerticalAlignment="Bottom" Foreground="#FFFFFFFF"/>
            <TextBlock Text="100%" HorizontalAlignment="Right"
                    VerticalAlignment="Bottom" Foreground="#FFFFFFFF"/>
        </Grid>

        <!-- Close Button -->
        <Button x:Name="butClose" Content="X"
        HorizontalAlignment="Right" VerticalAlignment="Top"
                Height="20" Width="20"/>

        <!-- Beckhoff Logo -->
        <Image Source="beckhoff_logo_white.jpg" Margin="0,64.502,15,0" HorizontalAlignment="Right"
                VerticalAlignment="Top" Height="43.151" Width="133.745"
                Stretch="Fill"/>
     </Grid>
</UserControl>

3. 创建一个新的 Win32 智能设备项目

一个新的 Win32 智能设备项目必须在 Visual Studio 2008中创建。

4. Integrating the XAML file as a resource

用户界面与Expression Blend的设计可以集成在一个新项目中。要做到这一点，打开资源文件(.rc).。鼠标右击Resource View Tab并选择 'Add - > Resource…' 打开一个可以整合XAML文件的对话框。

XAML文件可以导入都对话框的帮助项目中。

指定 XAML 的资源类型.

该例子中，可以保留标准源 ID (IDR_XAML1) 。然而在实际项目中，也可以重命名。

5. 创建一个AdsHelper 类型

Ads通信中的大部分可以储存在一个单独的类中，这里称之为 AdsHelper。

AdsHelper.h

 AdsHelper 头文件包含TcAds头文件
#include "..\_AdditionalFiles\TcpAdsApiCe\include\TcAdsDef.h"
#include "..\_AdditionalFiles\TcpAdsApiCe\include\TcAdsAPI.h"

这里同时可以发布声明.
typedef enum E_NOTIFICATION_IDENT
{
    engine = 0,
    deviceUp = 1,
    deviceDown = 2,
    steps,
    count,
    switchSpeed
};

long AdsGetVarHandle(AmsAddr* pServerAddr, const char* szVarname, long* pHandle);
long AdsFreeVarHandle(AmsAddr* pServerAddr, long handle);
long AdsGerVarHandleEx(long port, AmsAddr* pServerAddr, const char* szVarname, long* pHandle);
long AdsFreeVarHandleEx(long port, AmsAddr* pServerAddr, long handle);

long SpeedSlowEx(long port, AmsAddr* pServerAddr);
long SpeedFastEx(long port, AmsAddr* pServerAddr);

long connect(long port, AmsAddr* pServerAddr);
long disconnect(long port, AmsAddr* pServerAddr);

AdsHelper.cpp

AdsHelper.cpp包含头文件 StdAfx.h 和 AdsHelper.h
#include "StdAfx.h"
#include "AdsHelper.h"

以及之后的全局变量的定义。

long hEngine, hDeviceUp, hDeviceDown, hSteps, hCount, hSwitch;
unsigned long hEngineNotification, hDeviceUpNotification, hDeviceDownNotification,
              hStepsNotification, hCountNotification, hSwitchNotification;

方案 AdsGetVarHandle 和 AdsGetVarHandleEx 有助于创建PLC变量的句柄
long AdsGetVarHandle(AmsAddr* pServerAddr, const char* szVarname, long* pHandle)
{
    if (pHandle == NULL || pServerAddr == NULL)
        return E_POINTER;

    unsigned long read = 0;
    long nErr =
        AdsSyncReadWriteReqEx(pServerAddrm ADSIGRP_SYM_HNDBYNAME, 0x0,
        sizeof(long), pHandle,strlen(szVarname), (char*)szVarname, &read);

    return nErr;
}

long AdsGetVarHandleEx(long port, AmsAddr* pServerAddr, const char* szVarname, long* pHandle)
{
    if(pHandle == NULL || pServerAddr == NULL)
        return E_POINTER;

    unsigned long read = 0;

    long nErr =
        AdsSyncReadWriteReyEx2(port, pServerAddr, ADSIGRP_SYM_HNDBYNAME, 0x0,
        sizeof(long), pHandle, strlen(szVarname), (char*)szVarname, &read);

    return nErr;
}

PLC变量的句柄再次释放 AdsFreeVarHandle和AdsFreeVarHandleEx.
long AdsFreeVarHandle(AmsAddr* pServerAddr, long handle)
{
    return AdsSyncWriteReq(pServerAddr, ADSIGRP_SYM_RELEASEHND, 0,
                           sizeof(handle), &handle);
}

long AdsFreeVarHandleEx(long port, AmsAddr* pServerAddr, long* pHandle)
{
    return AdsSyncWriteReqEx(port, pServerAddr, ADSIGRP_SYM_REALEASEHND, 0,
                             sizeof(handle), &handle);
}

以下两种方法是写入PLC变量'.switch'并且设置其速度慢或者快.
long SpeedSlowEx(long port, AmsAddr* pServerAddr)
{
    // Handle der SPS-Variable ".switch" erstellen.
    long handleSpeedSlow = 0;
    long adserror = AdsGetVarHandleEx(port, pServerAddr, ".switch", &handleSpeedSlow);

    // Die SPS-Variable ".switch" auf FALSE setzen
    bool datafalse = false;
    adserror = AdsSyncWriteReqEx(port, pServerAddr, ADSIGRP_SYM_VALBYHND,
                                 handleSpeedSlow, 0x1, &datafalse);

    // Handle der SPS-Variable ".switch" freigeben
    adserror = AdsFreeVarHandleEx(port, pServerAddr, handleSpeedSlow);
    return adserror;
}

long SpeedFastEx(long port, AmsAddr* pServerAddr)
{
    // Handle der SPS-Variable ".switch" erstellen.
    long handleSpeedFast = 0;
    long adserror = AdsGetVarHandleEx(port, pServerAddr, ".switch", &handleSpeedFast);

    // Die SPS-Variable ".switch" auf TRUE setzen
    bool datatrue = true;
    adserror = AdsSyncWriteReqEx(port, pServerAddr, ADSIGRP_SYM_VALBYHND,
                                 handleSpeedFast, 0x1, &datatrue);

    // Handle der SPS-Variable ".switch" freigeben
    adserror = AdsFreeVarHandleEx(port, pServerAddr, handleSpeedFast);
    return adserror;
}

用这种连接方法，在PLC中创建一个变量连接。
long connect (long port, AmsAddr* pServerAddr, PAdsNotificationFuncEx Callback)
{
    // Attribute der Notification festlegen
    AdsNotificationAttrib attr;
    attr.cbLength = 2;
    attr.nTransMode = ADSTRANS_SERVERCYCLE;
    attr.nMaxDelay = 100000000; // = 1 sec
    attr.nCycleTime = 100000; // = 0,5 sec

    // Handles der SPS-Variablen holen

    long adserr = AdsGetVarHandleEx(port, addr, ".engine", &hEngine);

    if(adserr == 0)
        adserr = AdsGetVarHandleEx(port, addr, ".deviceUp", &hDeviceUp);

    if(adserr == 0)
        adserr = AdsGetVarHandleEx(port, addr, ".deviceDown", &hDeviceDown);

    if(adserr == 0)
        adserr = AdsGetVarHandleEx(port, addr, ".steps", &hSteps);

    if(adserr == 0)
        adserr = AdsGetVarHandleEx(port, addr, ".count", &hCount);

    if(adserr == 0)
        adserr = AdsGetVarHandleEx(port, addr, ".switch", &hSwitch);

    // Überwachung der SPS-Variablen initialisieren

    if(adserr == 0)
    {
        attr.cbLength = 1;
        adserr = AdsSyncAddDeviceNotificationReqEx(port, addr, ADSIGRP_SYM_VALBYHND, hEngine,
                                                   &attr, Callback, engine, &hEngineNotification);
    }
    if(adserr == 0)
    {
        attr.cbLength = 1;
        adserr = AdsSyncAddDeviceNotificationReqEx(port, addr, ADSIGRP_SYM_VALBYHND, hDeviceUp,
                                                   &attr, Callback, deviceUp, &hDeviceUpNotification);
    }
    if(adserr == 0)
    {
        attr.cbLength = 1;
        adserr = AdsSyncAddDeviceNotificationReqEx(port, addr, ADSIGRP_SYM_VALBYHND, hDeviceDown,
                                                   &attr, Callback, deviceDown, &hDeviceDownNotification);
    }
    if(adserr == 0)
    {
        attr.cbLength = 1
        adserr = AdsSyncAddDeviceNotificationReqEx(port, addr, ADSIGRP_SYM_VALBYHND, hSteps,
                                                   &attr, Callback, steps, &hStepsNotification);
    }
    if(adserr == 0)
    {
        attr.cbLength = 2;
        adserr = AdsSyncAddDeviceNotificationReqEx(port, addr, ADSIGRP_SYM_VALBYHND, hCount,
                                                   &attr, Callback, count, &hCountNotification);
    }
    if(adserr == 0)
    {
        attr.cbLength = 1;
        adserr = AdsSyncAddDeviceNotificationReqEx(port, addr, ADSIGRP_SYM_VALBYHND, hSwitch,
                                                   &attr, Callback, switchSpeed, &hSwitchNotification);
    }

    return adserr;
}

当Ads通信断开时，必须释放PLC变量的句柄且关闭端口。
long disconnect(long port, AmsAddr* addr)
{
    // Handles der SPS-Variablen freigeben
    AdsFreeVarHandleEx(port, addr, hEngine);
    AdsFreeVarHandleEx(port, addr, hDeviceUp);
    AdsFreeVarHandleEx(port, addr, hDeviceDown);
    AdsFreeVarHandleEx(port, addr, hSteps);
    AdsFreeVarHandleEx(port, addr, hCount);
    AdsFreeVarHandleEx(port, addr, hSwitch);

    // Notifications löschen
    AdsSyncDelDeviceNotificationReqEx(port, addr, hEngineNotification);
    AdsSyncDelDeviceNotificationReqEx(port, addr, hDeviceUpNotification);
    AdsSyncDelDeviceNotificationReqEx(port, addr, hDeviceDownNotification);
    AdsSyncDelDeviceNotificationReqEx(port, addr, hStepsNotification);
    AdsSyncDelDeviceNotificationReqEx(port, addr, hCountNotification);
    AdsSyncDelDeviceNotificationReqEx(port, addr, hSwitchNotification);

    // Kommunikationsport schließen
    AdsPortCloseEx(port);

    return 0;
}

6. 源代码处理

 首先，头文件必须包含SilverlightForEmbeddedMachineSample.cpp file.

#include "pwinuser.h"
#include "xamlruntime.h"
#include "xrdelegate.h"
#include "xrptr.h"

#include "resource.h"

以下是变量声明
IXRDelegate<XRMouseButtonEventArgs>* clickdelegate;

UINT exitcode;

IXRVisualHostPtr   vhost;
IXRButtonBasePtr   butClose;
IXRRadioButtonPtr  radSpeedSlow;
IXRRadioButtonPtr  radSpeedFast;
IXRTextBlockPtr    txtDeviceDown;
IXRTextBlockPtr    txtDeviceUp;
IXRTextBlockPtr    txtCount;
IXRProgressBarPtr  prgSteps;

IXRStoryboardPtr   timelineDeviceDown;
IXRStoryboardPtr   timelineDeviceUp;
IXRStoryboardPtr   timelineEngine;

long port;
AmsAddr addr;

unsigned long TimerID;
DWORD EventID;
CRITICAL_SECTION cs;
long event_cnt;
long event_cntold;

void __stdcall Callback(AmsAddr* addr, AdsNotificationHeader* handler, unsigned long User);

定时器回调功能检查Ads连接，必要时恢复连接。
VOID CALLBACK MyTimerProc(
    HWND hwnd,     // handle to window for timer messages
    UINT message,  // WM_TIMER message
    UINT idTimer,  // timer identifier
    DWORD dwTimer) // current system time
{
    if (event_cnt = event_cntold)
    {
        // Handels werden freigegen und der Port geschlossen
        disconnect(port, &addr);

        // Kommunikationsport auf dem ADS Router öffnen
        port = AdsPortOpenEx();

        addr.port = 0x321;
        long adserror = -1;

        // Neue Verbindung zur SPS herstellen.
        while(adserror != 0)
        {
            adserror = connect(port, &addr, Callback);
            Sleep(1000);
        }
    }

    event_cntold = event_cnt;
}

如果PLC变量连接发生改变，称之为Ads Event 处理。

// ADS-State Callback-Function
void __stdcall Callback(AmsAddr* addr, AdsNotificationHeader* handler, unsigned long User)
{
    event_cnt++;

对应的箭头是否变红，取决于deviceUp, deviceDown 或 engine 是否设置为TRUE.

这种效应可以进一步提高时间表的使用。

    if (User == deviceUp)
    {
        if (*(bool*)handler->data == true)
        {
            timelineDeviceDown->Stop();
            timelineEngine->Stop();
            timelineDeviceUp->Begin();
        }
    }
    else if (User == deviceDown)
    {
        if(*bool*)handler-data == true)
        {
            timelineDeviceUp->Stop();
            timelineEngine->Stop();
            timelineDeviceDown->Begin();
        }
    }
    else if (User == engine)
    {
        if (*(bool*)handler->data == true)
        {
            timelineDeviceDown->Stop();
            timelineDeviceUp->Stop();
            timelineEngine->Begin();
        }
    }

steps 显示了周期数。 该数值是通过进程条prgSteps输出的。由于相关的PLC变量类型是字节，因此，数据必须先转换成一个字节。 由于进度条只能传输float型的数据，因此需要先转换为float类型。
    else if (User == steps)
    {
        prgSteps->SetValue((float)*((byte*)handler->data));
    }

在count 的情况下，数据必须先转换成其类型的原始数据，才可以转换成文本并转移到文本块 txtCount.
    else if (User == count)
    {
        WCHAR text[6];
        wsprintf(text, L"%d", *(unsigned short*)handler->data);
        txtCount->SetText(text);
    }

速度类型通过 radio 按钮来输出。相应radio按钮设定取决于速度。
    else if (User == switchSpeed)
    {
        if (*(bool*)handler->data == true)
        {
            radSpeedFast->SetIsChecked(XRThreeState_Checked);
        }
        else
        {
            radSpeedSlow->SetIsChecked(XRThreeState_Checked);
        }
    }
}

我们可以利用名称来区分 OnClick 事件触发的各种实例和启动实例。

class BtnEventHandler
{
public:

    HRESULT OnClick(IXRDependencyObject* source, XRMouseButtonEventArgs* args)
    {
        BSTR name;
        HRESULT hr = NULL;
        source->GetName(&name);

        short state = 0;

        long adserror = 0;

        if wcscmp(name, L"butClose") == 0)
        {
            // Machine Dialog schließen
            vhost->EndDialog(exitcode);
        }
        if wcsmp(name, L"radSpeedSlow") == 0)
        {
            // Aufruf der Methode SpeedSlowEx um die Geschwindigkeit auf langsam zu setzen.
            adserror = SpeedSlowEx(port, &addr);
        }
        if wscmp(name, L"radSpeedFast") == 0)
        {
            // Aufruf der Methode SpeedFastEx um die Geschwindigkeit auf schnell zu setzen.
            adserror = SpeedFastEx(port, &addr);
        }

        if (adserror != NULL)
        {
            // Die Handels werden freigegen und der Port geschlossen
            disconnect(port, &addr);

            // Der Kommunikationsport auf dem ADS-Router wird geöffnet
            port = AdsPortOpenEx();

            addr.port = 0x321;

            // Neu Verbindung zur SPS herstellen.
            adserror = connect(port, &addr, Callback);

            Sleep(1000);
        }

        SysFreeString(name);
        return S_OK;
    }
};

在WinMain的方案中 , XMAL runtime必须先初始化。在XamlRuntime 完成初始化后, Windows Embedded Silverlight Runtime 在应用项目中启动.

int WINAPI WinMain(HINSTANCE hInstance
                  HINSTANCE hPrevInstance,
                  LPTSTR lpCmdLine,
                  int nCmdShow)
{
    // Initialisierung der XAML Runtime
    if (!XamlRuntimeInitialize())
        return -1;

每个 Windows Embedded application 的Silverlight 有自己的 "applications" 对象, 可以通过它访问全局对象。
利用GetXRApplicationInstance API 来访问该对象。
    HRESULT retcode;

    // Load an dinit XAML resource
    IXRApplicationPtr app;

    if (FAILED (retcode=GetXRApplicationInstance(&app)))
        return -1;

    if (FAILED (retcode=app->AddResourceModule(hInstance)))
        return -1;

在应用程序对象初始化后，可以创建一个主窗口，对象的管理可以交由Windows Embedded 的 Silverlight 来完成。
    XRWindowCreateParams wp;

    ZeroMemory(&wp, sizeof(XRWindowCreateParams));

    // Set window styles
    wp.Style = WS_BORDER;
    wp.pTitle = L"Silverlight for Windows Embedded Machine Sample";
    wp.Left = 0;
    wp.Top = 0;
    wp.AllowsMultipleThreadAccess = true;

    XRXamlSource xamlsrc;

    xamlsrc.SetResource(hInstance, TEXT("XAML"), MAKEINTRESOURCE(IDR_XAML1));

    if (FAILED(retcode=app->CreateHostFromXaml(&xamlsrc, &wp, &vhost)))
        return -1;

Windows Embedded application 的 Silverlight 中的对象可以在对象树种组织起来。 为了访问该对象，必须有一个指向根要素的指针。
    IXRFrameworkElementPtr root;

    if (FAILED (retocde=app->CreateHostFromXaml(&xamlsrc, &wp, &vhost)))
        return -1;

控制和时间表实例的创建
    // Get controls by name
    if (FAILED(retcode=root->FindName(TEXT("butClose"), &butClose)))
        return -1;

    if (FAILED(retcode=root->FindName(TEXT("radSpeedSlow", &radSpeedSlow)))
        return -1;

    if (FAILED(retcode=root->FindName(TEXT("radSpeedFast", &radSpeedFast)))
        return -1;

    if (FAILED(retcode=root->FindName(TEXT("txtDeviceDown", &txtDeviceDown)))
        return -1;

    if (FAILED(retcode=root->FindName(TEXT("txtDeviceUp", &txtDeviceUp)))
        return -1;

    if (FAILED(retcode=root->FindName(TEXT("txtCount", &txtCount)))
        return -1;

    if (FAILED(retcode=root->FindName(TEXT("prgSteps", &prgSteps)))
        return -1;

    // Get timelines by name
    if (FAILED (retcode=root->FindName(TEXT("timelineDeviceDown"), &timelineDeviceDown)))
        return -1;

    if (FAILED (retcode=root->FindName(TEXT("timelineDeviceUp"), &timelineDeviceUp)))
        return -1;

    if (FAILED (retcode=root->FindName(TEXT("timelineEngine"), &timelineEngine)))
        return -1;

创建 "RadioButtonGroup" 并从该组中分配两个单选按钮。
    WCHAR groupName[17];
    wsprintf(groupName, L"RadioButtonGroup");
    radSpeedFast->SetGroupName(groupName);
    radSpeedSlow->SetGroupName(groupName);

A redirecting object is needed to link the EventHandler with the buttons.
    BtnEventHandler handler;

    // Set the event handler for the buttons
    if (FAILED(retcode=CreateDelegate(&handler, &BtnEventHandler::OnClick, &clickdelegate)))
        return -1;

    if (FAILED(retcode=butClose->btnAddClickEventHandler(clickdelegate)))
        return -1;

    if (FAILED(retcode=radSpeedSlow->AddClickEventHandler(clickdelegate)))
        return -1;

    if (FAILED(retcode=radSpeedFast->AddClickEventHandler(clickdelegate)))
        return -1;

整合 Ads 组件
    long adserror = -1;
    port = AdsPortOpenEx();

    AdsGetLocalAddressEx(port, &addr);

    // connect to the PLC and register callbacks
    addr.port = 0x321;
    adserror = connect(port, &addr, Callback);

    event_cnt = 0;
    event_cntold = -1;

    // init timer for reconnect
    SetTimer(NULL, NULL, 5000, MyTimerProc);

    if (FAILED(retcode=vhost->StartDialoge(&exitcode)))
        return -1;

    // cleanup
    disconnect(port, &addr);
    clickdelegate->Release();

    return 0;
}

7. features

在project features中， xamlruntime.lib 与TcAdsDllCe.lib 之间必须建立一个连接。

Download Silverlight for Windows Embedded example

Sample Silverlight for Windows Embedded