/// <summary> /// Unloads the private AppDomain and the wkhtmltopdf library, and if applicable, destroys /// the synchronization thread. /// </summary> /// <param name="sender">Typically a null value, not used in the method.</param> /// <param name="e">Typically EventArgs.Empty, not used in the method.</param> private static void TearDownAppDomain(object sender, EventArgs e) { if (Factory.operatingDomain != null) { Func<object> del = () => { Factory.operatingDomain.DoCallBack(() => PechkinBindings.wkhtmltopdf_deinit()); return null; }; Factory.invocationDelegate.DynamicInvoke(del); AppDomain.Unload(Factory.operatingDomain); foreach (ProcessModule module in Process.GetCurrentProcess().Modules) { if (module.ModuleName == PechkinBindings.LibFilename) { while (PechkinBindings.FreeLibrary(module.BaseAddress)) { } } } Factory.operatingDomain = null; } if (Factory.synchronizer != null) { Factory.synchronizer.Terminate(); Factory.synchronizer = null; } }
/// <summary> /// Creates and initializes a private AppDomain and therein loads and initializes the /// wkhtmltopdf library. Attaches to the current AppDomain's DomainUnload event in IIS environments /// to ensure that on re-deploy, the library is freed so the new AppDomain will be able to use it. /// </summary> private static void SetupAppDomain() { if (Factory.useSync) { Factory.synchronizer = new SynchronizedDispatcherThread(); } String binPath = String.Empty; if (!String.IsNullOrEmpty(AppDomain.CurrentDomain.RelativeSearchPath)) { String[] paths = AppDomain.CurrentDomain.RelativeSearchPath.Split(';'); for (var i = 0; i < paths.Length; i++) { paths[i].Remove(0, AppDomain.CurrentDomain.BaseDirectory.Length); } binPath = String.Join(";", paths); } Factory.operatingDomain = AppDomain.CreateDomain("pechkin_internal_domain", null, new AppDomainSetup { ApplicationBase = AppDomain.CurrentDomain.BaseDirectory, // Sometimes, like in a web app, your bin folder is not the same // as the base dir. PrivateBinPath = binPath }); if (binPath != String.Empty) { Factory.operatingDomain.SetData("assemblyLocation", Assembly.GetExecutingAssembly().Location); Factory.operatingDomain.DoCallBack(() => { String location = AppDomain.CurrentDomain.GetData("assemblyLocation").ToString(); String filename = System.IO.Path.GetFileName(location); List<String> paths = new List<String>(AppDomain.CurrentDomain.RelativeSearchPath.Split(';')); foreach (String path in paths.ToArray()) { paths.Remove(path); paths.AddRange(System.IO.Directory.GetFiles(path, filename)); } Assembly.LoadFrom(paths[0]); AppDomain.CurrentDomain.SetData("assemblyLocation", paths[0]); }); Factory.realAssemblyLocation = Factory.operatingDomain.GetData("assemblyLocation").ToString(); } else { Factory.operatingDomain.Load(Assembly.GetExecutingAssembly().FullName); } Func<object> del = () => { Factory.operatingDomain.SetData("useX11Graphics", Factory.useX11Graphics); Factory.operatingDomain.DoCallBack(() => { PechkinBindings.wkhtmltopdf_init((bool)AppDomain.CurrentDomain.GetData("useX11Graphics") ? 1 : 0); }); return null; }; Factory.invocationDelegate.DynamicInvoke(del); if (AppDomain.CurrentDomain.IsDefaultAppDomain() == false) { AppDomain.CurrentDomain.DomainUnload += Factory.TearDownAppDomain; } }