/// <summary> /// Dupms the given Registry data into a file. /// </summary> public static void DumpInstallationData(InstallationDataXml data, string sRegistryRegistrationDataFile) { var serializer = new XmlSerializer(typeof(RegistryXml)); using (var stream = new FileStream(sRegistryRegistrationDataFile, FileMode.Create, FileAccess.Write, FileShare.Read)) serializer.Serialize(stream, data); }
/// <summary> /// Collects the one-time global registration data from the attribute installers, one that is not per-attribute or per-assembly. /// Invoked from <see cref="InvokeAttributeInstallersInstance"/>, don't call manually. /// </summary> protected void InvokeAttributeInstallersStatic(InstallationDataXml total) { foreach (IInstallAttributes installer in MapInstallerTypeToInstance.Values) { InstallationDataXml data = installer.InstallStatic(this); if (data != null) { total.MergeWith(data); } } }
/// <summary> /// Copies or deletes the files. /// </summary> private static void InstallFiles(InstallationDataXml dataxml, RegistrationStage stage, Action <string> LogMessage, Func <SourceRootXml, DirectoryInfo> ResolveSourceDirRoot, Func <TargetRootXml, DirectoryInfo> ResolveTargetDirRoot) { dataxml.AssertValid(); foreach (FolderXml folderxml in dataxml.Files) { var diSource = new DirectoryInfo(Path.Combine(ResolveSourceDirRoot(folderxml.SourceRoot).FullName, folderxml.SourceDir)); var diTarget = new DirectoryInfo(Path.Combine(ResolveTargetDirRoot(folderxml.TargetRoot).FullName, folderxml.TargetDir)); diTarget.Create(); foreach (FileXml filexml in folderxml.Files) { FileInfo[] files = diSource.GetFiles(filexml.SourceName); if (files.Length == 0) { throw new InvalidOperationException(string.Format("There are no files matching the “{0}” mask in the source folder “{1}”.", filexml.SourceName, diSource.FullName)); } if ((files.Length > 1) && (filexml.TargetName.Length > 0)) { throw new InvalidOperationException(string.Format("There are {2} files matching the “{0}” mask in the source folder “{1}”, in which case it's illegal to specify a target name for the file.", filexml.SourceName, diSource.FullName, files.Length)); } foreach (FileInfo fiSource in files) { var fiTarget = new FileInfo(Path.Combine(diTarget.FullName, (filexml.TargetName.Length > 0 ? filexml.TargetName : fiSource.Name))); // Explicit target name, if present and if a single file; otherwise, use from source // Don't copy and, especially, don't delete the inplace files if (fiSource.FullName == fiTarget.FullName) { LogMessage(string.Format("Skipping “{0}” because source and target are the same file.", fiSource.FullName, fiTarget.FullName)); continue; } switch (stage) { case RegistrationStage.Register: LogMessage(string.Format("Installing “{0}” -> “{1}”.", fiSource.FullName, fiTarget.FullName)); fiSource.CopyTo(fiTarget.FullName, true); break; case RegistrationStage.Unregister: LogMessage(string.Format("Uninstalling “{0}”.", fiTarget.FullName)); fiTarget.Delete(); break; default: throw new InvalidOperationException(string.Format("Unexpected stage {0}.", stage)); } } } } }
public InstallationDataXml HarvestInstallationData() { var data = new InstallationDataXml(); // Run the attribute installers statically (each instance once) InvokeAttributeInstallersStatic(data); // Run the attribute installers per each attribute instance InvokeAttributeInstallersInstance(data); data.EnsureNotNull(); data.RemoveDuplicates(); data.AssertValid(); return(data); }
/// <summary> /// Actions under the resolver. /// </summary> protected override void ExecuteTaskResolved() { // Prepare the GUID cache myGuidCache = GuidCacheXml.Load(new FileInfo(Bag.GetString(AttributeName.GuidCacheFile)).OpenRead()); // Global structure of the WiX fragment file var wix = new Wix(); var wixFragmentComponents = new Fragment(); // Fragment with the payload wix.AddChild(wixFragmentComponents); var wixDirectoryRef = new DirectoryRef(); // Mount into the directories tree, defined externally wixFragmentComponents.AddChild(wixDirectoryRef); wixDirectoryRef.Id = Bag.GetString(AttributeName.WixDirectoryId); var wixFragmentGroup = new Fragment(); // Fragment with the component-group that collects the components wix.AddChild(wixFragmentGroup); var wixComponentGroup = new ComponentGroup(); // ComponentGroup that collects the components wixFragmentGroup.AddChild(wixComponentGroup); wixComponentGroup.Id = Bag.GetString(AttributeName.WixComponentGroupId); // Get the dump from the product InstallationDataXml dataxml = CreateInstaller().HarvestInstallationData(); IDictionary <string, string> macros = GetMacros(); // Nullref guards dataxml.AssertValid(); // Convert into WiX int nProducedFiles = ConvertFiles(wixDirectoryRef, wixComponentGroup, dataxml, macros); int nProducedKeys = ConvertRegistryKeys(wixDirectoryRef, wixComponentGroup, dataxml, macros); int nProducedValues = ConvertRegistryValues(wixDirectoryRef, wixComponentGroup, dataxml, macros); // Save to the output file using (var xw = new XmlTextWriter(new FileStream(Bag.GetString(AttributeName.OutputFile), FileMode.Create, FileAccess.Write, FileShare.Read), Encoding.UTF8)) { xw.Formatting = Formatting.Indented; wix.OutputXml(xw); } // Report (also to see the target in the build logs) Log.LogMessage(MessageImportance.Normal, "Generated {0} files, {1} Registry keys, and {2} Registry values.", nProducedFiles, nProducedKeys, nProducedValues); }
protected InstallationDataXml InvokeAttributeInstallersInstance(InstallationDataXml retval) { // Process each known assembly foreach (Assembly assembly in Assemblies) { // Invoke registration try { foreach (var pair in MapAttributeToInstallers) { foreach (object attribute in assembly.GetCustomAttributes(pair.Key, false)) { foreach (IInstallAttributes installer in pair.Value) { try { // Collect installation data! InstallationDataXml data = installer.InstallInstance(this, attribute); if (data != null) { retval.MergeWith(data); } } catch (Exception ex) { throw new InvalidOperationException(string.Format("Failed to collect the installation data for the attribute of type “{0}” from the assembly “{1}” using the “{2}” installer. {3}", pair.Key.AssemblyQualifiedName, assembly.FullName, installer.GetType().AssemblyQualifiedName, ex.Message), ex); } } } } } catch (Exception ex) { throw new InvalidOperationException(string.Format("Failed to process the “{0}” assembly. {1}", assembly.FullName, ex.Message), ex); } } return(retval); }
/// <summary> /// Performs the local installation of the given installation data by writing the Registry keys and copying the files. /// </summary> /// <param name="dataxml">The installation data.</param> /// <param name="stage">Stage, either install or uninstall.</param> /// <param name="LogMessage">The logging facility.</param> /// <param name="ResolveSourceDirRoot">Resolves the source directory, for copying the files from.</param> /// <param name="ResolveTargetDirRoot">Resolves the target directory, for copying the files into.</param> /// <param name="macros">The maros to be substituted on install, if needed.</param> public static void Install(InstallationDataXml dataxml, RegistrationStage stage, IDictionary <string, string> macros, Func <SourceRootXml, DirectoryInfo> ResolveSourceDirRoot, Func <TargetRootXml, DirectoryInfo> ResolveTargetDirRoot, Action <string> LogMessage) { InstallRegistry(dataxml.Registry, stage, macros); InstallFiles(dataxml, stage, LogMessage, ResolveSourceDirRoot, ResolveTargetDirRoot); }
/// <summary> /// Emits WiX Registry Values from the installation data. /// </summary> private int ConvertRegistryValues(DirectoryRef directory, ComponentGroup componentgroup, InstallationDataXml dataxml, IDictionary <string, string> macros) { foreach (RegistryValueXml valuexml in dataxml.Registry.Value) { try { var value = new RegistryValue(); GetComponentForHive(valuexml.Hive, directory, componentgroup).AddChild(value); value.Root = GetRoot(valuexml.Hive); value.Key = LocalInstaller.SubstituteMacros(macros, valuexml.Key); if (!string.IsNullOrEmpty(valuexml.Name)) // The default value name must be Null not an empty string { value.Name = LocalInstaller.SubstituteMacros(macros, valuexml.Name); } value.Value = LocalInstaller.SubstituteMacros(macros, valuexml.Value); value.Type = GetValueType(valuexml.Type); value.Action = RegistryValue.ActionType.write; } catch (Exception ex) { throw new InvalidOperationException(string.Format("Failed to process the value {0}. {1}", valuexml, ex.Message), ex); } } return(dataxml.Registry.Value.Length); }
/// <summary> /// Emits WiX Registry Keys from the installation data. /// </summary> private int ConvertRegistryKeys(DirectoryRef directory, ComponentGroup componentgroup, InstallationDataXml dataxml, IDictionary <string, string> macros) { foreach (RegistryKeyXml keyxml in dataxml.Registry.Key) // Keys { try { var key = new RegistryKey(); GetComponentForHive(keyxml.Hive, directory, componentgroup).AddChild(key); key.Root = GetRoot(keyxml.Hive); key.Key = LocalInstaller.SubstituteMacros(macros, keyxml.Key); key.Action = RegistryKey.ActionType.createAndRemoveOnUninstall; } catch (Exception ex) { throw new InvalidOperationException(string.Format("Failed to process the key {0}. {1}", keyxml, ex.Message), ex); } } return(dataxml.Registry.Key.Length); }
/// <summary> /// Processes the installation files, produces the WiX data. /// </summary> private int ConvertFiles(DirectoryRef wixDirectoryRef, ComponentGroup wixComponentGroup, InstallationDataXml dataxml, IDictionary <string, string> macros) { int nProduced = 0; // Each installation folder derives a component, regardless of whether there are more files in the same folder, or not foreach (FolderXml folderxml in dataxml.Files) { folderxml.AssertValid(); // Create the component with the files var wixComponent = new Component(); wixComponent.Id = string.Format("{0}.{1}", ComponentIdPrefix, folderxml.Id); wixComponent.Guid = folderxml.MsiComponentGuid; wixComponent.DiskId = Bag.Get <int>(AttributeName.DiskId); wixComponent.Location = Component.LocationType.local; ConvertFiles_AddToDirectory(folderxml, wixComponent, wixDirectoryRef); // To the directory structure // Add to the feature var wixComponentRef = new ComponentRef(); wixComponentRef.Id = wixComponent.Id; wixComponentGroup.AddChild(wixComponentRef); // To the feature var diSource = new DirectoryInfo(Path.Combine(LocalInstallDataResolved.ResolveSourceDirRoot(folderxml.SourceRoot, Bag), folderxml.SourceDir)); if (!diSource.Exists) { throw new InvalidOperationException(string.Format("The source folder “{0}” does not exist.", diSource.FullName)); } // Add files foreach (FileXml filexml in folderxml.Files) { filexml.AssertValid(); FileInfo[] files = diSource.GetFiles(filexml.SourceName); if (files.Length == 0) { throw new InvalidOperationException(string.Format("There are no files matching the “{0}” mask in the source folder “{1}”.", filexml.SourceName, diSource.FullName)); } if ((files.Length > 1) && (filexml.TargetName.Length > 0)) { throw new InvalidOperationException(string.Format("There are {2} files matching the “{0}” mask in the source folder “{1}”, in which case it's illegal to specify a target name for the file.", filexml.SourceName, diSource.FullName, files.Length)); } foreach (FileInfo fiSource in files) { nProduced++; var wixFile = new File(); wixComponent.AddChild(wixFile); wixFile.Id = string.Format("{0}.{1}.{2}", FileIdPrefix, folderxml.Id, fiSource.Name).Replace('-', '_').Replace(' ', '_'); // Replace chars that are not allowed in the ID wixFile.Name = filexml.TargetName.Length > 0 ? filexml.TargetName : fiSource.Name; // Explicit target name, if present and if a single file; otherwise, use from source wixFile.Checksum = YesNoType.yes; wixFile.ReadOnly = YesNoType.yes; wixFile.Source = fiSource.FullName; } } } return(nProduced); }