||Cross-Platform .NET Development: Using Mono, Portable.NET, and Microsoft
||Mark Easton, Jason King|
The Spice of Life:
are two major products that came out of Berkeley: LSD and UNIX. We don’t
believe this to be a coincidence.” -Jeremy
SPAWNED IN THE EARLY 1970S, the decade
of sartorial flamboyance that brought us sequined jump suits, ridiculously
flared trousers, and the expression “Fat Elvis phase,” the graphical user
interface (GUI) has grown from a hacker’s convenience tool into the public
facade of the multibillion-dollar business that we all know and love. The
impact that a good user interface has on an application should not be
underestimated, and many projects, careers, and fortunes have been lost and
found in the twinkling of a treeview.
So, the world is full of shallow
aesthetes, but so what? It’s fun to pander to them, and the best thing about
graphical interfaces is that they provide a chance to make manifest the
underlying artistry that is software development. For those of you who don’t
think that software is art, take a moment when you finish your next project to
remind yourself that you’ve created something that didn’t previously exist. If
creation-even when infused with logic-isn’t art, then call me a sandal-wearing,
beard-chewing techie (brown kaftan and disastrous personal hygiene included).
TIP To read more
about the history of the GUI, visit the excellent Web site http://www.toastytech.com/guis.
Philosophical ramblings aside, it’s time to delve into
the exciting jumble of GUI tools that are available for .NET and that can help
make the difference between a professional, cross-platform GUI application and
a jarring profusion of pixel soup.
of a .NET Graphical User Interface
this book deals with a variety of CLI implementations and operating systems, a
good place to start is to figure out how an ideal managed GUI might work. After
that, we’ll take a look at how each of the CLI implementations shapes up to the
An Ideal Managed Windowing System
For the cross-platform developer dreaming of effortless
portability, the ideal .NET rendering system would be written entirely in
managed code.A sensible approach would involve the following steps:
- Creating a
basic rendering system for displaying primitive items-such as lines and
rectangles-on a device such as a screen, printer, or file.
- Developing a
higher-level drawing library that encapsulates more-advanced functionality by
using the basic rendering system.
- Designing a
class hierarchy that uses the high-level rendering library and catches the user
input to produce a windowing system.
Although there’s nothing wrong with this
approach, it raises the question of when to leave the safe haven of managed
code for the dangerous world of unsafe code and memory addresses. If this
approach were taken to the extreme, the rendering system would depend on video
drivers written to a managed interface, say
hardware vendors would release video drivers that conformed to the interface,
as illustrated by Figure 5-1.
Of course, if hardware manufacturers wrote part of
their video drivers in managed code, it wouldn’t just be a performance disaster
but it would seriously overstep the boundaries of user code, and it might
irreparably sour the relationship between kernel and user code.
In contrast to the managed approach, from a performance
point of view, it would be ideal if all the code were tightly written assembler
code, without a whiff of managed code.
Treading the fine line between these two approaches
involves carefully separating functionality between managed and unmanaged code
to deliver a compromise in performance and portability. Because device drivers
are intrinsically linked to the host operating system and most operating
systems provide some common rendering functionality, a more realistic split
would use managed windowing and drawing systems, with an unmanaged rendering
system calling to the device drivers, as shown in Figure 5-2.
While it’s one thing trying to balance tip-top
performance with easily portable code, the main complaint against the managed
approach that’s shown in Figure 5-2 is that it invariably leads to a
standardized interface that is styled the same way on all platforms, but is
contrary to each platform’s native look and feel.
Because some people prefer their applications to look
the same across all platforms and others prefer their applications to fit in
with the native feel of the operating system, frankly, a cross-platform GUI
developer just can’t win.
The Basic .NET Windowing System
considered an ideal approach for implementing a cross-platform windowing
system, it makes sense to root ourselves in the realities of .NET windowing
systems and take a quick, conceptual look at the route taken by the different
Because Microsoft .NET provides the System.Drawing.dll assembly for drawing and the System.Windows.Forms.dll assembly for windowing, it should come as no surprise
that the other CLI implementations have also chosen to implement these
assemblies. What’s interesting is to see how each CLI implementation has taken
a significantly different approach to achieve this goal.
Microsoft .NET Framework
.NET Framework currently implements both low-level rendering and higher-level
controls by using Platform Invoke (P/Invoke) to call the Win32 API.
While it would be tempting to condemn Microsoft for
reusing and extending the life of legacy technology, because the company’s
approach helped achieve an early release of .NET and fits perfectly into the
Windows user interface, it’s fair to say that Microsoft’s implementation
demonstrates a shrewd use of technology. While Windows Longhorn looks set to
break Microsoft’s reliance on the legacy Win32 API, in the meantime, the .NET
Framework relies on the design that’s illustrated in Figure 5-3.
Because Microsoft .NET is only available for Windows,
its use of Windows native functionality should come as no surprise, because it
provides good performance with little concern for portability.
However, while it’s perfectly acceptable that
Microsoft’s implementation isn’t portable, because
System.Windows.Forms encapsulates the Windows GUI rather than a generic
windowing system, one common complaint is that it should really be called
Microsoft.Windows.Forms, with anything scoped within the
System namespace being platform independent.
Mono’s approach to providing GUI functionality has
evolved over time, and with multiple rendering back ends and multiple
deployment platforms, the world of the GUI has been a tricky route to
negotiate. It remains to be seen exactly where it will all end.
For its implementation of
System.Drawing, Mono uses GDI+ on Windows, and Cairo on platforms
running X Windows. As shown in Figure 5-4, while Platform Invoke is used to
call directly into Gdiplus.dll on Windows, on non-Windows platforms, a library that
mimics GDI+ is used. This library in turn passes all calls on to the Cairo
NOTE Cairo provides modern vector graphics functionality and
features, including antialiased text rendering and mathematical transforms. Its
ethos is to provide a uniform output on all media, although currently only X
Windows and an in-memory image buffer implementation exist. Cairo plans to add
support for the Portable Document Format (PDF) and PostScript outputs, which
could elegantly lead into cross-platform printing support. See http://www.cairographics.org for more details.
While Mono’s implementation of
System.Drawing is relatively straightforward, things
are not so simple in regard to GUI toolkits. While we discuss a number of
alternative GUI toolkits later in the chapter, three GUI implementations are
currently directly related to Mono:
System.Windows.Forms, implemented using Winelib;
implemented using Gtk#; and Gtk#, a managed code wrapper for GTK+ that can be
used as an alternative for
Figure 5-5 shows these strategies in action.
Drowning Your Sorrows: Wine
it often seems that a bottle is the answer to your cross-platform development
woes, some help is at hand in the form of the Wine project.
is an adaptability layer for Windows programs and provides an environment that
allows Windows programs to be loaded on different operating systems and
executed with varying degrees of success. Wine consists of the following two
- The wine program, which loads Windows binaries and marshals calls to the Windows
- The Winelib library, which implements an ever-increasing subset of the functions
from the Win32 API libraries
the wine program only runs on x86 hardware and can only
be used for running native Windows applications, the Winelib libraries can be used as replacements for their Windows counterparts
and can be accessed from .NET applications by using Platform Invoke.
information on the Wine project, visit http://www.winehq.com.
TIP Because both of Mono’s
System.Windows.Forms implementations are currently heavily in development, they aren’t as
reliable as Gtk#, and therefore our advice is to use Gtk# where possible.
Because Gtk# has a strong following in the open source
community, choosing between Gtk# and
both a political and a practical dilemma, not made any easier by the fact that
both namespaces will eventually work on a variety of platforms. As you would
expect, the Gtk# namespace is not directly interchangeable with
System.Windows.Forms. This means to effectively use Gtk#, you need to learn
all about its types and peccadilloes, although that’s a small price to pay if
System.Windows.Forms doesn’t meet your needs.
As you can see from Figure 5-6, a number of supporting
assemblies are required for the Gtk# namespace. Each Gtk# assembly not only
calls directly into the equivalent GTK+ shared library, but each Gtk# assembly
also calls into a C shared library that acts as glue code and
exposes some higher-level facilities that are not provided by the GTK+
Microsoft .NET and Mono, Portable.NET’s graphical architecture tends toward the
linear design that was advocated in Figure 5-2, with
System.Windows.Forms building on the rendering functionality that is
System.Drawing. This results in all the controls being written in
To provide a portable rendering
System.Drawing uses a helper name-space,
defines a number of interfaces that can be used when wrapping arbitrary
rendering engines. To date, Portable.NET has created wrappers for Win32, which
provides Windows portability, and for X Windows, which provides portability to
GNU/Linux, Mac OS X, and other UNIX-based operating systems. This architecture
is illustrated in Figure 5-7.
This architecture could well prove to be the purist’s choice, because it
strives to accommodate a good, portable design. As other rendering systems are
brought into the fold, the core of the
namespaces will remain uncluttered, and the Portable.NET community has started
discussing wrapping up the Mac OS X Cocoa APIs for a more Mac-native feel on
Mac OS X.
TIP For those who are concerned with authoring controls or
who have a general interest in how widgets work, the source code for
Portable.NET’s implementation of
an invaluable resource, although should you choose to use it as the basis for
your own controls, the usual licensing rules apply.
Having examined the standard graphical
systems that are included with Mono, Portable.NET, and Microsoft .NET, it’s now
time to investigate a range of alternative GUI toolkits, each of which provides
its own set of features and challenges, while helping to spice up the already
colorful life of the cross-platform developer. While developers from a stringent Windows background might be inclined to shun
these toolkits and stick with
System.Windows.Forms, you have a
number of good reasons to embrace these alternative GUI toolkits. Not only are some of toolkits easily portable across different platforms, but
they also offer different feature sets, and some of them can provide a native
look and feel on any platform that they are deployed on. It’s also worth noting
that when Microsoft releases Windows Longhorn in 2006, it will herald the
arrival of a new Windows GUI system, Avalon, and will undoubtedly replace
System.Windows.Forms as the preferred tool for developing Windows GUIs.
NOTE Promising the latest in vector graphics–based GUIs and
using its own XML
language, XAML, Avalon is set to be the future of GUI
development on Windows. Luckily, an open source vector graphics library,
VG.NET, is already available for .NET. While VG.NET is not identical to Avalon,
it offers a number of similar features-such as exporting to MyXaml, an open
source implementation XAML-and unlike Avalon, it’s available for use today. Downloads and more information on VG.NET are available from http://www.vgdotnet.org, and details of MyXaml can be found at http://www.myxaml.com.The one advantage of investing in
that although its days are numbered, because Mono and PNET are both
implementing their own version,
System.Windows.Forms is likely to
be the most popular .NET GUI toolkit for the foreseeable future.