Desklighter which can convert a Silverlight application into a standalone desktop application.
 
Goals

The goals of this project can be put under two sections as below:

  • Desklight: The standalone exe application that renders Silverlight content.
    • Single exe file. To make it easily portable and accessible, the Desklight should be composed of just a single exe file. No dependent and loose xap file, or html file.
    • Server independent. The Desklight can run without a hosting server like IIS on the local computer.
    • Read-only operations. To make sure that Desklight is executable from a read-only media, like CD ROM, it should not include any file write operations (i.e. writing the xap on disk to render it later).
    • Lightweight. The Desklight can run on a windows computer with .NET Framework 2.0 and Silverlight plug-in installed. No dependency on WPF/.NET 3.0/.NET 3.5.

  • Desklighter: The utility that will create a Desklight from Silverlight xap file.
    • Single exe file. The Desklighter is composed of a single exe file. No dependent and loose configuration or source files. No installations or setups.
    • Data transfer with Desklight. It should be possible to pass any data (i.e. Application Name) from the Desklighter to the Desklight.
    • Lightweight. The Desklighter will run on a windows computer with .NET Framework 2.0 installed. No dependency on Silverlight plug-in /WPF/.NET 3.0/.NET 3.5.
Desklight Development

The first step in this project is to create an independent Desklight application. The Desklight will be a standard Windows Forms Application with a 'WebBrowser' control that is 'Fill' docked on the form.

In order to display the Silverlight content on this browser control, we need an html file with bare minimum content as below:


<html>
    <body>
        <object type="application/x-silverlight" width="100%" height="100%">
            <param  name="Source" value="silverlight.xap" />
        </object>
    </body>
</html>

As obvious from the goals, we cannot have this html file or the xap file mentioned in it, as loose files that can be just pointed to the browser control.

The next step is to embed these files into the application. The html content can be stored as a normal string. The Silverlight xap file will be embedded in the application as a resource.

The final step is to host this html file in a server. We cannot use any external servers so we will have to create one internally. A small web server running within the application that can dispatch static files with appropriate mime types will be perfect for this.

Tamir Khason has an excellent blog post implementing a small web server using TCPListener and Socket.

TcpListener class coming from the System.Net.Sockets namespace provides simple methods that listen for and accept incoming connection requests. It is possible to create an endpoint using an IP address and port number. If we specify ‘Any’ for the local IP address and ‘0’ for the local port number, the underlying service provider will assign those values for us.


TcpListener webServer = new TcpListener(IPAddress.Any, 0); 
webServer.Start();

Now our tiny internal web server is up and running. We can use the LocalEndpoint to get the assigned port and use this to point to the browser.


int port = ((IPEndPoint) webServer.LocalEndpoint).Port;
browser.Url = new Uri(string.Format("http://localhost:{0}", port)); 

Now the browser is essentially creating requests that our server can listen to and service. Once the server is started, we can enter a listening loop that will accept requests. We can use the Socket class from the System.Net.Sockets namespace to accept the requests.


while (true)
{
 Socket client = webServer.AcceptSocket();
 Console.WriteLine("Connected!");
}

The Receive method of the socket can be used to retrieve the request information. As mentioned in Tamir’s blog post, now it is possible to check the request header and send the appropriate content (html from a string variable and xap from the embedded resource) to the browser using the socket.

Desklighter Development

Now that we have the logic for our Desklight ready, the next step is to create a utility (Desklighter) that will make such a Desklight programmatically. The Desklighter will be a standard Windows Forms Application with few controls that will allow users to choose a Silverlight xap file, a location to save the output exe file, and a button to initiate the exe generation.

In .NET, there are two options to programmatically create assemblies. One is to use Reflection.Emit namespace which permits us to generate assemblies that are entirely transient; they can be generated in memory and executed without ever being persisted to disk. This option requires IL coding expertise and can be quit complex.

The other option is to use System.CodeDom namespace. ICodeCompiler's CompileAssemblyFromFile method allows us to compile an assembly from a source code file. This will save a lot of effort.

There is an MSDN article that explains both these options in the context of developing custom controls at runtime.

To use CodeDom, the complete logic required for the Desklight must be saved as a single class file to be used in this application. It is best to save it as .txt file and embed it as a resource so that it can be retrieved as a string. We can also have some placeholders in the source code file that we can replace from within this application.


TextWriter tw = new StreamWriter("desklightsource.cs");
String src = Resources.desklight;
src = src.Replace("@AppDate@", DateTime.Now.ToLongDateString);
tw.WriteLine(src);
tw.Close();

The above code creates a file named ‘desklightsource.cs ‘ on the disk using the source code of Desklight which is embedded as a resource. Before writing the file content, it provides values for any placeholders within the source code.

The final step is to compile this source code into an exe using CodeDom. Before invoking the compile command, we need to provide assembly references and add the input xap file as a resource. All these are easily possible using CompilerParameters class. The complete code snippet is given below:


CodeDomProvider provider = new CSharpCodeProvider();
ICodeCompiler compiler = provider.CreateCompiler();
      
CompilerParameters cp = new CompilerParameters();
cp.ReferencedAssemblies.Add("System.dll");
cp.ReferencedAssemblies.Add("System.Windows.Forms.dll");
cp.ReferencedAssemblies.Add("System.Drawing.dll");
cp.OutputAssembly = "newdesklight.exe"; 
cp.EmbeddedResources.Add("silverlight.xap");
cp.GenerateExecutable = true;

compiler.CompileAssemblyFromFile(cp, "desklightsource.cs");

That’s it! The user supplied xap file is now embedded into the Desklight exe named ‘newdesklight.exe’ which has its own internal web server to display the Silverlight content within a browser control.

 
Copyright © 2007 IdentityMine, Inc.  | Careers  | Policies  | License  | News & Press