July 15, 2004 Edition

By Adam Skutt (mailto:askutt@wnec.edu), Andrew Forgue (mailto:syndicate@arslinux.com)

 

An introduction to Mono

You've probably heard of .NET, and since you're reading a Linux column, you've probably also heard of the Mono Project (http://www.mono-project.com/), which provides a NET (http://arstechnica.com/paedia/n/net/net-1.html) compatible development platform. Mono has been the cause of a number of discussions regarding copyright, software patents, and other legal issues. So, instead of boring you with political ranting, we're going to concentrate on Mono's technical merits (of which there are many) and show you how you can use it for development. We also present ndiswrapper, which allows you to use some Windows network drivers with Linux, this enabling you to use a number of previously unsupported network cards.

 

Mono a unified development platform

We'll start out by introducing you to Mono (very briefly because you've probably had this pounded down your throat for the past 2 years) then we'll present some code and screenshots that demonstrate the versatility of the Mono project.

A brief history of Mono

The Mono project was conceived in the Summer of 2001 as an Open Source alternative to Microsoft's .NET development platform. Since then, it has come all the way to a 1.0 release among a flurry of controversy from mostly inside the Open Source community itself. Although we will not outline the reasons here, most of the criticism stems from the fact that .NET is Microsoft, and "we" don't like them.

At the end of June, 2004, Mono released their first major version (1.0) and the platform (especially C#) seems to be catching on very quickly. There's already a music player (http://muine.gooeylinux.org/), a new app called Dashboard (http://www.nat.org/dashboard/), an app I'm writing called MonoPlanet (http://ahab.arslinux.com/svn/MonoPlanet/), and not to mention an IDE for developing Mono Apps called MonoDevelop (http://www.monodevelop.com/) and much more (http://www.nullenvoid.com/gtksharp/wiki/index.php/SoftWare).

For users?

A user of a platform that supports Mono will hopefully see better-quality applications, applications that can just be installed (no compiling, not even for packaging), and applications that are secure. The ease for developers (given the proper tools) to write Mono applications will help to bring better applications to Linux (just as soon as Gtk# supports the current Gtk+ library).

Linux advocates have been saying all along that application support is key to its success. With the adoption of Mono, the accuracy of that statement should soon become clear.

For developers?

Mono's main pull for developers is that it is cross-platform and makes writing applications very fast because of its extensive framework. Mono also has the concept of garbage collection (http://en.wikipedia.org/wiki/Automatic_garbage_collection). Gone are the days of using malloc() and free() and recording where you allocated memory and making sure you free() it. Java has GC as well, but Java never really caught on as an application language.

Here we will show you how to write a very basic cross-platform application and run it on Windows and Linux. So without further delay, on to the code.

Note: Mono support in Mac OSX is still immature compared to other platforms, we expect this to change now that 1.0 is out the door.

The code: example 1

This code is simple, it takes command line argument and prompts the user for a Regular Expression. It test the command line string against the regular expression and prints whether it succeeded or failed.

using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
 
namespace Volume_27
{
  /// 
  /// Linux.Ars Volume 27 Example 1
  /// 
  class Example1
  {
    static void Main(string[] args)
    {
      if( args.Length == 0 )
      {
        Usage();
        Console.ReadLine();
        return;
      }
 
      String input = "";
      for(int i = 0; i < args.Length; i++)
      input = input + ((i==0)?"":" ") + args[i];
 
      Console.Write
      ("Enter a regular expression to test the string \"{0}\": ", input);
      String regex = Console.ReadLine();
 
      bool matches = Regex.IsMatch( input, regex );
 
      Console.WriteLine
      ("\"{0}\" DOES {1} Match \"{2}\"", input, (matches)?"":"NOT", regex);                 
    }
 
    public static void Usage()
    {
      String ExecPath = Environment.GetCommandLineArgs()[0];
      String Executable = 
      ExecPath.Substring(ExecPath.LastIndexOf(Path.DirectorySeparatorChar) + 1);
      Console.WriteLine("-------------------------------------------------");
      Console.WriteLine("{0} usage:", Executable );
      Console.WriteLine();
      Console.WriteLine("\t{0} [Input String]", Executable);
      Console.WriteLine();
      Console.WriteLine
      ("\t[Input String]: An input string that should be tested against");
      Console.WriteLine("\t                the prompted regular expression");
      Console.WriteLine();
      Console.WriteLine("-------------------------------------------------");
    }
  }
}

Download the compiled binary: Here (http://www.arslinux.com/viewcvs.cgi/*checkout*/linux.ars/v27e1.exe)

As you can see, the actual meat of this application is seven lines of code. Now, when we run this (on windows) we get this output:

C:\>md5sum v27e1.exe
492f501af39a990a873a008adf82e8c7 *v27e1.exe
C:\>v27e1 Linux.Ars is cool
Enter a regular expression to test the string "Linux.Ars is cool": ^L.*\.A*
"Linux.Ars is cool" DOES  Match "^L.*\.A*"

And now to execute the same exact binary on Linux (the case-mismatch is intentional)

forgue@ahab:~$ md5sum v27e1.exe
492f501af39a990a873a008adf82e8c7  v27e1.exe
forgue@ahab:~$
forgue@ahab:~$ ./v27e1.exe Linux.Ars is cool
Enter a regular expression to test the string "Linux.Ars is cool": ^L.*\.C*
"Linux.Ars is cool" DOES  Match "^L.*\.C*"

The great power of Mono and .NET lies in the ONE line of code:

bool matches = Regex.IsMatch( input, regex );

.NET and Mono are actually a collection of libraries that form a framework which allows you, the programmer, to write the logic of your application. I can call one line of code to do input validation on a string which saves you possibly hours of time. Things like Input validation, network communication, file reading and writing, text encoding, regular expressions, formatting, XML Parsing, LDAP Access, remoting, and GUI development are reduced to just a few lines of code compared to possibly hundreds.

 

Next: Gtk# Application

Next we'll demonstrate development of a Gtk# application that runs on both Linux and Windows. Using the brand new MonoDevelop, this makes it fairly quick. We'll do the same application, with two textboxes, and it will update the result label in real time (each character you type will verify the regex).

So lets open MonoDevelop and start a new Gtk# project, call it whatever you want. After the project is created you'll see a MyWindow.cs: open that and replace everything with the below code:

using System;
using Gtk;
using System.Text;
using System.Text.RegularExpressions;
 
public class MyWindow : Window {
 
  private VBox vBox;
  private HBox hbox1;
  private HBox hbox2;
  private HBox hbox3;
 
  private Entry txtInput;
  private Entry txtRegex;
  private Entry txtResult;
 
  private Label lblLeft1;
  private Label lblLeft2;
  private Label lblLeft3;
                               
  public MyWindow () : base ("Linux.ars")
  {
    this.SetDefaultSize (400, 300);
    this.DeleteEvent += new DeleteEventHandler (OnMyWindowDelete);
 
    /* Create a vertical panel, each with horizontal panels,*/
    /* the left side is the label and the right side is the textbox */
    vBox = new VBox(false, 3);
 
    hbox1 = new HBox(false, 2);
    hbox2 = new HBox(false, 2);
    hbox3 = new HBox(false, 2);
 
    txtInput = new Entry();
    txtRegex = new Entry();
    txtResult = new Entry();
 
    lblLeft1 = new Label();
    lblLeft2 = new Label();
    lblLeft3 = new Label();
 
    // Disable editing of the result box
    txtResult.Editable = false;
        // If anything changes in the text boxes,
    // call this function (These are event handler delegates)
    txtRegex.Changed += new EventHandler(ChangedSomething);
    txtInput.Changed += new EventHandler(ChangedSomething);
 
    // Set the text of the labels on the left
    lblLeft1.Text = "Input String:";
    lblLeft2.Text = "Regular Expression:";
    lblLeft3.Text = "Result:";
 
    // Make them the same size
    lblLeft1.SetSizeRequest(150, 20);
    lblLeft2.SetSizeRequest(150, 20);
    lblLeft3.SetSizeRequest(150, 20);
 
    // Align the text to the right
    lblLeft1.SetAlignment( 1, (float)0.5 );
    lblLeft2.SetAlignment( 1, (float)0.5 );
    lblLeft3.SetAlignment( 1, (float)0.5 );
 
    // Now we add the controls to the panels
    hbox1.PackStart(lblLeft1, true, true, 6);
    hbox1.PackEnd(txtInput, true, true, 6);
 
    hbox2.PackStart(lblLeft2, true, true, 6);
    hbox2.PackEnd(txtRegex, true, true, 6);
 
    hbox3.PackStart(lblLeft3, true, true, 6);
    hbox3.PackEnd(txtResult, true, true, 6);
 
    vBox.PackStart(hbox1, true, true, 0);
    vBox.PackStart(hbox2, true, true, 0);
    vBox.PackStart(hbox3, true, true, 0);
 
    // Set the window characteristics
    this.SetDefaultSize( 250, 80 );
    this.Resizable = false;
    this.BorderWidth = 10;
 
    // Add the whole shebang to the window
    this.Add( vBox );
 
    // Show everything
    this.ShowAll ();
  }
 
  void OnMyWindowDelete (object o, DeleteEventArgs args)
  {
    Application.Quit ();
  }
 
  void ChangedSomething(object o, EventArgs e)
  {
    // Get the text from the boxes 
    // (this gets called after it's updated)
    String Input = txtInput.Text;
    String RegEx = txtRegex.Text;
 
    try
    {
      if( Regex.IsMatch(Input,RegEx) )
        txtResult.Text = "Matches";
      else
        txtResult.Text = "Does Not Match";
    }
    catch(System.ArgumentException ae)
    {
      txtResult.Text = "Invalid Regular Expression";
    }
  }
}

Download the compiled binary: Here (http://www.arslinux.com/viewcvs.cgi/*checkout*/linux.ars/v27e2.exe)

The above code, should produce the result below (on Linux):

Missing Picture

This article is in need of attention.

Please improve it and then remove this notice.

And on Windows:

Missing Picture

This article is in need of attention.

Please improve it and then remove this notice.

Conclusion

As you can clearly see, Mono brings almost limitless possibilities in breaking down the barrier between desktops: a commercial software provider would target Mono and it would "just work" on all platforms that Mono supported. How is this different from Java? In my opinion Java makes things harder than it needs to be. For starters, enforced exception handling can't auto-box/unbox primitive types and doesn't support arbitrary length parameter lists String.Format() style.

The framework of Mono provides the ability to make a very tedious task in C/C++ almost trivial in C#. As the above example, RegEx, shows, it helps the programmer concentrate on the program itself, rather than the logic supporting the code.

 

Cool App of the Week

Ndiswrapper (http://ndiswrapper.sourceforge.net/) is a kernel module and set of userspace tools that let you use Windows network drivers on your Linux machine. NDIS stands for Network Driver Interface Specification, and it is the API used by Windows developers to write drivers for network cards, including wireless network cards. Ndiswrapper is specifically targeted for running cards that use newer 802.11g chipsets that do not have Linux drivers, including the chipsets by Broadcom, Atheros, and Intel ( see the completely supported list here (http://ndiswrapper.sourceforge.net/supported_chipsets.html)) including native drivers for some chipsets.

Using ndiswrapper is as simple as installing the tools, compiling support for your kernel, and then loading the Windows driver. It appears tolLinux as a regular wireless interface, and can be configured with the normal wireless-tools (http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html). For those who use with laptops that have unsupported chipsets, ndiswrapper is a useful way to allow you to make fuller use of your machines. I personally have excellent results with it on my Fujitsu E4100D, which uses a Broadcom 94306 chipset.

Not familiar with wireless in Linux at all? Don't worry, IBM has you covered (http://www-106.ibm.com/developerworks/wireless/library/wi-run.html?ca=dgr-lnxw04WirelessTools4Lnx).

 

/dev/random