XAML Playground
about XAML and other Amenities

SilverVNC - a VNC Viewer with Silverlight 4.0 RC

2010-03-15T19:07:00+01:00 by Andrea Boschin


I confess I wrote the code of this example few months ago, when only Silverlight 3.0 was on the scene, and I retained it for me because it was a beautiful example but not really useful. Since it uses a socket connection it is a little bit complicated to use it in real world scenario due the fact it needs a policy server, and it is restricted to few number of ports that does not have anything to do with VNC standard ports.

Finally, when I got the first bits of Silverlight 4.0 I decided it would be time to push it out to the folks, thanks to the new out-of-browser feature that now support full-trust installation. I've been persuaded from the opportunity of have a relaxed security on Socket connections meaning that I will be able to connect to any socket based service through a well known port and without having to install a policy server.

So, here is today SilverVNC, a basic implementation of the Remote Framebuffer protocol (RFB) written following the standard specifications (you can download them from the RealVNC website). I've implemented the protocol using the most recent build of UltraVNC to make tests.

As I've already said the implementation is basic. Differently from commercial version I only support the RAW encoding and avoid any type of compression. This simply because handling heavy socket communications with the asyncronous model of silverlight is a kind of bounce game that make simple things really complicated. So I preferred to give a simple example that let the user understand how it works.

How it works?

The core of the example is made of an RfbClient class that encapsulate all the logic needed to communicate with the server, decoding data and rasing events to the user interface. The class is made of methods that receive and send data to the socket. I will not detail the inner content of the class because the RFB protocol specifications are out of the scope of this article. You have only to be aware that while in OOB-Fulltrust the socket may be opened on every port and without any policy.

The main page of the application use the RfbClient to connect to the VNC server and pump data from the socket and decode. Every time RfbClient receive something it raises two types of event:

ResizeFrameBuffer : it mean the server notified a change of the size of the screen. It usually happens at the start of the connection to let the client resize the drawing area.

FramBufferUpdate: it mean the server detected a change on the screen so it cut out a rectangle and send it to the client. The event handler calculate the position of the rectangle on the drawing area and write it.

Here is how to handle these events:

   1: void Client_ResizeFrameBuffer(object sender, EventArgs e)
   2: {
   3:     this.MakeWindowProportional(this.Client.Server.Width, this.Client.Server.Height);
   4:     this.BitMap = new WriteableBitmap(this.Client.Server.Width, this.Client.Server.Height);
   5:     this.vnc.Source = this.BitMap;
   6: }
   8: private void MakeWindowProportional(double width, double height)
   9: {
  10:     double proportion = width / height;
  11:     Application.Current.MainWindow.Height = Application.Current.MainWindow.Width / proportion;
  12:     Application.Current.MainWindow.Activate();
  13: }
  15: private void Client_FrameBufferUpdate(object sender, FrameBufferUpdateEventArgs e)
  16: {
  17:     Rect rect = e.Rectangle;
  19:     int x = 0;
  20:     int y = 0;
  22:     foreach (uint color in e.Colors)
  23:     {
  24:         this.BitMap.Pixels[
  25:             (y + (int)rect.Y) *
  26:             this.Client.Server.Width +
  27:             (x + (int)rect.X)] = (int)color;
  29:         if (++x == rect.Width)
  30:         {
  31:             x = 0;
  32:             y++;
  33:         }
  34:     }
  36:     this.BitMap.Invalidate();
  37: }

Future implementations

There is some improvements I think will apply in the future. First of all I think the algorithm writing into the buffer might be more efficient than the code I showed here. My idea is to implement a MediaStreamSource to produce a video stream you can connect to a MediaElement. This should be better not only from the performances point of view but also may be simpler to be used by developers which needs to add a remote desktop viewer to his applications.

Another improvement is to implement the other compression algorithms. Probably I will implement RRE, CoreRRE and Hex. Finally I would like to transform the viewer in a full functional remote desktop client adding the capability to remote control the target machine. This shouldn't be too difficult.

Until then please have a try to this sample and give me any feedback you think useful to improve it.

Source: http://www.silverlightplayground.org/assets/sources/SilverlightPlayground.RFB.zip
Video: http://www.silverlightplayground.org/assets/video/SilverVNC.wmv
RFB Specifications: The RFB Protocol

Categories:   Networking | News
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed