Amir’s warning: this article contains a modest amount of code.

I often characterize desktop virtualization technologies in four different segments; virtual desktops that run on the client or endpoint, virtual desktops that are hosted, (hosted) application virtualization via seamless windows, and finally, client-side application virtualization where the bits of an app are streamed down to the endpoint and locally executed.

As you might already know, VDIworks is in the business of providing hosted virtual desktops, and the innovation planned on our roadmap will soon merge hosted VDI and endpoint VDI into a single category. Running Hypervisors on endpoints, among other things, supports the “disconnected use-case”, i.e. allows you access to your desktop even when you don’t have network connectivity. For situations where you might be travelling in an airplane, this can be important. However, when you are connected to the network, hosted VDI will most often provide you with the best experience by making use of the compute capacity of the datacenter. In most cases, this will dwarf what your local device – whatever it might be – can provide.

But I digress. The purpose of this article was to walk through Application Virtualization in a bit of depth to show you how you might build an Application Virtualization Framework. What’s that I hear? Why would I want to show you how to build an application virtualization framework? Well, because it can be fun… and it can also expose a lot of the issues related to delinking the local OS install from the app that runs on it. Hopefully, by the end of this article (or two if my carpal tunnel returns in the next few minutes) we’ll all have a better understanding of how application virtualization works and some of the key challenges in implementing virtualization of this variety.

First things first, what is application virtualization? Well, in a nutshell, it is a process by which an ordinary application is fooled into believing that it is directly interfacing with the operating system and all the resources managed by it, when in reality it is not. Application virtualization is different from what a Hypervisor does. Simply because the Hypervisor creates an abstraction for the entire underlying system (i.e. hardware such as memory, CPU, peripherals, video etc.) In order to virtualize a single application, you don’t have to do that… all you really have to do is insert a layer of “virtualization” between the OS and the app itself.

Ok, Amir, you say, I get that. But what does that layer of virtualization look like and what does it need to do. It needs to do several things. First, let’s look at what kinds of dependencies an application typically has on the OS from a footprint perspective.

  1. An app stores files on the filesystem when it installs and it makes requests to fetch these files when it runs. Instead of trying to categorize the various different kinds of files, let’s just put them all in one category for now.
  2. An app stores configuration and other information in the registry (we’re assuming Windows here, in case I neglected to mention that previously)
  3. An app also makes use of environment variables.
  4. An app may install certain components as “specially handled” elements. For instance, registering a binary as a Windows service would fall in this category.
  5. An application might modify existing files (typically configuration repositories) when it installs and may rely on these entries in subsequent executions.
  6. Finally, an application might also rely on systems such as database servers… this involves configuring and installing an ODBC data source as well as populating the database. Let’s leave this one out for now and focus on the pieces above.

Essentially, an Application Virtualization Framework must make it so that when a typical, unmodified app installs, it can perform all of the above but instead of actually committing those changes to the underlying OS instance, they are intercepted and logged separately. The application binaries, including the installer, is told that all the file copies, registry modifications etc. were done succesfully. But in fact, this “layer of virtualization” that we alluded to earlier, steps in and captures the changes in what I will refer to as a “delta catalog”. A set of changes the application made, that in the usual course of things, would have been committed to the OS environment.

Ok, so far so good. We now have a conceptual model for how our application will work. We’ll capture all these changes, store them in delta catalogs and hence categorize the unique resources our application needs. But what happens when we run the app? How do we actually fulfill the application’s resource expectations when the changes weren’t actually committed to the OS? By doing the reverse of the capture process. Now, we intercept the applications requests to the filesystem, the environment and the registry and when it asks for a file or a key that doesn’t exist on the physical OS install, we check the delta catalog that was created for this app. If it contains the file/key, we simply return it to the application.

Alright, well that sounds like a good story. But the story isn’t quite enough. The headline says, “How to build an Application Virtualization Framework”, and I mean my headlines. I can’t give you every single line of code that it takes to put a framework like this together because one must leave a little bit to the readers’ imagination. Or so I hear.

On to the code. The initial piece I’ll tell you about is how to watch for changes on the FileSystem. I am assuming you understand C/C++/C# code:

/* The FileSystemWatcher lets you monitor the filesystem for changes.  You can register to listen for particular kinds of change events and associate handlers with each */

FileSystemWatcher fsWatch = new FileSystemWatcher();
/* Watch the root – in order to make this more sophisticated, you would check for multiple drives and watch everything meaningful */

fsWatch.Path = “/”;
fsWatch.NotifyFilter = NotifyFilters.LastAccess | NotifyFilters.LastWrite  | NotifyFilters.FileName;
// Add event handlers.

fsWatch.Changed += new FileSystemEventHandler(OnFileChange);
fsWatch.Created += new FileSystemEventHandler(OnFileCreate);

Next, let’s look at how we can watch for changes to the registry. The code I am actually going to point to was outlined by Mark Russinovich who ran Sysinternals for many years and is currently at Microsoft. He wrote a great article a while back about getting around group policies by intercepting registry access requests and sending back arbitrary information to the requestor. That’s the technique you can use to capture requests to the registry, store the key/value pairs in the previously discussed delta catalog, and “playback” for the app at the appropriate time.

Here’s the code for hooking ZwQueryValueKey, which is responsible for returning values from the registry. Mark’s original blog article was a great overview, but he wasn’t proposing this code for app virtualization. We’re just “repurposing” the idea here to achieve a different end.

 

Finally, we get to the easy part. Capturing changes to the environment (i.e. environment variables). I’ll show you one possible way of many. Prior to app installation, you can use the C#/.NET Environment.GetEnvironmentVariables() method to retrieve the key value pairs that comprise the current environment variables/values. Post installation, you perform the same process again and compute a “diff” between the two. You can then revert to the original state of the environment pre-installation and store the computed changes in your “delta catalog”. When you need to execute the application, you simply spawn a new process and set its environment using the delta catalog. Once these variables are set, you kick-off the application. Voila!

The Environment.GetEnvironmentVariables() example shows how you can enumerate all the key value pairs:

IDictionary envars = Environment.GetEnvironmentVariables();
IDictionaryEnumerator varEnumerator = envars.GetEnumerator();
while(varEnumerator.MoveNext() != false) {
      Console.WriteLine(“{0}={1}”, varEnumerator.Key, varEnumerator.Value);
 }

We now have the basics for the hooks and capture methods that will allow us to “virtualize” application access to the registry, filesystem and environment variables. Another consideration would be: How would this system load files comprising a virtualized application “on demand”?

The answer to this is relatively simple. We covered the FileSystemWatcher earlier. You can use this to figure out when a request for a particular file is being made and then retrieve it from the network and place it where it is supposed to go. There’s a trifle more complexity here but you would think I was a kill-joy if I gave the ENTIRE plot away :-)

I hope you enjoyed this little tutorial on Application Virtualization and in following through the steps needed to build this functionality, you hopefully have a deeper understanding for the issues entailed in building and deploying products of this nature.

Till next time! Amir