Maarten Struys is principal consultant en embedded-Windows-evangelist bij Alten PTS.

3 April 2012

Silverlight for Embedded maakt het mogelijk om applicaties onder Windows Embedded Compact 7 een modern uiterlijk te geven, waardoor het OS niet meer herkenbaar is als een Microsoft-product. Maarten Struys van Alten PTS legt uit hoe dit in zijn werk gaat.

Windows Embedded Compact 7 is de jongste versie van Microsofts lichtgewicht embedded besturingssysteem met hard realtime gedrag. Naast ondersteuning voor multicore processoren en veel nieuwe features biedt het vooral nieuwe GUI-functionaliteit. Tot aan versie 6.0 R3 had Embedded CE (zoals het toen nog heette) in principe hetzelfde uiterlijk als Windows op de desktop. Wel was het mogelijk een eigen shell te gebruiken, waardoor het OS van een embedded toepassing niet direct te herkennen was als een Windows-variant. In de laatste versies kunnen we applicaties een moderner uiterlijk geven, onder meer via Adobe Flash of Silverlight for Embedded.

Silverlight

Net als Flash was Silverlight oorspronkelijk een in browsers inplugbare component waarmee bijvoorbeeld animaties eenvoudig zichtbaar zijn te maken in webapplicaties. In eerste instantie waren de toepassingen dan ook webapplicaties die een (kleine) deelverzameling van Microsofts .Net-framework kunnen gebruiken. Silverlight kent een losse koppeling tussen presentatie en functionaliteit. De userinterface wordt beschreven in Xaml, een XML-gebaseerde taal. Dat kan handmatig met een teksteditor, maar we kunnen de code ook genereren met het programma Expression Blend. Door de volledige loskoppeling tussen GUI en functionaliteit is het eenvoudig om in grotere projecten aparte ontwerpers verantwoordelijk te maken voor de complete GUI en kunnen softwareontwikkelaars zich beperken tot het realiseren van de gewenste functionaliteit. In dat geval kan Xaml worden gezien als contract tussen ontwerper en ontwikkelaar.

Silverlight for Embedded is de speciale implementatie voor Windows Embedded Compact. Deze uitvoering werkt buiten de browser en is dus toe te passen voor elke applicatie die op een embedded systeem moet draaien. De overeenkomst met Silverlight is het gebruik van Xaml. Afhankelijk van de exacte versie betekent dit dat we een GUI-ontwerp kunnen delen tussen applicaties voor het web, de desktop en Windows CE.

In de praktijk is dit echter nauwelijks relevant. Silverlight for Embedded is namelijk heel specifiek voor embedded-gebruik. Om commando‘s van gebruikers te kunnen ontvangen en informatie zichtbaar te maken, biedt Silverlight de mogelijkheid om achter elke GUI-component code te plaatsen. Bij de embedded-variant schrijven we deze code in C++ en koppelen we GUI-bouwblokken aan functionaliteit via een aantal Com-componenten. Bij de desktop- en browserversies gaat het om C# of Visual Basic.Net en zit de koppeling in de (kleine) deelverzameling van het .Net-framework. Het gebruik van C++ en Com kost minder geheugen en zorgt voor een betere performance, maar code uitwisselen is er in principe niet meer bij.

BCe24 save the date

Commando‘s van gebruikers

Om Silverlight for Embedded-applicaties te kunnen bouwen, moeten we het besturingssysteem daarop voorbereiden. Dit is eenvoudig te realiseren met Visual Studio 2008, waarin we de benodigde Silverlight for Embedded-functionaliteit kunnen toevoegen vanuit de catalogus van Windows CE-componenten. Voor een snelle start is zelfs een template aanwezig om een OS-design te maken dat alle verplichte ingrediënten bevat.

Silverlight for Embedded stelt ook eisen aan de uiteindelijke systeemhardware, onder meer aan de grafische mogelijkheden. Om de applicatie soepel te laten lopen, moet de hardware minimaal beschikken over een 2D- of 3D-GPU met Directdraw of OpenGL (ES 2.0). Is zo‘n grafische motor er niet, dan kunnen niet al te veeleisende toepassingen nog wel draaien, maar krijgt de CPU van het systeem veel meer werk te verstouwen.

Een succesvol gebouwd besturingssysteem kunnen we uittesten op fysieke hardware of in een virtuele pc-omgeving. Als we het OS eenmaal werkend hebben, dan kunnen we hier met Visual Studio 2008 eigen applicaties aan toevoegen, die daarbij als het ware worden geïntegreerd met het embedded systeem. Willen we de vaart erin houden, dan kunnen we vanuit een met Expression Blend gemaakte GUI een initieel C++-project genereren dat we kunnen opnemen in het OS-design en waarin alle interface-elementen zijn gedefinieerd. Dit project kunnen we vervolgens uitbreiden met specifieke applicatiefunctionaliteit.

Met Windows Embedded Silverlight Tools (een plug-in voor Visual Studio 2008) is de Xaml-code om te zetten in C++. De koppeling tussen GUI-elementen en C++-code is ook handmatig te realiseren, maar dat is uiteraard arbeidsintensiever en lastiger te onderhouden. Het gebruik van Windows Embedded Silverlight Tools maakt het bovendien mogelijk om eventuele wijzigingen in de userinterface via codegeneratie weer op te nemen in het Silverlight for Embedded-project.

Om code te kunnen genereren met Silverlight Tools moet de in Xaml gedefinieerde GUI wel aan een paar voorwaarden voldoen. Zo moeten de bestanden voor de Silverlight-applicatie en de hoofdpagina beschikbaar zijn onder de respectievelijke namen ’App.xaml‘ en ’MainPage.xaml‘. Vervolgens moeten we de gegenereerde code toevoegen aan het OS-design. Dit is een simpele handmatige handeling. Na compilatie van de nieuw toegevoegde applicatie kunnen we deze samen met het besturingssysteem uittesten.

Net als een traditioneel Windows-programma moet een toepassing met een Silverlight for Embedded-GUI natuurlijk reageren op commando‘s van gebruikers. In een Silverlight-applicatie komen deze binnen in de vorm van events. Door hier code aan te koppelen, krijgt de toepassing zijn eigen functionaliteit. Met Visual Studio 2008 en de Silverlight Tools-plug-in is deze koppeling zo gemaakt. De events die in de verschillende UI-elementen voor de applicatie beschikbaar zijn, zijn eenvoudig te selecteren.

Beschermde omgeving

Door de voorwaarden waaraan we moeten voldoen om codegeneratie van een applicatieraamwerk mogelijk te maken, is een Silverlight for Embedded-toepassing veel minder eenvoudig te bouwen dan een traditionele Silverlight-programma. Bovendien moeten we nog steeds onze toevlucht nemen tot C++ om specifieke functionaliteit te implementeren. Dat Silverlight for Embedded native code gebruikt, zorgt er wel voor dat de applicaties op de hoogst haalbare snelheid kunnen draaien in een embedded systeem en toch een moderne presentatie kunnen hebben, al dan niet voorzien van flitsende animaties.

De native implementatie van Silverlight for Embedded geeft elke Silverlight-applicatie in het embedded systeem toegang tot alle beschikbare Win32-Api‘s. Dit is een belangrijk voordeel boven een oplossing in managed code, omdat deze veel meer in een beschermde omgeving werkt en er daardoor minder functionaliteit beschikbaar is. Nadeel is wel dat de uitwisselbaarheid tussen traditionele Silverlight- en Silverlight for Embedded-toepassingen nihil is, tenzij we een extra abstractielaag introduceren die bijvoorbeeld native Silverlight for Embedded-code beschikbaar maakt voor managed talen als C#.

Aan de slag

Ter illustratie kiezen we het Click-event voor de eerste knop (btnPlay) in de voorbeeldapplicatie. Nadat de omgeving raamwerkcode voor de eventhandler heeft geproduceerd, kunnen we zelf functionaliteit toevoegen, bijvoorbeeld om een bericht te tonen. De geel gemarkeerde code is zelf ingevoerd, de rest is gegenereerd:

// ============================================================================
//  BtnPlay_Click
//
//  Description: Event handler implementation
//
//  Parameters:  pSender - The dependency object that raised the click event
//               pArgs - Event-specific arguments
// ============================================================================
HRESULT MainPage::BtnPlay_Click (IXRDependencyObject* pSender, XRMouseButtonEventArgs* pArgs)
{
   HRESULT hr = S_OK;
   IXRButtonPtr pButton;

   if ((NULL == pSender) || (NULL == pArgs))
   {
      hr = E_INVALIDARG;
   }
   else
   {
      BSTR btnName;

      pButton = pSender;
      pButton->GetName(&btnName);

      m_psldProgress->SetValue(50);

      MessageBox(NULL, _T("Msg from SL for Embedded Application"), btnName, MB_OK);
   }
   return hr;
}

Daarnaast stellen we vanuit de eventhandler de slider in die onder de knoppen zichtbaar is. Deze schuif kunnen we direct benaderen doordat de gegenereerde code declaraties bevat voor alle UI-elementen die Silverlight Tools in Xaml heeft gevonden:

// ============================================================================
//  WARNING: DO NOT EDIT THIS ALWAYS-GENERATED CODE
// ============================================================================
HRESULT OnLoaded(__in IXRDependencyObject* pRoot);
HRESULT InitializeComponent();

IXRGridPtr   m_pLayoutRoot;           // <Grid x:Name="LayoutRoot">
IXRButtonPtr m_pbtnPlay;              // <Button x:Name="btnPlay">
IXRImagePtr  m_pbtnPlay1;             // <Image x:Name="btnPlay1">
IXRSliderPtr m_psldProgress;          // <Slider x:Name="sldProgress">
IXRButtonPtr m_pbtnStop;              // <Button x:Name="btnStop">
IXRImagePtr  m_pbtnStop1;             // <Image x:Name="btnStop1">
// ============================================================================
//  WARNING: DO NOT EDIT THIS ALWAYS-GENERATED CODE
// ============================================================================

// ============================================================================
//  WARNING: DO NOT EDIT THIS ALWAYS-GENERATED CODE
// ============================================================================
HRESULT MainPage::InitializeComponent()
{
   HRESULT hr = E_FAIL;

   FindName(L"LayoutRoot", &m_pLayoutRoot);
   FindName(L"btnPlay", &m_pbtnPlay);
   FindName(L"btnPlay1", &m_pbtnPlay1);
   FindName(L"sldProgress", &m_psldProgress);
   FindName(L"btnStop", &m_pbtnStop);
   FindName(L"btnStop1", &m_pbtnStop1);

   if (m_pLayoutRoot &&
       m_pbtnPlay &&
       m_pbtnPlay1 &&
       m_psldProgress &&
       m_pbtnStop &&
       m_pbtnStop1
      )
   {
      hr = S_OK;
   }

   return hr;
}
// ============================================================================
//  WARNING: DO NOT EDIT THIS ALWAYS-GENERATED CODE
// ============================================================================

Nadat we vanuit Silverlight Tools een C++-raamwerk hebben gegenereerd op basis van de met Expression Blend ontworpen GUI en nadat we alle benodigde functionaliteit hebben toegevoegd, is een werkende applicatie beschikbaar die we in het embedded systeem kunnen opnemen.