Implementing the ASP.NET GUI designer with Mozilla's Gecko web rendering engine is an obvious decision: it's open-source, has strong standards support and a large feature set, is highly extensible and flexible thanks to its XPCOM component system, and using Gecko# it can be embedded in a GTK# GUI. Mozilla is becoming an application platform, with XUL for declaratively writting GUIs, and JavaScript for program logic.
Gecko# wraps GtkMozEmbed, which is a C GTK widget, hiding Mozilla's native C++. Understandably this widget isn't bloated by wrapping the Mozilla DOM or other internals: it claims to exposes enough functionality for "about 80% of uses". Essentially this means a basic web browser.
However, to do anything interesting I need to interact with Gecko# from my C# code, and vice versa. There are two obvious ways to approach this:
- Expose everything
Open up the whole of Mozilla's internals to Mono code, or at least the DOM and XPConnect for JavaScript interaction. This would be ideal, as it's the most flexible, and would find many other uses. However, wrapping enough functionality to do anything useful is a very significant task in itself.
- Message-passing
Simply restrict all of the Mozilla interaction code to JavaScript functions, which can be triggered from C# via a message-passing scheme of some kind. Pragmatic, and not inelegant, as JavaScript is a first-class citizen in the Mozilla world, and is used to write large parts of Mozilla.
So, assuming I choose the second for speed and ease of development, how do I go about implementing it? This time, I have four choices:
- Abusing Gecko#
Relatively harmlessly, we can raise C# events by changing the JavaScript status message.
A more serious abuse is to stream the document into Gecko#, then stream in additional elements containing our messages. JavaScript can catch these with the DOMNodeInserted event and act accordingly. Or so I thought. While Gecko will render an open HTML stream, it's not so forgiving in the case of XUL. Oh dear.
-
Mono-XPCOM bridge
Yes, there is one, and it would be the most elegant solution... unfortunately it's not nearly complete enough to begin using for a project like this just now, and I'm not familiar enough with XPCOM to fix it up myself. I can see switching to this when it becomes stable enough.
-
Web server
This would cause the editor to effectively become an "AJAX" application. Ouch. A horrible hack, and a horribly-named technology. On the upside, this would be relatively quick and easy.
- C++ wrapper and P/Invoke
Similar to the Gecko# abuse, but strangely, more elegant, despite the additional dependecies and build steps this method entails. The handle from Gecko# can be passed to a C/C++ wrapper via Platform Invoke. The wrapper function then uses GtkMozEmbed's "gtk_moz_embed_get_nsIWebBrowser" function to access Gecko's internals, does interesting thisgs to it with XPCOM, and optionally even returns values.
Well, I initially tried the fourth method, until I realised how much easier the first would be, and cursed XPCOM and the days it had taken from my life.
Fate has twisted sense of humour. Two days into the initial implementation of the editor's high-level architecture, as I began to flesh out the message passing system, I discovered the fickleness of Gecko#'s streams, and had to revert to XPCOM and P/Invoke.
More on this story later, once I have something working.
Comments
Mono, Gecko# and DOM APIs
Hi, I am really new to Mono and for what I understood, Gecko# just wraps GtkMozEmbed that is simply a web renderer, with no advanced functionalities like getting the DOM Document of the displayed page (for manipulation or interaction).
I would like in fact to write a Web Automation Tool in Mono which records the navigation of a user and is able to play it again, but without those functionalities in the WebControl I think it is infeasible.
Bye,
Alessio
It depends if you are prepared to use C++...
I actually ended up using a C++ wrapper library to poke around in the XPCOM internals of the underlying GtkMozEmbed widget.
Use the Handle property of the WebControl GTK# widget to get an unmanager pointer to the underlying GtkMozEmbed object using C#, and use P/Invoke to call an external C/C++ glue library, passing it this pointer.
Then use gtk_moz_embed_get_nsIWebBrowser to get the XPCOM nsIWebBrowser, from which you can do almost anything to Mozilla that you want.
You can see this in my code.
can you repost your source code
The link is invaild and I need it . Send it to my mailbox please.
Thanks you
I've updated the link
Mono SVN had moved, though you could probably have found it by Googling.
Note that I had to link a specific revision of the code, because in newer versions of JSCall# I used a "javascript://" URL hack to eliminate all unmanaged code.
gecko# & dom
I am in the same boat as you. I don't have the C++ skills to create a program that embeds the gecko engine, but I did it with Gecko# / Monodevelop (and an exmaple file from Novell)
If you ever figure out how to get Gecko# to give you the DOM, I would really appreciate it if you would share how you did it.
Thanks
--Taladon
--Taladon@gmail.com