/// <summary> /// Process the complex references. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="sections">Sections that are referenced during the link process.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToComponentGroupsComplexReferences">Component to ComponentGroup complex references.</param> /// <param name="componentGroupsToFeatures">ComponentGroups to features complex references.</param> /// <param name="componentGroupsToModules">ComponentGroups to modules complex references.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> /// <param name="featuresToFeatures">Feature to feature complex references.</param> private void ProcessComplexReferences( Output output, SectionCollection sections, StringCollection referencedSymbols, ComplexReferenceCollection componentsToComponentGroupsComplexReferences, ConnectToFeatureCollection componentGroupsToFeatures, ConnectToModuleCollection componentGroupsToModules, ConnectToFeatureCollection componentsToFeatures, ConnectToFeatureCollection featuresToFeatures) { Hashtable componentsToModules = new Hashtable(); foreach (Section section in sections) { foreach (ComplexReference cref in section.ComplexReferences) { ConnectToFeature connection; switch (cref.ParentType) { case ComplexReferenceParentType.ComponentGroup: switch (cref.ChildType) { case ComplexReferenceChildType.Component: componentsToComponentGroupsComplexReferences.Add(cref); break; default: throw new ApplicationException("Unexpected complex reference child type."); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; case ComplexReferenceParentType.Feature: switch (cref.ChildType) { case ComplexReferenceChildType.Component: connection = componentsToFeatures[cref.ChildId]; if (null == connection) { componentsToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = cref.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connection.ConnectFeatures.Add(cref.ParentId); } // add a row to the FeatureComponents table Row row = Common.CreateRowInSection(null, section, this.tableDefinitions["FeatureComponents"]); if (this.sectionIdOnTuples) { row.SectionId = section.Id; } row[0] = cref.ParentId; row[1] = cref.ChildId; // index the component for finding orphaned records string symbolName = String.Concat("Component:", cref.ChildId); if (!referencedSymbols.Contains(symbolName)) { referencedSymbols.Add(symbolName); } break; case ComplexReferenceChildType.ComponentGroup: connection = componentGroupsToFeatures[cref.ChildId]; if (null == connection) { componentGroupsToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); connection.PrimaryFeature = cref.ParentId; connection.IsExplicitPrimaryFeature = true; } else { connection.ConnectFeatures.Add(cref.ParentId); } break; case ComplexReferenceChildType.Feature: connection = featuresToFeatures[cref.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } featuresToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); break; case ComplexReferenceChildType.Module: connection = output.ModulesToFeatures[cref.ChildId]; if (null == connection) { output.ModulesToFeatures.Add(new ConnectToFeature(section, cref.ChildId, cref.ParentId, cref.IsPrimary)); } else if (cref.IsPrimary && connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, connection.PrimaryFeature)); continue; } else if (cref.IsPrimary) { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = cref.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connection.ConnectFeatures.Add(cref.ParentId); } break; default: throw new ApplicationException("Unexpected complex reference child type"); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; case ComplexReferenceParentType.Module: switch (cref.ChildType) { case ComplexReferenceChildType.Component: if (componentsToModules.ContainsKey(cref.ChildId)) { this.OnMessage(WixErrors.ComponentReferencedTwice(SourceLineNumberCollection.FromFileName(section.Intermediate.Path), cref.ChildId)); continue; } else { componentsToModules.Add(cref.ChildId, cref); // should always be new // add a row to the ModuleComponents table Row row = Common.CreateRowInSection(null, section, this.tableDefinitions["ModuleComponents"]); if (this.sectionIdOnTuples) { row.SectionId = section.Id; } row[0] = cref.ChildId; row[1] = cref.ParentId; row[2] = cref.ParentLanguage; } // index the component for finding orphaned records string componentSymbolName = String.Concat("Component:", cref.ChildId); if (!referencedSymbols.Contains(componentSymbolName)) { referencedSymbols.Add(componentSymbolName); } break; case ComplexReferenceChildType.ComponentGroup: ConnectToModule moduleConnection = componentGroupsToModules[cref.ChildId]; if (null == moduleConnection) { componentGroupsToModules.Add(new ConnectToModule(cref.ChildId, cref.ParentId, cref.ParentLanguage)); } break; default: throw new ApplicationException("Unexpected complex reference child type"); // TODO: come up with a real exception to throw (Unexpected complex reference child type) } break; } } } }
/// <summary> /// Resolve component groups. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToComponentGroupsComplexReferences">Component to ComponentGroup complex references.</param> /// <param name="componentGroupsToFeatures">ComponentGroups to features complex references.</param> /// <param name="componentGroupsToModules">ComponentGroups to modules complex references.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> private void ResolveComponentGroups( Output output, StringCollection referencedSymbols, ComplexReferenceCollection componentsToComponentGroupsComplexReferences, ConnectToFeatureCollection componentGroupsToFeatures, ConnectToModuleCollection componentGroupsToModules, ConnectToFeatureCollection componentsToFeatures) { foreach (ComplexReference cref in componentsToComponentGroupsComplexReferences) { // only connect a Component to a Feature if the ComponentGroup is connected to a Feature ConnectToFeature connectComponentGroupToFeature = componentGroupsToFeatures[cref.ParentId]; if (null != connectComponentGroupToFeature) { // create a list of all features (use an ArrayList because StringCollection lacks an AddRange method that takes an ICollection) ArrayList features = new ArrayList(connectComponentGroupToFeature.ConnectFeatures); features.Add(connectComponentGroupToFeature.PrimaryFeature); foreach (string feature in features) { ConnectToFeature connectComponentToFeature = componentsToFeatures[cref.ChildId]; bool isExplicitPrimaryFeature = (connectComponentGroupToFeature.IsExplicitPrimaryFeature && (connectComponentGroupToFeature.PrimaryFeature == feature)); if (null == connectComponentToFeature) { componentsToFeatures.Add(new ConnectToFeature(connectComponentGroupToFeature.Section, cref.ChildId, feature, isExplicitPrimaryFeature)); } else if (isExplicitPrimaryFeature && connectComponentToFeature.IsExplicitPrimaryFeature && feature != connectComponentToFeature.PrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(SourceLineNumberCollection.FromFileName(connectComponentToFeature.Section.Intermediate.Path), cref.ChildType.ToString(), cref.ChildId, cref.ParentId, feature)); continue; } else if (isExplicitPrimaryFeature) { connectComponentToFeature.ConnectFeatures.Add(connectComponentToFeature.PrimaryFeature); // move the guessed primary feature to the list of connects connectComponentToFeature.PrimaryFeature = feature; // set the new primary feature connectComponentToFeature.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } else { connectComponentToFeature.ConnectFeatures.Add(feature); } // add a row to the FeatureComponents table Row row = Common.CreateRowInSection(null, output.EntrySection, this.tableDefinitions["FeatureComponents"]); row[0] = feature; row[1] = cref.ChildId; // index the component for finding orphaned records Reference reference = new Reference("Component", cref.ChildId); if (!referencedSymbols.Contains(reference.SymbolicName)) { referencedSymbols.Add(reference.SymbolicName); } } } // only connect a Component to a Module if the ComponentGroup is connected to a Module ConnectToModule connectComponentGroupToModule = componentGroupsToModules[cref.ParentId]; if (null != connectComponentGroupToModule) { // add a row to the ModuleComponents table Row row = Common.CreateRowInSection(null, output.EntrySection, this.tableDefinitions["ModuleComponents"]); row[0] = cref.ChildId; row[1] = connectComponentGroupToModule.Module; row[2] = connectComponentGroupToModule.ModuleLanguage; // index the component for finding orphaned records Reference reference = new Reference("Component", cref.ChildId); if (!referencedSymbols.Contains(reference.SymbolicName)) { referencedSymbols.Add(reference.SymbolicName); } } } }
/// <summary> /// Process the complex references. /// </summary> /// <param name="output">Active output to add sections to.</param> /// <param name="sections">Sections that are referenced during the link process.</param> /// <param name="referencedSymbols">Collection of all symbols referenced during linking.</param> /// <param name="componentsToFeatures">Component to feature complex references.</param> /// <param name="featuresToFeatures">Feature to feature complex references.</param> /// <param name="modulesToFeatures">Module to feature complex references.</param> private void ProcessComplexReferences( Output output, SectionCollection sections, StringCollection referencedSymbols, ConnectToFeatureCollection componentsToFeatures, ConnectToFeatureCollection featuresToFeatures, ConnectToFeatureCollection modulesToFeatures) { Hashtable componentsToModules = new Hashtable(); foreach (Section section in sections) { Table wixComplexReferenceTable = section.Tables["WixComplexReference"]; if (null != wixComplexReferenceTable) { foreach (WixComplexReferenceRow wixComplexReferenceRow in wixComplexReferenceTable.Rows) { ConnectToFeature connection; switch (wixComplexReferenceRow.ParentType) { case ComplexReferenceParentType.Feature: switch (wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.Component: connection = componentsToFeatures[wixComplexReferenceRow.ChildId]; if (null == connection) { componentsToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentId, wixComplexReferenceRow.IsPrimary)); } else if (wixComplexReferenceRow.IsPrimary) { if (connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } else { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = wixComplexReferenceRow.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } } else { connection.ConnectFeatures.Add(wixComplexReferenceRow.ParentId); } // add a row to the FeatureComponents table Table featureComponentsTable = output.EnsureTable(this.tableDefinitions["FeatureComponents"]); Row row = featureComponentsTable.CreateRow(null); if (this.sectionIdOnRows) { row.SectionId = section.Id; } row[0] = wixComplexReferenceRow.ParentId; row[1] = wixComplexReferenceRow.ChildId; // index the component for finding orphaned records string symbolName = String.Concat("Component:", wixComplexReferenceRow.ChildId); if (!referencedSymbols.Contains(symbolName)) { referencedSymbols.Add(symbolName); } break; case ComplexReferenceChildType.Feature: connection = featuresToFeatures[wixComplexReferenceRow.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentId, wixComplexReferenceRow.IsPrimary)); break; case ComplexReferenceChildType.Module: connection = modulesToFeatures[wixComplexReferenceRow.ChildId]; if (null == connection) { modulesToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentId, wixComplexReferenceRow.IsPrimary)); } else if (wixComplexReferenceRow.IsPrimary) { if (connection.IsExplicitPrimaryFeature) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } else { connection.ConnectFeatures.Add(connection.PrimaryFeature); // move the guessed primary feature to the list of connects connection.PrimaryFeature = wixComplexReferenceRow.ParentId; // set the new primary feature connection.IsExplicitPrimaryFeature = true; // and make sure we remember that we set it so we can fail if we try to set it again } } else { connection.ConnectFeatures.Add(wixComplexReferenceRow.ParentId); } break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; case ComplexReferenceParentType.Module: switch (wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.Component: if (componentsToModules.ContainsKey(wixComplexReferenceRow.ChildId)) { this.OnMessage(WixErrors.ComponentReferencedTwice(section.SourceLineNumbers, wixComplexReferenceRow.ChildId)); continue; } else { componentsToModules.Add(wixComplexReferenceRow.ChildId, wixComplexReferenceRow); // should always be new // add a row to the ModuleComponents table Table moduleComponentsTable = output.EnsureTable(this.tableDefinitions["ModuleComponents"]); Row row = moduleComponentsTable.CreateRow(null); if (this.sectionIdOnRows) { row.SectionId = section.Id; } row[0] = wixComplexReferenceRow.ChildId; row[1] = wixComplexReferenceRow.ParentId; row[2] = wixComplexReferenceRow.ParentLanguage; } // index the component for finding orphaned records string componentSymbolName = String.Concat("Component:", wixComplexReferenceRow.ChildId); if (!referencedSymbols.Contains(componentSymbolName)) { referencedSymbols.Add(componentSymbolName); } break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; case ComplexReferenceParentType.Patch: switch(wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.PatchFamily: case ComplexReferenceChildType.PatchFamilyGroup: break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; case ComplexReferenceParentType.Product: switch (wixComplexReferenceRow.ChildType) { case ComplexReferenceChildType.Feature: connection = featuresToFeatures[wixComplexReferenceRow.ChildId]; if (null != connection) { this.OnMessage(WixErrors.MultiplePrimaryReferences(section.SourceLineNumbers, wixComplexReferenceRow.ChildType.ToString(), wixComplexReferenceRow.ChildId, wixComplexReferenceRow.ParentType.ToString(), wixComplexReferenceRow.ParentId, (null != connection.PrimaryFeature ? "Feature" : "Product"), (null != connection.PrimaryFeature ? connection.PrimaryFeature : this.activeOutput.EntrySection.Id))); continue; } featuresToFeatures.Add(new ConnectToFeature(section, wixComplexReferenceRow.ChildId, null, wixComplexReferenceRow.IsPrimary)); break; default: throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceChildType), wixComplexReferenceRow.ChildType))); } break; default: // Note: Groups have been processed before getting here so they are not handled by any case above. throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture, WixStrings.EXP_UnexpectedComplexReferenceChildType, Enum.GetName(typeof(ComplexReferenceParentType), wixComplexReferenceRow.ParentType))); } } } } }