Wednesday, February 22, 2012

Proof of Concept - Zonnon and WPF



Proof of Concept (POC) or a proof of principle is a realization of a certain method or idea(s) to demonstrate its feasibility, or a demonstration in principle, whose purpose is to verify that some concept or theory has the potential of being used. A proof-of-concept is usually small and may or may not be complete. (Wikipedia: Proof of Concept)
Concept is an idea formed from inference.
Inference is the act or process of deriving logical conclusions from premises known or assumed to be true.

Eh voilĂ ! I'm going to proof that you can use WPF and the .NET Framework 4.0 with the latest release of the ETH Zonnon compiler (2010-08-07: Zonnon Compiler 1.2.8) which officially runs on and targets .NET Framework 2.0, and to do that, I will show you some basic .NET hacking that I learned from the Cobra Programming Language guys :)

Let's start with the software you will need (in case you want to try it yourself) to follow this tutorial, then which files you will be using to reference, compile, decompile, edit and recompile, and finally, I will show step by step and with screenshots how to build a basic WPF program using Zonnon.

Software Requirements

Specific Assemblies
  • MSIL Disassembler for .NET 4.0
    • Ildasm.exe - version 4.0.30319.1
  • MSIL Assembler for .NET 4.0
    • Ilasm.exe - version 4.0.30319.1  
    • fusion.dll - version 4.0.30319.1
  • WPF 4.0 Assemblies
    • PresentationCore.dll - version 4.0.30319.1
    • PresentationFramework.dll - version 4.0.30319.1
    • WindowsBase.dll - version 4.0.30319.1
    • System.Xaml.dll - version 4.0.30319.1
  • ETH Zonnon compiler 1.2.8
    • zc.exe - Compiler Launcher Program
    • ETH.Zonnon.dll - Zonnon Compiler

Step #1: Installing ETH Zonnon Compiler 1.2.8

You can download from the link above. I installed in "C:\Zonnon" for ease of use (less typing).
After installation you should have the following files installed:






















Step #2: Project Directory

Create a new folder that will hold our source code and needed assemblies. Again, for ease of use, I created it within the Zonnon installation directoy "C:\Zonnon\wpfznn\" and copy all the assemblies listed in section "Specific Assemblies" except for the Zonnon Compiler assemblies (zc.exe and ETH.Zonnon.dll) which are located in the Zonnon folder.

At the end you should have something like the following:








Step #3: Writing Code

Using your favorite Text Editor, create a new Zonnon source code file for our program "wpfpoc.znn" and save it in our working directory we just created. Now type (or copy/paste) the following Zonnon source code on the file and save again.

module Main;
import 
    System.Byte as Byte,
    System.IO.Path as Path,
    System.Reflection.Assembly as Assembly,
    System.Reflection.AssemblyName as AssemblyName,
    (* WPF imports *)
    System.Xaml,
    System.Windows.Application as Application,
    System.Windows.Window as Window,
    System.Windows.Media.Color as Color,
    System.Windows.Media.SolidColorBrush as SolidColorBrush,    
    System.Windows.Controls.Button as Button,
    System.Windows.Controls.Label as Label,    
    System.Windows.Controls.StackPanel as StackPanel,
    System.Windows.SizeToContent as SizeToContent,
    System.Windows.Thickness as Thickness,
    System.Windows.Media.Brushes as Brushes,
    System.Windows.Media.Effects.DropShadowEffect as DropShadowEffect;
var        
    win: Window;    
    app: Application;
    c: Color;
    scb: SolidColorBrush;
    btn: Button;
    stk: StackPanel;
    asm : Assembly;
    asmn: AssemblyName;
    
procedure {public} onClick(sender: object; args: System.EventArgs);
var lbl: Label;
    msg: string;
begin
    msg := "Welcome to Zonnon!";
    lbl := new Label();
    lbl.FontSize := real(36);
    lbl.Foreground := Brushes.White;
    lbl.Content := msg;    
    stk.Children.Add(lbl);
    win.Height := lbl.Height;
    writeln(msg);
end onClick;
    
begin
    asm := Assembly.GetExecutingAssembly();
    asmn := asm.GetName();

    writeln;    
    writeln("Running Assembly: ", asm.Location:2);
    writeln("Assembly Name: ", asmn.Name:2);
    writeln;    

    win := new Window();
    win.Width := real(400);
    win.Height := real(150);
    win.SizeToContent := SizeToContent.Height;
    win.Title := "Hello Zonnon";        
    
    c.A := Byte(255); c.R := Byte(100); c.G := Byte(150); c.B := Byte(200);
    scb := new SolidColorBrush(c);
    win.Background := scb;
    
    stk := new StackPanel();
    stk.Margin := new Thickness(real(15));
    win.Content := stk;    
    
    btn := new Button();
    btn.Content := "Push Me";
    btn.FontSize := real(24);
    btn.Effect := new DropShadowEffect();
    
    btn.add_Click(onClick);
    stk.Children.Add(btn);
    
    app := new Application();
    app.Run(win);    
    
    (* Stop and exit *)  
    writeln;
    writeln("Press any key to exit...");  
    readln();    
end Main.    

The code is very straightforward and even if it is not commented you can easily understand it... ok ok let's do a quick summary: The program is an executable Zonnon Module program unit. We then import several namespaces and classes from the WPF assemblies and we declare some variables to be used in our main body. The program creates a Window and set its properties. Next, a StackPanel container control is added to the Window's content. We add a Button into the StackPanel we just created and add a Click Event to it. This event calls the onClick procedure that what it does is create a new Label and push it into the Stack (and printing it to the Console) for every click you do to the Button. Finally we create an instance of the Application and call its Run method toshow up our WPF window! Once you close the Window control will be return to the Console Application and wait for any key to be pressed to exit.

For those who read programming books... Alright, yes, this program is a mix of a C# WPF example I found in one of my WPF books and another one from IronPython in Action plus some other stuff of my own :)  CODE REUSE FTW ;)

Ok, let the fun begin!

Step #4: Compilation Completed Successfully - First Problem

We are ready to compile our program for the first time.
Assuming you copied/pasted the code above, let's see what we get by compiling our code into an EXE file.

Open a Windows Cmd window and navigate to our working folder. Then let's use the Zonnon Compiler with the following command line arguments to get our executable assembly.

Assuming you are using the same path structure than me you can copy/pase the following line:

C:\zonnon\zc.exe wpfpoc.znn /entry:Main /ref:PresentationCore.dll /ref:PresentationFramework.dll /ref:System.Xaml.dll /ref:WindowsBase.dll

If you have no syntax error in your code you should see the following result:


















SUCCESS! We did not get any compilation error. Lets run it...

BEEP!
















OK... that makes sense... when the program runs and it arrives to line 53 ( win := new Window(); ) it throws a BadImageFormatException. This is because the PresentationCore.dll and PresentationFramework.dll (where the Window class resides) target a newer .NET Framework than the one our program was compiled against. To fix that, we will change it by manually doing it on the zc.exe file.

Step #5: Let the Hacking Begin - Disassemble the zc.exe Assembly

We are going to make use of the Microsoft IL Dissasembler to change the target .NET Framework of the Zonnon Compiler launcher program from .NET 2.0 to 4.0.

Copy/pase the following command line into your console:

ildasm.exe C:\Zonnon\zc.exe /out=C:\Zonnon\zc.il

The ildasm program will decompile and extract the zc.exe assembly and give us a file containing all its Intermediate Language in a file ".il"

Step #6: Let the Hacking Begin - Change the Target .NET Framework

Open the zc.il file with any Text Editor. and locate the following 2 sections

.assembly extern mscorlib
.assembly extern System

Each of those 2 assemblies have a .ver 2:0:0:0
Change it to: .ver 4:0:0:0 and save.

If you compare the original zc.il and the one after the edit you should get:






















Step #7: Let the Hacking Begin - Assemble the zc.exe Assembly

Now that the target Framework is changed, lets use the Microsoft IL Asembler to regenerate the zc.exe from the edited zc.il file.

Copy/pase the following command line into your console: 

ilasm.exe C:\Zonnon\zc.il /EXE /out=C:\Zonnon\zc.exe

You should get an Operation completed successfully:



























Step #8: Compilation Completed Successfully - Second Problem

Run the compiler command line that we used in Step #4

C:\zonnon\zc.exe wpfpoc.znn /entry:Main /ref:PresentationCore.dll /ref:PresentationFramework.dll /ref:System.Xaml.dll /ref:WindowsBase.dll

You should get the same Compilation completed successfully message.

Run your program again.

BEEP!
















The problem now is that the UI application needs to run in a single Thread.
In C# apps you can solve this using the [STAThread] attribute to the program main method (the entry point) which indicates that the COM threading model for an application is single-threaded apartment (STA). However, it looks like there is no .NET Attributes support on Zonnon (or at least not documented).

I then tried using the Thread object and set the  SetApartmentState property to ApartmentState.STA, but I failed because I was not able to convert an activity to a System.Threading.ThreadStart delegate object so I can succesfully instantiate a Thread.

For more details on the those 2 last paragraphs please have a look at this link: Why is STAThread required?
"When the STAThreadAttribute is applied, it changes the apartment state of the current thread to be single threaded. "

Step #9: The System.STAThreadAttribute

At the end, I decided to fix it with a dirty hack (IL) again.
To fix this we will be using exaclty the same method we used before, but this time we will change the Main method of our program, but first, let's see how I knew what to change.

I created a C# program that used the [STAThread] attribute.
class Program
{
    // Methods
    [STAThread]
    private static void Main(string[] args)
    {
        //pass
    }
}

I decompiled it using Reflector to see the generated IL code:


















OK, what we see here is that within the Main method, which is the entrypoint method of our assembly, an instance of System.STAThreadAttribute is created. That's all we need to know to fix the problem with our WPF program we need to create that instance ourselves. Don't we?

Step #10: Fixing our WPF Program

Copy/pase the following command line into your console:

ildasm.exe wpfpoc.exe /out=wpfpoc.il

The ildasm program will decompile and extract the wpfpoc.exe assembly and give us a file containing all its Intermediate Language in a file ".il"

Open it in any text editor and go to the main method.


























Wait a second... it already has the System.STAThreadAttribute on it! What's wrong then?

The answer is the .param [0] line just above it. To make it work we need to either move the .custom instance line over the .param [0] or just comment/remove the .param [0] line and save.

I was intrigued by this .param [0] and search about it on the Expert .NET 2.0 IL Assembler Apress book and found the following:

<param_const_def> ::= <b>.param</b> [<sequence>] = <const_type> [ (<value>) ]

is the parameter’s sequence number. This number should not be 0, because
a 0 sequence number corresponds to the return type, and a “default return value” does not
make sense.

So needed or not needed to avoid any risk I opted to move the System.STAThreadAttribute line on top of .param [0]  (maybe an IL expert can explain why this behaviour?)

The code ends up like the following:

























We are ready to re-build our program.

Copy/pase the following command line into your console:

ilasm.exe wpfpoc.il /EXE /out=wpfpoc.exe

You should see a "Operation completed successfully" message.

Step #11: Running the WPF Program

Execute the wpfpoc.exe program from the command line.

Our WPF window will pop up.


















Every time you click on the Push Me button it will push a new Label to the StackPanel and resize the Window. At the same time, it prints the same text to the Console.













Summary

There you go. We finally have a .NET Framework 4.0 WPF program developed using the Zonnon Programming Language. This was just a proof of concept experiment just for fun. I think Zonnon is a very interesting programming language and hope that the people behind it ( ETH Zurich )  keep the good work and bring us a ETH Zonnon Compiler 1.2.9 soon with built in support for WPF and targets the .NET Framework 4.0.

And by the way, this little trick is the same I used in my previous post Factorial and Fibonacci in Zonnon to make use of System.Numerics.dll which is .NET 4.0 compatible only.


1 comment:

  1. Nice article! The moral of the story is, "Zonnon needs to be upgraded to be compatible with NET 4.0." I completely agree, and note that the latest version (just released as I write this) does not seem to (be intended to) work with .NET after 2.0. I tried using the 4.0 framework to compile an old example that has no problems with 2.0; with 4.0, I got many unresolved reference errors and no executable output. I wonder why, after all this time, they bothered to release a new version without upgrading it to work with the latest .NET? Anyway, I enjoyed your article.

    ReplyDelete