/// <summary> /// Adds a feature record to the Features table. /// </summary> /// <param name="featureTable">The MSI database Feature table.</param> /// <param name="conditionTable">The MSI database Condition table.</param> /// <param name="ParentFeature">The name of this feature's parent.</param> /// <param name="database">The MSI database.</param> /// <param name="Feature">This Feature's Schema element.</param> /// <param name="Depth">The tree depth of this feature.</param> /// <param name="Order">The tree order of this feature.</param> private void AddFeature(InstallerTable featureTable, InstallerTable conditionTable, string ParentFeature, InstallerDatabase database, MSIFeature Feature, int Depth, int Order) { const int TypicalInstallLevel = 3; const int NonTypicalInstallLevel = 4; int featureInstallLevel = Feature.typical ? TypicalInstallLevel : NonTypicalInstallLevel; // Insert the Feature featureTable.InsertRecord(Feature.name, ParentFeature, Feature.title, Feature.description, Feature.display, featureInstallLevel, GetFeatureDirectory(Feature), Feature.attr); Log(Level.Verbose, "\t" + Feature.name); AddFeatureConditions(Feature, conditionTable); if (Feature.feature != null) { foreach (MSIFeature childFeature in Feature.feature) { int newDepth = Depth + 1; int newOrder = 1; AddFeature(featureTable, conditionTable, Feature.name, database, childFeature, newDepth, newOrder); newOrder++; } } }
/// <summary> /// Loads the banner image. /// </summary> /// <param name="database">The MSI database.</param> private void LoadBannerImage(InstallerDatabase database) { // Try to open the Banner if (msi.banner != null) { string bannerFile = Path.Combine(Project.BaseDirectory, msi.banner); if (File.Exists(bannerFile)) { Log(Level.Verbose, "Storing banner '{0}'.", bannerFile); using (InstallerRecordReader reader = database.FindRecords("Binary", new InstallerSearchClause("Name", Comparison.Equals, "bannrbmp"))) { if (reader.Read()) { // Write the Banner file to the MSI database reader.SetValue(1, new InstallerStream(bannerFile)); reader.Commit(); } else { throw new BuildException("Banner Binary record not found in template database.", Location); } } } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Unable to open banner image '{0}'.", bannerFile), Location); } } }
/// <summary> /// Loads records for the Media table. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="LastSequence">The sequence number of the last file in the .cab.</param> private void LoadMedia(InstallerDatabase database, int LastSequence) { // Open the "Media" Table using (InstallerTable mediaTable = database.OpenTable("Media")) { mediaTable.InsertRecord("1", LastSequence.ToString(), null, "#" + Path.GetFileNameWithoutExtension(msi.output) + ".cab", null, null); } }
/// <summary> /// Loads records for the ModuleSignature table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleSignature(InstallerDatabase database) { if (msi.id != null) { Log(Level.Verbose, "Storing Module Signature:\n\tId:\t\t" + msi.id + "\n\tVersion:\t" + msi.version + "\n\tLanguage:\t" + Convert.ToInt32(msi.language)); using (InstallerTable modsigTable = database.OpenTable("ModuleSignature")) { modsigTable.InsertRecord( msi.id, Convert.ToInt32(msi.language), msi.version ); } } }
/// <summary> /// Loads records for the ModuleInstallUISequence, ModuleInstallExecuteSequence, /// ModuleAdminUISequence, ModuleAdminExecute, and ModuleAdvtExecuteSequence tables. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleSequence(InstallerDatabase database) { // Add custom actions from Task definition if (msi.modulesequences != null) { Log(Level.Verbose, "Adding Module Install/Admin Sequences:"); // Open the sequence tables using (InstallerTable installExecuteTable = database.OpenTable("ModuleInstallExecuteSequence"), installUITable = database.OpenTable("ModuleInstallUISequence"), adminExecuteTable = database.OpenTable("ModuleAdminExecuteSequence"), adminUITable = database.OpenTable("ModuleAdminUISequence"), advtExecuteTable = database.OpenTable("ModuleAdvtExecuteSequence")) { // Add binary data from Task definition foreach (MSMModuleSequence sequence in msi.modulesequences) { Log(Level.Verbose, "\t" + sequence.action + " to the module" + sequence.type.ToString() + "sequence table."); // Insert the record to the respective table InstallerTable currentTable = null; switch (sequence.type.ToString()) { case "installexecute": currentTable = installExecuteTable; break; case "installui": currentTable = installUITable; break; case "adminexecute": currentTable = adminExecuteTable; break; case "adminui": currentTable = adminUITable; break; case "advtexecute": currentTable = advtExecuteTable; break; } if (currentTable != null) { currentTable.InsertRecord(sequence.action, Convert.ToInt32(sequence.sequence), sequence.baseaction, Convert.ToInt32(sequence.after), sequence.condition); } } } } }
/// <summary> /// Loads records for the ModuleSignature table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleSignature(InstallerDatabase database) { if (msi.id != null) { Log(Level.Verbose, "Storing Module Signature:\n\tId:\t\t" + msi.id + "\n\tVersion:\t" + msi.version + "\n\tLanguage:\t" + Convert.ToInt32(msi.language)); using (InstallerTable modsigTable = database.OpenTable("ModuleSignature")) { modsigTable.InsertRecord(msi.id, Convert.ToInt32(msi.language), msi.version); } } }
/// <summary> /// Loads records for the ModuleConfiguration table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleConfiguration(InstallerDatabase database) { if (msi.moduleconfigurations != null) { Log(Level.Verbose, "Adding Module Configurations:"); using (InstallerTable modConfigurationTable = database.OpenTable("ModuleConfiguration")) { // Add properties from Task definition foreach (MSMModuleConfiguration configuration in msi.moduleconfigurations) { // Insert the Property int format = 0; switch (configuration.format.ToString()) { case "text": format = 0; break; case "key": format = 1; break; case "integer": format = 2; break; case "bitfield": format = 3; break; } if (configuration.name == null || configuration.name == "") { throw new BuildException("Configuration with no name attribute detected.", Location); } modConfigurationTable.InsertRecord(configuration.name, format, configuration.type, configuration.contextdata, configuration.defaultvalue, Convert.ToInt32(configuration.attr), configuration.displayname, configuration.description, configuration.helplocation, configuration.helpkeyword); Log(Level.Verbose, "\t" + configuration.name); } } } }
protected override void LoadTypeSpecificDataFromTask(InstallerDatabase database, int lastSequence) { LoadModuleSignature(database); LoadModuleDependency(database); LoadModuleExclusion(database); LoadModuleSequence(database); LoadModuleIgnoreTable(database); LoadModuleSubstitution(database); LoadModuleConfiguration(database); // Commit the MSI Database database.Commit(); ReorderFiles(database, ref lastSequence); // Delete unused tables Log(Level.Verbose, "Dropping unused tables"); database.DropEmptyTables(true); }
protected override void LoadTypeSpecificDataFromTask(InstallerDatabase database, int lastSequence) { LoadLaunchCondition(database); LoadFeatures(database); // The database file must be closed for merging to succeed database.Close(); LoadMergeModules(database.ArchivePath, TempFolderPath); // Reopen database after merging database.Open(); ReorderFiles(database, ref lastSequence); LoadMedia(database, lastSequence); LoadBannerImage(database); LoadBackgroundImage(database); LoadLicense(database); }
/// <summary> /// Loads the license file. /// </summary> /// <param name="database">The MSI database.</param> private void LoadLicense(InstallerDatabase database) { if (msi.license != null) { // Find the License control using (InstallerRecordReader recordReader = database.FindRecords("Control", new InstallerSearchClause("Control", Comparison.Equals, "AgreementText"))) { if (recordReader.Read()) { string licFile = Path.Combine(Project.BaseDirectory, msi.license); Log(Level.Verbose, "Storing license '{0}'.", licFile); // make sure license exists if (!File.Exists(licFile)) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "License file '{0}' does not exist.", licFile), Location); } StreamReader licenseFileReader = null; try { licenseFileReader = File.OpenText(licFile); } catch (IOException ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Unable to open license file '{0}'.", licFile), Location, ex); } try { recordReader.SetValue(9, licenseFileReader.ReadToEnd()); recordReader.Commit(); } finally { licenseFileReader.Close(); } } else { throw new BuildException("Couldn't find AgreementText Control in template database.", Location); } } } }
/// <summary> /// Loads records for the LaunchCondition table /// </summary> /// <param name="database">The MSI database.</param> private void LoadLaunchCondition(InstallerDatabase database) { // Add properties from Task definition if (msi.launchconditions != null) { Log(Level.Verbose, "Adding Launch Conditions:"); // Open the Launch Condition Table using (InstallerTable table = database.OpenTable("LaunchCondition")) { // Add binary data from Task definition foreach (MSILaunchCondition launchCondition in msi.launchconditions) { Log(Level.Verbose, "\t" + launchCondition.name); table.InsertRecord(launchCondition.condition, launchCondition.description); } } } }
protected override void LoadTypeSpecificDataFromTask(InstallerDatabase database, int lastSequence) { LoadModuleSignature(database); LoadModuleDependency(database); LoadModuleExclusion(database); LoadModuleSequence(database); LoadModuleIgnoreTable(database); LoadModuleSubstitution(database); LoadModuleConfiguration(database); // Commit the MSI Database database.Commit(); ReorderFiles(database, ref lastSequence); // Delete unused tables Log(Level.Verbose, "Dropping unused tables"); database.DropEmptyTables(true); }
protected override void LoadTypeSpecificDataFromTask(InstallerDatabase database, int lastSequence) { LoadLaunchCondition(database); LoadFeatures(database); // The database file must be closed for merging to succeed database.Close(); LoadMergeModules(database.ArchivePath, TempFolderPath); // Reopen database after merging database.Open(); ReorderFiles(database, ref lastSequence); LoadMedia(database, lastSequence); LoadBannerImage(database); LoadBackgroundImage(database); LoadLicense(database); }
/// <summary> /// Loads records for the Features table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadFeatures(InstallerDatabase database) { if (msi.features == null) { return; } Log(Level.Verbose, "Adding Features:"); using (InstallerTable featureTable = database.OpenTable("Feature"), conditionTable = database.OpenTable("Condition")) { // Add features from Task definition int order = 1; int depth = 1; foreach (MSIFeature feature in msi.features) { AddFeature(featureTable, conditionTable, null, database, feature, depth, order); order++; } } }
/// <summary> /// Loads records for the ModuleSubstitution table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleSubstitution(InstallerDatabase database) { if (msi.modulesubstitutions != null) { Log(Level.Verbose, "Adding Module Substitutions:"); using (InstallerTable modSubstitutionTable = database.OpenTable("ModuleSubstitution")) { foreach (MSMModuleSubstitution substitution in msi.modulesubstitutions) { if (substitution.table == null || substitution.table == "") { throw new BuildException("Substitution with no table attribute detected.", Location); } modSubstitutionTable.InsertRecord(substitution.table, substitution.row, substitution.column, substitution.value); Log(Level.Verbose, "\tRow: " + substitution.row + "\tColumn: " + substitution.column); } } } }
/// <summary> /// Loads records for the ModuleIgnoreTable table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleIgnoreTable(InstallerDatabase database) { if (msi.moduleignoretables != null) { Log(Level.Verbose, "Adding Tables To Ignore:"); using (InstallerTable modIgnoreTableTable = database.OpenTable("ModuleIgnoreTable")) { foreach (MSMModuleIgnoreTable table in msi.moduleignoretables) { if (table.name == null || table.name == "") { throw new BuildException("Table with no name attribute detected.", Location); } modIgnoreTableTable.InsertRecord(table.name); Log(Level.Verbose, "\t" + table.name); } } } }
/// <summary> /// Loads records for the ModuleDependency table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleDependency(InstallerDatabase database) { if (msi.moduledependencies != null) { Log(Level.Verbose, "Adding Module Dependencies:"); using (InstallerTable modDepTable = database.OpenTable("ModuleDependency")) { foreach (MSMModuleDependency dependency in msi.moduledependencies) { if (dependency.id == null || dependency.id == "") { throw new BuildException("Dependency with no id attribute detected.", Location); } modDepTable.InsertRecord(msi.id, Convert.ToInt32(msi.language), dependency.id, Convert.ToInt32(dependency.language), dependency.version); Log(Level.Verbose, " - " + dependency.id); } } } }
/// <summary> /// Loads records for the ModuleExclusion table. /// </summary> /// <param name="database">The MSM database.</param> private void LoadModuleExclusion(InstallerDatabase database) { if (msi.moduleexclusions != null) { Log(Level.Verbose, "Adding Module Exclusions:"); using (InstallerTable modExTable = database.OpenTable("ModuleExclusion")) { foreach (MSMModuleExclusion exclusion in msi.moduleexclusions) { // Insert the Property if (exclusion.id == null || exclusion.id == "") { throw new BuildException("Exclusion with no id attribute detected.", Location); } modExTable.InsertRecord(msi.id, Convert.ToInt32(msi.language), exclusion.id, Convert.ToInt32(exclusion.language), exclusion.minversion, exclusion.maxversion); Log(Level.Verbose, " - " + exclusion.id); } } } }
/// <summary> /// Loads records for the _UrlToDir table. /// "Load the url properties to convert /// url properties to a properties object" ?? /// </summary> /// <param name="database">The MSI database.</param> private void LoadUrlProperties(InstallerDatabase database) { if (msi.urlproperties == null) return; Log(Level.Verbose, "Adding URL Properties:"); using (InstallerTable urlpropTable = database.OpenTable("_UrlToDir")) { foreach (MSIURLProperty urlprop in msi.urlproperties) { Log(Level.Verbose, "\t" + urlprop.name); urlpropTable.InsertRecord(urlprop.name, urlprop.property); } } }
/// <summary> /// Loads records for the _AppMappings table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadAppMappings(InstallerDatabase database) { if (msi.appmappings == null) return; Log(Level.Verbose, "Adding Application Mappings:"); using (InstallerTable appmapTable = database.OpenTable("_AppMappings")) { foreach (MSIAppMapping appmap in msi.appmappings) { Log(Level.Verbose, "\t" + appmap.directory); appmapTable.InsertRecord(appmap.directory, appmap.extension, appmap.exepath, appmap.verbs); } } }
/// <summary> /// Loads records for the ActionText table. Allows users to specify descriptions/templates for actions. /// </summary> /// <param name="database">The MSI database.</param> private void LoadActionText(InstallerDatabase database) { if (msi.actiontext == null) return; Log(Level.Verbose, "Adding ActionText:"); using (InstallerTable actionTextTable = database.OpenTable("ActionText")) { foreach (MSIActionTextAction action in msi.actiontext) { Log(Level.Verbose, "\t" + action.name); try { actionTextTable.InsertRecord(action.name, action.description, action.template); } catch (Exception) { Log(Level.Warning, "Action text for '{0}' already" + " exists in the database.", action.name); } } } }
/// <summary> /// Adds a file record to the Files table. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="directoryTable">The MSI database view.</param> /// <param name="Component">The Component's XML Element.</param> /// <param name="fileTable">The MSI database view.</param> /// <param name="ComponentDirectory">The directory of this file's component.</param> /// <param name="ComponentName">The name of this file's component.</param> /// <param name="Sequence">The installation sequence number of this file.</param> /// <param name="msiAssemblyTable">View containing the MsiAssembly table.</param> /// <param name="msiAssemblyNameTable">View containing the MsiAssemblyName table.</param> /// <param name="componentTable">View containing the Components table.</param> /// <param name="featureComponentTable">View containing the FeatureComponents table.</param> /// <param name="classTable">View containing the Class table.</param> /// <param name="progIdTable">View containing the ProgId table.</param> /// <param name="selfRegTable">View containing the SelfReg table.</param> /// <param name="modComponentTable">ModuleComponent table.</param> private void AddFiles(InstallerDatabase database, InstallerTable directoryTable, MSIComponent Component, InstallerTable fileTable, string ComponentDirectory, string ComponentName, ref int Sequence, InstallerTable msiAssemblyTable, InstallerTable msiAssemblyNameTable, InstallerTable componentTable, InstallerTable featureComponentTable, InstallerTable classTable, InstallerTable progIdTable, InstallerTable selfRegTable, InstallerTable modComponentTable) { XmlElement fileSetElem = (XmlElement)((XmlElement)_xmlNode).SelectSingleNode( "nant:components/nant:component[@id='" + Component.id + "']/nant:fileset", NamespaceManager); FileSet componentFiles = (FileSet) Element.InitializeBuildElement( task, fileSetElem, new FileSet(), typeof(FileSet)); /* if (componentFiles.BaseDirectory == null) { componentFiles.BaseDirectory = new DirectoryInfo(Project.BaseDirectory); } */ string basePath = componentFiles.BaseDirectory.FullName; Hashtable dirMap = new Hashtable(); Hashtable componentMap = new Hashtable(); foreach (string filePath in componentFiles.FileNames) { // Insert the File string fileName = Path.GetFileName(filePath); string dirPath = Path.GetDirectoryName(filePath); #region Build the subdirectory structure -- Component.keepsubdirs == true if (Component.keepsubdirs) { // foreach file, add intermediate directory records as needed // foreach directory record added that has at least one file // add a component record // hook the component record up to the feature // add the file string tmpDirPath = dirPath; // Add intermediate directory records to the directory table // List of sub directory names. ArrayList subdirList = new ArrayList(); if (basePath.EndsWith(Path.DirectorySeparatorChar.ToString()) || basePath.EndsWith(Path.AltDirectorySeparatorChar.ToString())) basePath = basePath.Substring(0, basePath.Length - 1); while (tmpDirPath != basePath) { subdirList.Insert(0, Path.GetFileName(tmpDirPath)); tmpDirPath = Path.GetDirectoryName(tmpDirPath); } tmpDirPath = basePath; string parentDir = Component.directory; string relativeDirId = Component.directory; foreach (string folderName in subdirList) { tmpDirPath = Path.Combine(tmpDirPath, folderName); relativeDirId += "_" + folderName.ToUpper(); // Directory column is an identifier: identifiers may // contain the ASCII characters A-Z (a-z), digits, // underscores (_), or periods (.). However, every // identifier must begin with either a letter or an // underscore. relativeDirId = relativeDirId.Replace(" ","_"); if (!dirMap.ContainsKey(tmpDirPath)) { // Add entry to directory table dirMap[tmpDirPath] = relativeDirId; string path = GetShortPath(tmpDirPath) + "|" + folderName; // Insert the directory record directoryTable.InsertRecord(relativeDirId, parentDir, path); parentDir = relativeDirId; } else { parentDir = (string)dirMap[tmpDirPath]; } } tmpDirPath = dirPath; if (tmpDirPath != basePath && !componentMap.ContainsKey(tmpDirPath)) { // Create a component for this path. string name = "C_" + CreateIdentityGuid(); componentMap[tmpDirPath] = name; string newCompId = CreateRegistryGuid(); string directoryRef = (string)dirMap[tmpDirPath]; // Add a record for a new Component componentTable.InsertRecord(name, newCompId, directoryRef, Component.attr, Component.condition, null); // The null GUID is authored into any field of a msm database that references a feature. It gets replaced // with the guid of the feature assigned to the merge module. string feature = "{00000000-0000-0000-0000-000000000000}"; if (featureComponents[ComponentName] != null) { feature = (string)featureComponents[ComponentName]; } // Map the new Component to the existing one's Feature (FeatureComponents is only used in MSI databases) featureComponentTable.InsertRecord(feature, name); } } #endregion MSIFileOverride fileOverride = null; if (Component.forceid != null) { foreach (MSIFileOverride curOverride in Component.forceid) { if (curOverride.file == fileName) { fileOverride = curOverride; break; } } } string fileId = fileOverride == null ? CreateIdentityGuid() : fileOverride.id; // If the user specifies forceid & specified a file attribute, use it. Otherwise use the // fileattr assigned to the component. int fileAttr = ((fileOverride == null) || (fileOverride.attr == 0)) ? Component.fileattr : fileOverride.attr; if (Component.keepsubdirs && dirMap.ContainsKey(dirPath)) { // The file is down a subdirectory path string dirValue = (string)dirMap[dirPath]; files.Add(dirValue + "|" + fileName, fileId); } else { // Used to determine the keyfile files.Add(Component.directory + "|" + fileName, fileId); } string fileSize; try { fileSize = new FileInfo(filePath).Length.ToString(); } catch (Exception ex) { throw new BuildException(String.Format(CultureInfo.InvariantCulture, "Could not open file {0}", filePath), Location, ex); } Log(Level.Verbose, "\t" + filePath); // If the file is an assembly, create a new component to contain it, // add the new component, map the new component to the old component's // feature, and create an entry in the MsiAssembly and MsiAssemblyName // table. // bool isAssembly = false; Assembly fileAssembly = null; string fileVersion = string.Empty; try { FileVersionInfo fileVersionInfo = FileVersionInfo.GetVersionInfo(filePath); fileVersion = string.Format(CultureInfo.InvariantCulture, "{0}.{1}.{2}.{3}", fileVersionInfo.FileMajorPart, fileVersionInfo.FileMinorPart, fileVersionInfo.FileBuildPart, fileVersionInfo.FilePrivatePart); } catch {} try { fileAssembly = Assembly.LoadFrom(filePath); fileVersion = fileAssembly.GetName().Version.ToString(); isAssembly = true; } catch {} // Set the file version equal to the override value, if present if ((fileOverride != null) && (fileOverride.version != null) && (fileOverride.version != string.Empty)) { fileVersion = fileOverride.version; } if (!IsVersion(ref fileVersion)) { fileVersion = null; } string componentFieldValue = Component.name; if (isAssembly || filePath.EndsWith(".tlb")) { // The null GUID is authored into any field of a msm database that references a feature. It gets replaced // with the guid of the feature assigned to the merge module. string feature = "{00000000-0000-0000-0000-000000000000}"; if (featureComponents[ComponentName] != null) feature = (string)featureComponents[ComponentName]; string asmCompName = ComponentName; if ((componentFiles.FileNames.Count > 1) && !fileName.ToLower().Equals(Component.key.file.ToLower())) { asmCompName = "C_" + fileId; componentFieldValue = asmCompName; string newCompId = CreateRegistryGuid(); // Add a record for a new Component componentTable.InsertRecord(asmCompName, newCompId, ComponentDirectory, Component.attr, Component.condition, fileId); if (modComponentTable != null) { AddModuleComponentVirtual(database, modComponentTable, asmCompName); } else { // Map the new Component to the existing one's Feature (FeatureComponents is only used in MSI databases) featureComponentTable.InsertRecord(feature, asmCompName); } } if (isAssembly) { bool installToGAC = ((fileOverride == null) || (fileOverride.installtogac == false)) ? Component.installassembliestogac : fileOverride.installtogac; // Add a record for a new MsiAssembly if (installToGAC) { msiAssemblyTable.InsertRecord(asmCompName, feature, fileId, null, 0); } else { msiAssemblyTable.InsertRecord(asmCompName, feature, fileId, fileId, 0); } AddAssemblyManifestRecords(fileAssembly, msiAssemblyNameTable, asmCompName); bool checkInterop = Component.checkinterop; if (fileOverride != null) { checkInterop = fileOverride.checkinterop; } if (checkInterop) { CheckAssemblyForCOMInterop( database, filePath, fileAssembly, ComponentName, asmCompName, classTable, progIdTable); } // File can't be a member of both components // if (componentFiles.FileNames.Count > 1) { // files.Remove(ComponentDirectory + "|" + fileName); // files.Add(ComponentDirectory + "|" + fileName, "KeyIsDotNetAssembly"); // } } else if (filePath.EndsWith(".tlb")) { typeLibComponents.Add( Path.GetFileName(filePath), asmCompName); } } if (filePath.EndsWith(".dll") || filePath.EndsWith(".ocx")) { int hmod = LoadLibrary(filePath); if (hmod != 0) { int regSvr = GetProcAddress(hmod, "DllRegisterServer"); if (regSvr != 0) { Log(Level.Info, "Configuring '{0}' for COM Self Registration...", Path.GetFileName(filePath)); // Add a record for a new Component selfRegTable.InsertRecord(fileId, null); } FreeLibrary(hmod); } // Register COM .dlls with an embedded // type library for self registration. } CopyToTempFolder(filePath, fileId); // if (!isAssembly && !filePath.EndsWith(".tlb") // || componentFiles.FileNames.Count == 1) { // componentFieldValue = Component.name; // } // propagate language (if available) to File table to avoid // ICE60 verification warnings string language = GetLanguage(isAssembly, fileAssembly, filePath); Sequence++; if (Component.keepsubdirs && componentMap.ContainsKey(dirPath)) { // Use the component for the file's path componentFieldValue = (string)componentMap[dirPath]; } fileTable.InsertRecord(fileId, componentFieldValue, GetShortFile(filePath) + "|" + fileName, fileSize, fileVersion, language, fileAttr, Sequence.ToString()); } }
protected override void AddModuleComponentVirtual(InstallerDatabase database, InstallerTable modComponentTable, string componentName) { }
/// <summary> /// Creates a .cab file with all source files included. /// </summary> /// <param name="database">The MSI database.</param> private void CreateCabFile(InstallerDatabase database) { Log(Level.Info, "Compressing Files..."); string shortCabDir = GetShortDir(Path.Combine(Project.BaseDirectory, msi.sourcedir)); string cabFilePath = shortCabDir + @"\" + CabFileName; if (!Directory.Exists(TempFolderPath)) Directory.CreateDirectory(TempFolderPath); // holds output buffer MemoryStream ms = new MemoryStream(); // create task for creating cab file ExecTask cabarcTask = new ExecTask(); cabarcTask.Project = Project; cabarcTask.Parent = task; cabarcTask.Verbose = Verbose; // write output to (Memory)Stream cabarcTask.ErrorWriter = cabarcTask.OutputWriter = new StreamWriter(ms); // set tool to execute cabarcTask.FileName = "cabarc"; // set command line arguments cabarcTask.CommandLineArguments = "-r N " + cabFilePath + " *"; // use directory containing files to add as working directory cabarcTask.WorkingDirectory = new DirectoryInfo(TempFolderPath); try { // increment indentation level cabarcTask.Project.Indent(); // execute task cabarcTask.Execute(); } catch (Exception ex) { // read output of cabarc ms.Position = 0; StreamReader sr = new StreamReader(ms); string output = sr.ReadToEnd(); sr.Close(); // if anything was output, log it as warning if (output.Length != 0) { cabarcTask.Log(Level.Warning, output); } string path = Environment.GetEnvironmentVariable ("PATH"); if (path != null) { Console.WriteLine ("PATH=" + path); PathScanner scanner = new PathScanner (); scanner.Add ("cabarc.exe"); StringCollection files = scanner.Scan (); if (files.Count > 0) { foreach (string file in files) Console.WriteLine ("FILE=" + file); } else { Console.WriteLine ("NOT FOUND IN PATH!"); } } // signal error throw new BuildException("Error creating cab file.", Location, ex); } finally { // restore indentation level cabarcTask.Project.Unindent(); // close MemoryStream ms.Close(); } if (File.Exists(cabFilePath)) { Log(Level.Verbose, "Storing Cabinet in Installer Database..."); using (InstallerTable cabTable = database.OpenTable("_Streams")) { cabTable.InsertRecord(Path.GetFileName(cabFilePath), new InstallerStream(cabFilePath)); } } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Cabinet file '{0}' does not exist.", cabFilePath), Location); } }
/// <summary> /// Loads properties for the Summary Information Stream. /// </summary> /// <param name="database">The MSI database.</param> private void LoadSummaryInformation(InstallerDatabase database) { string title = string.Empty; string subject = string.Empty; string author = string.Empty; string keywords = string.Empty; string comments = string.Empty; string template = string.Empty; string revisionNumber = CreateRegistryGuid(); string creatingApplication = "NAnt"; // First try to get the values from the specified properties if (msi.properties != null) { foreach (property prop in msi.properties) { if (prop.name == "ProductName") { title = subject = prop.value; } else if (prop.name == "Manufacturer") { author = prop.value; } else if (prop.name == "Keywords") { keywords = prop.value; } else if (prop.name == "Comments") { comments = prop.value; } } } // Now attempt to get the values from the <summaryinformation> element if (msi.summaryinformation != null) { if (msi.summaryinformation.title != null) { title = msi.summaryinformation.title; } if (msi.summaryinformation.subject != null) { subject = msi.summaryinformation.subject; } if (msi.summaryinformation.author != null) { author = msi.summaryinformation.author; } if (msi.summaryinformation.keywords != null) { keywords = msi.summaryinformation.keywords; } if (msi.summaryinformation.comments != null) { comments = msi.summaryinformation.comments; } if (msi.summaryinformation.template != null) { template = msi.summaryinformation.template; } if (msi.summaryinformation.revisionnumber != null) { revisionNumber = msi.summaryinformation.revisionnumber; } if (msi.summaryinformation.creatingapplication != null) { creatingApplication = msi.summaryinformation.creatingapplication; } } SummaryInfo summaryInfo = database.GetSummaryInformation(); if (!String.IsNullOrEmpty(title)) { summaryInfo.set_Property(2, title); } if (!String.IsNullOrEmpty(subject)) { summaryInfo.set_Property(3, subject); } if (!String.IsNullOrEmpty(author)) { summaryInfo.set_Property(4, author); } if (!String.IsNullOrEmpty(keywords)) { summaryInfo.set_Property(5, keywords); } if (!String.IsNullOrEmpty(comments)) { summaryInfo.set_Property(6, comments); } if (!String.IsNullOrEmpty(template)) { summaryInfo.set_Property(7, template); } summaryInfo.set_Property(9, revisionNumber); summaryInfo.set_Property(14, 200); summaryInfo.set_Property(15, 2); if (!String.IsNullOrEmpty(creatingApplication)) { summaryInfo.set_Property(18, creatingApplication); } summaryInfo.Persist(); }
/// <summary> /// Loads records for the _IISProperties table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadIISDirectoryProperties(InstallerDatabase database) { if (msi.iisproperties == null) return; Log(Level.Verbose, "Adding IIS Directory Properties:"); using (InstallerTable iispropTable = database.OpenTable("_IISProperties")) { foreach (MSIIISProperty iisprop in msi.iisproperties) { Log(Level.Verbose, "\t" + iisprop.directory); iispropTable.InsertRecord(iisprop.directory, iisprop.attr, iisprop.defaultdoc); } } }
/// <summary> /// Loads records for the _VDirToUrl table. /// Used for converting a vdir to an url /// </summary> /// <param name="database">The MSI database.</param> private void LoadVDirProperties(InstallerDatabase database) { if (msi.vdirproperties == null) return; Log(Level.Verbose, "Adding VDir Properties:"); using (InstallerTable vdirpropTable = database.OpenTable("_VDirToUrl")) { foreach (MSIVDirProperty vdirprop in msi.vdirproperties) { Log(Level.Verbose, "\t" + vdirprop.name); vdirpropTable.InsertRecord(vdirprop.name, vdirprop.portproperty, vdirprop.urlproperty); } } }
protected override void AddModuleComponentVirtual(InstallerDatabase database, InstallerTable modComponentTable, string componentName) { // Add the new component to the modulecomponents table modComponentTable.InsertRecord(componentName, msi.id, Convert.ToInt32(msi.language)); }
/// <summary> /// Loads records for the _AppRootCreate table. /// Used for making a virtual directory a virtual application /// </summary> /// <param name="database">The MSI database.</param> private void LoadAppRootCreate(InstallerDatabase database) { if (msi.approots == null) return; Log(Level.Verbose, "Adding Application Roots:"); using (InstallerTable approotTable = database.OpenTable("_AppRootCreate")) { foreach (MSIAppRoot appRoot in msi.approots) { Log(Level.Verbose, "\t" + appRoot.urlproperty); approotTable.InsertRecord(appRoot.component, appRoot.urlproperty, appRoot.inprocflag); } } }
/// <summary> /// Loads records for the Properties table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadProperties(InstallerDatabase database) { if (msi.properties == null) return; using (InstallerTable propertyTable = database.OpenTable("Property")) { Log(Level.Verbose, "Adding Properties:"); property productName = null; property productCode = null; property productVersion = null; property manufacturer = null; // Add properties from Task definition foreach (property property in msi.properties) { // Insert the Property string name = property.name; string sValue = property.value; if (name == "ProductName") { productName = property; } else if (name == "ProductCode") { productCode = property; } else if (name == "ProductVersion") { productVersion = property; } else if (name == "Manufacturer") { manufacturer = property; } if (name == null || name.Length == 0) { throw new BuildException("Property with no name attribute detected.", Location); } if (sValue == null || sValue.Length == 0) { throw new BuildException(String.Format(CultureInfo.InvariantCulture, "Property {0} has no value.", name), Location); } propertyTable.InsertRecord(name, sValue); Log(Level.Verbose, "\t" + name); } if ((productName == null) && (this is MsiCreationCommand)) throw new BuildException("ProductName property must be specified. For more information please visit: http://msdn.microsoft.com/library/en-us/msi/setup/productname_property.asp"); if ((productCode == null) && (this is MsiCreationCommand)) throw new BuildException("ProductCode property must be specified. For more information please visit: http://msdn.microsoft.com/library/en-us/msi/setup/productcode_property.asp"); if ((productVersion == null) && (this is MsiCreationCommand)) throw new BuildException("ProductVersion property must be specified. For more information please visit: http://msdn.microsoft.com/library/en-us/msi/setup/productversion_property.asp"); if ((manufacturer == null) && (this is MsiCreationCommand)) throw new BuildException("Manufacturer property must be specified. For more information please visit: http://msdn.microsoft.com/library/en-us/msi/setup/manufacturer_property.asp"); } }
/// <summary> /// Enumerates the registry to see if an assembly has been registered /// for COM interop, and if so adds these registry keys to the Registry /// table, ProgIds to the ProgId table, classes to the Classes table, /// and a TypeLib to the TypeLib table. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="fileName">The Assembly filename.</param> /// <param name="fileAssembly">The Assembly to check.</param> /// <param name="componentName">The name of the containing component.</param> /// <param name="assemblyComponentName">The name of the containing component's assembly GUID.</param> /// <param name="classTable">View containing the Class table.</param> /// <param name="progIdTable">View containing the ProgId table.</param> private void CheckAssemblyForCOMInterop(InstallerDatabase database, string fileName, Assembly fileAssembly, string componentName, string assemblyComponentName, InstallerTable classTable, InstallerTable progIdTable) { AssemblyName asmName = fileAssembly.GetName(); string featureName = (string)featureComponents[componentName]; string typeLibName = Path.GetFileNameWithoutExtension(fileName) + ".tlb"; string typeLibFileName = Path.Combine(Path.GetDirectoryName(fileName), typeLibName); bool foundTypeLib = false; // Register the TypeLibrary RegistryKey typeLibsKey = Registry.ClassesRoot.OpenSubKey("Typelib", false); string[] typeLibs = typeLibsKey.GetSubKeyNames(); foreach (string typeLib in typeLibs) { RegistryKey typeLibKey = typeLibsKey.OpenSubKey(typeLib, false); if (typeLibKey == null) continue; string[] typeLibSubKeys = typeLibKey.GetSubKeyNames(); foreach (string typeLibSubKey in typeLibSubKeys) { RegistryKey win32Key = typeLibKey.OpenSubKey(typeLibSubKey + @"\0\win32"); if (win32Key == null) continue; string curTypeLibFileName = (string)win32Key.GetValue(null, null); if (curTypeLibFileName != null) { if (String.Compare(curTypeLibFileName, typeLibFileName, true) == 0) { Log(Level.Info, "Configuring '{0}' for COM Interop...", typeLibName); TypeLibRecord tlbRecord = new TypeLibRecord( typeLib, typeLibFileName, asmName, featureName, assemblyComponentName); typeLibRecords.Add(tlbRecord); foundTypeLib = true; win32Key.Close(); break; } } win32Key.Close(); } typeLibKey.Close(); if (foundTypeLib) break; } typeLibsKey.Close(); // Register CLSID(s) RegistryKey clsidsKey = Registry.ClassesRoot.OpenSubKey("CLSID", false); string[] clsids = clsidsKey.GetSubKeyNames(); foreach (string clsid in clsids) { RegistryKey clsidKey = clsidsKey.OpenSubKey(clsid, false); if (clsidKey == null) continue; RegistryKey inprocKey = clsidKey.OpenSubKey("InprocServer32", false); if (inprocKey == null) { clsidKey.Close(); continue; } string clsidAsmName = (string)inprocKey.GetValue("Assembly", null); if (clsidAsmName != null) { if (asmName.FullName == clsidAsmName) { // Register ProgId(s) RegistryKey progIdKey = clsidKey.OpenSubKey("ProgId", false); if (progIdKey != null) { string progId = (string)progIdKey.GetValue(null, null); string className = (string)clsidKey.GetValue(null, null); if (progId != null) { progIdTable.InsertRecord(progId, null, clsid, className, null, 0); classTable.InsertRecord(clsid, "InprocServer32", assemblyComponentName, progId, className, null, null, null, 0, null, null, featureName, 0); } progIdKey.Close(); progIdKey = null; } } } inprocKey.Close(); clsidKey.Close(); } clsidsKey.Close(); }
private void LoadCommonDataFromTask(InstallerDatabase database, ref int fileSequenceNumber) { LoadProperties(database); // Remove this next line LoadDepreciatedLocators(database); LoadRegistryLocators(database); LoadAppLocators(database); LoadIniLocators(database); LoadDirFileLocators(database); LoadApplicationSearch(database); LoadUserDefinedTables(database); LoadDirectories(database); LoadComponents(database, ref fileSequenceNumber); LoadDialogData(database); LoadDialogControlData(database); LoadDialogControlConditionData(database); LoadDialogControlEventData(database); LoadRegistry(database); LoadTypeLibs(database); LoadIconData(database); LoadShortcutData(database); LoadBinaryData(database); LoadCustomAction(database); LoadSequence(database); LoadActionText(database); LoadAppMappings(database); LoadUrlProperties(database); LoadVDirProperties(database); LoadAppRootCreate(database); LoadIISDirectoryProperties(database); LoadEnvironmentVariables(database); LoadSummaryInformation(database); }
/* * Common code for the two tasks */ /// <summary> /// Sets the sequence number of files to match their /// storage order in the cabinet file, after some /// files have had their filenames changed to go in /// their own component. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="LastSequence">The last file's sequence number.</param> protected void ReorderFiles(InstallerDatabase database, ref int LastSequence) { if (!Directory.Exists(TempFolderPath)) return; string[] curFileNames = Directory.GetFiles(TempFolderPath, "*.*"); LastSequence = 1; foreach (string curDirFileName in curFileNames) { using (InstallerRecordReader reader = database.FindRecords("File", new InstallerSearchClause("File", Comparison.Equals, Path.GetFileName(curDirFileName)))) { if (reader.Read()) { reader.SetValue(7, LastSequence.ToString()); reader.Commit(); LastSequence++; } else { throw new BuildException("File " + Path.GetFileName(curDirFileName) + " not found during reordering."); } } } }
/// <summary> /// Adds a directory record to the directories table. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="directoryTable">The MSI database view.</param> /// <param name="ParentDirectory">The parent directory.</param> /// <param name="Directory">This directory's Schema object.</param> /// <param name="Depth">The tree depth of this directory.</param> private void AddDirectory(InstallerDatabase database, InstallerTable directoryTable, string ParentDirectory, MSIDirectory Directory, int Depth) { string newParent; if (Directory is MSIRootDirectory) { newParent = ((MSIRootDirectory)Directory).root; } else { newParent = ParentDirectory; } StringBuilder relativePath = new StringBuilder(); GetRelativePath(database, Directory.name, ParentDirectory, Directory.foldername, relativePath, directoryTable); if (relativePath.ToString().Length != 0) { string fullPath = Path.Combine(Path.Combine(Project.BaseDirectory, msi.sourcedir), relativePath.ToString()); bool createTemp = false; DirectoryInfo di = new DirectoryInfo(fullPath); DirectoryInfo lastExistingDir = di.Parent; if (!di.Exists) { while (!lastExistingDir.Exists) { lastExistingDir = lastExistingDir.Parent; } di.Create(); createTemp = true; } string path = GetShortPath(fullPath) + "|" + Directory.foldername; if (createTemp) { while (!di.FullName.Equals(lastExistingDir.FullName)) { di.Delete(); di = di.Parent; } } if (Directory.foldername == ".") path = Directory.foldername; Log(Level.Verbose, "\t" + relativePath.ToString()); // Insert the Directory directoryTable.InsertRecord(Directory.name, newParent, path); if (Directory.directory != null) { foreach (MSIDirectory childDirectory in Directory.directory) { int newDepth = Depth + 1; AddDirectory(database, directoryTable, Directory.name, childDirectory, newDepth); } } } }
/// <summary> /// Loads records for the sequence tables. /// </summary> /// <param name="database">The MSI database.</param> private void LoadSequence(InstallerDatabase database) { if (msi.sequences == null) return; Log(Level.Verbose, "Adding Install/Admin Sequences:"); // Open the sequence tables using (InstallerTable installExecuteTable = database.OpenTable("InstallExecuteSequence"), installUITable = database.OpenTable("InstallUISequence"), adminExecuteTable = database.OpenTable("AdminExecuteSequence"), adminUITable = database.OpenTable("AdminUISequence"), advtExecuteTable = database.OpenTable(AdvtExecuteName)) { // Add binary data from Task definition foreach (MSISequence sequence in msi.sequences) { Log(Level.Verbose, "\t" + sequence.action + " to the " + sequence.type.ToString() + "sequence table."); switch(sequence.type.ToString()) { case "installexecute": installExecuteTable.InsertRecord(sequence.action, sequence.condition, sequence.value); break; case "installui": installUITable.InsertRecord(sequence.action, sequence.condition, sequence.value); break; case "adminexecute": adminExecuteTable.InsertRecord(sequence.action, sequence.condition, sequence.value); break; case "adminui": adminUITable.InsertRecord(sequence.action, sequence.condition, sequence.value); break; case "advtexecute": advtExecuteTable.InsertRecord(sequence.action, sequence.condition, sequence.value); break; } } } }
/// <summary> /// Loads TypeLibs for the TypeLib table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadTypeLibs(InstallerDatabase database) { // Open the "TypeLib" Table using (InstallerTable typeLibTable = database.OpenTable("TypeLib"), registryTable = database.OpenTable("Registry")) { for (int i = 0; i < typeLibRecords.Count; i++) { TypeLibRecord tlbRecord = (TypeLibRecord)typeLibRecords[i]; IntPtr pTypeLib = new IntPtr(0); int result = LoadTypeLib(tlbRecord.TypeLibFileName, ref pTypeLib); if (result != 0) continue; UCOMITypeLib typeLib = (UCOMITypeLib)Marshal.GetTypedObjectForIUnknown( pTypeLib, typeof(UCOMITypeLib)); if (typeLib == null) continue; int helpContextId; string name, docString, helpFile; typeLib.GetDocumentation( -1, out name, out docString, out helpContextId, out helpFile); IntPtr pTypeLibAttr = new IntPtr(0); typeLib.GetLibAttr(out pTypeLibAttr); TYPELIBATTR typeLibAttr = (TYPELIBATTR)Marshal.PtrToStructure(pTypeLibAttr, typeof(TYPELIBATTR)); string tlbCompName = (string)typeLibComponents[Path.GetFileName(tlbRecord.TypeLibFileName)]; typeLibTable.InsertRecord("{"+typeLibAttr.guid.ToString().ToUpper()+"}", Marshal.GetTypeLibLcid(typeLib), tlbCompName, 256, docString == null ? name : docString, null, tlbRecord.FeatureName, 0); typeLib.ReleaseTLibAttr(pTypeLibAttr); // If a .NET type library wrapper for an assembly if (tlbRecord.AssemblyName == null) continue; // Get all the types defined in the typelibrary // that are not marked "noncreatable" int typeCount = typeLib.GetTypeInfoCount(); for (int j = 0; j < typeCount; j++) { UCOMITypeInfo typeInfo = null; typeLib.GetTypeInfo(j, out typeInfo); if (typeInfo == null) continue; TYPEATTR typeAttr = GetTypeAttributes(typeInfo); if (IsCreatableCoClass(typeAttr)) { if (typeInfo is UCOMITypeInfo2) { string className = GetClassName(typeInfo); if (className != null) { string clsid = "{" + typeAttr.guid.ToString().ToUpper() + "}"; AddClassToRegistryTable(registryTable, clsid, className, tlbRecord); } } } else if (IsIDispatchInterface(typeAttr)) { string typeName, typeDocString, typeHelpFile; int typeHelpContextId; typeInfo.GetDocumentation(-1, out typeName, out typeDocString, out typeHelpContextId, out typeHelpFile); if (!(typeInfo is UCOMITypeInfo2)) continue; UCOMITypeInfo2 typeInfo2 = (UCOMITypeInfo2)typeInfo; if (typeInfo2 == null) continue; object custData; Guid g = new Guid("0F21F359-AB84-41E8-9A78-36D110E6D2F9"); typeInfo2.GetCustData(ref g, out custData); if (custData == null) continue; string iid = "{" + typeAttr.guid.ToString().ToUpper() + "}"; // Insert the Interface string typeLibComponent = (string)typeLibComponents[Path.GetFileName(tlbRecord.TypeLibFileName)]; registryTable.InsertRecord(CreateIdentityGuid(), 0, @"Interface\" + iid, null, typeName, typeLibComponent); registryTable.InsertRecord(CreateIdentityGuid(), 0, @"Interface\" + iid + @"\TypeLib", "Version", "1.0", typeLibComponent); registryTable.InsertRecord(CreateIdentityGuid(), 0, @"Interface\" + iid + @"\TypeLib", null, "{"+typeLibAttr.guid.ToString().ToUpper()+"}", typeLibComponent); registryTable.InsertRecord(CreateIdentityGuid(), 0, @"Interface\" + iid + @"\ProxyStubClsid32", null, "{00020424-0000-0000-C000-000000000046}", typeLibComponent); registryTable.InsertRecord(CreateIdentityGuid(), 0, @"Interface\" + iid + @"\ProxyStubClsid", null, "{00020424-0000-0000-C000-000000000046}", typeLibComponent); } } } } }
/// <summary> /// Loads records for the Components table. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="LastSequence">The sequence number of the last file in the .cab</param> private void LoadComponents(InstallerDatabase database, ref int LastSequence) { if (msi.components == null) return; Log(Level.Verbose, "Add Files:"); using (InstallerTable msiAssemblyTable = database.OpenTable("MsiAssembly"), msiAssemblyNameTable = database.OpenTable("MsiAssemblyName"), classTable = database.OpenTable("Class"), progIdTable = database.OpenTable("ProgId"), directoryTable = database.OpenTable("Directory"), componentTable = database.OpenTable("Component"), fileTable = database.OpenTable("File"), featureComponentTable = database.OpenTable("FeatureComponents"), selfRegTable = database.OpenTable("SelfReg")) { // Open ModuleComponents table (only exists in MSM archives) InstallerTable modComponentTable = null; if (database.VerifyTableExistance("ModuleComponents")) { modComponentTable = database.OpenTable("ModuleComponents"); } try { foreach (MSIComponent component in msi.components) { string keyFileName = component.key.file; if (component.fileset == null) { // Make sure the keyfile maps to a valid registry entry if (((XmlElement)_xmlNode).SelectSingleNode("registry/key[@component='" + component.name + "']/value[@id='" + keyFileName + "']") == null) { Log(Level.Warning, "Component '{0}' does not" + " map to a valid registry key. Skipping...", component.name); continue; } } if (this is MsiCreationCommand) featureComponents.Add(component.name, component.feature); AddModuleComponentVirtual(database, modComponentTable, component.name); if (component.fileset != null) { AddFiles(database, directoryTable, component, fileTable, component.directory, component.name, ref LastSequence, msiAssemblyTable, msiAssemblyNameTable, componentTable, featureComponentTable, classTable, progIdTable, selfRegTable, modComponentTable); keyFileName = GetKeyFileName(component); } // Insert the Component componentTable.InsertRecord(component.name, component.id.ToUpper(), component.directory, component.attr, component.condition, keyFileName); } // Add featureComponents from Task definition AddFeatureComponents(featureComponentTable); } finally { if (modComponentTable != null) { modComponentTable.Close(); } } } }
/// <summary> /// Loads records for the Registry table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadRegistry(InstallerDatabase database) { if (msi.registry == null) return; Log(Level.Verbose, "Adding Registry Values:"); using (InstallerTable registryTable = database.OpenTable("Registry")) { foreach (MSIRegistryKey key in msi.registry) { int rootKey = GetRegistryRootByName(key.root.ToString()); foreach (MSIRegistryKeyValue value in key.value) { if ((value.name == null || value.name == String.Empty) && (value.value == null || value.value == String.Empty) && (value.Value == null)) throw new BuildException("Registry value must have a name and/or value specified."); // Insert the Value Log(Level.Verbose, "\t" + GetDisplayablePath(key.path.Replace("}", "}}").Replace("{", "{{")) + @"#" + ((value.name == null || value.name == String.Empty) ? "(Default)":value.name.Replace("}", "}}").Replace("{", "{{"))); string keyValue = null; if (value.value != null && value.value != string.Empty) { keyValue = value.value; } else if (value.dword != null && value.dword != string.Empty) { keyValue = "#" + Int32.Parse(value.dword); } else { if (value.Value != null) { string val1 = value.Value.Replace(",", null); string val2 = val1.Replace(" ", null); string val3 = val2.Replace("\n", null); string val4 = val3.Replace("\r", null); keyValue = "#x" + val4; } } registryTable.InsertRecord((value.id != null ? value.id : CreateIdentityGuid()), rootKey.ToString(), key.path, value.name, keyValue, key.component); } } } }
/// <summary> /// Executes the Task. /// </summary> /// <remarks>None.</remarks> public void Execute() { string cabFilePath = Path.Combine(Project.BaseDirectory, Path.Combine(msi.sourcedir, CabFileName)); string errorsTempFile = null; try { CleanOutput(cabFilePath, TempFolderPath); string dest = GetDestinationPath(); // write the template resource to the destination file try { WriteResourceToFile(TemplateResourceName, dest); } catch (Exception ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Failed writing template to destination file '{0}'.", dest), Location, ex); } Log(Level.Info, "Building Installer Database '{0}'.", msi.output); // Open the Output Database. InstallerDatabase database = new InstallerDatabase(dest); database.Open(); if (msi.debug) { errorsTempFile = Path.GetTempFileName(); try { // write errors template to file WriteResourceToFile(ErrorsResourceName, errorsTempFile); // if debug is true, transform the error strings in database.ApplyTransform(errorsTempFile); } catch (IOException ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Failed writing errors template to '{0}'.", errorsTempFile), Location, ex); } } int fileSequenceNumber = 0; // Load data from the task specification LoadCommonDataFromTask(database, ref fileSequenceNumber); LoadTypeSpecificDataFromTask(database, fileSequenceNumber); // Compress Files CreateCabFile(database); Log(Level.Info, "Saving Installer Database..."); // Commit the MSI Database database.Close(); } catch (Exception ex) { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "Unable to build Installer database '{0}'.", msi.output), Location, ex); } finally { CleanOutput(cabFilePath, TempFolderPath); if (errorsTempFile != null) { File.Delete(errorsTempFile); } } }
/// <summary> /// Loads records for the ControlCondtion table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadDialogControlConditionData(InstallerDatabase database) { if (msi.controlconditions == null) return; Log(Level.Verbose, "Adding Dialog Control Conditions for:"); using (InstallerTable controlConditionTable = database.OpenTable("ControlCondition")) { foreach (MSIControlCondition controlCondition in msi.controlconditions) { if (controlCondition.remove) { Log(Level.Verbose, "\tRemoving: " + controlCondition.control); RemoveControlCondition(database, controlCondition); } else { Log(Level.Verbose, "\tAdding: " + controlCondition.control); controlConditionTable.InsertRecord(controlCondition.dialog, controlCondition.control, controlCondition.action, controlCondition.condition); } } } }
/// <summary> /// Loads records for the Directories table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadDirectories(InstallerDatabase database) { if (msi.directories == null) return; using (InstallerTable directoryTable = database.OpenTable("Directory")) { ArrayList directoryList = new ArrayList(msi.directories); AddTargetDir(directoryList); AddCommonDirectories(directoryList); MSIRootDirectory[] directories = new MSIRootDirectory[directoryList.Count]; directoryList.CopyTo(directories); msi.directories = directories; int depth = 1; Log(Level.Verbose, "Adding Directories:"); // Add directories from Task definition foreach (MSIRootDirectory directory in msi.directories) { AddDirectory(database, directoryTable, null, directory, depth); } } }
/// <summary> /// Loads records for the ControlEvent table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadDialogControlEventData(InstallerDatabase database) { if (msi.controlevents == null) return; Log(Level.Verbose, "Modifying Dialog Control Events:"); using (InstallerTable controlEventTable = database.OpenTable("ControlEvent")) { foreach (MSIControlEvent controlEvent in msi.controlevents) { Log(Level.Verbose, "\t{0}\tControl: {1}\tEvent: {2}", (controlEvent.remove ? "Removing" : "Adding"), controlEvent.control, controlEvent.name); if (controlEvent.remove) { RemoveControlEvent(database, controlEvent); } else { controlEventTable.InsertRecord(controlEvent.dialog, controlEvent.control, controlEvent.name, controlEvent.argument, controlEvent.condition, controlEvent.order); } } } }
/// <summary> /// Retrieves the relative path of a file based on /// the component it belongs to and its entry in /// the MSI directory table. /// </summary> /// <param name="database">The MSI database.</param> /// <param name="Name">The Name of the Folder</param> /// <param name="Parent">The Parent of the Folder</param> /// <param name="Default">The Relative Filesystem Path of the Folder</param> /// <param name="Path">The Path to the Folder from previous calls.</param> /// <param name="directoryTable">The MSI database view.</param> private void GetRelativePath( InstallerDatabase database, string Name, string Parent, string Default, StringBuilder Path, InstallerTable directoryTable) { if (Name == "TARGETDIR") { return; } for (int i = 0; i < commonFolderNames.Length; i++) { if (Name == commonFolderNames[i]) { return; } } if (msi.directories != null) { ArrayList directoryList = new ArrayList(); foreach(MSIRootDirectory directory in msi.directories) { directoryList.Add(directory); } if (msi.properties != null) { foreach (property property in msi.properties) { if (Name == property.name) { MSIDirectory directory = FindDirectory(Name); if (directory == null) { MSIRootDirectory propDirectory = new MSIRootDirectory(); propDirectory.name = Name; propDirectory.root = "TARGETDIR"; propDirectory.foldername = "."; directoryList.Add(propDirectory); MSIRootDirectory[] rootDirs = new MSIRootDirectory[directoryList.Count]; directoryList.CopyTo(rootDirs); msi.directories = rootDirs; } return; } } } if (Path.Length > 0) { Path.Insert(0, @"\"); } Path.Insert(0, Default); if (Parent != null) { MSIDirectory PathInfo = FindDirectory(Parent); if (PathInfo == null && msi.properties != null) { foreach (property property in msi.properties) { if (Parent == property.name) { MSIRootDirectory directory = new MSIRootDirectory(); directory.name = Parent; directory.root = "TARGETDIR"; directory.foldername = "."; directoryList.Add(directory); MSIRootDirectory[] rootDirs = new MSIRootDirectory[directoryList.Count]; directoryList.CopyTo(rootDirs); msi.directories = rootDirs; // Insert the Directory that is a Property directoryTable.InsertRecord(Parent, "TARGETDIR", "."); PathInfo = directory; break; } } } string newParent = null; if (PathInfo is MSIRootDirectory) { newParent = ((MSIRootDirectory)PathInfo).root; } else { newParent = FindParent(Parent); } GetRelativePath(database, Parent, newParent, PathInfo.foldername, Path, directoryTable); } } }
private void RemoveControlEvent(InstallerDatabase database, MSIControlEvent controlEvent) { // Search for a record using all required attributes using (InstallerRecordReader reader = database.FindRecords("ControlEvent", new InstallerSearchClause("Dialog_", Comparison.Equals, controlEvent.dialog), new InstallerSearchClause("Control_", Comparison.Equals, controlEvent.control), new InstallerSearchClause("Event", Comparison.Equals, controlEvent.name), new InstallerSearchClause("Argument", Comparison.Equals, controlEvent.argument), new InstallerSearchClause("Condition", Comparison.Equals, controlEvent.condition))) { if (reader.Read()) { // If the record is found, delete it reader.DeleteCurrentRecord(); } else { throw new BuildException(string.Format(CultureInfo.InvariantCulture, "ControlEvent not found for removal: Dialog={0}, Control={1}, Event={2}, Argument={3}, Condition={4}.", controlEvent.dialog, controlEvent.control, controlEvent.name, controlEvent.argument, controlEvent.condition), Location); } } }
/// <summary> /// Loads environment variables for the Environment table. /// </summary> /// <param name="database">The MSI database.</param> private void LoadEnvironmentVariables(InstallerDatabase database) { if (msi.environment == null) return; using (InstallerTable envTable = database.OpenTable("Environment")) { foreach (MSIVariable variable in msi.environment) { // Insert the Varible string environmentValue = null; if (variable.append != null && variable.append != string.Empty) { environmentValue = "[~];" + variable.append; } envTable.InsertRecord(CreateIdentityGuid(), variable.name, environmentValue, variable.component); } } }
/// <summary> /// Loads records for the CustomAction table /// </summary> /// <param name="database">The MSI database.</param> private void LoadCustomAction(InstallerDatabase database) { if (msi.customactions == null) return; Log(Level.Verbose, "Adding Custom Actions:"); using (InstallerTable customActionTable = database.OpenTable("CustomAction")) { foreach (MSICustomAction customAction in msi.customactions) { Log(Level.Verbose, "\t" + customAction.action); // Insert the record into the table customActionTable.InsertRecord(customAction.action, customAction.type, customAction.source, customAction.target); } } }
/// <summary> /// Loads records for the RegLocator table /// </summary> /// <param name="database">The MSI database.</param> private void LoadRegistryLocators(InstallerDatabase database) { if (msi.search == null || msi.search.registry == null) return; Log(Level.Verbose, "Adding Registry Search Locators:"); foreach (searchRegistry regKey in msi.search.registry) { int rootKey = GetRegistryRootByName(regKey.root.ToString()); if (regKey.value == null) continue; foreach (searchRegistryValue value in regKey.value) { string signature = "SIG_" + value.setproperty; int msidbLocatorTypeRawValue = 1; switch (regKey.type) { case MSILocatorTypeDirFileReg64.directory: msidbLocatorTypeRawValue = 0; break; case MSILocatorTypeDirFileReg64.file: msidbLocatorTypeRawValue = 1; break; case MSILocatorTypeDirFileReg64.registry: msidbLocatorTypeRawValue = 2; break; case MSILocatorTypeDirFileReg64.Item64bit: msidbLocatorTypeRawValue = 16; break; } // Select the "RegLocator" Table using (InstallerTable regLocatorTable = database.OpenTable("RegLocator")) { // Insert the signature to the RegLocator Table regLocatorTable.InsertRecord(signature, rootKey.ToString(), regKey.path, value.name, msidbLocatorTypeRawValue); Log(Level.Verbose, "\t" + GetDisplayablePath(regKey.path.Replace("}", "}}").Replace("{", "{{")) + @"#" + ((value.name == null) ? string.Empty : value.name.Replace("}", "}}").Replace("{", "{{"))); } } } }
public InstallerTable(View view, InstallerDatabase database) { _view = view; _database = database; }