About a week ago an old, crazy idea (re)occured to me: why not try to interface with VirtualBox from .Net? In case you did not know – VirtualBox is a Virtual Machine software, which allows you to run a virtual computer with it’s own operating system and software on another computer. The Microsoft .Net framework is an application (development) framework, runtime library, and comes with multiple high level programming languages. Microsoft calls programs that run in the .Net environment ‘Managed’. Ofcourse, .Net would not have been as good as it is if there were no Linux support for it, provided by the Mono software. And ofcourse, I could not resist making my VirtualBox frontend written in C# work on Linux.
On a Windows system, it’s all pretty straightforward. Create a new .Net project (I use C#), add a reference to the ‘VirtualBox type library’ COM library, and experiment. Create an instance of the VirtualBox.VirtualBoxClass, an instance of the VirtualBox.SessionClass, find an IMachine (using IVirtualBox.FindMachine), lock the machine to the session and power it up. You can find this code somewhere in the ProgramRun class. Yep, it is that simple. Now we have a running machine – but no graphics, no mouse, not even a keyboard. We’ve just created a simplified version of VBoxHeadless. No fun. Let’s start with some graphics.
By the way, notice that the IMachine interface also has a function call named LaunchVMProcess, which you can use to easily launch the standard “headless” or “gui” frontends, but this is ofcourse less fun. Also note that for the resulting executable to work, it may be necessary to copy it to the VirtualBox installation directory, or to copy a bunch of files from the VirtualBox installation directory to the application directory.
My approach, as I have done this before for the VirtualBox VNC support, was to create the Framebuffer class, which implements IFramebuffer. Basically, the framebuffer provides a buffer, a block of memory, where VirtualBox can write the image to. Now, to display the framebuffer, a Bitmap object is constructed, using the same block of memory. Then simply put this Bitmap instance in a PictureBox, or anything that can display an Image. All that’s left is to attach an instance of the framebuffer object to the Session.Console.Display. Note that the framebuffer may have to be resized when the Virtual Machine changes video modes, allocating a new block of memory and releasing the old one. Be careful that the old block of memory is really not used anymore, before releasing it. Also note that the form can set a VideoModeHint on the IDisplay interface, to inform the guest (additions) about the desired video mode. The guest may or may not listen to this request.
Adding some mouse support is quite simple, some mapping is needed for the buttons, and depending on the guest mouse driver, a relative position may have to be calculated. Also note that, when sending ‘absolute’ mouse positions, the top left pixel has the coordinate (1,1). This is handled in the Form’s Mouse* event handlers in the Display class.
The virtual keyboard is a bit more troublesome. VirtualBox expects ‘good old’ keyboard scancodes, as sent to the computer by old AT/PS2 keyboards. Each *key* has it’s own code (so the only difference between a 1 and a ! is whether the shift key is down). The scan codes appear to be ordered the same way as the keys on the keyboard (eg ‘Q’ comes before ‘W’). Some lookup tables are used to map the .Net key codes to these scancodes. Luckily, the framework does not differentiate between ‘1’ and ‘!’ either at this point, and sends the shift key like any other key, so we can get away with a simple one-to-one mapping, which is implemented in the VBoxKeyboardHelper class.
I have also added a VirtualBox EventListener to the user interface (Display class). The event listener itself is implemented in the VBoxEventListener class and simply forwards the events to a .Net EventHandler. It’s used for informative purposes, as well as to control the machine state flow.
My next blog post will talk about adding Linux/mono/XPCOM support to the application, which is perhaps (even) more interesting, and was definitely more challenging.
The sourcecode for the complete project, including Linux support, is available in my Mercurial repository at http://oss.ucis.nl/hg/vboxdotnet/.