Thursday, May 14, 2009

Unlocking application files (running from cached location)

Month or two ago, I was working on project for automatic installation and upgrade of windows forms application. In preparation for the project, I was trying to modify component (dll file) on which application depends. Result from those attempts was inconsistent, When I had tryed to modify component which I had already used in my application, modification fails, but when component was unused, modification succeeded.
That was not enough for me, because requirements ask for possibility of upgrading the files at any time.
First idea was, to download new file in some subfolder and when application exits, override the application or component file. Searching the msdn for better solution, I found way to load and run application from cached folder, here is the example of Main method which I had incorporated in the solution:


static void Main(string [] args)
{
// Aplication name ( from command line )
string appName=args[0];
// Get the startup path.
string startupPath = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
// cache path = directory where the assemblies get
// shadow copied
string cachePath = Path.Combine(startupPath,"cachedFiles");
string configFile = Path.Combine(startupPath,appName+".config");
string assembly = Path.Combine(startupPath,appName);

// Create the setup for the new domain
AppDomainSetup setup = new AppDomainSetup();
setup.ApplicationName = appName;setup.ShadowCopyFiles = "true";
// it isn't a bool it's a string,
// developer team decide to leave that inconsistent API for
//backward compatibility
setup.CachePath = cachePath;
setup.ConfigurationFile = configFile;
// Create the application domain with same evidence
AppDomain domain =
AppDomain.CreateDomain(appName,AppDomain.CurrentDomain.Evidence,setup);
// Start appName application by executing the assembly
domain.ExecuteAssembly(assembly);
// After the application has finished clean up
AppDomain.Unload(domain);
Directory.Delete(cachePath, true);
}