dinsdag 27 januari 2009

Prism: Compact Framework en Asynchrone functies

Ik heb een kleine test gedaan om te kijken of je met Delphi Prism en het Compact Framework ook "async" blokken en "future" variabelen kunt gebruiken (voor parallelle c.q. asynchrone verwerking). Hiervoor maakte ik een klein test project (zie mijn vorige blog) met onder een knop de volgende (nutteloze) test code:
method MainForm.button1_Click(sender: System.Object; e: System.EventArgs);
begin
var i: future Integer;
var j: Integer;

i := async 1; //background asigning 1 to i, next line will wait
j := 2 + i; //j should be 3 now
end;
Prism compileert de code gewoon, alleen als ik tijdens het runnen op de bewuste test knop druk, krijg ik een foutmelding: FileLoadException System.Core.dll.
Ook in de emulator gaat het fout, en krijg ik dezelfde foutmelding. Tijd om even wat dingen uit te zoeken!

RemObjects (de makers van de Oxygene c.q. Prism compiler) heeft gelukkig een aantal nieuwsgroepen waar actief en snel reactie gegeven wordt:
Support page: http://www.remobjects.com/support.aspx
Newsgroup support: http://www.remobjects.com/page.aspx?id={C4764DFE-288D-4C17-90F8-FA5B7BFB3BCB}

Aangezien de PublicKeyToken belangrijk is bij het laden van assembly's, heb ik met .Net Reflector gekeken naar de references van mijn executable. Hierbij viel gelijk het probleem op:
Alle references wezen naar assembly's met PublicKeyToken=969db8053d3322ac, behalve "System.Core.dll", deze verwees naar b77a5c561934e089!
In de nieuwsgroep kreeg ik de tip om het project te compileren met de gratis command line compiler. En om met de hand mijn .oxygene bestand (=project file) aan te passen, zodat het de goede reference voor System.Core.dll zou gebruiken:


(op de een of andere manier lukt het niet om als tekst te doen: opmaak gaat fout bij XML...)

Vervolgens gecompileerd via de command line:
oxygene.exe -rebuild -frameworkfolder="C:\Program files\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE"
En nu kan ik hem wel gewoon draaien en debuggen... alleen op de desktop... Helaas gaat het nog steeds fout in de emulator (harde crash zonder foutmelding).
Als je kijkt met Proces Explorer welke dlls hij op de desktop gebruikt, blijkt dat .Net altijd de volledige (niet de CF) System.Core.dll gebruikt: deze is wel aanwezig op de desktop, maar uiteraard niet in de emulator.

Als laatste poging heb ik via .Net Reflector met de FileGenerator plugin mijn assembly geëxporteerd naar C# code:
Het trouwens wel interessant om te kijken wat voor code automatisch gegenereerd wordt voor mijn paar regels code (de meeste code zit overigens in de "FutureHelper" class):
Vervolgens heb ik met C# Visual Studio Express een nieuw project aangemaakt (zie deze link voor VS Express en Compact Framework). Na wat aanpassingen compileerde het en kon ik het testen in de emulator. Deze geeft gelukkig wat meer informatie: op de volgende regel gaat het fout:
Func func = PrivateImplementationDetails.FutureHelper.ExecuteAsync(delegate {
return 1;
}, true);
Deze geeft de foutmelding:
NotSupportedException: .Net Compact Framework does not support invoking delegates asynchronously
Dus het Compact Framework ondersteunt deze functionaliteit gewoon niet! Dus einde oefening...

In ieder geval was het erg leerzaam (onder het motto: je leert het meest bij fouten). Waarschijnlijk zal CodeGear/RemObjects in de volgende versie een aantal kleine bugs die ik tegen kwam verhelpen. Misschien dat .Net CF versie 4 wel betere asynchrone ondersteuning heeft (dmv Parallel Extensions).

vrijdag 23 januari 2009

Delphi 2009: nieuwe IDE, Language en GUI features

Codegear heeft een aantal Whitepapers op hun website staan. Deze zijn erg interessant om door te lezen! Hierin staat veel nuttige informatie over de veranderingen die in Delphi 2009 zitten. Om eerlijk te zijn: er zijn veel meer veranderingen en verbeteringen dan ik eerst dacht! Ik kan niet alles opnoemen, maar ik heb wel even een overzicht gemaakt:

De nieuwste Whitepaper van Marco Cantu gaat over User Interface wijzigingen (VCL):
http://dn.codegear.com/article/images/39226/Building-User-Interfaces-with-Delphi-2009_WP.pdf

Om even een idee te geven zal ik de deze wijzigingen kort bespreken:

  • Custom hints en Balloon hints

In plaats van saaie simpele hints, kun je nu gelikte hints geven, met een image en title:

  • TButton uitbreidingen

Deze heeft nu standaard image support (net als TBitButton), CommandLink type, Dropdown button, Elevation required (Vista UAC) property:

  • Edit control uitbreidingen

Er is oa een Alignment property toegevoegd (text left/right), "numbers only" format, empty text hint, XP password char:

  • Nieuwe TButtonedEdit control

Dit is een nieuwe edit control, met rechts een button en een image, en de mogelijkheid voor een drop down menu:

  • Listview grouping

De listview ondersteunt nu ook geavanceerde groupings!

  • Nieuwe CatagoryPanelGroup control

Nog een nieuwe control, waarbij de panels kunnen in en uitklappen:

  • Verbeterde graphics support

Nu ingebouwde PNG ondersteuning, 32bit bitmaps (met transparantie kanaal), en "PartialTransparency" support.

  • Nieuwe Ribbon control (Office 2007 Ribbon)

Een door Codegear ontwikkelde Ribbon control (die veel lijkt qua werking en uiterlijk op de Office 2007 Ribbon):

Conclusie: redenen genoeg om Delphi 2009 te gaan gebruiken!

woensdag 21 januari 2009

Delphi Enumerators: "for o in MyObject do"

Ik gebruik Delphi 2007 nog niet zo heel lang, omdat de huidige klant nog de oude Delphi 6 versie gebruikte. Sowieso zijn er best veel bedrijven die bijvoorbeeld Delphi 7 nog steeds gebruiken (wat vaak gewoon goed bevalt). Best jammer, want Delphi 2007 en 2009 zijn mooie en goede Delphi versies, met veel verbeteringen: IDE, VCL en Language features.

Het nadeel van nieuwe features is echter: je moet ze wel gebruiken :-). Heel gauw ben je geneigd om je oude gewoontes te blijven gebruiken: bijvoorbeeld nog steeds "for i := 0 to stringlist.Count-1 do" gebruiken in plaats van "for s in stringlist".

Ik had al eens een serie interessante blogs gelezen over "fun with enumerators":
http://17slon.com/blogs/gabr/2007/03/fun-with-enumerators-part-1.html
http://17slon.com/blogs/gabr/2007/03/fun-with-enumerators-part-2-multiple.html
http://17slon.com/blogs/gabr/2007/03/fun-with-enumerators-part-3.html
http://17slon.com/blogs/gabr/2007/03/fun-with-enumerators-part-4-external.html
http://17slon.com/blogs/gabr/2007/03/fun-with-enumerators-part-5-class.html

In feite komt het erop neer, dat elke class die een "public GetEnumerator" functie heeft, gebruikt kan worden voor een "for in" loop.
De GetEnumerator functie moet een class teruggeven met de volgende functies (als voorbeeld van TStringList.GetEnumerator):
TStringsEnumerator = class
public
function GetCurrent: string;
function MoveNext: Boolean;
property Current: string read GetCurrent;
end;
Van de volgende code...:
for s in stringlist do
ShowMessage(s);
...maakt Delphi onderwater de volgende code ervan:
enumerator := stringlist.GetEnumerator;
while enumerator.MoveNext do
begin
s := enumerator.Current;
ShowMessage(s);
end;
enumerator.Free;
Je kunt dus ook zelf eenvoudig aan een eigen class deze handige enumerator functionaliteit toevoegen! Of via "class helpers" aan een bestaande class.

Op een gegeven moment was ik het namelijk zat om steeds "for i to count-1" te gebruiken, en toen moest ik weer denken aan de eerder genoemde blogs. Met de bovenstaande code kon ik zelf een veelgebruikte class even uitbreiden met enumerators :-).

Trouwens, "for in" kun je ook gebruiken met arrays en sets:
var i:integer;
c: char;
begin
for i in intergerarray do ;
for c in teststring do ;
end;

vrijdag 16 januari 2009

VMware ThinApp: Package Once, Deploy Everywhere

Met VMware ThinApp kun je willekeurige programma's gebruiken zonder te installeren. Hierbij draait het bewuste programma in een aparte "sandbox": je kunt dus virtualizeren zonder een complete VMware image te gebruiken! Alle harde schijf en Windows Registry toegang wordt afgevangen en geemuleerd.
Zo kun je bijvoorbeeld Microsoft Office 2007 op je USB stick zetten en op elke computer gebruiken, zonder te installeren!

Afhankelijk van de instellingen kun je ervoor kiezen voor een volledige sandbox: alle wijzigingen (behalve "My Documents" en Desktop) worden niet doorgevoerd in de echte Windows installatie, maar zijn alleen actief binnen de sandbox (ook na herstart). Maar er is ook een semi-sandbox mode: alle normale wijzigingen worden doorgevoerd, maar geen systeem wijzigingen. Deze laatste is handig voor Office: je kunt gewoon op de eigen plek je documenten opslaan.

Om een nieuwe ThinApp package te maken, moeten een aantal stappen in de ThinApp creator doorlopen worden:
  1. snapshot maken van Registry en lijst maken van huidige bestanden

  2. je programma installeren en instellen
  3. nieuwe snapshot maken van Registry en lijst maken van gewijzigde en nieuwe bestanden
  4. Alle verschillen tussen 1e en 2e snapshot worden in een aparte directory opgeslagen
  5. Selectie maken van de executables waarvoor een ThinApp koppeling gemaakt moet worden
  6. Isolation mode instellen
  7. Je kunt een MSI installer package maken, of ongecomprimeerd om makkelijk te testen

Vervolgens kun je een koppeling starten (zelfde icoontje etc, alleen executable start intern ThinApp op) en gebruiken. Het programma kan vervolgens alle bestanden op je computer normaal benaderen (lezen), maar wijzigingen worden (afhankelijk van instellingen) alleen binnen de sandbox opgeslagen. Alle registry instellingen die tijdens de installatie gemaakt zijn, zijn voor het programma binnen de sandbox gewoon transparant beschikbaar. Hierdoor denkt bijvoorbeeld MS Office 2007 dat het gewoon normaal op de computer geinstalleerd is.

Als je met bijvoorbeeld Process Explorer kijkt, zie je verder geen verschil tussen andere programma's. Het gebruikt alleen een extra dll, die waarschijnlijk de virtualisatie van Registry en Filesystem regelt:

dinsdag 13 januari 2009

Delphi Prism & Compact Framework

Met Delphi Prism kan ook voor het .Net Compact Framework gecompileerd worden.
Hiermee kan eenvoudig .Net applicaties voor mobile apparaten gemaakt worden.
Hoewel het Compact Framework beperkter is, kan met de nieuwste 3.5 versie ook bijv. LINQ
gebruikt worden.


Een nadeel echter is dat de Form designer door Microsoft hard-coded voor C# en VB gemaakt is.
(hopelijk dat dit in de 2010 versie van Visual Studio verholpen is). Hier is wel eenvoudig omheen
te werken: de normale WinForms designer kan namelijk ook gebruikt worden, met de hand moet
eenmalig de niet ondersteunde properties verwijderd worden.

Als eerste moet het .Net Compact Framework 3.5 geïnstalleerd worden:
http://msdn.microsoft.com/en-us/netframework/aa497280.aspx

Vervolgens kan in Delphi Prism een Windows Forms project gemaakt worden:

Project properties

Open na het maken van het project de properties van het project:

Hierin moet het "Framework folder" verwijzen naar het Compact Framework:
C:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE


Voor het gemak veranderen we gelijk het "Output path" naar een gedeelde directory, zodat we later eenvoudig in de Mobile Emulator het programma kunnen testen.

Om te voorkomen dat we tijdens het runnen een ResourceNotFound exception krijgen, verwijderen we het icoon:

References

Nu zal het project nog niet compileren: omdat voor het Compact Framework gecompileerd wordt, moeten de references aangepast worden. Selecteer alle references, rechtermuis klik, en dan "Properties":

Verander vervolgens de "Ignore version" van "False" naar "True":

Test scherm

We gaan nu een test scherm maken. Omdat de resolutie van ons mobiel apparaat niet zo groot is, stellen we ons form hierop in: 240x400

We plaatsen nu een aantal controls op het form, bijvoorbeeld:

Om de test compleet te maken, dubbel klikken we op de "Add to list" knop en voegen we de volgende regel code toe:

Main.pas

...

method MainForm.button1_Click(sender: System.Object; e: System.EventArgs);

begin

listBox1.Items.Add( textBox1.Text );

end;

Compileren

Nu zal het project nog steeds niet willen compileren, maar we zijn er bijna. Eerst moeten de regels code waar de compiler over struikelt uitgeschakeld worden, omdat het Compact Framework deze niet ondersteunt. Bijvoorbeeld: STAThread, Application.EnableVisualStyles, ThreadException, etc:

Program.pas

//[STAThread]

class method Program.Main;

begin

//Application.EnableVisualStyles();

//Application.SetCompatibleTextRenderingDefault(false);

//Application.ThreadException += OnThreadException;

using lMainForm := new MainForm do

Application.Run(lMainForm);

end;

In de Form designer bijvoorbeeld FormattingEnabled, AutoSize, etc:

Main.Designer.pas

...
//self.comboBox1.FormattingEnabled := true;//self.checkBox1.AutoSize := true;

//self.checkBox1.UseVisualStyleBackColor := true;

//self.listBox1.FormattingEnabled := true;

...

//self.PerformLayout();

We verwijderen nog een aantal regels, totdat alles compileert. Vervolgens kunnen we ons programma testen:

Op deze manier kun je eenvoudig en snel testen en debuggen: je hebt hiervoor geen mobiel apparaat of emulator nodig!

Mobile Emulator

Nu is het tijd om ons programma op een mobiel apparaat te testen. Het makkelijkste is om hiervoor een emulator te gebruiken. Installeer hiervoor de nieuwste emulator images:
Windows Mobile 6.1.4 Emulator Images

Vervolgens starten we de 240x400 image op:

Om ons programma te kunnen testen moeten we onze gedeelde directory instellen, via Configure:

En dan de "Shared Folder" in de "General" tab:

We kunnen nu deze map openen in de "File Explorer" door de "Storage Card" te selecteren:

Voordat we ons test programma kunnen testen, moet eerst het Compact Framework nog in de emulator geïnstalleerd worden. Hiervoor heb ik het bestand "NETCFv35.wm.armv4i.cab" in de gedeelde map gekopieerd. Dit bestand staat normaal gesproken in installatie map van het Compact Framework:
c:\Program Files\Microsoft.NET\SDK\CompactFramework\v3.5\WindowsCE\NETCFv35.wm.armv4i.cab

Nadat het Compact Framework geïnstalleerd is, kunnen we ons test programma starten:

Tip: Sluiten ipv minimize

Standaard worden mobiele programma's niet afgesloten (door te klikken op het X rechtsbovenin), maar geminimaliseerd: als de gebruiker het programma weer opstart, verschijnt het programma direct omdat het nog in het geheugen staat. Dit voorkomt dat de gebruiker elke keer een poos moet wachten totdat het programma weer gestart is.
Voor debuggen is dit natuurlijk lastig: je moet elke keer je programma "killen" via de "Task Manager". Verander hiervoor de propertie "MinimizeBox" van het form, en zet deze op "False", nu verschijnt een "Ok" knop in plaats van een "X" knop op het scherm, en wordt het programma afgesloten in plaats van geminimaliseerd!