.NET WinForms HelloWorld from Java (!) using embedded Mono + JNAerator
Many Java geeks might have been sad about seeing the .NET world use Java without Java thanks to Mono‘s excellent IKVM Java Virtual Machine (written in .NET).
While IKVM is an amazing technology, it has a taste of more-Microsoftish-than-Javaish in it (besides, some companies might have non-ideological reasons to use .NET from Java and not the other way around ;-)).
So how do we connect Java with .NET, letting Java be the master and .NET the slave ?
Well again, the cheapest and simplest answer comes from Mono (they do make marvels at Novell).
Note that there are commercial interop products that seem wonderful, but… a bit more expensive than the zero-dollar option we present here.
Mono has a very nicely done C Embedding API.
While this API is done for C and not for Java, you might have noticed recently that it’s become trivial to use C APIs from Java using JNAerator + JNA.
Our case is no exception : it is trivial to JNAerate Java bindings for Mono, all the steps (and the pre-JNAerated JAR) are available on the Mono NativeLibs4Java sub-project.
Based on that API and using Mono’s documentation, it is easy to create a WinForms HelloWorld, which useful code will look like :
MonoObject form = newInstance(m, domain, m.mono_class_from_name(winforms, "System.Windows.Forms", "Form"));
setProperty(m, domain, form, "Text", "Mono + JNAerator + JNA");
MonoObject button = newInstance(m, domain, m.mono_class_from_name(winforms, "System.Windows.Forms", "Button"));
setProperty(m, domain, button, "Text", "Hello .NET World\n(spawned from Java)");
setProperty(m, domain, button, "Dock", 5 /*DockStyle.Fill*/);
invokeMethod(m, domain, getProperty(m, domain, form, "Controls"), "Add", button);
invokeMethod(m, domain, m.mono_class_from_name(winforms, "System.Windows.Forms", "Application"), null, "Run", form);
The setProperty, getProperty, invokeMethod and newInstance methods are easy to write.
As an example here’s invokeMethod :
private static MonoObject invokeMethod(MonoLibrary m, MonoDomain domain, MonoClass cl, MonoObject ob, String methodName, MonoObject... args) {
Memory mem = new Memory(args.length * Native.POINTER_SIZE);
for (int i = 0; i < args.length; i++)
mem.setPointer(i * Native.POINTER_SIZE, args[i].getPointer());
PointerByReference pargs = new PointerByReference();
pargs.setPointer(mem.share(0));
return m.mono_runtime_invoke(m.mono_class_get_method_from_name(cl, methodName, args.length), ob == null ? null : ob.getPointer(), pargs, null);
}
To test it for yourself :
- Download and Install Mono (HelloDotNetWorld.java assumes it ends up in C:\Program Files\Mono-2.4.2.3, so you might have to tweak it to match your actual Mono path)
- Checkout Mono’s NativeLib4Java sub-project :
`svn checkout http://nativelibs4java.googlecode.com/svn/trunk/libraries/Mono/` 3. Go to the Mono/examples subdirectory and launch HelloDotNetWorld.cmd
This has only been tested on Windows XP 32 bits, but it might work with little to no modification on virtually any operating system, provided that you give the HelloDotNetWorld program the path to libmono.so. Please report any success or failure you might experience in this entry’s comments.
Enjoy !!!