I guess that it's time to write about it, after making a few people curious at the MVP summit in Seattle. This article is to be taken as a proof of concept, and (I hope) as a way to "motivate" Microsoft to integrate this ability into Silverlight.
As soon as I started playing with Silverlight, I saw the great potential that this technology has. As a RIA technology, it provides extended functionality over the web. As a WPF subset, it allows me to leverage the knowledge I already acquired in the past, and to reuse it for web applications. This in itself makes Silverlight a technology I *have to* learn.
But what if... what if we could use Silverlight to run lightweight .NET applications in standalone mode? A little like Adobe AIR is offering, but with the power of .NET instead of ActionScript. Imagine a small application, running on a small framework, installed in typically 10 seconds.
Why would you want a standalone Silverlight application?
There are many reasons why one would want to create a standalone, full-trust Silverlight application. To me, the most compelling ones are:
-
To get a .NET experience on more platform than "full" .NET supports. Silverlight is currently available to run on Firefox and IE on Windows, Safari and Firefox on Macintosh, and Firefox on Linux (the Moonlight version of Silverlight).
-
To install Silverlight is a much snappier and more comfortable experience than to get the full .NET to install. Granted, you don't get as much functionality. Silverlight is only a 5 MB setup, it downloads fast, you don't need to reboot, it's a great experience.
Note that the full .NET setup experience is going to get better soon, with a "client only" setup. Many .NET applications don't need server-side libraries, so giving the user a way to install only client-side libraries makes the whole .NET experience better. This "client only" setup is coming in .NET 3.5 SP1 and should be around 25 MB in size.
Why don't we have standalone Silverlight applications already?
Note: I don't have insider information here. This is only based on discussions I had with other Silverlight specialists and based on my own judgement.
-
Standalone Silverlight is trickier than having it run in a browser. In "full .NET", handling the permission system is really hard. Depending on where the application runs (browser, standalone, full trust, partial trust), the code is allowed or prevented to do certain operations. Adding this to Silverlight is something to be considered carefully, and will probably cost a lot.
-
Silverlight is designed to run in a plug-in. It's hard for me to evaluate what it would need to make it run in a window, but it's not just a matter of hosting the Silverlight plug-in. In the example below, the host is not able to support transparency, for example, and this is a limitation of my current proof of concept.
-
The experience needs to be consistent on every platform that Silverlight supports. This is a great challenge, greater than to run a plug-in in a browser. Accessing the underlying file system on multiple platforms, for example, is tricky (see the section below titled "Does it run on other platforms?").
-
There are most probably political issues at stake. Does Microsoft really want to allow small .NET applications to run everywhere? What does it mean for Windows?
At this time, Silverlight is *not* a light WPF application. It was not inteneded to run as standalone. The technique demonstrated here does not represent what Silverlight was made for, which is running in the web browser.
This application is a proof of concept more than anything else. It relies only on documented Microsoft technologies, so there are no dirty tricks at work here. It is based on a few facts that I happen to have learned in past projects:
-
An HTML application can run in HTTP mode and in file mode.
-
JavaScript gets partial trust in HTTP mode and full trust in file mode.
-
Silverlight can communicate very well with JavaScript.
These facts alone are sufficient to create a standalone Silverlight application using JavaScript as a fully trusted API to perform operations that would otherwise be forbidden. To start the HTML file with elevated permissions, in other words to run it in "file" mode, you must double-click the HTML file in Windows Explorer (or the equivalent on other platforms).
Running a HTML file in "file" mode is not much different for the user than running it in HTTP mode. The location bar, back and forward buttons and all the other browser controls are visible. To give the user a better experience, there is a better, though lesser known way:
-
By changing the extension of a HTML file to ".hta", you create a standalone HTML Application, which gives the user a very "application-like" experience.
-
The HTA can be double clicked to start.
-
It runs in a host named "MSHTA.EXE".
-
You can create shortcuts to the HTA file.
-
It doesn't have any location bar, back and forward buttons.
The HTA experience has limitations though:
-
A HTA application is Windows only. Even though the HTML and Silverlight it hosts are multi-platform, the host itself is Windows only.
-
A HTA application is a GDI application, so it doesn't support transparency or other WPF-like features. This is not a WPF-light application.
-
Because of the need to channel every full trust call through JavaScript, it is slower than a normal Silverlight application.
Why do we need JavaScript at all?
For the moment, Silverlight doesn't support any full trust at all. Some classes exist, which could require elevated permissions (the whole System.IO comes to mind). However, if you try to create a DirectoryInfo or a FileInfo, you get a security exception, even if the HTML/JavaScript host runs in full trust. These exceptions are likely hard coded for the moment. FileInfo and DirectoryInfo are needed for the access to the IsolatedStorage to work, but as soon as you want to do something on the hard drive, you get issues.
JavaScript allows these operations to occur in full trust, however. This is why, as long as Silverlight won't allow such functionality to work, using JavaScript from Silverlight is the only alternative.
The following image shows the layers involved in the standalone Silverlight application.
Components involved in a standalone Silverlight application
What is "file" mode and "http" mode
An HTML page can be run in "file" mode (or "local" mode) by double-clicking it to start it. In "file" mode, the URL displayed in the location bar starts with the "file:" protocol. In IE, you will see a Windows-like path, for example "c:\temp\test.html". This mode offers elevated permissions to the JavaScript code, running in full trust.
In "http" mode, the URL starts with the "http:" protocol, and the elevated permission is not available. The application runs in partial trust.
Does it run on other platforms?
MSHTA is for Windows only, so the HTML Application host will not run on other platforms (Mac, Linux) at all.
However, the ability that JavaScript has to access the underlying file system is also available for other platforms.
-
Mozilla has a "components" based interface allowing to make calls to full trust operations like file system operations.
-
Some browsers support Java operations, allowing to access the file system using the Java framework. Java, like ActiveX, may run with elevated permissions and allow these operations.
-
The current example relies on ActiveX to access the file system. The FileSystemObject component is accessible to JavaScript and VBScript.
Some time ago, I published a "proof of concept" JavaScript class allowing file system operations in JavaScript, and auto-detecting which are possible on the current platform. This file contains an implementation for multiple platforms of certain file system operations. The elevated permission can be reached by running the HTML application using this JavaScript file in "file" mode. I am reusing some of this code here, and implemented only one method for Mozilla-based browsers: "fileExists". This method returns true if a given file exists, and false if it cannot be found.
However, programming for the "components" based platform is a real pain. The syntax is overly complex and not well documented. If anyone is willing to implement additional operations for Mozilla-based platforms, don't hesitate. On my side, I think I will pass for now :) This is why other operations will fail.
To install the demo, follow the steps:
-
Download the Zip file.
-
Extract the Zip file to a folder on your hard drive.
-
On Windows: double-click the file "Start.hta".
This starts the MSHTA host, and displays the Silverlight application.
Silverlight application in MSHTA
-
Enter a directory path in the first textbox, and then click on "Get list of files". This displays the corresponding list in the listbox.
-
Select a file. Its name is displayed in the second textbox.
-
You can now modify the file name and press on "Rename".
-
Enter any file path in the last textbox and press "Does file exist?". A corresponding message is displayed in the status bar.
This last functionality is also available in Mozilla-based browsers, for example Firefox. You can try it by setting Firefox to be your default browser, and then double-clicking the file "index.html" located in the same folder as "index.hta". This starts the application in "file" mode, and you get the same permissions. The other functionalities "Get list of files" and "Rename" are not implemented in Firefox and will raise an error.
Silverlight application in Firefox
As usual, the source code is available for download. It contains the following projects:
-
GalaSoft.SL.TestHta: This is the Silverlight application you want to run. It contains an "index.html" file, which should be the start page if you run the application in "F5" or "Ctrl-F5" mode in Studio. Visual Studio runs the HTML file in file mode, so you get a chance to debug the Silverlight code, but unfortunately it is not possible to debug the JavaScript code. When you build the project, a "index.hta" file is automatically created. This is exactly the same as "index.html", but with a different extension. Double-clicking this file in Windows Explorer will start the MSHTA host.
-
GalaSoft.SL.IO: This is a library defining a new DirectoryInfo and FileInfo classes. These classes mimic the actual System.IO.DirectoryInfo and System.IO.FileInfo classes. They use the class "GalaSoft.SL.IO.ScriptFacade" to channel the full-trust calls to the script code contained in the file "script\gslb.filesystemexplorer.js".
-
GalaSoft.SL.IO.Test: A Unit Test application for GalaSoft.SL.IO. Written using the Silverlight Unit Test framework and accessing JavaScript as described here. I use this to unit test all my IO classes and methods, including the corresponding JavaScript file.
Note: The console application "GalaSoft.SL.IO.Test.Prepare" must be executed before the unit test is run.
-
GalaSoft.SL.IO.Test.Prepare: This console application is needed to create a few directories and files in the local drive in order to unit test the library GalaSoft.SL.IO. It requires write-permission to the folder c:\temp. Unfortunately, I don't think that Mock frameworks exist for JavaScript yet.
In normal use, the project GalaSoft.SL.TestHta should be chosen as startup project, and its file "index.html" as startup page. You can modify the application code. If you change the HTML code, the changes will automatically be copied to "index.hta" when you build the application.
Ideas for further development
As I wrote, this application is more a "proof of concept" than anything else. I have a few ideas for further development that I will pursue if time allows, and I also have a couple of ideas of projects in which I could use this kind of lightweight .NET application.
-
Extend the JavaScript / ScriptFacade / GalaSoft.SL.IO with additional features, in order to get always more compliant with the DirectoryInfo and FileInfo specs.
NB: I do that by unit testing the DirectoryInfo and FileInfo classes in the System.IO namespace, and reusing the same unit tests against my own DirectoryInfo and FileInfo classes.
-
Clean up the error behaviour of ScriptFacade, to give better error messages if there is an error with the script.
-
Extend the support to the Mozilla platform in order to get the same specs for Mozilla-based browsers as for HTA and IE. That means opening the dark pit of the components-based JavaScript development... yay.
-
Make the application self-updatable. That should be relatively easy to achieve, considering the amazing connectivity that Silverlight offers.
-
Create a small add-in for Visual Studio to allow easy creation of such applications, including the unit test project.
-
I would love to find an elegant way to provide the same kind of functionality than HTA provides on the Macintosh platform. Unfortunately I never really developed for the Mac (well, I did a couple of simple apps years ago), so maybe the community could help there.
If you have any idea how we could make this better, don't hesitate to write to me. If enough interest is available, we can even start an open-source project at Codeplex or something.