/// <summary>
        /// Decompile the Class table.
        /// </summary>
        /// <param name="table">The table to decompile.</param>
        private void DecompileClassTable(Table table)
        {
            foreach (Row row in table.Rows)
            {
                Wix.Class wixClass = new Wix.Class();

                wixClass.Advertise = Wix.YesNoType.yes;

                wixClass.Id = Convert.ToString(row[0]);

                switch (Convert.ToString(row[1]))
                {
                    case "LocalServer":
                        wixClass.Context = Wix.Class.ContextType.LocalServer;
                        break;
                    case "LocalServer32":
                        wixClass.Context = Wix.Class.ContextType.LocalServer32;
                        break;
                    case "InprocServer":
                        wixClass.Context = Wix.Class.ContextType.InprocServer;
                        break;
                    case "InprocServer32":
                        wixClass.Context = Wix.Class.ContextType.InprocServer32;
                        break;
                    default:
                        this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[1].Column.Name, row[1]));
                        break;
                }

                // ProgId children are handled in FinalizeProgIdTable

                if (null != row[4])
                {
                    wixClass.Description = Convert.ToString(row[4]);
                }

                if (null != row[5])
                {
                    wixClass.AppId = Convert.ToString(row[5]);
                }

                if (null != row[6])
                {
                    string[] fileTypeMaskStrings = (Convert.ToString(row[6])).Split(';');

                    try
                    {
                        foreach (string fileTypeMaskString in fileTypeMaskStrings)
                        {
                            string[] fileTypeMaskParts = fileTypeMaskString.Split(',');

                            if (4 == fileTypeMaskParts.Length)
                            {
                                Wix.FileTypeMask fileTypeMask = new Wix.FileTypeMask();

                                fileTypeMask.Offset = Convert.ToInt32(fileTypeMaskParts[0], CultureInfo.InvariantCulture);

                                fileTypeMask.Mask = fileTypeMaskParts[2];

                                fileTypeMask.Value = fileTypeMaskParts[3];

                                wixClass.AddChild(fileTypeMask);
                            }
                            else
                            {
                                // TODO: warn
                            }
                        }
                    }
                    catch (FormatException)
                    {
                        this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
                    }
                    catch (OverflowException)
                    {
                        this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[6].Column.Name, row[6]));
                    }
                }

                if (null != row[7])
                {
                    wixClass.Icon = Convert.ToString(row[7]);
                }

                if (null != row[8])
                {
                    wixClass.IconIndex = Convert.ToInt32(row[8]);
                }

                if (null != row[9])
                {
                    wixClass.Handler = Convert.ToString(row[9]);
                }

                if (null != row[10])
                {
                    wixClass.Argument = Convert.ToString(row[10]);
                }

                if (null != row[12])
                {
                    if (1 == Convert.ToInt32(row[12]))
                    {
                        wixClass.RelativePath = Wix.YesNoType.yes;
                    }
                    else
                    {
                        this.core.OnMessage(WixWarnings.IllegalColumnValue(row.SourceLineNumbers, table.Name, row.Fields[12].Column.Name, row[12]));
                    }
                }

                Wix.Component component = (Wix.Component)this.core.GetIndexedElement("Component", Convert.ToString(row[2]));
                if (null != component)
                {
                    component.AddChild(wixClass);
                }
                else
                {
                    this.core.OnMessage(WixWarnings.ExpectedForeignRow(row.SourceLineNumbers, table.Name, row.GetPrimaryKey(DecompilerCore.PrimaryKeyDelimiter), "Component_", Convert.ToString(row[2]), "Component"));
                }

                this.core.IndexElement(row, wixClass);
            }
        }
        private void MutateComponents()
        {
            if (suppressVB6COMElements)
            {
                // Search for VB6 specific COM registrations
                foreach (Wix.Component component in this.components)
                {
                    ArrayList vb6RegistryValues = new ArrayList();

                    foreach (Wix.RegistryValue registryValue in component[typeof(Wix.RegistryValue)])
                    {
                        if (Wix.RegistryValue.ActionType.write == registryValue.Action && Wix.RegistryRootType.HKCR == registryValue.Root)
                        {
                            string[] parts = registryValue.Key.Split('\\');

                            if (String.Equals(parts[0], "CLSID", StringComparison.OrdinalIgnoreCase))
                            {
                                // Search for the VB6 CLSID {D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731}
                                if (2 <= parts.Length)
                                {
                                    if (String.Equals(parts[1], "{D5DE8D20-5BB8-11D1-A1E3-00A0C90F2731}", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (!vb6RegistryValues.Contains(registryValue))
                                        {
                                            vb6RegistryValues.Add(registryValue);
                                        }
                                    }
                                }
                            }
                            else if (String.Equals(parts[0], "TypeLib", StringComparison.OrdinalIgnoreCase))
                            {
                                // Search for the VB6 TypeLibs {EA544A21-C82D-11D1-A3E4-00A0C90AEA82} or {000204EF-0000-0000-C000-000000000046}
                                if (2 <= parts.Length)
                                {
                                    if (String.Equals(parts[1], "{EA544A21-C82D-11D1-A3E4-00A0C90AEA82}", StringComparison.OrdinalIgnoreCase) ||
                                        String.Equals(parts[1], "{000204EF-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (!vb6RegistryValues.Contains(registryValue))
                                        {
                                            vb6RegistryValues.Add(registryValue);
                                        }
                                    }
                                }
                            }
                            else if (String.Equals(parts[0], "Interface", StringComparison.OrdinalIgnoreCase))
                            {
                                // Search for any Interfaces that reference the VB6 TypeLibs {EA544A21-C82D-11D1-A3E4-00A0C90AEA82} or {000204EF-0000-0000-C000-000000000046}
                                if (3 <= parts.Length)
                                {
                                    if (String.Equals(parts[2], "TypeLib", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (String.Equals(registryValue.Value, "{EA544A21-C82D-11D1-A3E4-00A0C90AEA82}", StringComparison.OrdinalIgnoreCase) ||
                                            String.Equals(registryValue.Value, "{000204EF-0000-0000-C000-000000000046}", StringComparison.OrdinalIgnoreCase))
                                        {
                                            // Having found a match we have to loop through again finding the matching Interface entries
                                            foreach (Wix.RegistryValue regValue in component[typeof(Wix.RegistryValue)])
                                            {
                                                if (Wix.RegistryValue.ActionType.write == regValue.Action && Wix.RegistryRootType.HKCR == regValue.Root)
                                                {
                                                    string[] rvparts = regValue.Key.Split('\\');
                                                    if (String.Equals(rvparts[0], "Interface", StringComparison.OrdinalIgnoreCase))
                                                    {
                                                        if (2 <= rvparts.Length)
                                                        {
                                                            if (String.Equals(rvparts[1], parts[1], StringComparison.OrdinalIgnoreCase))
                                                            {
                                                                if (!vb6RegistryValues.Contains(regValue))
                                                                {
                                                                    vb6RegistryValues.Add(regValue);
                                                                }
                                                            }
                                                        }
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }

                    // Remove all the VB6 specific COM registry values
                    foreach (Object entry in vb6RegistryValues)
                    {
                        component.RemoveChild((Wix.RegistryValue)entry);
                    }
                }
            }

            foreach (Wix.Component component in this.components)
            {
                SortedList indexedElements = CollectionsUtil.CreateCaseInsensitiveSortedList();
                SortedList indexedRegistryValues = CollectionsUtil.CreateCaseInsensitiveSortedList();
                List<Wix.RegistryValue> duplicateRegistryValues = new List<Wix.RegistryValue>();

                // index all the File elements
                foreach (Wix.File file in component[typeof(Wix.File)])
                {
                    indexedElements.Add(String.Concat("file/", file.Id), file);
                }

                // group all the registry values by the COM element they would correspond to and
                // create a COM element for each group
                foreach (Wix.RegistryValue registryValue in component[typeof(Wix.RegistryValue)])
                {
                    if (!String.IsNullOrEmpty(registryValue.Key) && Wix.RegistryValue.ActionType.write == registryValue.Action && Wix.RegistryRootType.HKCR == registryValue.Root && Wix.RegistryValue.TypeType.@string == registryValue.Type)
                    {
                        string index = null;
                        string[] parts = registryValue.Key.Split('\\');

                        // create a COM element for COM registration and index it
                        if (1 <= parts.Length)
                        {
                            if (String.Equals(parts[0], "AppID", StringComparison.OrdinalIgnoreCase))
                            {
                                // only work with GUID AppIds here
                                if (2 <= parts.Length && parts[1].StartsWith("{", StringComparison.Ordinal) && parts[1].EndsWith("}", StringComparison.Ordinal))
                                {
                                    index = String.Concat(parts[0], '/', parts[1]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Wix.AppId appId = new Wix.AppId();
                                        appId.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                        indexedElements.Add(index, appId);
                                    }
                                }
                            }
                            else if (String.Equals(parts[0], "CLSID", StringComparison.OrdinalIgnoreCase))
                            {
                                if (2 <= parts.Length)
                                {
                                    index = String.Concat(parts[0], '/', parts[1]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Wix.Class wixClass = new Wix.Class();
                                        wixClass.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                        indexedElements.Add(index, wixClass);
                                    }
                                }
                            }
                            else if (String.Equals(parts[0], "Component Categories", StringComparison.OrdinalIgnoreCase))
                            {
                                // If this is the .NET Component Category it should not end up in the authoring. Therefore, add
                                // the registry key to the duplicate list to ensure it gets removed later.
                                if (String.Equals(parts[1], "{62C8FE65-4EBB-45e7-B440-6E39B2CDBF29}", StringComparison.OrdinalIgnoreCase))
                                {
                                    duplicateRegistryValues.Add(registryValue);
                                }
                                else
                                {
                                    // TODO: add support for Component Categories to the compiler.
                                }
                            }
                            else if (String.Equals(parts[0], "Interface", StringComparison.OrdinalIgnoreCase))
                            {
                                if (2 <= parts.Length)
                                {
                                    index = String.Concat(parts[0], '/', parts[1]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Wix.Interface wixInterface = new Wix.Interface();
                                        wixInterface.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                        indexedElements.Add(index, wixInterface);
                                    }
                                }
                            }
                            else if (String.Equals(parts[0], "TypeLib", StringComparison.Ordinal))
                            {
                                if (3 <= parts.Length)
                                {
                                    // use a special index to ensure progIds are processed before classes
                                    index = String.Concat(".typelib/", parts[1], '/', parts[2]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Version version = TypeLibraryHarvester.ParseHexVersion(parts[2]);
                                        if (version != null)
                                        {
                                            Wix.TypeLib typeLib = new Wix.TypeLib();
                                            typeLib.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                            typeLib.MajorVersion = version.Major;
                                            typeLib.MinorVersion = version.Minor;
                                            indexedElements.Add(index, typeLib);
                                        }
                                        else // not a valid type library registry value
                                        {
                                            index = null;
                                        }
                                    }
                                }
                            }
                            else if (parts[0].StartsWith(".", StringComparison.Ordinal))
                            {
                                // extension
                            }
                            else // ProgId (hopefully)
                            {
                                // use a special index to ensure progIds are processed before classes
                                index = String.Concat(".progid/", parts[0]);

                                if (!indexedElements.Contains(index))
                                {
                                    Wix.ProgId progId = new Wix.ProgId();
                                    progId.Id = parts[0];
                                    indexedElements.Add(index, progId);
                                }
                            }
                        }

                        // index the RegistryValue element according to the COM element it corresponds to
                        if (null != index)
                        {
                            SortedList registryValues = (SortedList)indexedRegistryValues[index];

                            if (null == registryValues)
                            {
                                registryValues = CollectionsUtil.CreateCaseInsensitiveSortedList();
                                indexedRegistryValues.Add(index, registryValues);
                            }

                            try
                            {
                                registryValues.Add(String.Concat(registryValue.Key, '/', registryValue.Name), registryValue);
                            }
                            catch (ArgumentException)
                            {
                                duplicateRegistryValues.Add(registryValue);

                                if (String.IsNullOrEmpty(registryValue.Value))
                                {
                                    this.Core.OnMessage(UtilWarnings.DuplicateDllRegistryEntry(String.Concat(registryValue.Key, '/', registryValue.Name), component.Id));
                                }
                                else
                                {
                                    this.Core.OnMessage(UtilWarnings.DuplicateDllRegistryEntry(String.Concat(registryValue.Key, '/', registryValue.Name), registryValue.Value, component.Id));
                                }
                            }
                        }
                    }
                }

                foreach (Wix.RegistryValue removeRegistryEntry in duplicateRegistryValues)
                {
                    component.RemoveChild(removeRegistryEntry);
                }

                // set various values on the COM elements from their corresponding registry values
                Hashtable indexedProcessedRegistryValues = new Hashtable();
                foreach (DictionaryEntry entry in indexedRegistryValues)
                {
                    Wix.ISchemaElement element = (Wix.ISchemaElement)indexedElements[entry.Key];
                    string parentIndex = null;
                    SortedList registryValues = (SortedList)entry.Value;

                    // element-specific variables (for really tough situations)
                    string classAppId = null;
                    bool threadingModelSet = false;

                    foreach (Wix.RegistryValue registryValue in registryValues.Values)
                    {
                        string[] parts = registryValue.Key.ToLower(CultureInfo.InvariantCulture).Split('\\');
                        bool processed = false;

                        if (element is Wix.AppId)
                        {
                            Wix.AppId appId = (Wix.AppId)element;

                            if (2 == parts.Length)
                            {
                                if (null == registryValue.Name)
                                {
                                    appId.Description = registryValue.Value;
                                    processed = true;
                                }
                            }
                        }
                        else if (element is Wix.Class)
                        {
                            Wix.Class wixClass = (Wix.Class)element;

                            if (2 == parts.Length)
                            {
                                if (null == registryValue.Name)
                                {
                                    wixClass.Description = registryValue.Value;
                                    processed = true;
                                }
                                else if (String.Equals(registryValue.Name, "AppID", StringComparison.OrdinalIgnoreCase))
                                {
                                    classAppId = registryValue.Value;
                                    processed = true;
                                }
                            }
                            else if (3 == parts.Length)
                            {
                                Wix.Class.ContextType contextType = Wix.Class.ContextType.None;

                                switch (parts[2])
                                {
                                    case "control":
                                        wixClass.Control = Wix.YesNoType.yes;
                                        processed = true;
                                        break;
                                    case "inprochandler":
                                        if (null == registryValue.Name)
                                        {
                                            if (null == wixClass.Handler)
                                            {
                                                wixClass.Handler = "1";
                                                processed = true;
                                            }
                                            else if ("2" == wixClass.Handler)
                                            {
                                                wixClass.Handler = "3";
                                                processed = true;
                                            }
                                        }
                                        break;
                                    case "inprochandler32":
                                        if (null == registryValue.Name)
                                        {
                                            if (null == wixClass.Handler)
                                            {
                                                wixClass.Handler = "2";
                                                processed = true;
                                            }
                                            else if ("1" == wixClass.Handler)
                                            {
                                                wixClass.Handler = "3";
                                                processed = true;
                                            }
                                        }
                                        break;
                                    case "inprocserver":
                                        contextType = Wix.Class.ContextType.InprocServer;
                                        break;
                                    case "inprocserver32":
                                        contextType = Wix.Class.ContextType.InprocServer32;
                                        break;
                                    case "insertable":
                                        wixClass.Insertable = Wix.YesNoType.yes;
                                        processed = true;
                                        break;
                                    case "localserver":
                                        contextType = Wix.Class.ContextType.LocalServer;
                                        break;
                                    case "localserver32":
                                        contextType = Wix.Class.ContextType.LocalServer32;
                                        break;
                                    case "progid":
                                        if (null == registryValue.Name)
                                        {
                                            Wix.ProgId progId = (Wix.ProgId)indexedElements[String.Concat(".progid/", registryValue.Value)];

                                            // verify that the versioned ProgId appears under this Class element
                                            // if not, toss the entire element
                                            if (null == progId || wixClass != progId.ParentElement)
                                            {
                                                element = null;
                                            }
                                            else
                                            {
                                                processed = true;
                                            }
                                        }
                                        break;
                                    case "programmable":
                                        wixClass.Programmable = Wix.YesNoType.yes;
                                        processed = true;
                                        break;
                                    case "typelib":
                                        if (null == registryValue.Name)
                                        {
                                            foreach (DictionaryEntry indexedEntry in indexedElements)
                                            {
                                                string key = (string)indexedEntry.Key;
                                                Wix.ISchemaElement possibleTypeLib = (Wix.ISchemaElement)indexedEntry.Value;

                                                if (key.StartsWith(".typelib/", StringComparison.Ordinal) &&
                                                    0 == String.Compare(key, 9, registryValue.Value, 0, registryValue.Value.Length, StringComparison.OrdinalIgnoreCase))
                                                {
                                                    // ensure the TypeLib is nested under the same thing we want the Class under
                                                    if (null == parentIndex || indexedElements[parentIndex] == possibleTypeLib.ParentElement)
                                                    {
                                                        parentIndex = key;
                                                        processed = true;
                                                    }
                                                }
                                            }
                                        }
                                        break;
                                    case "version":
                                        if (null == registryValue.Name)
                                        {
                                            wixClass.Version = registryValue.Value;
                                            processed = true;
                                        }
                                        break;
                                    case "versionindependentprogid":
                                        if (null == registryValue.Name)
                                        {
                                            Wix.ProgId progId = (Wix.ProgId)indexedElements[String.Concat(".progid/", registryValue.Value)];

                                            // verify that the version independent ProgId appears somewhere
                                            // under this Class element - if not, toss the entire element
                                            if (null == progId || wixClass != progId.ParentElement)
                                            {
                                                // check the parent of the parent
                                                if (null == progId || null == progId.ParentElement || wixClass != progId.ParentElement.ParentElement)
                                                {
                                                    element = null;
                                                }
                                            }

                                            processed = true;
                                        }
                                        break;
                                }

                                if (Wix.Class.ContextType.None != contextType)
                                {
                                    wixClass.Context |= contextType;

                                    if (null == registryValue.Name)
                                    {
                                        if ((registryValue.Value.StartsWith("[!", StringComparison.Ordinal) || registryValue.Value.StartsWith("[#", StringComparison.Ordinal))
                                            && registryValue.Value.EndsWith("]", StringComparison.Ordinal))
                                        {
                                            parentIndex = String.Concat("file/", registryValue.Value.Substring(2, registryValue.Value.Length - 3));
                                            processed = true;
                                        }
                                        else if (String.Equals(Path.GetFileName(registryValue.Value), "mscoree.dll", StringComparison.OrdinalIgnoreCase))
                                        {
                                            wixClass.ForeignServer = "mscoree.dll";
                                            processed = true;
                                        }
                                        else if (String.Equals(Path.GetFileName(registryValue.Value), "msvbvm60.dll", StringComparison.OrdinalIgnoreCase))
                                        {
                                            wixClass.ForeignServer = "msvbvm60.dll";
                                            processed = true;
                                        }
                                        else
                                        {
                                            // Some servers are specifying relative paths (which the above code doesn't find)
                                            // If there's any ambiguity leave it alone and let the developer figure it out when it breaks in the compiler

                                            bool possibleDuplicate = false;
                                            string possibleParentIndex = null;

                                            foreach (Wix.File file in this.files)
                                            {
                                                if (String.Equals(registryValue.Value, Path.GetFileName(file.Source), StringComparison.OrdinalIgnoreCase))
                                                {
                                                    if (null == possibleParentIndex)
                                                    {
                                                        possibleParentIndex = String.Concat("file/", file.Id);
                                                    }
                                                    else
                                                    {
                                                        possibleDuplicate = true;
                                                        break;
                                                    }
                                                }
                                            }

                                            if (!possibleDuplicate)
                                            {
                                                if (null == possibleParentIndex)
                                                {
                                                    wixClass.ForeignServer = registryValue.Value;
                                                    processed = true;
                                                }
                                                else
                                                {
                                                    parentIndex = possibleParentIndex;
                                                    wixClass.RelativePath = Microsoft.Tools.WindowsInstallerXml.Serialize.YesNoType.yes;
                                                    processed = true;
                                                }
                                            }
                                        }
                                    }
                                    else if (String.Equals(registryValue.Name, "ThreadingModel", StringComparison.OrdinalIgnoreCase))
                                    {
                                        Wix.Class.ThreadingModelType threadingModel;

                                        if (String.Equals(registryValue.Value, "apartment", StringComparison.OrdinalIgnoreCase))
                                        {
                                            threadingModel = Wix.Class.ThreadingModelType.apartment;
                                            processed = true;
                                        }
                                        else if (String.Equals(registryValue.Value, "both", StringComparison.OrdinalIgnoreCase))
                                        {
                                            threadingModel = Wix.Class.ThreadingModelType.both;
                                            processed = true;
                                        }
                                        else if (String.Equals(registryValue.Value, "free", StringComparison.OrdinalIgnoreCase))
                                        {
                                            threadingModel = Wix.Class.ThreadingModelType.free;
                                            processed = true;
                                        }
                                        else if (String.Equals(registryValue.Value, "neutral", StringComparison.OrdinalIgnoreCase))
                                        {
                                            threadingModel = Wix.Class.ThreadingModelType.neutral;
                                            processed = true;
                                        }
                                        else if (String.Equals(registryValue.Value, "rental", StringComparison.OrdinalIgnoreCase))
                                        {
                                            threadingModel = Wix.Class.ThreadingModelType.rental;
                                            processed = true;
                                        }
                                        else if (String.Equals(registryValue.Value, "single", StringComparison.OrdinalIgnoreCase))
                                        {
                                            threadingModel = Wix.Class.ThreadingModelType.single;
                                            processed = true;
                                        }
                                        else
                                        {
                                            continue;
                                        }

                                        if (!threadingModelSet || wixClass.ThreadingModel == threadingModel)
                                        {
                                            wixClass.ThreadingModel = threadingModel;
                                            threadingModelSet = true;
                                        }
                                        else
                                        {
                                            element = null;
                                            break;
                                        }
                                    }
                                }
                            }
                            else if (4 == parts.Length)
                            {
                                if (String.Equals(parts[2], "implemented categories", StringComparison.Ordinal))
                                {
                                    switch (parts[3])
                                    {
                                        case "{7dd95801-9882-11cf-9fa9-00aa006c42c4}":
                                            wixClass.SafeForScripting = Wix.YesNoType.yes;
                                            processed = true;
                                            break;
                                        case "{7dd95802-9882-11cf-9fa9-00aa006c42c4}":
                                            wixClass.SafeForInitializing = Wix.YesNoType.yes;
                                            processed = true;
                                            break;
                                    }
                                }
                            }
                        }
                        else if (element is Wix.Interface)
                        {
                            Wix.Interface wixInterface = (Wix.Interface)element;

                            if (2 == parts.Length && null == registryValue.Name)
                            {
                                wixInterface.Name = registryValue.Value;
                                processed = true;
                            }
                            else if (3 == parts.Length)
                            {
                                switch (parts[2])
                                {
                                    case "proxystubclsid":
                                        if (null == registryValue.Name)
                                        {
                                            wixInterface.ProxyStubClassId = registryValue.Value.ToUpper(CultureInfo.InvariantCulture);
                                            processed = true;
                                        }
                                        break;
                                    case "proxystubclsid32":
                                        if (null == registryValue.Name)
                                        {
                                            wixInterface.ProxyStubClassId32 = registryValue.Value.ToUpper(CultureInfo.InvariantCulture);
                                            processed = true;
                                        }
                                        break;
                                    case "nummethods":
                                        if (null == registryValue.Name)
                                        {
                                            wixInterface.NumMethods = Convert.ToInt32(registryValue.Value, CultureInfo.InvariantCulture);
                                            processed = true;
                                        }
                                        break;
                                    case "typelib":
                                        if (String.Equals("Version", registryValue.Name, StringComparison.OrdinalIgnoreCase))
                                        {
                                            parentIndex = String.Concat(parentIndex, registryValue.Value);
                                            processed = true;
                                        }
                                        else if (null == registryValue.Name) // TypeLib guid
                                        {
                                            parentIndex = String.Concat(".typelib/", registryValue.Value, '/', parentIndex);
                                            processed = true;
                                        }
                                        break;
                                }
                            }
                        }
                        else if (element is Wix.ProgId)
                        {
                            Wix.ProgId progId = (Wix.ProgId)element;

                            if (null == registryValue.Name)
                            {
                                if (1 == parts.Length)
                                {
                                    progId.Description = registryValue.Value;
                                    processed = true;
                                }
                                else if (2 == parts.Length)
                                {
                                    if (String.Equals(parts[1], "CLSID", StringComparison.OrdinalIgnoreCase))
                                    {
                                        parentIndex = String.Concat("CLSID/", registryValue.Value);
                                        processed = true;
                                    }
                                    else if (String.Equals(parts[1], "CurVer", StringComparison.OrdinalIgnoreCase))
                                    {
                                        // If a progId points to its own ProgId with CurVer, it isn't meaningful, so ignore it
                                        if (!String.Equals(progId.Id, registryValue.Value, StringComparison.OrdinalIgnoreCase))
                                        {
                                            // this registry value should usually be processed second so the
                                            // version independent ProgId should be under the versioned one
                                            parentIndex = String.Concat(".progid/", registryValue.Value);
                                            processed = true;
                                        }
                                    }
                                }
                            }
                        }
                        else if (element is Wix.TypeLib)
                        {
                            Wix.TypeLib typeLib = (Wix.TypeLib)element;

                            if (null == registryValue.Name)
                            {
                                if (3 == parts.Length)
                                {
                                    typeLib.Description = registryValue.Value;
                                    processed = true;
                                }
                                else if (4 == parts.Length)
                                {
                                    if (String.Equals(parts[3], "flags", StringComparison.OrdinalIgnoreCase))
                                    {
                                        int flags = Convert.ToInt32(registryValue.Value, CultureInfo.InvariantCulture);

                                        if (0x1 == (flags & 0x1))
                                        {
                                            typeLib.Restricted = Wix.YesNoType.yes;
                                        }

                                        if (0x2 == (flags & 0x2))
                                        {
                                            typeLib.Control = Wix.YesNoType.yes;
                                        }

                                        if (0x4 == (flags & 0x4))
                                        {
                                            typeLib.Hidden = Wix.YesNoType.yes;
                                        }

                                        if (0x8 == (flags & 0x8))
                                        {
                                            typeLib.HasDiskImage = Wix.YesNoType.yes;
                                        }

                                        processed = true;
                                    }
                                    else if (String.Equals(parts[3], "helpdir", StringComparison.OrdinalIgnoreCase))
                                    {
                                        if (registryValue.Value.StartsWith("[", StringComparison.Ordinal) && (registryValue.Value.EndsWith("]", StringComparison.Ordinal)
                                            || registryValue.Value.EndsWith("]\\", StringComparison.Ordinal)))
                                        {
                                            typeLib.HelpDirectory = registryValue.Value.Substring(1, registryValue.Value.LastIndexOf(']') - 1);
                                        }
                                        else if (0 == String.Compare(registryValue.Value, Environment.SystemDirectory, StringComparison.OrdinalIgnoreCase)) // VB6 DLLs register their help directory as SystemFolder
                                        {
                                            typeLib.HelpDirectory = "SystemFolder";
                                        }
                                        else if (null != component.Directory) // -sfrag has not been specified
                                        {
                                            typeLib.HelpDirectory = component.Directory;
                                        }
                                        else if (component.ParentElement is Wix.Directory) // -sfrag has been specified
                                        {
                                            typeLib.HelpDirectory = ((Wix.Directory)component.ParentElement).Id;
                                        }
                                        else if (component.ParentElement is Wix.DirectoryRef) // -sfrag has been specified
                                        {
                                            typeLib.HelpDirectory = ((Wix.DirectoryRef)component.ParentElement).Id;
                                        }

                                        //If the helpdir has not matched a known directory, drop it because it cannot be resolved.
                                        processed = true;
                                    }
                                }
                                else if (5 == parts.Length && String.Equals("win32", parts[4], StringComparison.OrdinalIgnoreCase))
                                {
                                    typeLib.Language = Convert.ToInt32(parts[3], CultureInfo.InvariantCulture);

                                    if ((registryValue.Value.StartsWith("[!", StringComparison.Ordinal) || registryValue.Value.StartsWith("[#", StringComparison.Ordinal))
                                        && registryValue.Value.EndsWith("]", StringComparison.Ordinal))
                                    {
                                        parentIndex = String.Concat("file/", registryValue.Value.Substring(2, registryValue.Value.Length - 3));
                                    }

                                    processed = true;
                                }
                            }
                        }

                        // index the processed registry values by their corresponding COM element
                        if (processed)
                        {
                            indexedProcessedRegistryValues.Add(registryValue, element);
                        }
                    }

                    // parent the COM element
                    if (null != element)
                    {
                        if (null != parentIndex)
                        {
                            Wix.IParentElement parentElement = (Wix.IParentElement)indexedElements[parentIndex];

                            if (null != parentElement)
                            {
                                parentElement.AddChild(element);
                            }
                        }
                        else if (0 < indexedProcessedRegistryValues.Count)
                        {
                            component.AddChild(element);
                        }

                        // special handling for AppID since it doesn't fit the general model
                        if (null != classAppId)
                        {
                            Wix.AppId appId = (Wix.AppId)indexedElements[String.Concat("AppID/", classAppId)];

                            // move the Class element under the AppId (and put the AppId under its old parent)
                            if (null != appId)
                            {
                                // move the AppId element
                                ((Wix.IParentElement)appId.ParentElement).RemoveChild(appId);
                                ((Wix.IParentElement)element.ParentElement).AddChild(appId);

                                // move the Class element
                                ((Wix.IParentElement)element.ParentElement).RemoveChild(element);
                                appId.AddChild(element);
                            }
                        }
                    }
                }

                // remove the RegistryValue elements which were converted into COM elements
                // that were successfully nested under the Component element
                foreach (DictionaryEntry entry in indexedProcessedRegistryValues)
                {
                    Wix.ISchemaElement element = (Wix.ISchemaElement)entry.Value;
                    Wix.RegistryValue registryValue = (Wix.RegistryValue)entry.Key;

                    while (null != element)
                    {
                        if (element == component)
                        {
                            ((Wix.IParentElement)registryValue.ParentElement).RemoveChild(registryValue);
                            break;
                        }

                        element = element.ParentElement;
                    }
                }
            }
        }
        /// <summary>
        /// Creates the shim component.
        /// </summary>
        /// <returns>Component for the shim.</returns>
        private Wix.Component GenerateShimComponent()
        {
            Wix.Component shimComponent = new Wix.Component();

            if (Guid.Empty == this.shimGuid)
            {
                this.shimGuid = Guid.NewGuid();
            }

            shimComponent.Id = "ThisApplicationShimDllComponent";
            shimComponent.Guid = this.shimGuid.ToString("B");

            Wix.File file = new Wix.File();
            file.Id = "ThisApplicationShimDll";
            file.Name = String.Concat(Path.GetFileNameWithoutExtension(this.entryFileRelativePath), "Shim.dll");
            file.Vital = Wix.YesNoType.yes;
            file.KeyPath = Wix.YesNoType.yes;
            file.Source = this.shimPath;
            shimComponent.AddChild(file);

            // Add the CLSID and ProgId to the component.
            Wix.Class classId = new Wix.Class();
            classId.Id = this.ShimClsid.ToString("B");
            classId.Context = Wix.Class.ContextType.InprocServer32;
            if (null != this.Description && String.Empty != this.Description)
            {
                classId.Description = this.Description;
            }

            classId.ThreadingModel = Wix.Class.ThreadingModelType.apartment;
            file.AddChild(classId);

            Wix.ProgId progId = new Wix.ProgId();
            progId.Id = this.ShimProgid;
            progId.Description = "Connect Class";
            classId.AddChild(progId);

            // Add the Addin to the extended Office applications.
            foreach (OfficeAddinFabricator.OfficeApplications extendedOfficeApp in this.extendedOfficeApplications)
            {
                Wix.RegistryKey registryKey = new Wix.RegistryKey();
                registryKey.Root = Wix.RegistryRootType.HKMU;
                registryKey.Key = String.Format("Software\\Microsoft\\Office\\{0}\\Addins\\{1}", OfficeAddinFabricator.OfficeApplicationStrings[(int)extendedOfficeApp], this.ShimProgid);
                shimComponent.AddChild(registryKey);

                Wix.RegistryValue registryValue = new Wix.RegistryValue();
                registryValue.Name = "Description";
                registryValue.Value = "[ProductName] v[ProductVersion]";
                registryValue.Type = Wix.RegistryValue.TypeType.@string;
                registryKey.AddChild(registryValue);

                registryValue = new Wix.RegistryValue();
                registryValue.Name = "FriendlyName";
                registryValue.Value = "[ProductName]";
                registryValue.Type = Wix.RegistryValue.TypeType.@string;
                registryKey.AddChild(registryValue);

                registryValue = new Wix.RegistryValue();
                registryValue.Name = "LoadBehavior";
                registryValue.Value = "3";
                registryValue.Type = Wix.RegistryValue.TypeType.integer;
                registryKey.AddChild(registryValue);
            }

            return shimComponent;
        }
Beispiel #4
0
        /// <summary>
        /// Creates the shim component.
        /// </summary>
        /// <returns>Component for the shim.</returns>
        private Wix.Component GenerateShimComponent()
        {
            Wix.Component shimComponent = new Wix.Component();

            if (Guid.Empty == this.shimGuid)
            {
                this.shimGuid = Guid.NewGuid();
            }

            shimComponent.Id   = "ThisApplicationShimDllComponent";
            shimComponent.Guid = this.shimGuid.ToString("B");

            Wix.File file = new Wix.File();
            file.Id      = "ThisApplicationShimDll";
            file.Name    = String.Concat(Path.GetFileNameWithoutExtension(this.entryFileRelativePath), "Shim.dll");
            file.Vital   = Wix.YesNoType.yes;
            file.KeyPath = Wix.YesNoType.yes;
            file.Source  = this.shimPath;
            shimComponent.AddChild(file);

            // Add the CLSID and ProgId to the component.
            Wix.Class classId = new Wix.Class();
            classId.Id      = this.ShimClsid.ToString("B");
            classId.Context = Wix.Class.ContextType.InprocServer32;
            if (null != this.Description && String.Empty != this.Description)
            {
                classId.Description = this.Description;
            }

            classId.ThreadingModel = Wix.Class.ThreadingModelType.apartment;
            file.AddChild(classId);

            Wix.ProgId progId = new Wix.ProgId();
            progId.Id          = this.ShimProgid;
            progId.Description = "Connect Class";
            classId.AddChild(progId);

            // Add the Addin to the extended Office applications.
            foreach (OfficeAddinFabricator.OfficeApplications extendedOfficeApp in this.extendedOfficeApplications)
            {
                Wix.RegistryKey registryKey = new Wix.RegistryKey();
                registryKey.Root = Wix.RegistryRootType.HKMU;
                registryKey.Key  = String.Format("Software\\Microsoft\\Office\\{0}\\Addins\\{1}", OfficeAddinFabricator.OfficeApplicationStrings[(int)extendedOfficeApp], this.ShimProgid);
                shimComponent.AddChild(registryKey);

                Wix.RegistryValue registryValue = new Wix.RegistryValue();
                registryValue.Name  = "Description";
                registryValue.Value = "[ProductName] v[ProductVersion]";
                registryValue.Type  = Wix.RegistryValue.TypeType.@string;
                registryKey.AddChild(registryValue);

                registryValue       = new Wix.RegistryValue();
                registryValue.Name  = "FriendlyName";
                registryValue.Value = "[ProductName]";
                registryValue.Type  = Wix.RegistryValue.TypeType.@string;
                registryKey.AddChild(registryValue);

                registryValue       = new Wix.RegistryValue();
                registryValue.Name  = "LoadBehavior";
                registryValue.Value = "3";
                registryValue.Type  = Wix.RegistryValue.TypeType.integer;
                registryKey.AddChild(registryValue);
            }

            return(shimComponent);
        }
Beispiel #5
0
        /// <summary>
        /// Mutate the components.
        /// </summary>
        private void MutateComponents()
        {
            foreach (Wix.Component component in this.components)
            {
                SortedList indexedElements       = CollectionsUtil.CreateCaseInsensitiveSortedList();
                SortedList indexedRegistryValues = CollectionsUtil.CreateCaseInsensitiveSortedList();

                // index all the File elements
                foreach (Wix.File file in component[typeof(Wix.File)])
                {
                    indexedElements.Add(String.Concat("file/", file.Id), file);
                }

                // group all the registry values by the COM element they would correspond to and
                // create a COM element for each group
                foreach (Wix.RegistryValue registryValue in component[typeof(Wix.RegistryValue)])
                {
                    if (Wix.RegistryValue.ActionType.write == registryValue.Action && Wix.RegistryRootType.HKCR == registryValue.Root && Wix.RegistryValue.TypeType.@string == registryValue.Type)
                    {
                        string   index = null;
                        string[] parts = registryValue.Key.Split('\\');

                        // create a COM element for COM registration and index it
                        if (1 <= parts.Length)
                        {
                            if (0 == String.Compare(parts[0], "AppID", true))
                            {
                                // only work with GUID AppIds here
                                if (2 <= parts.Length && parts[1].StartsWith("{") && parts[1].EndsWith("}"))
                                {
                                    index = String.Concat(parts[0], '/', parts[1]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Wix.AppId appId = new Wix.AppId();
                                        appId.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                        indexedElements.Add(index, appId);
                                    }
                                }
                            }
                            else if (0 == String.Compare(parts[0], "CLSID", true))
                            {
                                if (2 <= parts.Length)
                                {
                                    index = String.Concat(parts[0], '/', parts[1]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Wix.Class wixClass = new Wix.Class();
                                        wixClass.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                        indexedElements.Add(index, wixClass);
                                    }
                                }
                            }
                            else if (0 == String.Compare(parts[0], "Component Categories", true))
                            {
                                // TODO: add support for this to the compiler
                            }
                            else if (0 == String.Compare(parts[0], "Interface", true))
                            {
                                if (2 <= parts.Length)
                                {
                                    index = String.Concat(parts[0], '/', parts[1]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        Wix.Interface wixInterface = new Wix.Interface();
                                        wixInterface.Id = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                        indexedElements.Add(index, wixInterface);
                                    }
                                }
                            }
                            else if (0 == String.Compare(parts[0], "TypeLib"))
                            {
                                if (3 <= parts.Length)
                                {
                                    // use a special index to ensure progIds are processed before classes
                                    index = String.Concat(".typelib/", parts[1], '/', parts[2]);

                                    if (!indexedElements.Contains(index))
                                    {
                                        try
                                        {
                                            // TODO: properly handle hexadecimal in version
                                            Version version = new Version(parts[2]);

                                            Wix.TypeLib typeLib = new Wix.TypeLib();
                                            typeLib.Id           = parts[1].ToUpper(CultureInfo.InvariantCulture);
                                            typeLib.MajorVersion = version.Major;
                                            typeLib.MinorVersion = version.Minor;
                                            indexedElements.Add(index, typeLib);
                                        }
                                        catch // not a valid type library registry value
                                        {
                                            index = null;
                                        }
                                    }
                                }
                            }
                            else if (parts[0].StartsWith("."))
                            {
                                // extension
                            }
                            else // ProgId (hopefully)
                            {
                                // use a special index to ensure progIds are processed before classes
                                index = String.Concat(".progid/", parts[0]);

                                if (!indexedElements.Contains(index))
                                {
                                    Wix.ProgId progId = new Wix.ProgId();
                                    progId.Id = parts[0];
                                    indexedElements.Add(index, progId);
                                }
                            }
                        }

                        // index the RegistryValue element according to the COM element it corresponds to
                        if (null != index)
                        {
                            SortedList registryValues = (SortedList)indexedRegistryValues[index];

                            if (null == registryValues)
                            {
                                registryValues = CollectionsUtil.CreateCaseInsensitiveSortedList();
                                indexedRegistryValues.Add(index, registryValues);
                            }

                            registryValues.Add(String.Concat(registryValue.Key, '/', registryValue.Name), registryValue);
                        }
                    }
                }

                // set various values on the COM elements from their corresponding registry values
                Hashtable indexedProcessedRegistryValues = new Hashtable();
                foreach (DictionaryEntry entry in indexedRegistryValues)
                {
                    Wix.ISchemaElement element        = (Wix.ISchemaElement)indexedElements[entry.Key];
                    string             parentIndex    = null;
                    SortedList         registryValues = (SortedList)entry.Value;

                    // element-specific variables (for really tough situations)
                    string classAppId        = null;
                    bool   threadingModelSet = false;

                    foreach (Wix.RegistryValue registryValue in registryValues.Values)
                    {
                        string[] parts     = registryValue.Key.ToLower(CultureInfo.InvariantCulture).Split('\\');
                        bool     processed = false;

                        if (element is Wix.AppId)
                        {
                            Wix.AppId appId = (Wix.AppId)element;

                            if (2 == parts.Length)
                            {
                                if (null == registryValue.Name)
                                {
                                    appId.Description = registryValue.Value;
                                    processed         = true;
                                }
                            }
                        }
                        else if (element is Wix.Class)
                        {
                            Wix.Class wixClass = (Wix.Class)element;

                            if (2 == parts.Length)
                            {
                                if (null == registryValue.Name)
                                {
                                    wixClass.Description = registryValue.Value;
                                    processed            = true;
                                }
                                else if (0 == String.Compare(registryValue.Name, "AppID", true))
                                {
                                    classAppId = registryValue.Value;
                                    processed  = true;
                                }
                            }
                            else if (3 == parts.Length)
                            {
                                Wix.Class.ContextType contextType = Wix.Class.ContextType.None;

                                switch (parts[2])
                                {
                                case "inprochandler":
                                    if (null == registryValue.Name)
                                    {
                                        if (null == wixClass.Handler)
                                        {
                                            wixClass.Handler = "1";
                                            processed        = true;
                                        }
                                        else if ("2" == wixClass.Handler)
                                        {
                                            wixClass.Handler = "3";
                                            processed        = true;
                                        }
                                    }
                                    break;

                                case "inprochandler32":
                                    if (null == registryValue.Name)
                                    {
                                        if (null == wixClass.Handler)
                                        {
                                            wixClass.Handler = "2";
                                            processed        = true;
                                        }
                                        else if ("1" == wixClass.Handler)
                                        {
                                            wixClass.Handler = "3";
                                            processed        = true;
                                        }
                                    }
                                    break;

                                case "inprocserver":
                                    contextType = Wix.Class.ContextType.InprocServer;
                                    break;

                                case "inprocserver32":
                                    contextType = Wix.Class.ContextType.InprocServer32;
                                    break;

                                case "localserver":
                                    contextType = Wix.Class.ContextType.LocalServer;
                                    break;

                                case "localserver32":
                                    contextType = Wix.Class.ContextType.LocalServer32;
                                    break;

                                case "progid":
                                    if (null == registryValue.Name)
                                    {
                                        Wix.ProgId progId = (Wix.ProgId)indexedElements[String.Concat(".progid/", registryValue.Value)];

                                        // verify that the versioned ProgId appears under this Class element
                                        // if not, toss the entire element
                                        if (null == progId || wixClass != progId.ParentElement)
                                        {
                                            element = null;
                                        }
                                        else
                                        {
                                            processed = true;
                                        }
                                    }
                                    break;

                                case "typelib":
                                    if (null == registryValue.Name)
                                    {
                                        foreach (DictionaryEntry indexedEntry in indexedElements)
                                        {
                                            string             key             = (string)indexedEntry.Key;
                                            Wix.ISchemaElement possibleTypeLib = (Wix.ISchemaElement)indexedEntry.Value;

                                            if (key.StartsWith(".typelib/") &&
                                                0 == String.Compare(key, 9, registryValue.Value, 0, registryValue.Value.Length, true))
                                            {
                                                // ensure the TypeLib is nested under the same thing we want the Class under
                                                if (null == parentIndex || indexedElements[parentIndex] == possibleTypeLib.ParentElement)
                                                {
                                                    parentIndex = key;
                                                    processed   = true;
                                                }
                                            }
                                        }
                                    }
                                    break;

                                case "version":
                                    if (null == registryValue.Name)
                                    {
                                        wixClass.Version = registryValue.Value;
                                        processed        = true;
                                    }
                                    break;

                                case "versionindependentprogid":
                                    if (null == registryValue.Name)
                                    {
                                        Wix.ProgId progId = (Wix.ProgId)indexedElements[String.Concat(".progid/", registryValue.Value)];

                                        // verify that the version independent ProgId appears somewhere
                                        // under this Class element - if not, toss the entire element
                                        if (null == progId || wixClass != progId.ParentElement)
                                        {
                                            // check the parent of the parent
                                            if (null == progId || null == progId.ParentElement || wixClass != progId.ParentElement.ParentElement)
                                            {
                                                element = null;
                                            }
                                        }

                                        processed = true;
                                    }
                                    break;
                                }

                                if (Wix.Class.ContextType.None != contextType)
                                {
                                    wixClass.Context |= contextType;

                                    if (null == registryValue.Name)
                                    {
                                        if ((registryValue.Value.StartsWith("[!") || registryValue.Value.StartsWith("[#")) && registryValue.Value.EndsWith("]"))
                                        {
                                            parentIndex = String.Concat("file/", registryValue.Value.Substring(2, registryValue.Value.Length - 3));
                                            processed   = true;
                                        }
                                    }
                                    else if (0 == String.Compare(registryValue.Name, "ThreadingModel", true))
                                    {
                                        Wix.Class.ThreadingModelType threadingModel;

                                        switch (registryValue.Value.ToLower(CultureInfo.InvariantCulture))
                                        {
                                        case "apartment":
                                            threadingModel = Wix.Class.ThreadingModelType.apartment;
                                            processed      = true;
                                            break;

                                        case "both":
                                            threadingModel = Wix.Class.ThreadingModelType.both;
                                            processed      = true;
                                            break;

                                        case "free":
                                            threadingModel = Wix.Class.ThreadingModelType.free;
                                            processed      = true;
                                            break;

                                        case "neutral":
                                            threadingModel = Wix.Class.ThreadingModelType.neutral;
                                            processed      = true;
                                            break;

                                        case "rental":
                                            threadingModel = Wix.Class.ThreadingModelType.rental;
                                            processed      = true;
                                            break;

                                        case "single":
                                            threadingModel = Wix.Class.ThreadingModelType.single;
                                            processed      = true;
                                            break;

                                        default:
                                            continue;
                                        }

                                        if (!threadingModelSet || wixClass.ThreadingModel == threadingModel)
                                        {
                                            wixClass.ThreadingModel = threadingModel;
                                            threadingModelSet       = true;
                                        }
                                        else
                                        {
                                            element = null;
                                            break;
                                        }
                                    }
                                }
                            }
                        }
                        else if (element is Wix.Interface)
                        {
                            Wix.Interface wixInterface = (Wix.Interface)element;

                            if (2 == parts.Length && null == registryValue.Name)
                            {
                                wixInterface.Name = registryValue.Value;
                                processed         = true;
                            }
                            else if (3 == parts.Length)
                            {
                                switch (parts[2])
                                {
                                case "proxystubclsid":
                                    if (null == registryValue.Name)
                                    {
                                        wixInterface.ProxyStubClassId = registryValue.Value.ToUpper(CultureInfo.InvariantCulture);
                                        processed = true;
                                    }
                                    break;

                                case "proxystubclsid32":
                                    if (null == registryValue.Name)
                                    {
                                        wixInterface.ProxyStubClassId32 = registryValue.Value.ToUpper(CultureInfo.InvariantCulture);
                                        processed = true;
                                    }
                                    break;

                                case "nummethods":
                                    if (null == registryValue.Name)
                                    {
                                        wixInterface.NumMethods = Convert.ToInt32(registryValue.Value, CultureInfo.InvariantCulture);
                                        processed = true;
                                    }
                                    break;

                                case "typelib":
                                    if (0 == String.Compare("Version", registryValue.Name, true))
                                    {
                                        parentIndex = String.Concat(parentIndex, registryValue.Value);
                                        processed   = true;
                                    }
                                    else if (null == registryValue.Name)     // TypeLib guid
                                    {
                                        parentIndex = String.Concat(".typelib/", registryValue.Value, '/', parentIndex);
                                        processed   = true;
                                    }
                                    break;
                                }
                            }
                        }
                        else if (element is Wix.ProgId)
                        {
                            Wix.ProgId progId = (Wix.ProgId)element;

                            if (null == registryValue.Name)
                            {
                                if (1 == parts.Length)
                                {
                                    progId.Description = registryValue.Value;
                                    processed          = true;
                                }
                                else if (2 == parts.Length)
                                {
                                    if (0 == String.Compare(parts[1], "CLSID", true))
                                    {
                                        parentIndex = String.Concat("CLSID/", registryValue.Value);
                                        processed   = true;
                                    }
                                    else if (0 == String.Compare(parts[1], "CurVer", true))
                                    {
                                        // this registry value should usually be processed second so the
                                        // version independent ProgId should be under the versioned one
                                        parentIndex = String.Concat(".progid/", registryValue.Value);
                                        processed   = true;
                                    }
                                }
                            }
                        }
                        else if (element is Wix.TypeLib)
                        {
                            Wix.TypeLib typeLib = (Wix.TypeLib)element;

                            if (null == registryValue.Name)
                            {
                                if (3 == parts.Length)
                                {
                                    typeLib.Description = registryValue.Value;
                                    processed           = true;
                                }
                                else if (4 == parts.Length)
                                {
                                    switch (parts[3].ToLower(CultureInfo.InvariantCulture))
                                    {
                                    case "flags":
                                        int flags = Convert.ToInt32(registryValue.Value, CultureInfo.InvariantCulture);

                                        if (0x1 == (flags & 0x1))
                                        {
                                            typeLib.Restricted = Wix.YesNoType.yes;
                                        }

                                        if (0x2 == (flags & 0x2))
                                        {
                                            typeLib.Control = Wix.YesNoType.yes;
                                        }

                                        if (0x4 == (flags & 0x4))
                                        {
                                            typeLib.Hidden = Wix.YesNoType.yes;
                                        }

                                        if (0x8 == (flags & 0x8))
                                        {
                                            typeLib.HasDiskImage = Wix.YesNoType.yes;
                                        }

                                        processed = true;
                                        break;

                                    case "helpdir":
                                        if (registryValue.Value.StartsWith("[") && (registryValue.Value.EndsWith("]") || registryValue.Value.EndsWith("]\\")))
                                        {
                                            typeLib.HelpDirectory = registryValue.Value.Substring(1, registryValue.Value.LastIndexOf(']') - 1);
                                            processed             = true;
                                        }
                                        break;
                                    }
                                }
                                else if (5 == parts.Length && 0 == String.Compare("win32", parts[4], true))
                                {
                                    typeLib.Language = Convert.ToInt32(parts[3], CultureInfo.InvariantCulture);

                                    if ((registryValue.Value.StartsWith("[!") || registryValue.Value.StartsWith("[#")) && registryValue.Value.EndsWith("]"))
                                    {
                                        parentIndex = String.Concat("file/", registryValue.Value.Substring(2, registryValue.Value.Length - 3));
                                    }

                                    processed = true;
                                }
                            }
                        }

                        // index the processed registry values by their corresponding COM element
                        if (processed)
                        {
                            indexedProcessedRegistryValues.Add(registryValue, element);
                        }
                    }

                    // parent the COM element
                    if (null != element)
                    {
                        if (null != parentIndex)
                        {
                            Wix.IParentElement parentElement = (Wix.IParentElement)indexedElements[parentIndex];

                            if (null != parentElement)
                            {
                                parentElement.AddChild(element);
                            }
                        }
                        else
                        {
                            component.AddChild(element);
                        }

                        // special handling for AppID since it doesn't fit the general model
                        if (null != classAppId)
                        {
                            Wix.AppId appId = (Wix.AppId)indexedElements[String.Concat("AppID/", classAppId)];

                            // move the Class element under the AppId (and put the AppId under its old parent)
                            if (null != appId)
                            {
                                // move the AppId element
                                ((Wix.IParentElement)appId.ParentElement).RemoveChild(appId);
                                ((Wix.IParentElement)element.ParentElement).AddChild(appId);

                                // move the Class element
                                ((Wix.IParentElement)element.ParentElement).RemoveChild(element);
                                appId.AddChild(element);
                            }
                        }
                    }
                }

                // remove the RegistryValue elements which were converted into COM elements
                // that were successfully nested under the Component element
                foreach (DictionaryEntry entry in indexedProcessedRegistryValues)
                {
                    Wix.ISchemaElement element       = (Wix.ISchemaElement)entry.Value;
                    Wix.RegistryValue  registryValue = (Wix.RegistryValue)entry.Key;

                    while (null != element)
                    {
                        if (element == component)
                        {
                            ((Wix.IParentElement)registryValue.ParentElement).RemoveChild(registryValue);
                            break;
                        }

                        element = element.ParentElement;
                    }
                }
            }
        }