Posts Tagged ‘mono’

Trilite, application design experiment with XULRunner and .NET

Goodbye Adobe Air

Despite positive first impressions with Adobe Air, I began avoiding it a while ago for a few reason:

  • Air’s focus was very much geared towards Flash development, not HTML/CSS/JS, and I had no interest in Flash development
  • A lot of interesting web technologies never manifested within Air (SVG, WebGL) and it looked doubtful that Adobe cared to add anything that might challenge Flash
  • Linux support was dropped – a platform dropping OS support is not a good sign
  • Native interaction support, a feature in Air 2 which I was excited about, didn’t impress me in its implementation and it was very much geared towards Flash/ActionScript development
  • Adobe’s push for Air became more a platform for mobile development rather than desktop development, to the extent that desktop development was pushed far into the background

With all of the negatives above, coupled with the propriety, vendor lock-in, nature of Air, I really didn’t feel like using it for development of anything.

XULRunner / XPCOM

I was still optimistic and interested in web technologies (HTML/CSS/JS) for layout and styling in desktop applications. As I stated previous:

Looking into cross-platform GUI frameworks, I’ve played around with WinForms (cross platform with Mono), Qt, Gtk, and wxWidgets. I’ve been disappointed to various degrees with all of them. It hit me that the most flexible and powerful cross-platform layout and styling framework out there is the HTML/CSS combo. It’s not perfect (e.g. floats, vertical centering) but it’s pretty damn good.

I stated looking at other solutions. I didn’t want to relive my experiences dealing with compiling webkit (though I was, and still am, tempted to play around with chromiumembedded), so I went with XULRunner, which allows for bootstrapping XUL-based applications (e.g. Firefox). XUL is not HTML, and in actuality provides markup to design a UI with native controls, but one control provided is the iframe control which renders and interprets HTML, CSS, and Javascript.

Having XUL for the application interface, you could write a desktop application with the application logic in Javascript, but you’re bound by the same limitations as a web application. XPCOM is a solution to these limitations and allows for interactions with the host system for things such as reading files, running another process, etc. That said, I wasn’t excited to learn XPCOM – it seemed convoluted and I didn’t want to waste time doing a deep-dive into yet another framework and being tied down to its limitations. I figured if I could write the application logic in another executable and have it communicate with the UI via a lightweight (very lightweight) XPCOM-based component, that would be ideal. In terms of simplicity and availability, sockets seemed like the go-to solution for Inter-process communication between XPCOM and anything else.

The Socket Bridge

So I came around to the idea of a Socket Bridge (I had originally played around with it in an Adobe Air project and was able to apply it here as well). Within the XUL application, Javascript-based XPCOM code would implement the Socket Bridge client and the executable handling the application logic would implement the Socket Bridge server, and the 2 could communicate easily.

SocketBridge

An HTTP server could take the place of the SocketBridge server, but I felt that was overkill, less flexible, and added an additional layer of complexity as the server then needed to be connected to the application code.

Trilite

As a proof-of-concept, I began working on Trilite, a simple HTTP profiling tool, with the application logic done in C#, that would send a number of HTTP requests to a server, capture the time it took to get a response, and calculate some simple stats about the results. A pretty simple application but something pretty handy for optimization work.

I’m pretty happy with the results thus far, particularly with regards to having a consistent, stable, and cross-platform UI.

You can find the current code in the Trilite repository.

There is no bootstrap to launch the Socket Bridge server and XULRunner app, they need to be executed manually for the application to launch:

  • Launch the server by running /trilite.public/app-server/trilite/trilite/bin/Debug/trilite.exe
  • Launch XULRunner, in /trilite.public/xulrunner, with the application.ini file in the root directory. For Windows, you can also run the trilite shortcut in the root directory.

A few screenshots under Windows:

Trilite

Trilite

Trilite

And here’s Trilite running under Ubuntu:

Trilite on Ubuntu

This post should, hopefully, provide a top-level overview of the application architecture. I’ll be writing more about XUL, XPCOM, the Socket Bridge, and Trilite in subsequent posts, providing more details and code.

Launching a Mono/.NET exe from Adobe Air

I’m working on some bridging code between Adobe Air and Mono/.NET stuff. The first challenge in the process was figuring out how the launch the .exe from Adobe Air. In Windows you can just launch the .exe file (assuming the .NET Framework is installed), but for other system you need to pass it as an argument to the mono executable. The JavaScript code is shown below.

var proc = new air.NativeProcess();
if
(air.Capabilities.os.toLowerCase().indexOf("win") > -1) {
    
var file = air.File.applicationDirectory;
    file = file.resolvePath(
"air.SocketBridgeServer.exe");
                            
    
var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
    nativeProcessStartupInfo.executable = file;

    proc.start(nativeProcessStartupInfo);
}
else {
    
var mono = new air.File();
    mono = mono.resolvePath(
"/usr/bin/mono");
                            
    
var exeFile = air.File.applicationDirectory;
    exeFile = exeFile.resolvePath(
"air.SocketBridgeServer.exe");
                            
    
var args = new air.Vector["<String>"];
    args.push(exeFile.nativePath);
                            
    
var nativeProcessStartupInfo = new air.NativeProcessStartupInfo();
    nativeProcessStartupInfo.executable = mono;
    nativeProcessStartupInfo.arguments = args;
    proc.start(nativeProcessStartupInfo);
}

This handles Windows, OS X, and should handle most distros of Linux; the location of the mono executable is the tricky part, Adobe Air doesn’t read the path environment variable, so the exact location of mono must be specified. mono is usually in /usr/bin, but custom distros, installations, etc. could put it elsewhere.

Mono Stream issue

An issue I discovered in Mono. When attempting to write a zero-length byte array (representing an empty string of UTF8 characters) to a HttpWebRequest stream, the stream is cut short at the position the write is being attempted; nothing after it gets written to the stream.

protected void WriteAllToStream(Stream stream, byte[] data)
{
// data.Length needs to be > 0
stream.Write(data, 0, data.Length);
}

I’m not sure if this is specific to the HttpWebRequest stream. I encounter the issue on Mono 2.4 (under Ubuntu) and Mono 2.6.1 (under openSUSE).

Mono.Unix.Native

After spending some time attempting to P/Invoke the stat() function, I discovered the wonderful Mono.Unix.Native namespace (found in the Mono.Posix assembly) which has some great stuff for lower-level Unix/Linux work.

Here’s what I did to pull a file’s inode number:

static public ulong GetFileInodeNum(string path)
{
    Mono.Unix.Native.Stat statOut =
new Mono.Unix.Native.Stat();
    
int statRet = Mono.Unix.Native.Syscall.stat(path, out statOut);
    
    
if(statRet == -1)
    {
        
throw new IOException("stat on " + path + " failed.");
    }
    
    
return statOut.st_ino;
}

Mono PlatformID on MacOS X

Unfortunately, the method mentioned in the Mono Technical FAQ, where you can check System.Environment.OSVersion.Platform for a value of 6 doesn’t work (as of Mono 2.6). I got the following code from this thread, which works well enough,

[DllImport("libc")]
static extern int uname(IntPtr buf);

static bool IsRunningOnMac()
{
IntPtr buf = IntPtr.Zero;
try
{
buf =
Marshal.AllocHGlobal(8192);
if (uname(buf) == 0)
{
string os = Marshal.PtrToStringAnsi(buf);
if (os == "Darwin") return true;
}
}
catch { }
finally
{
if (buf != IntPtr.Zero) Marshal.FreeHGlobal(buf);
}
return false;
}

Miscellaneous Mono and Mono WinForms issues

A few issues I stumbled across as I was working on porting Fragment Sync,

Issue #1: Explicit null second argument with ArrayList.BinarySearch
The second argument is optional and leaving it out should (I assume) be the same as passing null resulting in the method using the object’s CompareTo() method (implemented b/c of required IComparable interface). However, Mono threw an exception: System.ArgumentException : Comparer threw an exception

Issue #2: LinkLabel rendering issues
You can see this in the screenshot from my previous post,

mono winforms linklabel rendering issue

The linklabels at the bottom have their AutoSize properties set to false and their TextAlign properties set to MiddleCenter; the rendering issue is obvious (oddly enough, I noticed when a linklabel is disabled it renders correctly). Setting AutoSize to true and redoing some positioning, I got the following (note that a lot of other things have been fixed here as well focus on the menu at the bottom),

mono winforms linklabel rendering issue 2

I’m still working on this and haven’t really found an optimal or pragmatic solution as yet.

Issue #3: No WYSIWYG for improperly anchored controls
Microsoft .Net Framework seems to be able to display a form as-is despite any sort of improper anchoring which would cause issues when resizing. Mono WinForms seems to behave a bit differently, and the position and layout of these controls are not identical to how they look in the designer. My guess would be that form are loaded differently between the 2 implementations.

Issue #4: Panel anchor issue
In Fragment Sync, there is a panel just above the bottom menu that appears and displays notifications. This panel is anchored to stay just above the bottom menu. For reasons I still haven’t figured out, this panel disappeared (I assumed behind the menu). I fought with this for quite a while, but finally surrendered and simply docked it to the bottom. I’m still not sure exactly what the issue was here and anchoring and docking seems to work fine in other forms and controls.

Issue #5: AutoScaleMode
This is something I never payed attention to, but the Visual Studio designer automatically sets AutoScaleMode to AutoScaleMode.Font for every form or user control created. This can very much screw up positioning and layout of elements, so I set it to AutoScaleMode.None for everything. Fragment Sync doesn’t really concern itself with scaling, so this might not be appropriate for every app. Not that this should be done within the designer, trying to change it after InitializeComponent() is called in the constructor seems to have no effect.

Issue #6: Form icon issue
I mentioned in the previous post about problem with Vista-compatible icons which have an embedded 256×256 png. Rather than muck around in the form designer code this can be addressed in the form constructor after the InitializeComponent() call, as the exception for the problematic icon is thrown when the form is shown not initialized. So simply set this.Icon = null; after InitializeComponent() or set this.Icon to a compatible icon.

Issue #7: Notify icon issue
This is caused by the same problem as above (Vista-compatible icons), but can’t be addressed after InitializeComponent() as the exception is thrown earlier, within InitializeComponent(). The easiest fix to just use another icon with the 256×256 bitmaps removed. You could also muck around in the form designer code and edit the offending line.

That’s it for now. I’m eager to do a OS X compile and run, which I’ll try to do within the week.

First thoughts on porting to Mono

I’ve known about Mono since its inception, but a few months ago I really became interested as support for C# 2.0 and WinForms 2.0 was announced. I played around with some code and was pretty impressed at how easy it was to get stuff compiled and running. This weekend I made a concerted effort to tackle something more complex, getting Fragment Sync compiled and running. I’ve read you can simply use Mono with the managed executable and not have to deal with compiling source code, but Fragment Sync does quite a bit of interop with unmanaged code so that really wasn’t an option.

I first attempted to import all the source files into MonoDevelop (commenting out win32 specific stuff), but this proved problematic when it came to resources. I tried a ton of different things, but could not get MonoDevelop to properly compile in the app’s resources. I then read you can just open the Visual Studio solution with MonoDevelop; this proved to be effortless and resolved the compilation issue with resources.

After a successful compiled, I had some issues getting a window up. There was an issue loading the application icon. This seems to be an issue with using Vista-compatible icons (where the 256×256 sized bitmap, is an embedded png). I changed the icon to null for a few forms to resolve this; which involves the following line in the form designer code:

this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));

The final and most serious issue I encountered was with Fragment Sync’s Rijndael encryption code. You can find the issue described in detail here. Note the issue will pop up when using CryptoStream as well, since CryptoStream simply abstracts the calls to the underlying Transform methods of ICryptoTransform. The trick here is to always check that you can reuse the transform. With Microsoft’s implementation you can, with Mono you can’t. So you have to recreate the transform object.

if (!decryptor.CanReuseTransform)
{
    decryptor = rij.CreateDecryptor();
}

With these issues resolved I could get things up and running.

fragment sync running on mono in opensuse

Obviously things don’t look pretty, but I think this is a good starting point to work from to get Linux support for Fragment Sync.

I should mention I did consider using Gtk# and redoing the Fragment Sync user interfaces, but I found Gtk’s design methodology unbearable… let’s just say I’m not a fan of packing widgets into containers.